How to make milliseconds optional in @JsonFormat for Timestamp parsing with Jackson?
Solution 1
If you are using Java 8 Try specifying .SSS
inside square brackets [.SSS]
JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]X")
Solution 2
If millis consist of 1 or 2 or 3 digit you can use this pattern
JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS][.SS][.S]X")
Optional section order strict
Solution 3
For those of you that were not able to get the [.SSS]
solution to work, here is what I ended up doing.
Retain the @JsonFormat
annotation on your field for serialization, but build a custom deserializer for parsing Dates which might not have the milliseconds portion specified. Once you implement the deserializer you will have to register it with your ObjectMapper
as a SimpleModule
class DateDeserializer extends StdDeserializer<Date> {
private static final SimpleDateFormat withMillis = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
private static final SimpleDateFormat withoutMillis = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
public DateDeserializer() {
this(null);
}
public DateDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String dateString = p.getText();
if (dateString.isEmpty()) {
//handle empty strings however you want,
//but I am setting the Date objects null
return null;
}
try {
return withMillis.parse(dateString);
} catch (ParseException e) {
try {
return withoutMillis.parse(dateString);
} catch (ParseException e1) {
throw new RuntimeException("Unable to parse date", e1);
}
}
}
}
Now that you have a custom deserializer, all that is left is to register it. I am doing so with a ContextResolver<ObjectMapper>
that I already had in my project, but however you work with your ObjectMapper
should be fine.
@Provider
class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperContextResolver() {
mapper = new ObjectMapper();
SimpleModule dateModule = new SimpleModule();
dateModule.addDeserializer(Date.class, new DateDeserializer());
mapper.registerModule(dateModule);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
Related videos on Youtube
Comments
-
onkami almost 2 years
I have the following declaration in my object:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX") private ZonedDateTime start;
And when I parse timestamps like 2016-12-08T12:16:07.124Z (using Jackson Json De-serilaizer) it works fine, but once I receive timestamps without milliseconds (such as "2016-12-08T12:16:07Z"), it throws exception.
How I can possibly make milliseconds optional in format specification?
-
onkami over 7 yearsWorked! Thanks!
-
k_o_ over 7 yearsDoes not work on Java 8 version 102. The brackets are also not mentioned in the JavaDoc: docs.oracle.com/javase/8/docs/api/java/text/…
-
Luke almost 6 yearsVery useful information on how to register a custom ObjectMapper in a JEE application.
-
user1697575 over 4 years[.SSS] works only for a 3 digit millisecond values. if its one digit or 2 digit it breaks. E.g. 2019-03-24T16:14:08.23 will need "yyyy-MM-dd'T'HH:mm:ss[.SS] pattern