java—如何将多种格式的日期字段反序列化为localdate变量

liwlm1x9  于 2021-07-12  发布在  Java
关注(0)|答案(3)|浏览(426)

我有一个简单的dto,我想作为json接收,并使用jackson的 ObjectMapper ```
class SimpleDto {
LocalDate date;
}

问题是这个日期的格式应该是 `yyyy-MM-dd` ,不是固定的,它可能会丢失某些部分-例如,它可能是完整日期

{
"date": "2020-01-01"
}

或者只是一年一个月没有一天

{
"date": "2020-01"
}

甚至仅仅一年

{
"date": "2020"
}

我试着用 `ObjectMapper` 与 `JavaTimeModule` 已注册,但不支持例如没有月份和日期格式的年份

ObjectMapper mapper = new ObjectMapper().registerModule(JavaTimeModule());

有没有可能把它Map到 `LocalDate` ? 我看到一些类似的主题(像这样),但似乎他们没有回答我的问题
编辑
现在我开始思考,我应该把这个领域当作 `LocalDate` -据我所知 `LocalDate.of(2000, 0, 0)` (实际上是抛出异常)然后反序列化 `1990` 去(什么?) `1990-01-01` 显然是一个错误,可能会导致逻辑中的一些异常 `01` 是有效且提供的月份和 `01` 是一个有效和规定的日期
pgx2nnw8

pgx2nnw81#

您可以创建具有 DateTimeFormatter 使用 DateTimeFormatterBuilder#parseDefaulting .

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        //Test
        Stream.of(
                    "2020-01-01",
                    "2020-01",
                    "2020"
        ).forEach(s -> System.out.println(parseToLocalDate(s)));
    }
    static LocalDate parseToLocalDate(String date) {
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                    .appendPattern("u[-M[-d]]")
                                    .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                                    .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
                                    .toFormatter(Locale.ENGLISH);

        return LocalDate.parse(date, dtf);
    }
}

输出:

2020-01-01
2020-01-01
2020-01-01

模式, u[-M[-d]] 在方括号内有可选字段。

nbnkbykc

nbnkbykc2#

扩展localdatedeserializer,然后使用@jsonserialize(using=yourlocaldateserializer.class)怎么样

vsmadaxz

vsmadaxz3#

LocalDate 只能保存有效日期。我从您的编辑中了解到,您不希望日期为2020年1月1日,以防您的json输入中只出现了2020年。您可以围绕以下代码构建一个自定义反序列化程序,但它有一些缺点。

public TemporalAccessor deserialize(String inputDate) {
    switch (inputDate.length()) {
    case 10:
        return LocalDate.parse(inputDate);
    case 7:
        return YearMonth.parse(inputDate);
    case 4:
        return Year.parse(inputDate);
    default:
        throw new IllegalArgumentException("Not a valid input date: " + inputDate);
    }
}

但是,你不知道结果的确切类型是不现实的。如果解析的值包含一个月或一个月的某一天,那么这些值来自输入。为了演示:

String[] exampleInputs = { "2020-01-01", "2020-01", "2020" };
    for (String example : exampleInputs) {
        TemporalAccessor parsed = deserialize(example);
        System.out.format(
                "%-10s parsed into %-10s, a %-9s. Has month? %-5b Has day? %b%n",
                example, parsed, parsed.getClass().getSimpleName(),
                parsed.isSupported(ChronoField.MONTH_OF_YEAR),
                parsed.isSupported(ChronoField.DAY_OF_MONTH));
    }

输出为:

2020-01-01 parsed into 2020-01-01, a LocalDate. Has month? true  Has day? true
2020-01    parsed into 2020-01   , a YearMonth. Has month? true  Has day? false
2020       parsed into 2020      , a Year     . Has month? false Has day? false

相关问题