Camel JSON serialization of joda DateTime using Jackson in Spring DSL - json

I have been using the json, dataFormats, and marshall/unmarshall tags in the Camel Spring DSL as described in the following url and snippet from applicationContext.xml.
http://camel.apache.org/json.html
...
<dataFormats>
<json id="json" library="Jackson" unmarshalTypeName="com.example.Foo" />
</dataFormats>
...
<route>
<from uri="direct:inPojo"/>
<marshal ref="json"/>
</route>
<route>
<from uri="direct:backPojo"/>
<unmarshal ref="json"/>
</route>
...
I want to serialize my joda DateTime objects as longs, as mentioned here:
http://wiki.fasterxml.com/JacksonFAQDateHandling
I understand that I need to register the separate Jackson-datatype-Joda module, and how to do that when I have an instance of an ObjectMapper, as mentioned in How to serialize Joda DateTime with Jackson JSON processer?, but is there a way to do it using the Camel/Spring XML tags?

Pass in ObjectMapper to JacksonDataFormat. I'm not using Spring DSL, but you should be able to do the same thing like what I do in Java DSL:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule( ... );
JacksonDataFormat df = new JacksonDataFormat(mapper, Pojo.class);
from("direct:source").unmarshal(df);

Related

Camel way: JSON to Array of Object

Need to deserialize stringls like "[100,200]" into array of Integer to later use from:
<to uri="class:java.awt.Robot?method=mouseMove&multiParameterArray=true"/>
multiParameterArray=true is a key.
<unmarshal ref="json"/>
with
<dataFormats>
<json id="json" library="Jackson" allowJmsType="true"/>
</dataFormats>
and stuck. Working in restricted environment, can't create custom beans that perform the stuff. Need some standard camel way.
UPDATE 1
Seems this construct does exactly what I need. But I'd better use <unmarshal/> rather then it
<setBody>
<constant>[100,200]</constant>
</setBody>
<setBody>
<jsonpath>$.*</jsonpath>
</setBody>

Spring Boot Microservice Jackson JSON serialisation NON NULL

I'm currently working on a Spring Boot ( Version 1.3.1 ) Microservice which connects to MongoDB backend and provides the backend data ( Ex: Provider object ) to the client via controller.
The project has got one class file which extends ResourceSupport ( Ex: ProviderResourceSupport ) and also another class which extends ResourceSupportAssembler class ( Ex: ProviderAssembler ) for generating Links to the Response objects.
Ideally my requirement is to customise the JSON objects on a need basis and as such using #JsonView ( followed this link - https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring ) and added Spring Jackson dependencies in the maven project.
I have also added spring.jackson.serialization-inclusion=non-null & spring.jackson.serialization.indent_output=true in the application.properties.
For one of the method in the controller, the response will be 'ResponseEntity< List< ProviderResourceSupport>>' , and this method is returning with a 'null' response if the data is not present.
I have added #JsonInclude(Include=NON_NULL) on my entity objects and controllers but still getting the 'null' response.
I don't want the 'null' as the response and request you to help me incase if anyone has faced the similar issue.
I fixed this null properties escaping from json response extending a Jackson Mapper Bean but I don't use Spring Boot, take a quickly look and check if this is suitable for you
public class Jackson2ObjectMapperCustom extends Jackson2ObjectMapperFactoryBean {
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
getObject().setSerializationInclusion(JsonInclude.Include.NON_NULL).setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
Hibernate5Module hibernateModule = new Hibernate5Module();
hibernateModule.disable(Feature.USE_TRANSIENT_ANNOTATION);
hibernateModule.enable(Feature.FORCE_LAZY_LOADING);
getObject().registerModules(new JavaTimeModule(), hibernateModule);
getObject().configure(SerializationFeature.INDENT_OUTPUT, true);
getObject().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
getObject().setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"));
}
}
And in my case I use Spring Xml configuration
<bean id="objectMapper" class="com.xxx.common.Jackson2ObjectMapperCustom" />
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

Spring MVC: using Jackson for incoming requests and FlexJSON Serializer for responses

I'd like to use Jackson to deserialize JSON strings from client requests to Java objects and use FlexJson to serialize Java objects to response.
In the nutshell the issue is: how to setup the Spring to use Jackson ONLY for request handling and not for response?
In servlet-context.xml I have:
<beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonMessageConverter"/>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</beans:bean>
And in the controller:
#RequestMapping(value = "settings")
public #ResponseBody String getSomeData(#RequestBody UserData userData) {
// userData is automatically deserialized by Jackson
MyView viewForClient = new MyView(userData);
return new JSONSerializer().include(MyView.SERILIZABLE_FIELDS).exclude("*", "*.class").serialize(viewForClient); // here I don't want Jackson to handle the response
}
But this way Jackson also converts to JSON the response already converted by FlexJSON that I don't want.
Is there any solution? Thanks.
You should be able to build a custom MappingJackson2HttpMessageConverter bean where you plug in Jackson for the serialization methods, and FlexJSON for the deserialization methods.

spring-mvc return raw json string

I want the convenience of automatically serializing objects into JSON and ability to return raw JSON string. I am using Gson instead of Jackson, since Gson has been in my app for a while and I have existing tweaks, converters, and annotations peppered throughout my app.
<mvc:annotation-driven >
<mvc:message-converters register-defaults="true">
<bean class="com.test.GSONHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
I can automatically serialize pojo's:
#RequestMapping(value="foo/{name}", method = RequestMethod.GET)
public #ResponseBody Shop getShopInJSON(#PathVariable String name) {
return new Shop();
}
I want this to work also:
#RequestMapping(value="rawJsonTest/{name}", method = RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody String rawJsonTest(#PathVariable String name) {
return "{\"test\":5}";
}
Result right now is an escaped value:
"{\"test\":5}"
instead of:
{"test":5}
The problem is that your custom converter takes precedence over the default ones. It's thus called, considers the String as a raw String that must be converted to JSON, and thus escapes the double quotes.
I'm not sure if and how it's possible with XML to register a converter after (and not before) the default ones, but you could set register-defaults to false and provide an explicit list of all the converters you want to apply. If org.springframework.http.converter.StringHttpMessageConverter is registered before your custom one, it will be called first and will send the returned String as is.
Thanks for the correct answer, #JB Nizet
Order matters:
<mvc:annotation-driven >
<mvc:message-converters register-defaults="true">
<bean class = "org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json; charset=UTF-8" />
</bean>
<bean class="com.test.GSONHttpMessageConverter" />
</mvc:message-converters>

Jackson JSON not working with CXF

The JacksonJsonProvider is not working with CXF.
CXF v2.6.0
Jackson v2.1.2 (com.fasterxml.jackson)
RESTClient (for testing)
I do have the provider configured like below in beans.xml.
<bean id="jacksonMapper" class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd'T'HH:mm:ss.SSSZ"> </constructor-arg>
</bean>
</property>
</bean>
<bean id="jacksonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider">
<property name="mapper" ref="jacksonMapper" />
</bean>
in jaxrs:server.....>
<jaxrs:providers>
<ref bean="jaxbProvider" />
<ref bean="jacksonProvider" />
</jaxrs:providers>
</jaxrs:server>
The application gets deployed without any issues, it gives good JSON while I give the request as "application/xml" and the response as "application/json".
When I try to give JSON in request by setting Content-Type=application/json I'm facing the 500 Internal Server Error
The request is getting logged in the log file thru CXF-logging.
The request is not at all landing in the service implementation class of my webservice.
The JSON in request body is :
{"SearchOrdersRequest":{"LoginCredentials":{"AppId":"BookStore","Username":"myuser","Password":"abcd1234","SecurityToken":"Vcvx45YilzX1"},"SearchHeader":{"SearchCategory":"Rep","FilterLogic":"1 AND 2","SearchParams":{"Field":"Order Number (s)","Operator":"EQUALS","Values":"600045335"}}}}
Any immediate help is appreciated.
In CXF documentation , you can see where you need to add json provider and include a dependency. But, I still getting errors when I tried to add jackson instead of jettison, after some hours I figured that you need to include one more jackson dependency.
Add JSON provider
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
</jaxrs:providers>
Add dependencies
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.12</version>
</dependency>
As I undertood you, your application produces and consumes xml and json format. So, first of all. Make it sure that your cxf resource endpoint are able to do it.
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
Otherwise your request won't find any resource implementation. (at these line at class level or method level)
Then if this is not enough check out this jackson cxf integration:
<bean id="jsonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" />
<bean id="jsonContextResolver" class="net.sf.gazpachoquest.rest.support.JacksonContextResolver" />
Also
<jaxrs:server id="services" address="/">
<jaxrs:providers>
<ref bean="jsonProvider" />
<ref bean="jsonContextResolver" />
</jaxrs:providers>
</jaxrs:server>
The context resolver the class where the mapper is defined:
#Provider
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper = new ObjectMapper();
public JacksonContextResolver() {
/*
* Register JodaModule to handle Joda DateTime Objects.
* https://github.com/FasterXML/jackson-datatype-jsr310
*/
mapper.registerModule(new JSR310Module());
mapper.setSerializationInclusion(Include.NON_EMPTY);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
#Override
public ObjectMapper getContext(Class<?> arg0) {
return mapper;
}
}
And just in case you deploy your application into a j2ee container, you may require a application config class:
#ApplicationPath("/api")
public class ApplicationConfig extends javax.ws.rs.core.Application{
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
// add here your resources
classes.add(JacksonContextResolver.class);
classes.add(JacksonJsonProvider.class);
...
return classes;
}
Hope this help.
Some time ago I had problem with a json request when I had not jettison library in classpath.
Check http://www.javatips.net/blog/2012/02/cxf-restful-tutorial tutorial.
In order to use jackson library by overriding jettison, you need to configure jacksonprovider like following
<bean id="jacksonJsonProvider" class="com.student.CustomJsonProvider"/>
<jaxrs:providers>
<ref bean="jacksonJsonProvider" />
</jaxrs:providers>
In normal circumstances if you deploy to a EE server by simply adding that dependency the provider had to be automatically discovered and used (I tested width TomEE 7):
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.8.6 </version>
</dependency>
But be careful to use the correct version. CFX guide suggests a Jackson JAX-RS provider that is only compatible with Jackson 1 and not for Jackson 2. Look at that question for more details
This is happening because when you are using the jackson library with group com.fasterxml.jackson.jaxrs, the server is expecting the request in following format:
{
"LoginCredentials": {
"AppId" : "BookStore",
"Username":"myuser",
"Password":"abcd1234",
"SecurityToken":"Vcvx45YilzX1"
},
"SearchHeader":{
"SearchCategory":"Rep",
"FilterLogic":"1 AND 2",
"SearchParams":{
"Field":"Order Number (s)",
"Operator":"EQUALS",
"Values":"600045335"
}
}
}
But your client will be sending in following format:
{
"SearchOrdersRequest": {
"LoginCredentials": {
"AppId" : "BookStore",
"Username":"myuser",
"Password":"abcd1234",
"SecurityToken":"Vcvx45YilzX1"
},
"SearchHeader":{
"SearchCategory":"Rep",
"FilterLogic":"1 AND 2",
"SearchParams":{
"Field":"Order Number (s)",
"Operator":"EQUALS",
"Values":"600045335"
}
}
}
}
It seems to be the issue with this fasterxml version of library only. Using the library with group org.codehaus.jackson will fix the issue. Both request and response will be without root element.
So you need to replace the following maven dependency
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.9.3</version>
</dependency>
with
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.13</version>
</dependency>
I checked that the library mentioned in the cxf docs (https://cxf.apache.org/docs/jax-rs-data-bindings.html#JAX-RSDataBindings-Jackson) is also the one with com.fasterxml.jackson.jaxrs but if you check the classes that are mentioned there in beans are from org.codehaus.jackson.jaxrs. So I think this is a mistake in docs and needs correction.