I'm trying to deserialise the following Json String into a Java record using Micronaut 4.2.4 with Micronaut Serialization (No Jackson Implemenation involved) and having troubles to successfully parse American time values (such as sunrise
, sunset
, …) into a java.time.LocalTime
.
{
"results": {
"date": "2024-02-02",
"sunrise": "7:52:59 AM",
"sunset": "5:27:56 PM",
"first_light": "6:07:12 AM",
"last_light": "7:13:44 PM",
"dawn": "7:20:03 AM",
"dusk": "6:00:52 PM",
"solar_noon": "12:40:28 PM",
"golden_hour": "4:41:39 PM",
"day_length": "9:34:56",
"timezone": "Europe/Zurich",
"utc_offset": 60
},
"status": "OK"
}
@Serdeable
record EntityResponse(Result results, String status) {}
@Serdeable
record CollectionResponse(List<Result> results, String status) {}
@Serdeable
record Result(
LocalDate date,
LocalTime sunrise,
LocalTime sunset,
@JsonProperty("first_light") @JsonFormat(pattern = TIME_FORMAT, locale = "en_US")
LocalTime firstLight,
@JsonProperty("last_light") @JsonFormat(pattern = TIME_FORMAT, locale = "en_US")
LocalTime lastLight,
LocalTime dawn,
LocalTime dusk,
@JsonProperty("solar_noon") @JsonFormat(pattern = TIME_FORMAT, locale = "en_US")
LocalTime solarNoon,
@JsonProperty("golden_hour") @JsonFormat(pattern = TIME_FORMAT, locale = "en_US")
LocalTime goldenHour,
Duration dayLength,
ZoneId timezone,
ZoneOffset utcOffset) {
public static final String TIME_FORMAT = "h:mm:ss a";
}
Notice that I'm using @JsonFormat(pattern = TIME_FORMAT, locale = "en_US")
to indicate with what pattern and locale the DateTimeFormatter should parse the string value.
But when I am trying to execute this test
MicronautTest
public class MyTest {
@Inject
private ObjectMapper objectMapper;
@Test
@DisplayName("Verify that the deserialization works")
public void deserialize() throws IOException {
// given
final String json =
"""
{
"results": {
"date": "2024-02-02",
"sunrise": "7:52:59 AM",
"sunset": "5:27:56 PM",
"first_light": "6:07:12 AM",
"last_light": "7:13:44 PM",
"dawn": "7:20:03 AM",
"dusk": "6:00:52 PM",
"solar_noon": "12:40:28 PM",
"golden_hour": "4:41:39 PM",
"day_length": "9:34:56",
"timezone": "Europe/Zurich",
"utc_offset": 60
},
"status": "OK"
}
""";
// when
SunriseSunsetClient.EntityResponse response =
objectMapper.readValue(json, SunriseSunsetClient.EntityResponse.class);
// then
assertEquals("OK", response.status());
assertNotNull(response.results());
}
}
the test fails with this exception
Caused by: java.time.format.DateTimeParseException: Text '7:52:59 AM' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2108)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:2010)
at io.micronaut.serde.support.serdes.DefaultFormattedTemporalSerde.deserialize(DefaultFormattedTemporalSerde.java:71)
at io.micronaut.serde.support.serdes.DefaultFormattedTemporalSerde.deserialize(DefaultFormattedTemporalSerde.java:35)
at io.micronaut.serde.Deserializer.deserializeNullable(Deserializer.java:85)
at io.micronaut.serde.support.deserializers.DeserBean$DerProperty.deserializeAndSetConstructorValue(DeserBean.java:838)
... 34 more
Suppressed: java.lang.NumberFormatException: Character : is neither a decimal digit number, decimal point, nor "e" notation exponential mark.
at java.base/java.math.BigDecimal.<init>(BigDecimal.java:608)
at java.base/java.math.BigDecimal.<init>(BigDecimal.java:497)
at java.base/java.math.BigDecimal.<init>(BigDecimal.java:903)
at io.micronaut.serde.support.serdes.NumericSupportTemporalSerde.deserializeFallback(NumericSupportTemporalSerde.java:62)
at io.micronaut.serde.support.serdes.DefaultFormattedTemporalSerde.deserialize(DefaultFormattedTemporalSerde.java:73)
Isn't JsonFormat
not fully supported by Micronaut Serialization or am I using it wrong?
This is rather a stupid one. I did not annotate all the LocalTime
fields and therefore the error is explainable. Please find complete annotated records below.
@Serdeable
record Result(
LocalDate date,
@JsonFormat(pattern = TIME_FORMAT, locale = "en_US") LocalTime sunrise,
@JsonFormat(pattern = TIME_FORMAT, locale = "en_US") LocalTime sunset,
@JsonProperty("first_light") @JsonFormat(pattern = TIME_FORMAT, locale = "en_US")
LocalTime firstLight,
@JsonProperty("last_light") @JsonFormat(pattern = TIME_FORMAT, locale = "en_US")
LocalTime lastLight,
@JsonFormat(pattern = TIME_FORMAT, locale = "en_US") LocalTime dawn,
@JsonFormat(pattern = TIME_FORMAT, locale = "en_US")LocalTime dusk,
@JsonProperty("solar_noon") @JsonFormat(pattern = TIME_FORMAT, locale = "en_US")
LocalTime solarNoon,
@JsonProperty("golden_hour") @JsonFormat(pattern = TIME_FORMAT, locale = "en_US")
LocalTime goldenHour,
Duration dayLength,
ZoneId timezone,
ZoneOffset utcOffset) {
public static final String TIME_FORMAT = "h:mm:ss a";
}