我面临以下问题。当Jackson序列化程序传递一个用于序列化的包装原语时,该原语按原样序列化,例如:
objectMapper = new ObjectMapper();
StringWriter w = new StringWriter();
objectMapper.writeValue(w, Integer.valueOf(10));
System.out.println(w.toString());
生成10
作为输出。但是10
不是有效的JSON(根据jsonlint)并且应该用方括号([10]
包装,因此它将是单元素数组)或大括号括起来( {value:10}
,因此它将是一个具有虚拟属性的对象)。该问题会影响数字,java.lang.String
,java.util.Date
,...
我的问题是:如何让杰克逊进行包装?杰克逊不应该总是生成有效的JSON吗?
我已经启用了SerializationConfig.Feature.WRAP_ROOT_VALUE
分析了杰克逊的行为:它无法正常工作。现在,基元被序列化为有效的JSON({"Integer":10}
),但“正常”的Java bean也被包装,这是不受欢迎的({"MyBean":{"field":value, ...}}
而不是{"field":value, ...}
)。
如果有人可以建议如何定制杰克逊,也许可以使用自定义序列化器。困难在于有必要区分根原始包装器(需要包装)和bean原始属性(不需要包装)。
为了使故事完整:Jackson序列化程序被用作Spring MVC的消息转换器,我怀疑编写一个钩子来拦截原语序列化是很容易的(它不会调用Jackson而只会返回{{1} } 必要时)。所以我更喜欢与杰克逊合作的解决方案。
答案 0 :(得分: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());
}
}
}
为我做了一份工作。 Serializer可以注册为模块(参见here)。
使用此序列化器时请注意:由于它将所有原语转换为只有一个元素的原始数组,因此在A != desrialize(serialize(A))
A
中{{1}}是某种原语的意义上会破坏反射原理。