Category Archives: Joda-Time

Spring MVC: Handling Joda Data Types as JSON

PROBLEM

Let’s assume we have the following bean that contains Joda’s LocalDate and LocalDateTime objects:-

public class MyBean {
    private LocalDate date;
    private LocalDateTime dateTime;

    public LocalDate getDate() {
        return date;
    }

    public void setDate(LocalDate date) {
        this.date = date;
    }

    public LocalDateTime getDateTime() {
        return dateTime;
    }

    public void setDateTime(LocalDateTime dateTime) {
        this.dateTime = dateTime;
    }
}

This simple Spring MVC rest controller creates this bean and returns the JSON data back to the client:-

@RequestMapping(value = "/joda", method = RequestMethod.GET)
public ResponseEntity joda() {
    MyBean myBean = new MyBean();
    myBean.setDate(LocalDate.now());
    myBean.setDateTime(LocalDateTime.now());
    
    return new ResponseEntity<MyBean>(myBean, HttpStatus.OK);
}

By default, the generated JSON looks like this:-

{
   "date":
   [
       2015,
       3,
       28
   ],
   "dateTime":
   [
       2015,
       3,
       28,
       18,
       12,
       58,
       992
   ]
}

How do we nicely format these values and still retain the correct data types (LocalDate and LocalDateTime) in MyBean instead of writing our custom formatter and store the values as String?

SOLUTION

First, add a dependency for jackson-datatype-joda.

<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-databind</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.datatype</groupId>
    <artifactId>jackson-datatype-joda</artifactId>
    <version>2.5.1</version>
</dependency>

Next, instruct MappingJackson2HttpMessageConverter to accept a custom ObjectMapper.

<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
      p:indentOutput="true" p:simpleDateFormat="yyyy-MM-dd'T'HH:mm:ss.SSSZ">
</bean>

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" p:targetObject-ref="objectMapper"
      p:targetMethod="registerModule">
    <property name="arguments">
        <list>
            <bean class="com.fasterxml.jackson.datatype.joda.JodaModule"/>
        </list>
    </property>
</bean>

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

The generated JSON output now looks like this:-

{
   "date": "2015-03-28",
   "dateTime": "2015-03-28T18:11:16.348"
}

Jadira Usertype: Under JDK 6 it may not be possible to handle DST transitions correctly

PROBLEM

When saving a Hibernate entity that contains Joda Time object, Jadira UserType throws the following warning:-

[WARN ] [JavaTimeZoneWorkaroundHelper] [<clinit>:40] - Under JDK 6 it may not be possible 
to handle DST transitions correctly
[ERROR] [JavaTimeZoneWorkaroundHelper] [<clinit>:42] - Running under a Zone that uses 
daylight saving time. To avoid incorrect datetimes being stored during DST transition, 
either update to JDK 7 or use a Timezone for the JDK without Daylight Saving Time

This warning occurs when using this version:-

<dependency>
    <groupId>org.jadira.usertype</groupId>
    <artifactId>usertype.core</artifactId>
    <version>3.0.0.GA</version>
</dependency>

SOLUTION

Upgrade Jadira Usertype to the latest version, and the problem goes away:-

<dependency>
    <groupId>org.jadira.usertype</groupId>
    <artifactId>usertype.core</artifactId>
    <version>3.1.0.CR10</version>
</dependency>

Hibernate + Joda Time: Auto Registering Type

OVERVIEW

Jadira Usertype is required when using Joda Time with Hibernate 4. The Joda Time objects are annotated accordingly in the Hibernate entity, and they looks something like this:-

@Entity
@Table(name = "person")
public class Person implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "personId")
    private Long id;

    @Column
    private String name;
	
    @Column
    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
    private LocalDate birthDate;

    @Column
    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
    private LocalDateTime createdDatetime;
	
    // getters and setters
}

PROBLEM

This solution works, but it is rather tedious because I can never remember the actual @Type to write, thus I always end up copying and pasting it from past project code.

Further, that additional annotations clutter up my otherwise beautiful code.

SOLUTION

Jadira Usertype provides a clean way to auto register these Joda Time object types.

In the Hibernate configuration, add the following line:-

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>

    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="jadira.usertype.autoRegisterUserTypes">true</prop>
        </props>
    </property>
    <property name="packagesToScan">
        <list>
            <value>com.choonchernlim.project.entity</value>
        </list>
    </property>
</bean>

Now all @Type annotations can be safely removed from the Hibernate entity:-

@Entity
@Table(name = "person")
public class Person implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "personId")
    private Long id;

    @Column
    private String name;
	
    @Column
    private LocalDate birthDate;

    @Column
    private LocalDateTime createdDatetime;
	
    // getters and setters
}

Hibernate: Migrating from XML-Based Configuration to Annotation-Based Configuration

Overview

At some point of time, as your project scope grows, the Hibernate mapping XML files are going to get to a point where it becomes very difficult to maintain. This is where the annotation-based configuration comes in. It took me a few years to convince myself that annotation-based configuration is the way to go. Change is hard, yet necessary.

This tutorial covers the following:-

  • Upgrade Hibernate from 3.x to 4.x.
  • Configure Spring-Hibernate integration to replace XML-based configuration with annotation-based configuration.
  • Configure Joda-Time to work properly in Hibernate 4.
  • Activate @Transactional instead of relying on AOP-based transaction.

Maven Dependencies

Change the Hibernate dependency version from 3.x to 4.x. On top of that, add org.jadira.usertype:usertype.core:[version] dependency to get Joda-Time to work properly with Hibernate 4.

Hibernate 3.x

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>3.6.9.Final</version>
</dependency>
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.3</version>
</dependency>
<dependency>
	<groupId>joda-time</groupId>
	<artifactId>joda-time-hibernate</artifactId>
	<version>1.3</version>
</dependency>

Hibernate 4.x

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>4.2.6.Final</version>
</dependency>
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.3</version>
</dependency>
<dependency>
	<groupId>joda-time</groupId>
	<artifactId>joda-time-hibernate</artifactId>
	<version>1.3</version>
</dependency>
<dependency>
    <groupId>org.jadira.usertype</groupId>
    <artifactId>usertype.core</artifactId>
    <version>3.1.0.CR8</version>
</dependency>

By the way, if you don’t know what Joda-Time is or haven’t use it by now, then you should be spanked by the Date God. With that added dependency, the @Type for date field will look a little different ( see here for more info ):-

@Entity
@Table(name = "MrMeow")
public class MrMeow implements Ideable, Serializable {
	...
	
	@Column
	@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
	private LocalDate whenMeowed;
}

Spring Integration

Hibernate 3.x

This configuration uses Hibernate XML mapping files to configure mappings between the domain objects and the database tables. Further, AOP is used to configure the transaction.

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
</bean>

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<tx:advice id="txAdvice">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

<aop:config proxy-target-class="true">
    <aop:advisor pointcut="execution(* myproject..*.*(..))" advice-ref="txAdvice"/>
</aop:config>

Hibernate 4.x

This configuration scans myproject.domain package, which contains all Hibernate annotated domain classes. Further, it activates @Transactional so that you can place it in your code to manage the transaction.

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>

    <property name="hibernateProperties">
        <props>
			<!-- Configure your Hibernate dialect  -->
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
            <prop key="hibernate.show_sql">false</prop>
        </props>
    </property>
    <property name="packagesToScan">
        <list>
			<!-- Configure your domain package -->
            <value>myproject.domain</value>
        </list>
    </property>
</bean>

web.xml

Change filter class for OpenSessionInViewFilter.

Hibernate 3.x

<filter>
    <filter-name>hibernateFilter</filter-name>
	<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Hibernate 4.x

<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Domain Classes

Finally, time to annotate your Hibernate domain classes!

Helpful Note

Please make sure you don’t have JPA 1.x in your classpath in the first place. Read java.lang.NoSuchMethodError: javax/persistence/OneToMany.orphanRemoval()Z for more information.