我们之前使用的是一个框架(Cloud Endpoints),它自动将java.lang.Long序列化为JSON字符串(同时将整数和双数作为JSON数字)。我们正在迁移使用更标准的Jackson序列化框架。
为了向后兼容,我们需要Jackson能够将Longs序列化为字符串,同时默认情况下将整数和双打保持为JSON数字。我没有看到杰克逊的任何功能。这可能吗?
答案 0 :(得分:4)
为Long.class
和long.class
使用自定义序列化工具:
public static class LongSerializer extends JsonSerializer<Long> {
@Override
public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(value.toString());
}
}
public static class LongDeserializer extends JsonDeserializer<Long> {
@Override
public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return p.getValueAsLong();
}
}
您需要在映射器中注册它们:
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(long.class, new LongSerializer());
module.addSerializer(Long.class, new LongSerializer());
module.addDeserializer(long.class, new LongDeserializer());
module.addDeserializer(Long.class, new LongDeserializer());
objectMapper.registerModule(module);
Test test = new Test();
String json = objectMapper.writeValueAsString(test);
System.out.println(json);
}
答案 1 :(得分:1)
选项1.自定义序列化程序
@teppic answer应该适用于大多数情况,但是
您不需要自定义反序列化程序。默认的反序列化器可以处理String =&gt;
可以使用com.fasterxml.jackson.databind.ser.std.ToStringSerializer
序列化程序
module.addSerializer(Long.class, ToStringSerializer.instance);
module.addSerializer(long.class, ToStringSerializer.instance);
您将获得边缘情况,因为当另一个自定义序列化程序使用this JsonGenerator method时,自定义序列化程序方法实际上无法处理案例
(JsonGenerator) g.writeNumber((long)value);
这里最重要的边缘案例是long[].class
static class MyBean {
long val = 1; // works fine "1"
Long val2 = 2L; // works fine "2"
long[] vals = {1,2}; // doesn't work [1,2]
}
所以你实际上可以
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Long.class, ToStringSerializer.instance);
module.addSerializer(long.class, ToStringSerializer.instance);
module.addSerializer(long[].class, new JsonSerializer<long[]>(){
@Override
public final void serialize(
long[] value, JsonGenerator g, SerializerProvider provider)
throws IOException {
g.writeStartArray();
for (int i = 0, len = value.length; i < len; ++i)
g.writeString(String.valueOf(value[i]));
g.writeEndArray();
}
});
// register every other serializers that use
// (JsonGenerator) g.writeNumber((long)value);
// like AtomicLong, if you use it in your code
mapper.registerModule(module);
MyBean bean = new MyBean();
String json = mapper.writeValueAsString(bean);
MyBean myBean2 = mapper.readValue(json, MyBean.class);
System.out.println(json);
System.out.println(myBean2);
System.out.println(mapper.writeValueAsString(myBean2));
}
选项2.自定义JsonFactory和JsonGenerator
但话又说回来,这对你来说已经足够了吗?你确定没有人会尝试使用jsonGenerator.writeNumber(long)
或者你是否有其他类,实际上是默认使用它?所以100%工作的解决方案是在ObjectMapper上注册自定义JsonFactory,使用2个重写方法_createGenerator
和_createUTF8Generator
JsonFactory factory = new JsonFactory(){
@Override
protected JsonGenerator _createGenerator(Writer out, IOContext ctxt)
throws IOException {
WriterBasedJsonGenerator gen = new WriterBasedJsonGenerator(ctxt,
_generatorFeatures, _objectCodec, out){
@Override
public void writeNumber(long l) throws IOException {
writeString(String.valueOf(l));
}
};
return _internalSuperSetup(gen);
}
@Override
protected JsonGenerator _createUTF8Generator(OutputStream out, IOContext ctxt)
throws IOException {
UTF8JsonGenerator gen = new UTF8JsonGenerator(ctxt,
_generatorFeatures, _objectCodec, out){
@Override
public void writeNumber(long l) throws IOException {
writeString(String.valueOf(l));
}
};
return _internalSuperSetup(gen);
}
// reuse code from _createUTF8Generator and _createGenerator super methods
private JsonGenerator _internalSuperSetup(JsonGenerator gen){
if (_characterEscapes != null) gen.setCharacterEscapes(_characterEscapes);
SerializableString rootSep = _rootValueSeparator;
if (rootSep != DefaultPrettyPrinter.DEFAULT_ROOT_VALUE_SEPARATOR)
gen.setRootValueSeparator(rootSep);
return gen;
}
};
ObjectMapper mapper = new ObjectMapper(factory);