1

I am trying to make Java POJO with java.time packages, which binds the columns of "Federal Reserve Economic Data(FRED)" API. Some of these columns include time matters like below,

 columns name             example
---------------------------------------------
observation_end      2024-10-01 00:00:00
observation_start    2017-10-01 00:00:00
  last_updated       2014-02-04 10:06:03-06:00

So I make the following Java POJO:

@Data
public class FredColumnPojo {
    
    @JsonProperty("realtime_start")
    @JsonFormat(pattern="yyyy-MM-dd")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    private LocalDate realtime_start;
    
    @JsonProperty("realtime_end")
    @JsonFormat(pattern="yyyy-MM-dd")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    private LocalDate realtime_end;
    
    @JsonProperty("last_updated")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss Z")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    private LocalDateTime last_updated;

The realtime_start and realtime_end columns are successfully bound with FRED api. But the last_updated lines throws Exceptions.

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.time.LocalDateTime` from String "2020-12-18 16:04:07-06": Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text '2020-12-18 16:04:07-06' could not be parsed at index 19
 at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: java.util.ArrayList[0]->com.aaa.etl.pojo.FredColumnPojo["last_updated"])
    at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1676)
    at com.fasterxml.jackson.databind.DeserializationContext.handleWeirdStringValue(DeserializationContext.java:932)
    at com.fasterxml.jackson.datatype.jsr310.deser.JSR310DeserializerBase._handleDateTimeException(JSR310DeserializerBase.java:176)

Caused by: java.time.format.DateTimeParseException: Text '2020-12-18 16:04:07-06' could not be parsed at index 19
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)

I think the json format patterns of realtime_start and realtime_end are correct with time format of actual value of FRED api (yyyy-MM-dd). But the last_updated columns throws the exception because the pattern yyyy-MM-dd HH:mm:sss Z is not correct with the string value from the FRED api(Text '2020-12-18 16:04:07-06'). I already insert various value 'Z', 'ZZ', 'x' in the json format pattern. But all of my efforts have failed.

Updated

I solve my issue partly with below codes.

String input = "2014-02-04 10:06:03-06:00".replace(" ", "T");
DateTimeFormatter date = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime ldt = LocalDateTime.parse(input, date);
System.out.println(idt);

My target goal is to make pojo class which contains DateTimeFormatter.ISO_DATE_TIME in JsonFormat of last_updated column. But I have no idea how to implement pojo class with DateTimeFormatter.ISO_DATE_TIME.

@JsonProperty("last_updated")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss Z")  <-- How to set the pattern to DateTimeFormatter.ISO_DATE_TIME
private LocalDateTime last_updated;

Updated Again

So I make the JsonDeserialize class like below:

public class DefaultLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        // TODO Auto-generated method stub
        String input = p.getText().replace(" ", "T");
        DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
        LocalDateTime localDateTime = LocalDateTime.parse(input, formatter);

        return localDateTime;
    }

}

And I change the JsonDeserialize class of POJO class:

@JsonProperty("last_updated")
@JsonDeserialize(using = DefaultLocalDateTimeDeserializer.class)
private LocalDateTime last_updated;

But the codes still throw the exceptions

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Text '2020-12-18T16:04:07-06' could not be parsed, unparsed text found at index 19 (through reference chain: java.util.ArrayList[0]->com.aaa.etl.pojo.FredColumnPojo["last_updated"])
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1714)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:290)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:286)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
    at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:4173)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2492)
    at com.aaa.etl.processor.Fred2Hdfs.getEtlListData(Fred2Hdfs.java:146)
    at com.aaa.etl.processor.EtlFileUploader.main(EtlFileUploader.java:39)
Caused by: java.time.format.DateTimeParseException: Text '2020-12-18T16:04:07-06' could not be parsed, unparsed text found at index 19
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2049)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
    at com.aaa.etl.pojo.DefaultLocalDateTimeDeserializer.deserialize(DefaultLocalDateTimeDeserializer.java:20)
    at com.aaa.etl.pojo.DefaultLocalDateTimeDeserializer.deserialize(DefaultLocalDateTimeDeserializer.java:1)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
    ... 8 more
halfer
  • 19,824
  • 17
  • 99
  • 186
Joseph Hwang
  • 1,337
  • 3
  • 38
  • 67
  • Did you try Timestamp instead of LocalDateTime? – Alter Jan 24 '21 at 00:43
  • @AlejandroDeulofeu The `java.sql.Timestamp` class is now legacy, and should never be used because of flawed design. As of the adoption of JSR 310, the legacy date-time classes became obsolete. The appropriate class for a date with time-of-day and an offset-from-UTC such as `2014-02-04 10:06:03-06:00` is [`OffsetDateTime`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/OffsetDateTime.html). – Basil Bourque Jan 24 '21 at 05:36
  • Kindly check my updated again part and inform me of your smart reply. – Joseph Hwang Jan 25 '21 at 11:13

1 Answers1

0

You don't need to use deserializer. Use JSON format annotation as follows

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssZ")

See this question for more info: Spring Data JPA - ZonedDateTime format for json serialization

UPDATED: The mask mentioned above - "yyyy-MM-dd'T'HH:mm:ssZ" conforms to DateTimeFormatter.ISO_DATE_TIME. However, this format implements several possible masks. If you run toString() methof for DateTimeFormatter.ISO_DATE_TIME you will get the following output:

(ParseCaseSensitive(false)(Value(Year,4,10,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2))'T'(Value(HourOfDay,2)':'Value(MinuteOfHour,2)[':'Value(SecondOfMinute,2)[Fraction(NanoOfSecond,0,9,DecimalPoint)]]))[Offset(+HH:MM:ss,'Z')['['ParseCaseSensitive(true)ZoneRegionId()']']]

For more details see Javadoc. The short answer is the same as before:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssZ")

Also, I can refer you to an article I wrote about how to implement parsing String to Date when you don't know the format in advance. The general idea is that you prepare the list of all formats that you'd like to support and try to parse your String with those formats one by one until you find one that works. There are, however, several details and implications in that solution. Also, some enhancements. See the article about it here: Java 8 java.time package: parsing any string to date

Michael Gantman
  • 7,315
  • 2
  • 19
  • 36