java - 如何使用 objectMapper 设置 java.time.Instant 的字符串格式?

标签 java java-8 jackson java-time objectmapper

我有一个带有 java.time.Instant 的实体用于创建数据字段:

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Item {
    private String id;
    private String url;
    private Instant createdDate;
}

我正在使用 com.fasterxml.jackson.databind.ObjectMapper 将项目作为 JSON 保存到 Elasticsearch:

bulkRequestBody.append(objectMapper.writeValueAsString(item));

ObjectMapper 将这个字段序列化为一个对象:

"createdDate": {
    "epochSecond": 1502643595,
    "nano": 466000000
}

我正在尝试注释 @JsonFormat(shape = JsonFormat.Shape.STRING) 但它对我不起作用。

我的问题是如何将此字段序列化为 2010-05-30 22:15:52 字符串?

最佳答案

一种解决方案是使用 jackson-modules-java8 .然后您可以将 JavaTimeModule 添加到您的对象映射器:

ObjectMapper objectMapper = new ObjectMapper();

JavaTimeModule module = new JavaTimeModule();
objectMapper.registerModule(module);

默认情况下,Instant 被序列化为纪元值(单个数字中的秒和纳秒):

{"createdDate":1502713067.720000000}

您可以通过在对象映射器中进行设置来更改它:

objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

这将产生输出:

{"createdDate":"2017-08-14T12:17:47.720Z"}

以上两种格式都是反序列化的,没有任何额外的配置。

要更改序列化格式,只需在字段中添加一个JsonFormat注解即可:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
private Instant createdDate;

您需要设置时区,否则 Instant 无法正确序列化(它会抛出异常)。输出将是:

{"createdDate":"2017-08-14 12:17:47"}

如果您不想(或不能)使用 java8 模块,另一种选择是使用 java.time.format.DateTimeFormatter 创建自定义序列化器和反序列化器:

public class MyCustomSerializer extends JsonSerializer<Instant> {

    private DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC);

    @Override
    public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
        String str = fmt.format(value);

        gen.writeString(str);
    }
}

public class MyCustomDeserializer extends JsonDeserializer<Instant> {

    private DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC);

    @Override
    public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return Instant.from(fmt.parse(p.getText()));
    }
}

然后用这些自定义类注释该字段:

@JsonDeserialize(using = MyCustomDeserializer.class)
@JsonSerialize(using = MyCustomSerializer.class)
private Instant createdDate;

输出将是:

{"createdDate":"2017-08-14 12:17:47"}

一个细节是,在序列化字符串中,您将丢弃秒的小数部分(小数点后的所有内容)。因此,在反序列化时,此信息无法恢复(它将被设置为零)。

在上面的例子中,原始的Instant2017-08-14T12:17:47.720Z,但是序列化后的字符串是2017-08-14 12:17:47(没有秒的小数部分),所以当反序列化时生成的 Instant2017-08-14T12:17:47Z(.720 毫秒丢失)。

关于java - 如何使用 objectMapper 设置 java.time.Instant 的字符串格式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45662820/

相关文章:

java - Optional.ofNullable() 和 `Optional.of() 有什么区别

java - 通用 Java 函数 - 返回通用值

java - 从 Java 8 升级到 Java 11 - 包 sun.util 不存在

java - Jackson 无法在 Android 上加载 JDK7 类型

java - 学习 XML 和 Java 的书

java - 无法将 JSON 数据发布到 Jersey Restful Web 服务

Java 2D 数组越界错误

java - SQL用IN语句选择所有记录

java - 无法写入 JSON : failed to lazily initialize a collection of role

java - JSON 字段 - 将字符串解析为 Int