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).


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.

          autoRegisterUserTypes: true

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

@Column(nullable = false)
private LocalDate startDate;

@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:

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:

        "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.