How to add custom Classloader to ObjectMapper? - json

Is there any way to instruct Jackson 2 ObjectMapper to use custom Classloader to deserialize JSON strings?

Here is the solution:
ClassLoader myClassLoader = ...
ObjectMapper om = new ObjectMapper();
TypeFactory tf = TypeFactory.defaultInstance()
.withClassLoader(myClassLoader);
om.setTypeFactory(tf);

Take a look at the Jackson Wiki for Modules, a Jackson Module can be used to create custom serialization / deserialization. While the wiki talks about what they can do
Add custom serializers and deserializers
Add mix-in annotations
Override or add AnnotationIntrospector
Access SerializationConfig and DeserializationConfig settings.
It is pretty light on details, just giving a very basic example. The Module JavaDoc is light on details as well. Fortunately the wiki also has a list of existing Jackson Modules on GitHub, which is more helpful as examples if you need to create your own Module from scratch.

To preserve the existing TypeMapper, you might want to do something like this (this is Scala, but same pattern works in Java), where you adjust the current type factory.
def updateClassLoader(cl: ClassLoader): Unit = {
objectMapper.setTypeFactory(objectMapper.getTypeFactory.withClassLoader(cl))
}
This will preserve cached type data from possible prior configuration calls like this:
mapper.registerModule(new Jdk8Module)
.registerModule(new JavaTimeModule)
.registerModule(new DefaultScalaModule)

Related

Is it a good practice to add redundant #JsonProperty when using JacksonMapper

Is it a good practice to add redundant #JsonProperty when using JacksonMapper? Even if the class vars are same named as the incoming json(and you deserialize the json)?
What can be possible upsides?
What can be possible downsides?
The downside,as you suggested, it's reduandant,especially when this class was replaced from codehaus package to fasterxml so if you have old property you will have to refactor class
org.codehaus.jackson is an older version of Jackson.
com.fasterxml.jackson represents the new project and package.

Camel ignores custom Jackson ObjectMapper

I am trying to replace the standard Jackson as it is described here: http://camel.apache.org/json.html
I am using the following configuration
<bean name="myJsonObjectMapper" class="com.my.app.MyJsonObjectMapper" primary="true"/>
<camel:camelContext id="camel-client">
<camel:template id="camelTemplate"/>
<camel:dataFormats>
<camel:json id="json" library="Jackson" objectMapper="myJsonObjectMapper"/>
</camel:dataFormats>
</camel:camelContext>
MyJsonObjectMapper extends ObjectMapper. I can see it in Spring context, I can autowire and use it. I see that Camel context is started OK, I am using the Camel version 2.20 where this feature is enabled and fixed. However when I am trying to parse JSON I am getting the exceptions which will non-modified ObjectMapper generate.
When debugging I see that JacksonDataFormat is not initialized with customized ObjectMapper but rather creates a new one on doStart() method.
What am I missing on the Camel configuration?
UPD:
I am using that mapper in scope of Camel REST DSL routes in one of the following ways:
restConfiguration().component("servlet").bindingMode(RestBindingMode.json);
rest("/somepath")
.description("blah")
.post("/subpath/")
.type(MyRQ.class)
.outType(MyRS.class)
.route().id("under-test")
.bean(service)
.endRest();
or
restConfiguration().component("servlet");
rest("/somepath")
.description("blah")
.post("/subpath/")
.route().id("under-test")
.unmarshal().json(JsonLibrary.Jackson)
.bean(service)
.marshal().json(JsonLibrary.Jackson)
.endRest();
In both cases I am getting the marshaller error due to the usage of the default marshaller instead of custom one. The routes seem to be started in scpe of the correct context, the same I am configuring ObjectMapper for.

Is there a way to use Jackson's SerializationFeature with annotations

I'm trying to use SerializationConfig.Feature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS but I'm not configuring the mapper myself, relying on annotations exclusively and letting Spring's RestTemplate (de)serialize automatically. Is there a way to enable the aforementioned feature in this scenario (i.e. annotations only)?
NOTE: I'm using Jackson 1.x and can't upgrade due to other libs...
With JAX-RS (like DropWizard) you can actually annotated resource endpoints, using #JacksonFeatures
public class Resource {
#Path("item")
#GET
#JacksonFeatures(serializationEnable={ SerializationFeature.WRAP_ROOT_VALUE })
public Pojo getItem(String id) {
...
}
}
I don't know if Spring exposes similar functionality, but it seems possible it does. And if not, it is something they should be able to add to allow per-endpoint setting/clearing of SerializationFeatures / DeserializationFeatures. So if it is not available, maybe file a feature request for Spring project?
Yes, it is possible.
checkout this link: http://jackson.codehaus.org/1.7.0/javadoc/org/codehaus/jackson/map/annotate/JsonSerialize.html
Example:
#JsonSerialize(using=MySerializer.class,
as=MySubClass.class,
include=JsonSerialize.Inclusion.NON_NULL,
typing=JsonSerialize.Typing.STATIC
)

Seam 2.3 RESTEasy on JBoss 7.1 #JsonIgnore

How to achieve that some properties are ignored in the JSON-output (like XmlTransient for XML-output)?
#GET
#Path("/{companyId}")
#Produces(MediaType.APPLICATION_JSON)
public PortfolioCompany getCompany(#PathParam("companyId") long id);
I've been playing around with the RESTeasy-support in Seam 2.3 deployed as an EAR on a JBoss 7.1. I started by adding the same dependencies to my ejb-project as in the Seam-restbay-example.
It is basically working fine for #Produces(MediaType.APPLICATION_XML), where all properties annotated with #XmlTransient are ignored, in order to prevent some LazyInitialisationExceptions.
But how to achieve this behavior for #Produces(MediaType.APPLICATION_JSON)?
I've read Seam uses Jettison by default, which uses the #XmlTransient annotation for both, XML and JSON (because technically it transforms from XML -> to JSON). But I get a "Caused by: org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer" which indicates that in fact it is using Jackson..?
For Jackson there is the annotation like #JsonIgnore, but having the same maven dependencies like restbay - this "cannot to be resolved to a type".
/**
* #return the contact
*/
#OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
#XmlTransient // working for produces XML but not for JSON
//#JsonIgnore = unknown type
public Contact getContact() {
return contact;
}
Anyone any experiences or hints on that?
thanks
EDIT: Really no one having the need of realizing lazy collections for REST-services with Seam??
After some research:
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property ="#id")
is what apparently would be needed. But that is only provided with Jackson 2.x. But the seam2.3/jboss7 setup is obviously using Jackson 1.9...
The default annotation mode of #XmlType/#XmlRootElement is to capture everyfield, including the lazy initializer from hibernate. Use #XmlAccessorType(XmlAccessType.NONE) in your entities and then individually annotate the fiels with #XmlElement so that only the necessary fields are processeded

Globally configure Jackson properties using Spring?

i am using Jackson and was wondering if it is possible to set global properties using resources.xml?
Example:
In some places i need to do:
jsonMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
It would be nice that i can configure Jackson to do this global using spring resources.xml,
any suggestion on how to do this?
You can do this easily, just extend the org.codehaus.jackson.map.ObjectMapper class and specify all your properties in the constructor(or you can accept a map as well): Then autowire your own ObjectMapper where you need it.
Not out of the box -- but maybe someone could build such an extension, release as Jackson module?