简体   繁体   中英

Serialization of root primitive objects with Jackson

I am facing the following problems. When 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());

produces 10 as output. However 10 is not a valid JSON (according to jsonlint ) and should be wrapped either in square brackets ( [10] , so it will be a single-element array) or in curly brackets ( {value:10} , so it will be an object with dummy property). The problem affects numbers, java.lang.String , java.util.Date , ...

My question is: How to make Jackson to perform the wrapping? Shouldn't Jackson always produce a valid JSON?

I have analyzed Jackson behavior with SerializationConfig.Feature.WRAP_ROOT_VALUE enabled: it does not work as I expect. Primitives are now serialized to valid JSON ( {"Integer":10} ), but "normal" Java beans are also wrapped which is undesired ( {"MyBean":{"field":value, ...}} instead of {"field":value, ...} ).

If somebody can advise how to customize Jackson, perhaps with custom serializer. The difficulty would be that it is necessary to distinguish the root primitive wrapper (which needs to be wrapped) from bean primitive property (does not need to be wrapped).

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

Finally the 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 a job for me. Serializer can be registered as module (see here ).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM