Serializing polymorphic collections with ServiceStack.Text - json

We're in a process of switching from Json.NET to ServiceStack.Text and I came across an issue with serialization of polymorphic collections.
In JSON.NET I used to create a custom JsonCreationConverter and overriding the Create() method to select the type I want to create - as outlined here:
http://dotnetbyexample.blogspot.co.uk/2012/02/json-deserialization-with-jsonnet-class.html
The collection in question is List<ItemBase> which can contain FlightItem or CarHireItem objects.
This is my version of the Create() method for JSON.NET:
protected override ItemBase Create(Type objectType, JObject jsonObject)
{
var itemType = jsonObject["Type"].ToString();
switch (itemType)
{
case "flight":
return new FlightItem();
case "carhire":
return new CarHireItem();
default:
return null;
}
}
Is that possible with ServiceStack?
Serialization and deserialization in ServiceStack for polymorphic collections works, however, it appends the object type to the JSON output, e.g.
"__type" : "TestProject.Model.FlightItem, TestProject"
This means that I need to supply the type when posting JSON and I'm not too keen on having the .NET type visible for anyone within the API calls.
Any suggestions? If it's possible to do this in a different way, can you point me to some examples?

Firstly, Interfaces or abstract types in DTOs are a bad idea.
You're now in the strange position where you're trying to support polymorphic types in DTOs, but don't want to provide JSON Serializer-specific info? The reason why you need bespoke code to support polymorphic DTO's is because it's impossible to tell what concrete type should be used based on the wire format, hence why ServiceStack emits the __type property for this purpose.
To avoid these hacks, and have it work equally well in all JSON Serializers, you're better off "flattening" your polymorphic types into a single "flat" DTO and send that across the wire instead. Once you're back in C# you can use code to project it into the ideal types.
ServiceStack does provide some JsConfig<ItemBase>.RawDeserializeFn that will let you do something similar, see the CustomSerializerTests for an example. There's also the JsConfig<ItemBase>.OnDeserializedFn hook that can potentially help, but it's dependent on whether ItemBase contains a complete property list of both concrete types.

Related

How to convert Model to JSON

When I naively use Jackson to convert to JSON i receive this exception:
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.apache.cayenne.access.DefaultDataRowStoreFactory and no properties discovered to create BeanSerializer
Edit: I'd like to do something like this:
ObjectContext context = cayenneRuntime.newContext();
List<User> users = ObjectSelect.query(User.class).select(context);
JsonObject json = Json.mapper.convertValue(obj, Map.class)
Are there any existing solutions? Thanks
Considering that in a general case Cayenne gives you not just objects, but a virtual graph of objects, serialization to JSON becomes a more quirky topic than it initially appears.
The short answer: you'd have manually build JSON for whatever subgraph of your object graph.
While not a direct answer, it may be worth mentioning that Agrest framework (ex. LinkRest) supports rule-based serialization of Cayenne object graphs to JSON. But it is not a standalone component. I.e. it will only work if you use it for your REST services.

Efficient way of parsing Jax-ws Restful Response

I need to parse the jax-ws rest response and I tried the following two ways of parsing the response.Both works good.But I am in need to know the best efficient way of implementation.Please provide me your view.
First Approach:
Use getEntity Object and get the response as Input Stream.
Using Jackson ObjectMapper readValue() -covert the inputstream to java
object.
Using getters and setters of nested java class get the response objects member values.
Second Approach:
Use getEntity Object and get the response as Input Stream and and
convert the Input Stream to String.
Using Google Json API,convert the string to json object.
Using Json parser and get the nested objects member values.
I would say the first approach is better for two reasons:
You don't go through the intermediate process of reading the response payload into String
The setter methods that are called during Jackson deserialization may perform validation on input and throw appropriate exceptions, so you do validation during deserialization.
Maybe not a general answer to this question but another variant of what you're describing under "First approach". I would start with a generic data structure and would only introduce an extra bean if necessary. I wouldn't use String to pass structured data around.
Use jackson to convert the JSON response to a
Map<String,Object> or JsonNode.
Advantage:
You don't need to implement a specialized bean class. Even a very simple bean can become unhandy over time (if format changes or new nested structures are added to the json response, etc.). It also introduces some kind of metaphor to your code which sometimes helps but also can be misleading.
Map<String,Object> is in the JDK and offers a good interface to access data. You don't have to change any interfaces even if the JSON format changes.
You can always pass your data in form of a Map<String,Object>
Disadvantage
Data Encapsulation. The map is a very close representation of the input data and therefore offers not same level of abstraction like a bean.

GWT Autobeans, parsing root-level as Map or List

Autobeans are pretty powerful. Yet, for the life of me, I cannot figure out how to handle root-level JSON maps or lists.
Most of the documentation suggests that you have a defined top level object that can contain a variety of sub-objects (including lists and maps), yet there is no documentation on autobeaning a Map or List.
public interface Types {
List<FieldType> getTypes();
}
public interface TypesAutoBeanFactory extends AutoBeanFactory {
AutoBean<Types> jsonItems();
}
Above is the referenced way to accomplish Lists, where incoming data will look like:
{"types":[{...},{...}]}
Yet, I find this ugly and the REST service should correctly return:
[{...},{...}]
but I cannot find a simple way to handle this with the Autobean framework. Same goes for root-level maps.
Why does this not work and is there an alternative:
public interface TypesAutoBeanFactory extends AutoBeanFactory {
AutoBean<List<FieldType>> jsonItems();
}
AutoBean works by scanning your class for get and set methods (maybe is methods too). List doesn't have those methods.
You could write a patch to hook the inner List parsing methods directly to the outer decode methods of AutoBeanCodex - most of the code you need is in there. Maybe instead of decode(Class type, Splittable input) you could just add decodeList(Splittable input). The result will probably be an actual List instead of an AutoBean.
Another easy way I can see isn't fully autobean solution.
It's obvious, that if string starts with [{, than it's array, so we can use
Object[] array = jsonString.replaceAll("[\[\]]","").split(",");
and then just work with elements of array with autobean.
I use the method you describe to decode JSON payloads containing a list under a single key.
This answer also explains another method you could take to combine the approach you mentioned with unkeyed JSON list payloads.

Is there a way to tell GSON to parse strings with type names at beginning?

from Jersey a classic JSON output of List looks like:
{"SubtaskType":{"id":"4","name":"mozaika","metric":"m2","code":"104"}}
But GSON will say it's not a JSON array and experimentally, it accepts:
{"id":"4","name":"mozaika","metric":"m2","code":"104"} for single SubtaskType.
I tested it with JSON validator and it seems that both forms are acceptable.
GSON's output of List looks like:
[{"name":"aa","metric":"m2","id":1,"code":200},{"name":"bb","metric":"m","id":2,"code":300}]
Is there a way to configure GSON to parse/generate the longer form (with type name)?
Edit:
This is the structure (added for change/discussion):
public class SubtaskType {
private int id;
private String name;
private String metric;
private int code;
//getters & setters
}
Note: This answer is based on the original version of the question.
from Jersey a classic JSON output of List looks like:
{"SubtaskType":{"id":"4","name":"mozaika","metric":"m2","code":"104"}}
Really? That's not a JSON array, i.e., list. It's an object with one element named "SubtaskType", for which the element's value is an object with four elements. There is no list.
Is that just what a list with a single component comes out like? Does a list with two components come out like
{"SubtaskType":[{"id":"4","name":"mozaika","metric":"m2","code":"104"},{"name":"bb","metric":"m","id":2,"code":300}}
If this is the case, and you must receive such poorly-generated* JSON, and you must use Gson, then you'll have to implement custom deserialization processing to handle the situation where it's sometimes a list and it's sometimes an object. This is an all-too-often occurring problem. Gson unfortunately does not yet have a simple configuration available to handle this often-occurring problem. I posted an example of such custom deserialization processing in response to the question at Parsing JSON with GSON, object sometimes contains list sometimes contains object
* Just because it's valid JSON, doesn't mean it's not crap. An API should generate consistently-structured JSON. Anything less is crap.
GSON's output of List looks like:
[{"name":"aa","metric":"m2","id":1,"code":200},{"name":"bb","metric":"m","id":2,"code":300}]
Good. That's what a list in JSON is supposed to look like.
Is there a way to configure GSON to parse/generate the longer form (with type name)?
Yes. The specific solution depends on what your Java data structure currently looks like, and whether you're able to change the structure to match the desired JSON. If you cannot change the Java data structure accordingly, then you must custom process serialization/deserialization. Post the Java data structure you'd like to use, and indicate whether it can be changed.
Also, post an exact example of the "longer form" JSON you want to generate that represents a list with at least two components. You have not done this, yet. So, it leaves me guessing about what you really want to do.
It does seem pretty clear that you want polymorphic type handling in whatever the ultimate solution is. This will require custom deserialization processing, if using Gson.
Regarding any question on polymorphic deserialization, please note that the issue was discussed a few times on StackOverflow.com already. I posted a link to four different such questions and answers (some with code examples) at Can I instantiate a superclass and have a particular subclass be instantiated based on the parameters supplied.
For polymorphic serialization, not only will it likely be necessary to implement custom serialization to generate the desired type element, but convincing Gson to serialize all of the fields from polymorphic types also requires custom processing. See Serializing List of Interfaces GSON for more information.

Handling Unknown JSON Properties with Jackson

For deserializing json with unknown field into an object there's #JsonAnySetter.
But what if I read such json into my object, modify some known fields and write it back to json?
The unknown properties will be lost.
How do I handle such cases? Is it possible to map an object or do I have to read the data into a JsonNode or Map?
Unmarshalling into a custom java class has its advantages and disadvantages. It's gives you nice static typing, but it's well, static. The javadoc for #JsonAnySetter suggests that it's similar to JAXB's #XmlAnyElement, but unlike #XmlAnyElement, the data objects don't contain naming information, so it's a one-way street.
if you need to handle dynamic JSON streams, then you need to bite the bullet and use Map or JsonNode.
It is now possible to use #JsonAnyGetter to provide a method which allows serialization of dynamic properties:
#JsonAnyGetter
public Map<String, String> getDynamicProperties() {
return dynamicProperties; // a field like this exists
}
There's this RFE for Jackson: http://jira.codehaus.org/browse/JACKSON-292 to add such a feature. Makes total sense when you think about it.