Ivaylo Slavov Ivaylo Slavov - 2 years ago 84
Java Question

ObjectToJsonTransformer in Spring 4 throws NPE when having null values

I am processing a JSON message with spring integration. The message can vary in format and I am interested in a particular sub-object (called

) of the whole JSON I receive. I match the Java class for that sub-object against another field (
) from the received message in order to know how to deserialize it.

To achieve this, I convert the message to a
<int:json-to-object-transformer type="java.lang.Object" />
- this will in fact convert the initial JSON to a
object which I can query for fields and perform filtering and routing within my spring integration xml - for example:

<int:recipient-list-router input-channel="jsonInputChannel" ignore-send-failures="false" default-output-channel="fallbackChannel">
selector-expression="payload.containsKey('type') and payload.containsKey('payload')"/>

In the above the
is treated as a
object. Then I extract the relevant object I need to further transform into a specific Java class:

<int:chain input-channel="validInputChannel" output-channel="objectResolveChannel">
<int:transformer expression="payload.get('payload')" />
<int:object-to-json-transformer />

Here I am getting a NPE when the payload propery of the message looks like
{"field1": null, "field2": "something", ....}

I had a look at the Spring 4.2.4.RELEASE source code and I can see that
this.jsonObjectMapper.populateJavaTypes(headers, message.getPayload());

This in order calls the method implementation in
, which is the following:

public void populateJavaTypes(Map<String, Object> map, Object object) {
map.put(JsonHeaders.TYPE_ID, object.getClass());
if (object instanceof Collection && !((Collection) object).isEmpty()) {
map.put(JsonHeaders.CONTENT_TYPE_ID, ((Collection) object).iterator().next().getClass());
if (object instanceof Map && !((Map) object).isEmpty()) {
map.put(JsonHeaders.CONTENT_TYPE_ID, ((Map) object).values().iterator().next().getClass());
map.put(JsonHeaders.KEY_TYPE_ID, ((Map) object).keySet().iterator().next().getClass());

You can see that when the object is treated like a Map instance, the code uses
on the first element of the map values, but this of course can be
and hence the NPE is thrown.

We were using Spring 3.2.1.RELEASE together with Spring Integration 2.2.6.RELEASE previously and the same Spring integration XML configuration was working perfectly. As far as I know the problematic code above was not present in Spring 3.

Could someone suggest a nice workaround for this issue or a way to get back to the Spring 3 behavior?

Answer Source

This is a bug; I opened a JIRA Issue.

The only work-around, I think, is to fix the bug locally (subclass ObjectToJsonTransformer, fixing doTransform() by removing the populateJavaTypes call) and replace the <object-to-json-transformer/> with a normal <transformer/> referencing your bean.

Populating the java type headers was added in 3.0.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download