如何使用 Jackson 将 ISO8601 持续时间字符串反序列化为 Duration 和 period 对象

问题描述 投票:0回答:4

我有一个包含 ISO8601 持续时间字符串(P3Y6M4DT12H30M5S)的字符串值。 如何使用 Jackson 将其反序列化为 Duration 和 period 对象? 我知道 Duration 接受天、小时、分钟、秒和 Period 年和月。

java jackson duration iso8601 period
4个回答
0
投票

tl;博士

org.threeten.extra.PeriodDuration.parse( "P3Y6M4DT12H30M5S" ) ;

详情

  • A
    Period
    代表年、月、日规模的时间跨度。
  • A
    Duration
    表示以小时为单位的时间跨度, 分钟、秒和纳秒。

注意事项:将这两个概念合并为一个,如示例输入字符串所示,在实践中很少有意义。

PeriodDuration
班级

但是,如果您坚持使用这些值,则有一个类可以实现。将 ThreeTen-Extra 库添加到您的项目中。然后您就可以访问

PeriodDuration
课程。

无需定义格式化模式。您的输入符合 ISO 8601 标准。 java.time 类在解析/生成文本时默认使用标准格式。

org.threeten.extra.PeriodDuration pd = PeriodDuration.parse( "P3Y6M4DT12H30M5S" ) ;

以标准 ISO 8601 格式生成文本。

String output = pd.toString() ;

您会在该类中找到一些方便的方法,用于构造、标准化、数学(加法、减法、求反)等。

至于杰克逊,我不是用户。我不知道如何在 Jackson 中使用第三方类作为自动格式化程序。


0
投票

我不想使用外部依赖来使用如此简单的方法,所以我自己实现了它。

我创建了 PeriodDuration 类,其中包含周期和持续时间字段。

接下来,我创建了扩展 StdDeserializer 的反序列化器,并用 @JsonDeserializer(using = "nameOfMyCustomDeserializer.class) 注释了

PeriodDuration
类。该解串器将 iso8601 持续时间字符串拆分为两个字符串,即“T”之前和“T”之后。如果周期部分为空,则设置Period.ZERO,但如果持续时间部分为空,则设置Duration.ZERO。


0
投票

将 com.fasterxml.jackson.datatype.jsr310.JavaTimeModule 添加到您的 JsonMapper/ObjectMapper - 请参阅 https://github.com/FasterXML/jackson-modules-java8

对于序列化,您需要禁用 SerializationFeature.WRITE_DATES_AS_TIMESTAMPS - 默认情况下处于启用状态。禁用时,持续时间输出为 ISO-8601 格式(例如 PT12H 为 12 小时)。


0
投票

我使用的 API 可在月份(期间)和天(持续时间)内返回 ISO8601。这是我在客户端代码中所做的:

  1. 设置对应字段类型TemporalAmount
  2. 创建 objectMapper 时导入 java time 模块
  3. 创建一个 TemporalAmountDeserializer 类(使用 Java Time Module 的反序列化器)尝试反序列化为周期,如果失败,则作为持续时间,否则抛出异常

public class ObjectMapperFactory {

    private ObjectMapper buildMapper() {
        return JsonMapper.builder()
            .addModule(new JavaTimeModule())
            .addModule(new SimpleModule().addDeserializer(TemporalAmount.class, new TemporalAmountDeserializer()))
            .build();
    }

    public static class TemporalAmountDeserializer extends JsonDeserializer<TemporalAmount> {
        @Override
        public TemporalAmount deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            try {
                var durationDeserializer = ctxt.findRootValueDeserializer(ctxt.constructType(Period.class));
                return (Period) durationDeserializer.deserialize(p, ctxt);
            } catch (Exception e) {
                try {
                    var periodDeserializer = ctxt.findRootValueDeserializer(ctxt.constructType(Duration.class));
                    return (Duration) periodDeserializer.deserialize(p, ctxt);
                } catch (Exception ex) {
                    throw JsonMappingException.from(p, "Could not deserialize as either Duration or Period", ex);
                }
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.