I have a Jackson polymorphic question.
I want to deserialize JSON data into polymorphic types. Reading Jackson documentation, I can deserialize JSON data to polymorphic types. However, I have a special case. I have a class structure as follows:
class Supreme {
private String type;
}
class Foo extends Supreme {
public String label;
}
class Bar extends Supreme {
}
Note: Class Bar does not have any other member variable other than the inherited "type" field.
I have transformed that structure to:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property ="type")
#JsonSubTypes({#Type(value = Foo.class, name = "Foo"),#Type(value = Bar.class, name = "Bar") })
class Supreme {
}
class Foo extends Supreme {
public String label;
}
class Bar extends Supreme {
}
String data=
"[{
"type": "Foo",
"label": "abc"
},
{
"type": "Bar"
}]"
If I pass in the above json data like:
new ObjectMapper().readValue(data, new TypeReference<List<Supreme>>());
I get something like "Unable to deserialize class Bar out of the END_TOKEN". And I believe that is because the JsonTypeInfo and JsonSubTypes annotations have parsed "type" property and figured out that the 2nd entity in the array should be mapped to Bar class; however it tries to find "something" after the type property in that 2 entity. In other words, Jackson thinks it is an empty JSON object.
(Note: the above data without the 2nd entry in the array works fine. In other words, we can deserialize to a list containing Foo object since it at least has a property other than "type")
Any idea how to get around this?
By mistake, I was using Jackson 1.5
I bumped to Jackson 1.9 and the exception went away. So there was a bug in Jackson 1.5
Related
I have a series of classes MyConcreteClass : MyBaseClass and a series of collection classes MyConcreteCollection : MyBaseCollection.
Where the fun part is that
public abstract class MyBaseCollection
{
public List<MyBaseClass> MyItems :get; set;}
}
It serializes fine, and the objects inside MyItems do show up as the right items (lookin in the JSON with { TypeNameHandling = TypeNameHandling.All }; set
My problem is when I go to deserialize - obviously we can't create an object of List<MyBaseClass> (It is abstract) - I need to deserialize to List<MyConcreteClass>
The good news? The List<MyConcreteClass> is ALWAYS the same for each type of MyConcreteCollection, aka
MyFirstCollectionType: MyBaseCollection the MyItems will always be of type FistConcreteType : MyBaseClass and MySecondCollectionType: MyBaseCollection will always be of type SecondConcreteType : MyBaseClass
I THINK it might be just a custom Converter, but I just don't get it.
I want to deserialize 2 level polymorphic subtypes using jackson annotations.
Basically I want to convert following json to xml using json annotations and jacksons as follows
{
"mainSet": {
"name": "bla bla",
"myItems": [
{
"MySubItem": {
"id": 1,
"name": "Value1",
"itemAProperty1": "Some stuff",
"itemAProperty2": "Another property value",
"type": "MySubItemA"
}
},
{
"MySubItem": {
"id": 2,
"name": "Value2",
"itemBProperty1": 1000,
"itemBProperty2": "B property",
"type": "MySubItemB"
}
}
]
}
}
And Final Xml i want is
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mainTag schemaVersion="1" xmlns="http://www.utiba.com/xml/ns/brms/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>bla bla</name>
<MySubItem xsi:type="MySubItemA" id="1" name="value1" itemAProperty1="Some stuff" itemAProperty2="Another property value"/>
<MySubItem xsi:type="MySubItemB" id="2" name="value2" itemAProperty1=1000 itemAProperty2="B Property"/>
</mainTag>
I have following set of classes - Main class
public abstract class MyItem {
private int id;
private String name;
//getter and setter
}
Its having abstract subclass
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "MySubItem")
#XmlSeeAlso({
MySubItemA.class,
MySubItemB.class,
MySubItemC.class
})
public abstract class MySubItem extends MyItem {
private String itemAProperty1;
private String itemAProperty2;
//getter and setter
}
And MySubItem have concrete subclases say
MySubItemA,MySubItemB, MySubItemC
Now Finally, we create a client class that contains a list of objects of the abstract class
import java.util.ArrayList;
import java.util.List;
public class MainSet{
#XmlElements({
#XmlElement(name = "MysubItem", type = MySubItem.class),
})
private List<MyItem> myItems;
public List<MyItem> getMyItems() {
return this.myItems;
}
}
I tried creating Mixin classes for MyItem as
#JsonTypeInfo(use=Id.MINIMAL_CLASS, include=As.PROPERTY, property="itemType")
#JsonSubTypes({
#Type(MySubItem.class)
})
And for and MySubItem
#JsonTypeInfo(use=Id.MINIMAL_CLASS, include=As.PROPERTY, property="type")
#JsonSubTypes({
#Type(MySubItemA.class)
#Type(MySubItemB.class)
#Type(MySubItemC.class)
})
Error i am getting is :
Error parsing JSON from client: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of MySubItem, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: java.io.StringReader#26bd8952; line: 1, column: 498] (through reference chain: bla bla class ["mainSet"]->com.bla.bla["myItems"])
ISSUE : create mixin class for myItems list, having 2 level of abstract subclasses hierarchy
Multiple levels of polymorphic type hierarchy is not supported by Jackson api’s.
You can have a look at : https://github.com/FasterXML/jackson-databind/issues/374
So what you need to do is:
Please create a deserializer (for MySubItem.class say MySubItemDeserializerMixin.class) for and configure that to jsonMapper as we do for other Mixin classes.
mapper.addMixInAnnotations(MySubItem.class, MySubItemDeserializerMixin.class);
The MySubItemDeserializerMixin.java would look like :
#JsonDeserialize(using = MySubItemDeserializer.class)
public abstract class MySubItemDeserializerMixin{
}
You would also need to create a deserializer(MySubItemDeserializer) for MySubItem as specified in MySubItemDeserializerMixin.java.
Now you need to create MySubItemMixin.java which would look like this:
#JsonTypeInfo(use=Id.MINIMAL_CLASS, include=As.PROPERTY, property="type")
#JsonSubTypes({
#Type(MySubItemA.class)
#Type(MySubItemB.class)
#Type(MySubItemC.class)
})
In MySubItemDeserializer you would do something like:
#Override
public MySubItem deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
ObjectMapper jsonMapper = new ObjectMapper();
// Omit null values from the JSON.
jsonMapper.setSerializationInclusion(Include.NON_NULL);
// Treat received empty JSON strings as null Java values.
// Note: doesn't seem to work - using custom deserializer through module
// below instead.
jsonMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
jsonMapper.addMixInAnnotations(MySubItem.class, MySubItemMixin.class);
// Enable interpretation of JAXB annotations on our beans (e.g. for
// resolving ID/IDREF references).
jsonMapper.registerModule(new JaxbAnnotationModule());
MySubItem condition = jsonMapper.readValue(node.toString(), MySubItem.class);
}
Hope that resolves your concerns.
Thanks & Regards
Nakul Vashishth
Your sub-types annotation is telling JAXB what to do but not telling Jackson, which is what is trying to deserialize your request from JSON. Try adding this to your abstract class, in addition to the TypeInfo:
#JsonSubTypes({
MySubItemA.class,
MySubItemB.class,
MySubItemC.class
})
I am using Jackson as a mapper for a REST Service. A sample json response is
{
"id": 1,
"name": "One fine name",
"child": 1 //this is a primary key referencing a composite object
}
Now, using Jackson to map this notation into POJOs, the class would probably look like the following
class Parent{
protected Integer id;
protected String name;
protected Child child;
//....
//appropriate Getters and Setters
}
But when Jackson is about to deserialize the object, it complains about converting an integer into the Child object. Any idea how to make Jackson understand that the value for the child field is a reference?
I have an interface Employee and Department. I'm loading JSON from server that I need to "parse" to object that implements those interfaces. Is there a way how to achieve this automatically since all types in interface and JSON object are base types (String, number, list, map)?
// Abstract classes represents interfaces
abstract class Employee {
String firstName;
String lastName;
}
abstract class Department {
String name;
List<Employee> employees;
}
// JSON
{
"name": "Development",
"employees":
[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}
]
}
I want to parse it like this
main() {
...
Department department = someMethodToParse(jsonFromServer);
...
}
There are a few packages that deal with JSON de/serialization
http://www.dartdocs.org/documentation/serialization/0.9.1+1/index.html#serialization/serialization (serialization package)
Can I automatically serialize a Dart object to send over a Web Socket? (package exportable)
Convert JS object into Dart classes (manual)
How to convert an object containing DateTime fields to JSON in Dart? (handling DateDime)
Add JSON serializer to every model class?
I have a JSON object which I don't have control of and want to map it to a Java object which is pre-created.
There is one attribute in the JSON object which can be a URL or it could be a JSONArray.
Class SomeClass {
private URL items;
public URL getURL() {
return items;
}
public void setURL(URL url) {
this.items = url;
}
}
Below is the JSON:
Case A:
{
...
items: http://someurl.abc.com/linktoitems,
...
}
OR
Case B
{
...
items: [
{ "id": id1, "name": name1 },
{ "id": id2, "name": name2 }
]
...
}
If i create the POJO to map for Case A, Case B fails and vice versa. In short, is there a way to map the JSON attribute to the POJO field with different data types? In that case I will create two separate fields in the POJO named,
private URL itemLink;
private Item[] itemList;
It depends on exact details, but if what you are asking is if it is possible to map either JSON String or JSON array into a Java property, yes this can be done.
Obvious way would be to define a custom deserializer which handles both kinds of JSON input.
But it is also possible to define Java type in such a way that it can be constructed both by setting properties (which works from JSON Object) and have a single-String-arg constructor or static single-String-arg factory method marked with #JsonCreator.
Yet another possibility is to use an intermediate type that can deserialized from any JSON: both java.lang.Object and JsonNode ("JSON tree") instances can be created from any JSON. From this value you would need to do manual conversion; most likely in setter, like so:
public void setItems(JsonNode treeRoot) { .... }
What will not work, however, is defining two properties with the same name.
One thing I don't quite follow is how you would convert from List to URL though. So maybe you actually do need two separate internal fields; and setter would just assign to one of those (and getter would return value of just one).