OS: Windows 11 JDK: corretto-17.0.6 IDE: IntelliJ IDEA 2022.3.1 Micronaut Application Version: 3.7.3
I have a Micronaut application to do some basic IO operations. I have a DTO class that has a duration field, but I want this field to work in milliseconds rather than seconds. Here's my POST request:
@Post
public EventBean create(@Body EventBean eventBean) {
return eventBean;
}
and JSON body sent:
{
"from": "2023-03-05T12:26:43.538Z",
"duration": 600000
}
expected the same but recieved
{
"from": "2023-03-05T12:26:43.538Z",
"duration": 600000000
}
and EventBean
class:
@Introspected
public class EventBean {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
private final Instant from;
@JsonSerialize(converter = DurationSerializer.class)
@JsonDeserialize(converter = DurationDeserializer.class)
private final Duration duration;
public EventBean(Instant from, Duration duration) {
this.from = from;
this.duration = duration;
}
public Instant getFrom() {
return from;
}
public Duration getDuration() {
return duration;
}
public static class DurationSerializer extends StdConverter<Duration, Long> {
@Override public Long convert(Duration value) {
return value.toMillis();
}
}
public static class DurationDeserializer extends StdConverter<Long, Duration> {
@Override public Duration convert(Long value) {
return Duration.ofMillis(value);
}
}
}
But DurationDeserializer
class is not being used while deserializing my JSON from body. ( DurationSerializer
is working just fine )
I also tried using JsonDeserializer<T>
class and using
field in JsonDeserialize
annotation but to no avail.
EDIT
I found a workaround, I override the default DurationDeserializer
by jackson using micronaut @Replaces
as follows:
@Replaces(value = com.fasterxml.jackson.datatype.jsr310.deser.DurationDeserializer.class)
public class DurationDeserializer extends JsonDeserializer<Duration> {
@Override public Duration deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
return Duration.ofMillis(p.getLongValue());
}
}
I recommend to configure date/time serialisation globally in your application.yml
jackson:
dateFormat: yyyyMMdd
timeZone: UTC
serialization:
writeDatesAsTimestamps: false
This will do the Instant
deser for you without using any additional Jackson annotation on your POJO.
In order to make the duration deser work you need to make sure that your serializer/deserializer are Micronaut beans and I recommend to have them in separate Java source files.
@Singleton
public class DurationSerializer extends StdConverter<Duration, Long> {
@Override public Long convert(Duration value) {
return value.toMillis();
}
}
@Singleton
public class DurationDeserializer extends StdConverter<Long, Duration> {
@Override public Duration convert(Long value) {
return Duration.ofMillis(value);
}
}