After moving our application war from Glassfish3 to a deployment with Payara Micro, the JAX-RS serialization (jersey + jackson) doesn't work any more.
Thanks to Adam, we solved the issue with serializing pure collections, we now encounter similar errors when returning POJOs:
#GET
#Produces("application/json")
public BirdyTO findAllDaBirdy() {
return getBirdy();
}
where BirdyTO is a POJO which contains other POJOS and/or collections of POJOS.
That one gives us the error:
MessageBodyWriter not found for media type=application/json;charset=utf-8, type=class org.example.BirdyTO, genericType=class org.example.BirdyTO.
Strange thing is that similar interfaces in same application work fine.
Any idea?
Mapping of POJOs to JSON is not standardized in Java EE. Glassfih 4/Payara use MOXy to map POJO to JSON by default, which uses JAXB for the mapping. See [this post by Reza Rahman] (https://blogs.oracle.com/theaquarium/entry/moxy_is_the_new_default). It is possible that BirdyTO cannot be mapped by Moxy.
If you want to use Jackson, you have to:
disable default Moxy feature (by setting jersey.config.server.disableMoxyJson property to true)
add Jackson library into your app (com.fasterxml.jackson.jaxrs)
turn on the JacksonFeature (provided by the Jackson library) in your JAX-RS application
More info how to do it in this answer: Customizing JSON marhsalling with GlassFish v4
Related
We're using Payara 4 which uses Eclipselink Moxy as the default JSON to/from object mapper.
We're now looking into switching to Jackson which is more suitable and easy to work with when it comes to JSON.
There is a known issue with Moxy where when it serializing a Map, the JSON will look like this:
"productsPerCost":{"entry":[{"key":"PS4","value":999}, {"key":"TV","value":1233}]}
And Jackson cannot deserialize this, and so it'll fail, because Jackson expect the Map's JSON representation to be:
"productsPerCost": {
"PS4": 999,
"TV": 1233
},
jackson with jaxb
Let's say we'll switch our application to work with Jackson. If we'll call to some external system that is working with Moxy, we'll get this weird JSON from them and fail.
How to handle this?
I am using Kie Execution Server 6.5 (docker image). I deploy a kie container (kjar) which contains some rules and some custom java classes. Everything was working so far.
Now, I added some 3rd party classes to my java classes (geojson-jackson
), which use a custom jackson serializer and deserializer declared with #JsonDeserialize(using = LngLatAltDeserializer.class), see LngLatAlt.
First I had class loading issues, apparently because of different jackson versions, which I solved by using geojson-jackson 1.3 and excluding the jackson dependency in my pom.xml.
The container is now started successfully, but objects cannot be deserialized, because the custom deserializer is not used. I get a MarshallingException caused by
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of
org.geojson.LngLatAlt out of START_ARRAY token
at [Source: java.io.StringReader#33714932; line: 1, column: 385] (through reference chain:
org.drools.core.command.runtime.BatchExecutionCommandImpl["commands"]->
org.drools.core.command.runtime.rule.InsertObjectCommand["object"]->
MYPACKAGE.MYCLASS["polygon"]->org.geojson.Polygon["coordinates"])
at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
This is exactly the part the custom deserializer should take care of.
Update: Karel Suta's answer helped me to investigate further.
The issue 5776 to the PR indicates that annotating a DTO should be possible to extend the JSON marshaller. The new JSONMarshallerExtension should only be needed if the object model is not to be annotated.
https://issues.jboss.org/browse/JBPM-5776
https://github.com/kiegroup/droolsjbpm-integration/pull/851
Enabling debug log level for org.kie.server, I got:
DEBUG [org.kie.server.services.drools.DroolsKieServerExtension] (default task-1) Adding org.geojson.Polygon type into extra jaxb classes set
DEBUG [org.kie.server.services.drools.DroolsKieServerExtension] (default task-1) Added org.geojson.Polygon type into extra jaxb classes set
DEBUG [org.kie.server.services.drools.DroolsKieServerExtension] (default task-1) Adding org.geojson.LngLatAlt type into extra jaxb classes set
DEBUG [org.kie.server.services.drools.DroolsKieServerExtension] (default task-1) Added org.geojson.LngLatAlt type into extra jaxb classes set
...
and
DEBUG [org.kie.server.api.marshalling.BaseMarshallerBuilder] (default task-2) About to build default instance of JSON marshaller with classes [
..., class org.geojson.Polygon, org.geojson.LngLatAlt, ...
Together with over hundred other classes (all dependencies it seems). So the classes are recognized and maybe supplying a JSONMarshallerExtension for them would work (I have not figured out, how to do that), but it should be possible with annotations as well.
Any other suggestions to get the annotations working?
In latest snapshot it could be possible to define custom marshaller for classes using JSONMarshallerExtension, see this PR.
I wrote a UnwrappingBeanSerializer for my entity. Currently this serializer was registered using ConfigureJacksonObjectMapper
This serializer is working fine for REST APIs generated from spring-data-rest. But I have a custom #RestController for the same entity, But it doesn't know about the serializer registered in spring-data-rest configuration.
I want to serialize my response with UnwrappingBeanSerializer both in spring-data-rest APIs and also to my custom controllers.
How to achieve this?
I also tried with #JsonSerialize on my entity class. But I am unable to create bean for unWrappingBeanSerializer with BeanSerializerBase
Regular #RestController and Spring Data REST controllers have different flows and configuration. If you are using Spring Data REST, you'd better use #RepositoryRestController for custom endpoints of the same resource, this will use the same Spring Data REST chain and its configuration, like the one you used in ConfigureJacksonObjectMapper, otherwise your ObjectMapper is visible only for Spring Data REST.
If you want to have #RestController and use the same ObjectMapper for both - you need to have two configurations: one for Spring Data REST (like you already have) and another for regular controllers, so just register it in Spring context (for instance, if you are using Spring MVC, see Customize the Jackson ObjectMapper).
Is is possible to have multiple JSON providers executing at the same time for the same content type(application/json)?
I want to include objectmapper configurations specific to my module in the application.
Is it possible to do this using the ContextResolver mechanism?
Thanks and Regards,
Jyothi
is there a way in jax-rs to plugin custom serializer and deserializer,
This is kind of important to migrate some of the existing consumers to REST world.
You should define a custom Provider with message body readers/writers:
Entity providers supply serialization and/or deserialization services between resource representations and their associated Java types. An entity provider that supports deserialization of a representation to a Java type implements the MessageBodyReader interface. An entity provider that supports serialization of a Java type to a representation implements the MessageBodyWriter interface.
See http://www.oracle.com/technetwork/articles/javaee/jax-rs-159890.html