如何配置Jackson将Longs序列化为字符串,而不是整数或双精度?

时间:2017-11-03 21:44:21

标签: java json serialization jackson

我们之前使用的是一个框架(Cloud Endpoints),它自动将java.lang.Long序列化为JSON字符串(同时将整数和双数作为JSON数字)。我们正在迁移使用更标准的Jackson序列化框架。

为了向后兼容,我们需要Jackson能够将Longs序列化为字符串,同时默认情况下将整数和双打保持为JSON数字。我没有看到杰克逊的任何功能。这可能吗?

2 个答案:

答案 0 :(得分:4)

Long.classlong.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应该适用于大多数情况,但是

  1. 您不需要自定义反序列化程序。默认的反序列化器可以处理String =&gt;

  2. 可以使用com.fasterxml.jackson.databind.ser.std.ToStringSerializer序列化程序

    module.addSerializer(Long.class, ToStringSerializer.instance);
    module.addSerializer(long.class, ToStringSerializer.instance);
    
  3. 您将获得边缘情况,因为当另一个自定义序列化程序使用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]
    }
    
  4. 所以你实际上可以

    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);