This is my user class, and I to save ISO compliant date time in my database.
public class User {
@Id
private String id;
private String email;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime loginDate;
}
Here is my Jersey controller:
@POST
@Consumes("application/json")
@Produces("application/json")
public Response create( User user) {
Map<Object, Object> apiResponse = new HashMap<Object, Object>();
Map<Object, Object> response = new HashMap<Object, Object>();
user = (User) userService.create(user);
}
How can can I consume a datetime format like this one in jersey? Is it possible to send a datatime String
and create Java 8 date time object automatically?
{
"email" : "[email protected]"
"loginDate" : "2015-04-17T06:06:51.465Z"
}
#
Update:
I was using Spring boot jersey, and had other jsr packages
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
So I removed all the packages except from spring-boot-jersey package. use this annotation for LocalDateTime
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
This way I can consume ISODate and save ISODate() to mongodb and produce full formated mongodb LocalDateTime to frontend.
Problem solved.
The Java Date Time API was added from Java version 8. instant() method of Clock class returns a current instant of Clock object as Instant Class Object. Instant generates a timestamp to represent machine time. So this method generates a timestamp for clock object.
The LocalDateTime class represents the date-time,often viewed as year-month-day-hour-minute-second and has got no representation of time-zone or offset from UTC/Greenwich.
ZonedDateTime is an immutable representation of a date-time with a time-zone. This class stores all date and time fields, to a precision of nanoseconds, and a time-zone, with a zone offset used to handle ambiguous local date-times.
Assuming you have JAXB annotation support with Jackson as the JSON provider...
You could use an XmlAdapter
. For example
public class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime> {
@Override
public LocalDateTime unmarshal(String dateString) throws Exception {
Instant instant = Instant.parse(dateString);
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
return dateTime;
}
@Override
public String marshal(LocalDateTime dateTime) throws Exception {
Instant instant = dateTime.toInstant(ZoneOffset.UTC);
return DateTimeFormatter.ISO_INSTANT.format(instant);
}
}
See the Instant API for more information.
Then you can just annotate the field/property with the adapter
@XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
private LocalDateTime loginDate;
You could also declare the annotation at the package level, so that all uses in the package will use the adapter, without the need to annotate. You do so in a file named package-info.java
put inside the package
@XmlJavaTypeAdapters({
@XmlJavaTypeAdapter(type = LocalDateTime.class,
value = LocalDateTimeAdapter.class)
})
package thepackage.of.the.models;
import java.time.LocalDateTime;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
Use the Jackson APIs directly. Meaning, use a JsonDeserializer
and JsonSerializer
. For example
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser jp,
DeserializationContext dc) throws IOException, JsonProcessingException {
ObjectCodec codec = jp.getCodec();
TextNode node = (TextNode)codec.readTree(jp);
String dateString = node.textValue();
Instant instant = Instant.parse(dateString);
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
return dateTime;
}
}
public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime dateTime, JsonGenerator jg,
SerializerProvider sp) throws IOException, JsonProcessingException {
Instant instant = dateTime.toInstant(ZoneOffset.UTC);
jg.writeString(DateTimeFormatter.ISO_INSTANT.format(instant));
}
}
You can apply this at the field/property level
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
public LocalDateTime loginDate;
Or at the ObjectMapper
level (so you don't need to annotate everywhere)
@Provider
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
final ObjectMapper mapper = new ObjectMapper();
public ObjectMapperContextResolver() {
SimpleModule module = new SimpleModule();
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
mapper.registerModule(module);
// add JAXB annotation support if required
mapper.registerModule(new JaxbAnnotationModule());
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
Basically what happens, is that the MessageBodyWriter
/MessageBodyReader
used for ummarshalling/marshalling, will call the getContext
method to get the ObjectMapper
Note:
The above solutions will parse from the format 2007-12-03T10:15:30.00Z
, as documented in Instant.parse
, and will serialize to the same format, as documented in DateTimeFormatter.ISO_INSTANT
The above is also assuming you are using Jackson as the Serializer. I used the below dependency (with Jersey 2.16) to test
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.16</version>
</dependency>
The dependency uses a JacksonJaxbJsonProvider
for JAXB annotation support. If you are using a lower version of Jersey like 1.x, the jersey-json
dependency should offer JAXB annotation support, if you enable the POJO mapping feature. Alternatively for Jersey 1.x, if you want to use Jackson 2, you can use this dependency
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.0</version>
</dependency>
which is actually what is used by jersey-media-json-jackson
. So you could explicitly register the JacksonJaxbJsonProvider
, or add the Jackson package (com.fasterxml.jackson.jaxrs.json
) to list packages to scan
See Also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With