9
votes

I'm writing a Java 8 Spring MVC application that communicates with a legacy Progress OpenEdge application using a REST service (I'm using Spring's RestTemplate for this). The data I need to read from and write to the Progress application contains some dates. In the Java application, I use a java.time.LocalDate datatype to represent these fields and I'm using Jackson to serialize / deserialize the data into / from Json.

The problem I'm having is the following. When I send data from the Progress Application, the date is send as '2015-01-02' and stored in my Java entity as a LocalDate as expected. When the data is send to the web front-end the Json also contains the date in the same format. When I change information in the web front-end and apply it, it's also send back to the Java application as '2015-01-02' and again stored as a LocalDate without problems. But when I than send the data onwards to the Progress application, the Json I receive doesn't contain the date as '2015-01-02' but as an array containing three fields (2015.0, 1.0, 2.0) and the Progress application is unable to assign this back to a date field in the database.

Offcourse I could write a conversion on the Progress side to convert the array back into a date, but I'd like to avoid this as I would expect the date to always be send in the ISO 8601 format.

According to the information I find on Jackson, a java.time.LocalDate is represented as an array when WRITE_DATES_AS_TIMESTAMPS is enabled, but I have this disabled (And when the date is send to the web front-end, it's not being send as an array...)

Here is some relevant code:

The CustomObjectMapper:

@Service
public class CustomObjectMapper extends ObjectMapper
{
  public CustomObjectMapper()
  {
    this.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
                   false);
  }
}

The configuration in my servlet.xml

<mvc:annotation-driven>
  <mvc:message-converters>
    <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
      <property name="objectMapper" ref="customObjectMapper"/>
    </bean>
  </mvc:message-converters>
</mvc:annotation-driven>

<bean id="customObjectMapper" class="com.msoft.utility.CustomObjectMapper"/>

The field definition:

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

I'm using Java 8 with Spring 4.1.5 and Jackson 2.5.1.

Any tips how I could get this working or were to search for a solution would be greatly appreciated as I've already been working on this for almost 2 days...

Thanks

EDIT:

Some extra info...

I've included the Jackson JSR-310 module in my pom.xml. Here is the releveant part of my pom file...

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.5.1</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.5.1</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.5.1</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jsr310</artifactId>
  <version>2.5.1</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>4.1.5.RELEASE</version>
  <scope>test</scope>
  <type>jar</type>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>4.1.5.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.data</groupId>
  <artifactId>spring-data-jpa</artifactId>
  <version>1.7.2.RELEASE</version>
</dependency>

Also, if I understood correctly, Spring will register this module automatically when it's detected. See the info on Jackson2ObjectMapperFactoryBean

Note that Jackson's JSR-310 and Joda-Time support modules will be registered automatically when available (and when Java 8 and Joda-Time themselves are available, respectively).

So I don't think I should have to do anything else to get this working correctly, but obviously I'm still missing something...

2
For what it is worth, you should NOT use annotations, IF the module is properly registered. Annotation overrides would be used, and registered default handlers not called. This may or may not matter, as initialization differs slightly. - StaxMan
If I remove the annotations at the deliveryDate property, the date is send from Java as an object with the following structure: {"year":2015,"month":"JANUARY","dayOfMonth":2,"dayOfWeek":"FRIDAY","era":"CE","dayOfYear":2,"leapYear":false,"monthValue":1,"chronology":{"id":"ISO","calendarType":"iso8601"}} instead of the 2015/01/02 I would like. Thanks for the help, but still not what I'm looking for... - HeinoVDS
same problem... have you found a solution - robert trudel
Hi, I just checked back in our code and it seems in the end I just wrote a conversion on the Progress side of things to convert the array in a date (which isn't that hard to do...). This project has been delivered to the client and it seems to be working fine. As I haven't been working on this project for about 4 - 5 months now, I haven't been able to try out the solution Niclas proposed. Maybe you should look into that. If it helps, please let me know and I'll accept his answer as the solution. - HeinoVDS

2 Answers

8
votes

This worked for me, and I'm not using Spring boot.

@Configuration
@EnableWebMvc
public class SpringMvcConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    }
}
5
votes

I think you just need to register JSR-310 (Java 8 Date/Time) module:

https://github.com/FasterXML/jackson-datatype-jsr310/

since Jackson core can not rely on any Java 8 features (baseline at this point, with 2.5, is Java 6). And going forward support for most datatype libraries will go through plug-in modules anyway.