Joda Time with JPA and Jackson

java.util.Date is the devil. It really is. Java 8 has made some improvements via the java.time API but from what I can tell, most devs have resolved to using Joda Time as it fixed Java's core Date API's before Java did.

While writing a small API service I got caught up in java.util.Date hell and decided to replace it with Joda Time. However, I'm using Spring with JPA/Hibernate so I researched the best way to integrate Joda Time into my stack. I found that there is quite a bit of information available but nothing that I would call the "definitive guide". I'm not suggesting mine is either, but this is how I got Joda Time to work with JPA as well as Serialization / Deserialization with Jackson.

First, we need the dependencies so add the following (I'm using Gradle so adjust for Maven if need be).

compile("com.fasterxml.jackson.datatype:jackson-datatype-joda:2.7.5")  
compile('org.jadira.usertype:usertype.core:4.0.0.GA')  
compile('joda-time:joda-time:2.9.4')  

As of this writing, those are the most recent stable versions with the exception of jadira. Since it has to be compiled against each Hibernate release, I've used version 4 to better match the Hibernate version I'm using.

I've added the following to my application.yml configuration file so that the Joda Time types are automatically mapped correctly to the database.

spring:  
  jpa:
    properties:
      jadira:
        usertype:
          autoRegisterUserTypes: true

In my entity class, I've defined two dates like this:

@NotNull
@Column(nullable = false)
private LocalDate startDate;

@NotNull
@Column(nullable = false)
private LocalDate expirationDate;  

Next, we need to tell Jackson to use the JodaModule and since I'm POST'ing JSON to my REST controllers, I need to tell Jackson what date format to use. This will be used for both Serialization and Deserialization. In my @SpringBootApplication class, I've added the following:

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {  
    ObjectMapper mapper = new ObjectMapper();
    mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
    mapper.registerModule(new JodaModule());
    return new MappingJackson2HttpMessageConverter(mapper);
}

Chances are you already have this @Bean defined. If you do, just add the setDateFormat and registerModule calls to yours.

And that's all I had to do. I'm posting the following JSON to my REST controller:

{
"notification":
    {
        "sendingEmployee":"1234",
        "startDate":"2016-01-01",
        "expirationDate":"2016-10-10",
        "notificationType":"E",
        "message":"This is the message",
    }
}

The data is persisted exactly as I'd expect:

And the table was created with the appropriate data types:

CREATE TABLE "public"."notification" (  
    "id" Bigint DEFAULT nextval('notification_id_seq'::regclass) NOT NULL,
        "start_date" Date NOT NULL,
    "expiration_date" Date NOT NULL,
    "message" Character Varying( 500 ) NOT NULL,
    "notification_type" Character Varying( 255 ) NOT NULL,
    "sending_employee" Character Varying( 255 ) NOT NULL,
    PRIMARY KEY ( "id" ) );

Please let me know if I've missed anything but so far, this has been working like a champ.