簡體   English   中英

使用 Jackson ObjectMapper 將 JSON 反序列化為 Java POJO 時如何將日期字符串正確解析為 java.util.Date

[英]How to parse properly Date string to java.util.Date when deserializing JSON to Java POJO with Jackson ObjectMapper

我正在實現一個應用程序,它以 json 格式從 certin 端點獲取數據,並嘗試將 tem 反序列化為 Java 對象,但我在解析 JSON 中的日期時遇到問題。這是日期在 JSON 中的樣子:“/ Date(1633122000000+0300)/" 我在谷歌中找不到如何成功解析這種格式的信息。

{
  "Date": "/Date(1633122000000+0300)/",
  "Filled": 0,
  "Needed": 0,
  "Paid": 0
}

這是我用來將數據反序列化為使用 Jackson ObjectMapper 的 pojo:

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TimeByDateSheet {

    @JsonProperty("Date")
    @JsonFormat(timezone = "GMT+03:00")
    @JsonDeserialize(using = DateDeserializer.class, as=Date.class)
    private Date date;
    
    @JsonProperty("Filled")
    private Long filled;
 
    @JsonProperty("Needed")
    private Long needed;
    
   @JsonProperty("Paid")
   private Integer paid;

}

這是我的 DateDeserializer:

@SuppressWarnings("serial")
public class DateDeserializer extends JsonDeserializer<Date> {

@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context) 
throws IOException, JsonProcessingException {
    SimpleDateFormat simpleDateFormat = 
         new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz", Locale.getDefault());
    String dateStr = jsonParser.getText();
    Date date;
    try{
        date = simpleDateFormat.parse(dateStr);
    }catch(ParseException e){
        throw new RuntimeException(e);
    }
    return date;
}

}

但它不能正常工作。 我收到以下異常:

連接到目標VM,地址:'127.0.0.1:52760',傳輸:'socket' SLF4J:加載類“org.slf4j.impl.StaticLoggerBinder”失敗。 SLF4J:默認為無操作 (NOP) 記錄器實現 SLF4J:有關更多詳細信息,請參閱http://www.slf4j.org/codes.html#StaticLoggerBinder 線程“main”中的異常 com.fasterxml.jackson.databind.JsonMappingException: java.text.ParseException: Unparseable date: "/Date(1633035600000+0300)/"(通過引用鏈:java.util.ArrayList[0]-> com.dataart.forecasts.pojo.timebydate.TimeByDateSheet["Date"]) 在 com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:392) 在 com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException) .java:351) 在 com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1821) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:315) 在fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176) 在 com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:355) 在 com.fasterxml.datajackson deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:24 4) 在 com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28) 在 com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322) 在 com. .jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4675) 在 com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3630) 在 com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java) :3613) 在 com.dataart.forecasts.DataProcessor.deserializeTimeByDateSheetsList(DataProcessor.java:198) 在 com.dataart.forecasts.ForecastReportApplication.main(ForecastReportApplication.java:50) 由:java.lang.RuntimeException: java.text. ParseException:無法解析的日期:“/Date(1633035600000+0300)/” at com.dataart.forecasts.DateDeserializer.deserialize(DateDeserializer.java:28) at com.dataart.forecasts.DateDeserializer.deserialize(Date16Deserializer) at com.dataart.forecasts.DateDeserializer.deserialize(DateDeserializer.java:28) com.fasterxml.jackson.databind.deser.impl.MethodPro perty.deserializeAndSet(MethodProperty.java:129) at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313) ... 10個以上引起:java.text.ParseException:無法解析的日期:“/ Date(1633035600000+0300)/" at java.base/java.text.DateFormat.parse(DateFormat.java:395) at com.dataart.forecasts.DateDeserializer.deserialize(DateDeserializer.java:26) ... 13 更多

有人可以幫我嗎,請。 我在互聯網上搜索了很多,但找不到解決方案。 先感謝您! :)

時間

對於這個答案,我假設:

  1. JSON 中的時間可能帶有或不帶有 UTC 偏移量。
  2. 例如,您可以全面使用現代 Java 日期和時間 API java.time,並將變量聲明為InstantOffsetDateTime類型(而不是Date )。

對於帶有偏移量(例如+0300 JSON,將變量聲明為OffsetDateTime 然后使用以下解串器。

public class OdtDeserializer extends JsonDeserializer<OffsetDateTime> {

    private static final DateTimeFormatter JSON_DATE_FORMATTER = new DateTimeFormatterBuilder()
            .appendLiteral("/Date(")
            .appendValue(ChronoField.INSTANT_SECONDS)
            .appendValue(ChronoField.MILLI_OF_SECOND, 3)
            .appendOffset("+HHMM", "Z")
            .appendLiteral(")/")
            .toFormatter();

    @Override
    public OffsetDateTime deserialize(JsonParser jsonParser, DeserializationContext context)
            throws IOException {
        String dateStr = jsonParser.getText();
        return OffsetDateTime.parse(dateStr, JSON_DATE_FORMATTER);
    }

}

對於沒有偏移量的 JSON,/Date(1636510000000)/聲明您的變量Instant 使用類似的解串器。 忽略格式化程序的偏移量。 解析為Instant — 語法有點不同。

public class InstantDeserializerWIthoutOffset extends JsonDeserializer<Instant> {

    private static final DateTimeFormatter JSON_DATE_FORMATTER = new DateTimeFormatterBuilder()
            .appendLiteral("/Date(")
            .appendValue(ChronoField.INSTANT_SECONDS)
            .appendValue(ChronoField.MILLI_OF_SECOND, 3)
            .appendLiteral(")/")
            .toFormatter();

    @Override
    public Instant deserialize(JsonParser jsonParser, DeserializationContext context)
            throws IOException {
        String dateStr = jsonParser.getText();
        return JSON_DATE_FORMATTER.parse(dateStr, Instant::from);
    }

}

對於可能帶有或不帶有偏移量的 JSON仍然使用Instant並且只需修改后一個反序列化器的格式化程序以包含一個可選的偏移量:

    private static final DateTimeFormatter JSON_DATE_FORMATTER = new DateTimeFormatterBuilder()
            .appendLiteral("/Date(")
            .appendValue(ChronoField.INSTANT_SECONDS)
            .appendValue(ChronoField.MILLI_OF_SECOND, 3)
            .optionalStart()
            .appendOffset("+HHMM", "Z")
            .optionalEnd()
            .appendLiteral(")/")
            .toFormatter();

如果您無法修改您的 POJO 類並且需要使用Date ,請通過更改聲明並返回一個Date來將我的Instant deserializer 修改為Date反序列化器,如下所示:

        String dateStr = jsonParser.getText();
        Instant inst = JSON_DATE_FORMATTER.parse(dateStr, Instant::from);
        return Date.from(inst);

捕獲兩者的最終解決方案:/Date(1633035600000+0300)/ 和 /Date(-62135596800000)/(后者也出現在其中一個 JSON 中的一個位置)。 謝謝@DavidConrad

@Override
    public Date deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
        String dateString = jsonParser.getText();
        Pattern pattern = Pattern.compile("/Date\\((-)?(\\d+)([+-]\\d+)?\\)/");
        Matcher matcher = pattern.matcher(dateString);
        if (!matcher.find()) {
            throw new RuntimeException("Invalid format: " + dateString);
        }
        String timestamp = matcher.group(2);
        String offset = matcher.group(3);
        Instant instant = Instant.ofEpochMilli(Long.parseLong(timestamp));
        if (nonNull(offset)) {
            ZonedDateTime zdt = instant.atZone(ZoneId.of(offset));
            instant = zdt.toInstant();
        }
        return Date.from(instant);
    }

生成 JSON 似乎存在問題。 我真的不認為你想要這樣格式化日期。 現在,您有一些奇怪的文本圍繞着以毫秒為單位的 unix 時間戳,后跟區域偏移量。 您還使用了舊的、 java.time Date 和 SimpleDateFormat 類,而不是較新的java.time API。 但是,可以反序列化您的日期格式。 這是一種方法:

public class DateDeserializer extends JsonDeserializer<Date> {
    @Override
    public Date deserialize(JsonParser jsonParser, DeserializationContext context) 
            throws IOException, JsonProcessingException {
        Pattern pattern = Pattern.compile("/Date\\((\\d+)([+-]\\d+)\\)/");
        Matcher matcher = pattern.matcher(jsonParser.getText());
        if (matcher.find()) {
            String timestamp = matcher.group(1);
            String offset = matcher.group(2);
            Instant instant = Instant.ofEpochMilli(Long.parseLong(timestamp));
            ZonedDateTime zdt = instant.atZone(ZoneId.of(offset));
            instant = zdt.toInstant();
            return Date.from(instant);
        } else {
          throw new RuntimeException("Invalid format: " + jsonParser.getText());
        }
    }
}

@DavidConrad 謝謝,我會嘗試您的解決方案。 順便說一句,現在我做了一個對我有用的解決方法:

@Override
    public Date deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
        SimpleDateFormat dateFormattter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = jsonParser.getText();
        String timeZone = dateStr.substring(dateStr.indexOf("+") + 1, dateStr.indexOf(")"));
        String timeZoneShift = String.format("%s:%s",
                timeZone.substring(0, timeZone.length()/2),
                timeZone.substring(timeZone.length()/2));
        dateFormattter.setTimeZone(TimeZone.getTimeZone(String.format("GMT+%s", timeZoneShift)));
        Long millis = 0L;
        if (dateStr.contains("+") && !dateStr.contains("-")) {
            millis = Long.parseLong(dateStr.substring(dateStr.indexOf("(") + 1, dateStr.indexOf("+")));
        } else if (dateStr.contains("+") && !dateStr.contains("-")) {
            millis = Long.parseLong(dateStr.substring(dateStr.indexOf("(") + 1, dateStr.indexOf(")")));
        }
        Date date = new Date(millis);
        String stringDate= dateFormattter.format(date);
        try {
            date = dateFormattter.parse(stringDate);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        return date;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM