Front-end sends dates in format: 2024-06-01T05:55:04
from datetime-local
control.
Example REST controller:
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ExampleResource {
@POST
public RestResponse<Example> create(Example example) {
return RestResponse.ok(exampleService.create(example));
}
}
@Data
public class Example {
@JsonProperty("creationTime")
private OffsetDateTime creationTime; // from front-end comes 2024-06-01T05:55:04
}
Custom deserializer for OffsetDateTime
is added here:
@Singleton
public class ObjectMapperConfig implements ObjectMapperCustomizer {
public void customize(ObjectMapper mapper) {
var module = new SimpleModule();
module.addDeserializer(OffsetDateTime.class, new CustomOffsetDateTimeDeserializer());
mapper.registerModule(module);
}
static class CustomOffsetDateTimeDeserializer extends JsonDeserializer<OffsetDateTime> {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
// figured out that this method is not called during deserialization
@Override
public OffsetDateTime deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
String dateString = p.getText();
try {
return OffsetDateTime.parse(dateString);
} catch (Exception e) {
var localDateTime = LocalDateTime.parse(dateString, FORMATTER);
return localDateTime.atOffset(ZoneOffset.systemDefault().getRules().getOffset(localDateTime));
}
}
}
}
I tried another approach - override default ObjectMapper bean:
@Produces
@Singleton
public ObjectMapper objectMapper() {
var module = new SimpleModule();
module.addDeserializer(OffsetDateTime.class, new CustomOffsetDateTimeDeserializer());
var objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
return objectMapper;
}
None of the above works and Quarkus fails to deserialize dates. Browser gets HTTP 400 Bad Request response without body.
I ran debugger and figured out that the default InstantDeserializer is used to deserialize OffsetDateTime.
How to properly configure custom deserializer for OffsetDateTime?
Should I use another approach to parse dates like 2024-06-01T05:55:04
to OffsetDateTime
?
Finally created a mixin and it works.
@Singleton
public class ObjectMapperConfig implements ObjectMapperCustomizer {
public void customize(ObjectMapper mapper) {
mapper.addMixIn(OffsetDateTime.class, DateMixin.class); // add mixin
}
// This mixin will be used to deserialize OffsetDateTime
@JsonDeserialize(converter = CustomOffsetDateTimeConverter.class)
static class DateMixin {
}
// Define a converter from String to OffsetDateTime
static class CustomOffsetDateTimeConverter extends StdConverter<String, OffsetDateTime> {
// We will try to parse this format on error
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
@Override
public OffsetDateTime convert(String dateString) {
try {
// First try to parse as OffsetDateTime
return OffsetDateTime.parse(dateString);
} catch (Exception e) {
// Then continue to parse using our format (without offset)
var localDateTime = LocalDateTime.parse(dateString, FORMATTER);
// Now use system default timezone to convert local datetime to offset datetime
return localDateTime.atOffset(ZoneOffset.systemDefault().getRules().getOffset(localDateTime));
}
}
}
}