使用Jackson序列化根原始对象

dma*_*a_k 6 java serialization json jackson

我面临以下问题.当Jackson序列化程序传递一个用于序列化的包装原语时,该原语按原样序列化,例如:

objectMapper = new ObjectMapper();

StringWriter w = new StringWriter();
objectMapper.writeValue(w, Integer.valueOf(10));
System.out.println(w.toString());
Run Code Online (Sandbox Code Playgroud)

产生10输出.但是,10它不是一个有效的JSON(根据jsonlint),应该用方括号([10]因此它将是一个单元素数组)或大括号({value:10}因此它将是一个具有虚拟属性的对象)包装.该问题影响的数字,java.lang.String,java.util.Date,...

我的问题是:如何让杰克逊进行包装?Jackson不应该总是生成有效的JSON吗?

我已经SerializationConfig.Feature.WRAP_ROOT_VALUE启用了杰克逊的行为分析:它不能像我预期的那样工作.现在,基元被序列化为有效的JSON({"Integer":10}),但"正常"的Java bean也被包装,这是不希望的({"MyBean":{"field":value, ...}}而不是{"field":value, ...}).

如果有人可以建议如何定制杰克逊,也许可以使用自定义序列化器.难点在于有必要区分根原语包装器(需要包装)和bean原始属性(不需要包装).

为了使故事完整:Jackson序列化程序被用作Spring MVC的消息转换器,我怀疑编写一个钩子来拦截原语序列化(它不会调用Jackson但只会"[" + String.toString(obj) + "]"在必要时返回)相当容易.所以我更喜欢调优杰克逊的解决方案.

dma*_*a_k 3

最后是自定义序列化器

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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

为我做了一份工作。序列化器可以注册为模块(请参阅此处)。

使用此序列化器时请注意:由于它将所有基元转换为只有一个元素的基元数组,因此在某种意义上打破了反射原理,即A != desrialize(serialize(A))whereA是某个基元。