Serializing root primitive objects with Jackson

I ran into the following issues. When the Jackson serializer is passed a wrapped primitive for serialization, this primitive is serialized as is, for example:

objectMapper = new ObjectMapper(); StringWriter w = new StringWriter(); objectMapper.writeValue(w, Integer.valueOf(10)); System.out.println(w.toString()); 

outputs 10 as output. However, 10 not valid JSON (according to jsonlint ) and must be enclosed in square brackets ( [10] , so it will be a singleton array) or in curly brackets ( {value:10} , so this will be an object with a dummy property). The problem affects numbers, java.lang.String , java.util.Date , ...

My question is: how to get Jackson to do the wrapper? Shouldn't Jackson give out valid JSON?

I analyzed Jackson's behavior with SerializationConfig.Feature.WRAP_ROOT_VALUE enabled: it does not work as I expect. The primitives are now serialized for valid JSON ( {"Integer":10} ), but the "normal" Java beans are also wrapped, which is undesirable ( {"MyBean":{"field":value, ...}} instead of {"field":value, ...} ).

If anyone can advise how to configure Jackson, perhaps with a custom serializer. The difficulty would be to distinguish the root primitive shell (which needs to be wrapped) from the primitive bean property (no need to wrap).

To make the story complete: Jackson's serializer is used as a message converter for Spring MVC, and I doubt it's pretty easy to write a hook to intercept the serialization of primitives (which will not call Jackson, but just return "[" + String.toString(obj) + "]" if necessary). Therefore, I would prefer a solution with tuned Jackson.

+6
source share
1 answer

Finally, a custom serializer

 import java.io.IOException; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.ser.std.ScalarSerializerBase; public class NumberSerializer extends ScalarSerializerBase<Number> { protected NumberSerializer() { super(Number.class); } @Override public void serialize(Number value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { if (jgen.getOutputContext().inRoot()) { jgen.writeStartArray(); jgen.writeNumber(value.longValue()); jgen.writeEndArray(); } else { jgen.writeNumber(value.longValue()); } } } 

did the job for me. A serializer can be registered as a module (see here ).

Note that when using this seriazlier: since it turns all primitives into primitive arrays with only one element, it violates the principle of reflection in the sense that A != desrialize(serialize(A)) where A is some primitive.

+3
source

Source: https://habr.com/ru/post/920897/


All Articles