json - Java 8 LocalDate Jackson format

ID : 20062

viewed : 22

Tags : javajsonjacksonjax-rsresteasyjava

Top 5 Answer for json - Java 8 LocalDate Jackson format

vote vote

99

I was never able to get this to work simple using annotations. To get it to work, I created a ContextResolver for ObjectMapper, then I added the JSR310Module (update: now it is JavaTimeModule instead), along with one more caveat, which was the need to set write-date-as-timestamp to false. See more at the documentation for the JSR310 module. Here's an example of what I used.

Dependency

<dependency>     <groupId>com.fasterxml.jackson.datatype</groupId>     <artifactId>jackson-datatype-jsr310</artifactId>     <version>2.4.0</version> </dependency> 

Note: One problem I faced with this is that the jackson-annotation version pulled in by another dependency, used version 2.3.2, which cancelled out the 2.4 required by the jsr310. What happened was I got a NoClassDefFound for ObjectIdResolver, which is a 2.4 class. So I just needed to line up the included dependency versions

ContextResolver

import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JSR310Module; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider;  @Provider public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {       private final ObjectMapper MAPPER;      public ObjectMapperContextResolver() {         MAPPER = new ObjectMapper();         // Now you should use JavaTimeModule instead         MAPPER.registerModule(new JSR310Module());         MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);     }      @Override     public ObjectMapper getContext(Class<?> type) {         return MAPPER;     }   } 

Resource class

@Path("person") public class LocalDateResource {      @GET     @Produces(MediaType.APPLICATION_JSON)     public Response getPerson() {         Person person = new Person();         person.birthDate = LocalDate.now();         return Response.ok(person).build();     }      @POST     @Consumes(MediaType.APPLICATION_JSON)     public Response createPerson(Person person) {         return Response.ok(                 DateTimeFormatter.ISO_DATE.format(person.birthDate)).build();     }      public static class Person {         public LocalDate birthDate;     } } 

Test

curl -v http://localhost:8080/api/person
Result: {"birthDate":"2015-03-01"}

curl -v -POST -H "Content-Type:application/json" -d "{\"birthDate\":\"2015-03-01\"}" http://localhost:8080/api/person
Result: 2015-03-01


See also here for JAXB solution.

UPDATE

The JSR310Module is deprecated as of version 2.7 of Jackson. Instead, you should register the module JavaTimeModule. It is still the same dependency.

vote vote

89

@JsonSerialize and @JsonDeserialize worked fine for me. They eliminate the need to import the additional jsr310 module:

@JsonDeserialize(using = LocalDateDeserializer.class)   @JsonSerialize(using = LocalDateSerializer.class)   private LocalDate dateOfBirth; 

Deserializer:

public class LocalDateDeserializer extends StdDeserializer<LocalDate> {      private static final long serialVersionUID = 1L;      protected LocalDateDeserializer() {         super(LocalDate.class);     }       @Override     public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)             throws IOException, JsonProcessingException {         return LocalDate.parse(jp.readValueAs(String.class));     }  } 

Serializer:

public class LocalDateSerializer extends StdSerializer<LocalDate> {      private static final long serialVersionUID = 1L;      public LocalDateSerializer(){         super(LocalDate.class);     }      @Override     public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider sp) throws IOException, JsonProcessingException {         gen.writeString(value.format(DateTimeFormatter.ISO_LOCAL_DATE));     } } 
vote vote

74

ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); 
vote vote

63

In Spring Boot web app, with Jackson and JSR 310 version "2.8.5"

compile "com.fasterxml.jackson.core:jackson-databind:2.8.5" runtime "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.5" 

The @JsonFormat works:

import com.fasterxml.jackson.annotation.JsonFormat;  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") private LocalDate birthDate; 
vote vote

56

The simplest solution (which supports deserialization and serialization as well) is

import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy") @JsonDeserialize(using = LocalDateDeserializer.class) @JsonSerialize(using = LocalDateSerializer.class) private LocalDate dateOfBirth; 

While using the following dependencies in your project.

Maven

<dependency>    <groupId>com.fasterxml.jackson.core</groupId>    <artifactId>jackson-databind</artifactId>    <version>2.9.7</version> </dependency> <dependency>    <groupId>com.fasterxml.jackson.datatype</groupId>    <artifactId>jackson-datatype-jsr310</artifactId>    <version>2.9.7</version> </dependency> 

Gradle

compile "com.fasterxml.jackson.core:jackson-databind:2.9.7" compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.7" 

No additional implementation of a ContextResolver, Serializer or Deserializer is required.

Top 3 video Explaining json - Java 8 LocalDate Jackson format

Related QUESTION?