【问题标题】:custom jackson serializer not working with gson自定义杰克逊序列化程序不适用于 gson
【发布时间】:2017-06-16 13:21:27
【问题描述】:

我正在使用 Jackson & Jersey 制作一个网络应用程序。我已经为托管的 API 制作了响应 POJO。我为日期字段制作了一个自定义 Jackson 序列化程序,如下所示。

class A{
    LocalDateTime localDateTime = LocalDateTime.now();

    @JsonSerialize(using = JacksonSerializers.DateSecondsFromEpochUTCSerializer.class)
    public LocalDateTime getLocalDateTime() {
        return localDateTime;
    }

    public void setLocalDateTime(LocalDateTime localDateTime) {
        this.localDateTime = localDateTime;
    }
}

序列化器如下:

public class JacksonSerializers {

@Component
public static class DateSecondsFromEpochUTCSerializer extends JsonSerializer<LocalDateTime> {

    @Override
    public void serialize(LocalDateTime localDateTime, JsonGenerator gen, SerializerProvider provider)
            throws IOException, JsonProcessingException {
        gen.writeNumber(localDateTime.toEpochSecond(ZoneOffset.UTC));
    }

}

当调用 API 并且响应包含 epoch 格式的日期时,上述代码工作正常。

但是,当我尝试使用 GSON 库制作类的 JSON 时,上述序列化不起作用。我得到以下不正确的输出:

System.out.print(new Gson().toJson(new A()));

给了

{"localDateTime":{"date":{"year":2017,"month":1,"day":31},"time":{"hour":12,"minute":55,"second":53,"nano":481000000}}}

但我想要1485847871。基本上,我想在两个流程中以纪元时间序列化 LocalDateTime 。我现在正在尝试使用 GSON,但这不是核心要求。实现这两个结果的任何优雅的解决方案都可以。

【问题讨论】:

  • 这个问题基本上不能归结为“如何使用 GSON 将 LocalDateTime 序列化为纪元格式?”?为什么杰克逊部分(显然按预期工作)甚至是问题的一部分?
  • 因为这不是我要问的。我已经能够使用杰克逊将 LocalDateTime 解析为泽西岛的纪元格式。现在,我将相同的 POJO 用于其他一些任务,这次我使用 GSON 将 POJO 序列化为 JSON,并且这种方法不会产生类似于 Jackson 产生的所需结果。我想要一个共同的解决方案来解决这两个问题,因为这两个问题必须同时运行。
  • ObjectMapper (Jackson) 解决了这两个问题。后一部分有一个先决条件,即早期使用杰克逊的序列化不能改变,但后者可以
  • 如果有人用 Gson 解决方案回答怎么办?
  • 那么这也是这个问题的正确答案。一个问题可以有多个解决方案。 :)

标签: java json serialization jackson gson


【解决方案1】:

您可以创建一个统一的序列化程序,供 Jackson 和 GSON 使用。类似这样的东西:

public class DateSecondsFromEpochUTCSerializer
        extends com.fasterxml.jackson.databind.JsonSerializer<LocalDateTime>
        implements com.google.gson.JsonSerializer<LocalDateTime> {

    @Override
    public void serialize(LocalDateTime localDateTime, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeNumber(convert(localDateTime));
    }

    @Override
    public JsonElement serialize(LocalDateTime ldt, Type type, JsonSerializationContext jsonSerializationContext) {
        return new JsonPrimitive(convert(ldt));
    }

    private long convert(LocalDateTime ldt) {
        return ldt.toEpochSecond(ZoneOffset.UTC);
    }
}

像这样在你的 GSON 实例中安装它:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(LocalDateTime.class, new DateSecondsFromEpochUTCSerializer())
    .create();
System.out.println(gson.toJson(LocalDateTime.now())); // Epoch

【讨论】:

    【解决方案2】:

    如果您仍然可以使用 Gson,并且不需要引入 Jackson,因为它是一个完全不同的库,您可以使用自定义 Gson 类型适配器:

    final class LocalDateTimeTypeAdapter
            extends TypeAdapter<LocalDateTime> {
    
        private static final TypeAdapter<LocalDateTime> localDateTimeTypeAdapter = new LocalDateTimeTypeAdapter();
    
        private LocalDateTimeTypeAdapter() {
        }
    
        static TypeAdapter<LocalDateTime> getLocalDateTimeTypeAdapter() {
            return localDateTimeTypeAdapter;
        }
    
        @Override
        @SuppressWarnings("resource")
        public void write(final JsonWriter out, final LocalDateTime value)
                throws IOException {
            out.value(value.toEpochSecond(UTC));
        }
    
        @Override
        public LocalDateTime read(final JsonReader in)
                throws IOException {
            return Instant.ofEpochSecond(in.nextLong()).atZone(UTC).toLocalDateTime();
        }
    
    }
    

    这类似于 JsonSerializer/JsonDeserializer 对的 Gson,但它更有效,因为后者需要在内存中构建 JSON 树,而类型适配器以流方式工作,并且可能生成不累积中间状态的值很多。然后只需配置您的 Gson 实例:

    final Gson gson = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, getLocalDateTimeTypeAdapter())
            .create();
    final String json = gson.toJson(new A());
    out.println(json);
    final A a = gson.fromJson(json, A.class);
    out.println(a.localDateTime);
    

    它会产生类似的东西:

    {"localDateTime":1485871467}
    2017-01-31T14:04:27

    用于序列化和反序列化。

    【讨论】:

      【解决方案3】:

      对我有用的解决方案:

      new ObjectMapper().writeValueAsString(new A())
      

      【讨论】:

        猜你喜欢
        • 2013-05-20
        • 2016-02-19
        • 1970-01-01
        • 2016-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-31
        • 2016-12-18
        相关资源
        最近更新 更多