I am new to JACKSON serialization, and writing Test cases for model classes.
So when i serialise an another object initialized in this model class following anomaly is seen::
Example::
class ToTest{
ABC abc;
//getter setter
}
class Test{
//everything that is needed
#Test
public void serialize() throws Exception{
ToTest toTest = new ToTest();
ABC abc = new ABC();
toTest.setABC(abc);
}
Now when I serilize this toTest object: the json string is missing the "ABC" class name. So i am not able to equalise them. Please help.
Jackson does not explicitly write out the class names when doing serialization do JSON. This is by design as the POJO objects used in serialization are intended for describing the contents of the JSON data, not necessarily preserving the class.
With that said, there are a few things you can do. If you want to preserve the original class, you can use annotations to add a class field, which might solve your issue. A quick search resulted in this as an example:
include class name in all objects serialized by jackson
Related
I've searched and found Jackson ObjectMapper throwing NullPointerException even with NON_NULL, but I don't have control of the class to change my setter.
I have am being given
{... "fieldNames": null,...}
and am supposed to deserialize it to
Collection<String> fieldNames
I don't have control of the class or the json I'm getting.
Is there some setting I can use to handle for this? I've looked at DeserializationFeature, but could not find it
You can use mix-ins when you don't control the class you are deserializing. You don't mention the name of the class containing Collection<String> fieldNames so lets assume it's called Fields. Then create a new class:
class FieldsMixin {
#JsonSetter(nulls = Nulls.SKIP)
Collection<String> fieldNames;
}
and add the mixin class to your ObjectMapper associating it with the original unmodified class:
mapper.addMixIn(Fields.class, FieldsMixin.class);
This is a new feature in Jackson 2.9 and as you guess it will skip calling a setter method or otherwise set a field if the value in JSON is null. Documentation
I have a bunch of interfaces annotated as follows:
#MyAnnotation(DefaultImplementation.class)
interface SomeInterface {
...
}
and an accompanying implementation
class DefaultImplementation implements SomeInterface {
...
}
When my ObjectMapper runs into a field of type SomeInterface I would like it to deserialize it as if it was a DefaultImplementation. That is, I would like encode the following logic in the deserialization process:
if (staticTypeToDeserialize.isAnnotationPresent(MyAnnotation.class))
deserializeAs(type.getAnnotation(MyAnnotation.class).value());
else
fallBackOnRegularDeserialization();
I hope I have a complete answer for you. Jackson can do this through a MixIn. I'm no expert on that, but I did it recently so ... In essence, you stick type information into the JSON, then Jackson can use that type information to deserialize it the way you want.
So first, you need a mixin class that knows about the types you are going to serialize and deserialize.
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = MyString.class, name = "mystring"),
#JsonSubTypes.Type(value = MyEvent.class, name = "myevent") })
public abstract class PolymorphicMixIn {
}
The MyString and MyEvent class derive from the same base class in my case. So everything I stick in and out of Jackson is that one class type. Say that baseclass is MyBaseClass.
So then in your jackson class, you need to tell the object mapper about this.
private ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixInAnnotations(MyBaseClass.class, PolymorphicMixIn.class);
That's pretty much it. Now you can just call objectMapper.writeValueAsString and it'll write the Jackson and stick in type information.
To read it out, just pass in the class type you are expecting:
MyString outputString = objectMapper.readValue(argAsString, MyString.class);
I hope that's enough to get you where you need to be!
My question is, whether it is necessary to add #XmlElement before each element in your pojo to be picked up by jaxb, when making a JSON response. I am using jersey-json 1.17 . The reason I ask this is because, the example given on Jersey site does not use the annotation.
I get an out put as {}, but when I add #XmlElement before the attributes, I get the expected JSON output. Am I doing something wrong, because of which my JSON string is empty ?
My code :
The vertices list is populated in the constructor.
This produces the wrong output of {}
#XmlRootElement
public class SquareModel {
List<Float> vertices = new ArrayList<Float>();
....
}
Whereas this produces the a correct JSON string :
#XmlRootElement
public class SquareModel {
#XmlElement(name="vertices")
List<Float> vertices = new ArrayList<Float>();
....
}
My resource class which returns the JSON
#GET
#Produces(MediaType.APPLICATION_JSON)
public SquareModel getJsonString() {
return new SquareModel();
}
Thanks :)
No, by default a JAXB (JSR-22#) implementation will treat all public fields and properties (get/set combinations) as mapped (not requiring the #XmlElement annotation).
http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html
If you wish to annotate a field I would recommend annotating your class with #XmlAccessorType(XmlAccessType.FIELD)
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
According to this http://jersey.java.net/nonav/documentation/latest/json.html#json.jaxb.approach.section
You should have this annotation (I'm also using it in my code, even though it XML oriented, but it gives me cool JSON also)
Taking this approach will save you a lot of time, if you want to
easily produce/consume both JSON and XML data format. Because even
then you will still be able to use a unified Java model. Another
advantage is simplicity of working with such a model, as JAXB
leverages annotated POJOs and these could be handled as simple Java
beans.
A disadvantage of JAXB based approach could be if you need to work
with a very specific JSON format. Then it could be difficult to find a
proper way to get such a format produced and consumed. This is a
reason why a lot of configuration options are provided, so that you
can control how things get serialized out and deserialized back.
Following is a very simple example of how a JAXB bean could look like.
Example 5.3. Simple JAXB bean implementation
#XmlRootElement
public class MyJaxbBean {
public String name;
public int age;
public MyJaxbBean() {} // JAXB needs this
public MyJaxbBean(String name, int age) {
this.name = name;
this.age = age;
}
}
Is it possible to configure jackson to always add the type of the serialized object to the generated json output.
For example:
package org.acme;
class ClassA
{
String a;
String b;
}
and I want the generated json to be:
["org.acme.ClassA",{"a":"str1","b":"str2"}]
You can do that with enableDefaultTyping() of the ObjectMapper
e.g.
mapper.enableDefaultTyping(DefaultTyping.OBJECT_AND_NON_CONCRETE);
See ObjectMapper API
If your are free to change from Jackson and do not especially need the format to match the one your are showing you can try Genson http://code.google.com/p/genson.
For example if your requirement is to be able to deserialize interfaces or abstract classes based on the original type of the object you serialized you can do:
interface Entity {}
static class Person implements Entity {}
Genson genson = new Genson.Builder().setWithClassMetadata(true).create();
// json will be equal to {"#class":"my.package.Person"}
String json = genson.serialize(new Person());
// and now Genson is able to deserialize it back to Person using the information
// in the Json Object
Person person = (Person) genson.deserialize(json, Entity.class);
Another nice feature is the ability to define aliases for your classes, so you show less information in the json stream but also this allows you to do refactoring without worring of existing json streams (for example if you store it in a database).
Genson genson = new Genson.Builder().addAlias("person", Person.class).create();
// json value is {"#class": "person"}
String json = genson.serialize(new Person());
Have a look at the wiki.
I have the following json:
{"resourceWithType":
{"parentId":0,
"pluginId":0,
"pluginName":"Platforms",
"resourceId":10001,
"resourceName":"snert",
"typeId":10057,
"typeName":"Mac OS X"
}
}
And a class
public class ResourceWithType {
String resourceName;
int resourceId;
String typeName;
with all the getters and setters and so on.
The above JSON was actually created via RESTeasy and the Jettison provider where the class was marked with #XmlRootElement.
When I try to deserialize the above JSON via
ObjectMapper mapper=new ObjectMapper();
ResourceWithType rwt = mapper.readValue(json,ResourceWithType.class);
It fails with
06-13 11:07:55.360: WARN/System.err(26040):
org.codehaus.jackson.map.exc.UnrecognizedPropertyException:
Unrecognized field "resourceWithType"
(Class org.rhq.core.domain.rest.ResourceWithType),
not marked as ignorable
Which is sort of understandable.
How can I tell Jackson, that the embedded 'resourceWithType' is actually the class to deserialize into?
Other option would be to tell jettison not to include that type - how?
Tree model is a possibility; or just a simple wrapper like:
class {
public ResourceWithType resourceWithType;
}
to let you unwrap it. But often framework itself should handle unwrapping, since they are ones adding extra wrapping (Jackson does not add 'resourceWithType' in there by default).
Perhaps use the TreeModel API to unwrap the first (tag name) level, then deserialize the inner contents as usual (using the binding API)?