当前位置: 首页 > 面试题库 >

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

车峻熙
2023-03-14
问题内容

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

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

我正在使用com.fasterxml.jackson.databind.ObjectMapperJSON将项目保存到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"}

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

在上面的示例中,原始Instant值为2017-08-14T12:17:47.720Z,但是序列化的字符串为2017-08-14 12:17:47(不包括秒),因此反序列化时的结果Instant2017-08-14T12:17:47Z.720丢失了毫秒)。



 类似资料:
  • 我有一个关键字列表,我想从中创建一个名为的特定查询。我有一个查询后缀,我想返回一个字符串,它以开头,后面跟着每个关键字从: 大概是这样的: 我希望返回的字符串看起来像这样:

  • 问题内容: 我想知道是否有可能在Java中使用String.format方法给出一个在零之前的整数? 例如: 1将变为001 2将变为002 … 11将变为011 12将变为012 … 526将保留为526 … 目前,我尝试了以下代码: 不幸的是,它在数字之前带有3个空格。可以在数字前加零吗? 问题答案: 使用格式说明为整数。的装置,该数目将是零填充,如果它是少于三个(在这种情况下)位。 有关其他

  • 问题内容: 如果我想使格式化后的字符串动态可调,则可以从 至 但是,这里的字符串连接似乎很麻烦。还有其他简化方法吗? 问题答案: 您可以从参数列表中获取填充值: 您甚至可以动态插入填充值:

  • 我是Android开发新手,我正在尝试以下代码: 我明白了: 隐式使用默认语言环境是常见的错误源: 使用字符串。格式(区域设置,…)相反 我不知道如何修改代码以实现建议。

  • 我试图使用新的Java8time-API和一个模式将即时格式化为字符串: 使用上面的代码,我得到了一个异常,它抱怨一个不受支持的字段:

  • 问题内容: 如何使用JAX-RS设置字符集?我试过了,但是被忽略了,只用HTTP标头发送。我想在MessageBodyWriter中设置字符集,但是不想自己通过反射来分析@Produces批注来提取媒体类型。 问题答案: 正如Daemon在评论中指出的那样,JAX-RS的最新版本(包括截至2012年9月的稳定版本)现在 确实 支持该语法。因此,您可以使用: