Recipe: Spring + JPA Annotation + Hibernate

1
Modern OO applications use a lot of Models to present the business domain object. It is often that we have to write a matching data access object for each models, and in most cases they are just normal CRUD operations.

What I am trying to do here is to create a generic way to create DAO from POJO that uses JPA as mapping tool to simplify the repeating tasks. The following example uses hibernate for DB connectivity.

Of course you can simply use EJB 3.0 and remove all this completely by using method like entityManager.persist(), but if we want to stay away from EJB and persistence model, this should give you a very good place to start. (I am using JPA as my mapping tool only because of my personal preference, you can use hibernate annotation, and it should work exactly the same way).

Step 1 - Create the Generic class
I am using the sample from the "Don't repeat the DAO". I think this is pretty neat.

GenericDao Interface

package com.blogspot.programmingpanda.commons

import java.io.Serializable;
import java.util.Collection;

public interface GenericDao&ls;T, PK extends Serializable> {
Collection<T> listAll();
}


The implementation...
GenericDaoHibernateImpl

package com.blogspot.programmingpanda.commons

import java.io.Serializable;
import java.util.Collection;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class GenericDaoHibernateImpl<T, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK> {

private Class<T> type;

public GenericDaoHibernateImpl(Class<T> type){
this.type = type;
}

public Collection<T> listAll() {
return this.getHibernateTemplate().loadAll(this.type);
}

/**
* @return the type
*/
public Class<T> getType() {
return type;
}

/**
* @param type the type to set
*/
public void setType(Class<T> type) {
this.type = type;
}
}


Once we have the generic DAO class, we can use spring to inject the model into the DAO.

Now we have to create the model and use JPA to do the O/R Mapping

Step 2 - Create the model and map it to the database

package com.blogspot.programmingpanda.commons.models;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="myschema.model")
public class MyModel implements Serializable {

private Integer id;
private String col1;
private String col2;

/**
* @return the id
*/
@Id
@Column(name="id")
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}

@Column(name="col1")
public String getCol1() {
return col1;
}

@Column(name="col2")
public String getCol2() {
return col2;
}

/** And all those setter method **/



Step 3 - Spring Config
After the Model and GenericDao class, all we have to do is to
i) Let the session factory know the class(es) to map

<!-- Annotation Session Factory Bean -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="mysqlDataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
<property name="annotatedClasses">
<list>

<value>com.blogspot.programmingpanda.commons.models.MyModel</value>
</list>

</property>
</bean>

ii) Create the dao by injecting the class into the GenericDao

<!-- This bean will replace the actual Dao class -->
<bean id="myModelDao" class="com.blogspot.programmingpanda.commons.GenericDaoHibernateImpl" autowire="byName">
<constructor-arg>
<value>com.blogspot.programmingpanda.commons.models.MyModel</value>
</constructor-arg>
</bean>


The full applicationContext.xml will look something like this

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/spring-config/dev.properties</value>
</list>
</property>
</bean>

<bean id="systemPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />

<!-- MySql DS -->
<bean id="mysqlDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${mysql.url}" />
<property name="username" value="${mysql.username}" />
<property name="password" value="${mysql.password}" />
</bean>

<!-- Annotation Session Factory Bean -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="mysqlDataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
<property name="annotatedClasses">
<list>

<value>com.blogspot.programmingpanda.commons.models.MyModel</value>
</list>

</property>
</bean>
<!--sessionFactory will get autowired-->
<bean id="hibernateInterceptor"
class="org.springframework.orm.hibernate3.HibernateInterceptor"
autowire="byName" />

<!-- This bean will replace the actual Dao class -->
<bean id="myModelDao" class="com.blogspot.programmingpanda.commons.GenericDaoHibernateImpl" autowire="byName">
<constructor-arg>
<value>com.blogspot.programmingpanda.commons.models.MyModel</value>
</constructor-arg>
</bean>

<!-- Inject the Dao to an action -->
<bean id="action" class="actions.ListAction">
<property name="myModelDao" ref="myModelDao" />
</bean>

</beans>


Conclusion
This is only a minimal example demonstrating how we can use spring, JPA annotation and a generic dao template to avoid writing DAO class for each model we create in our application. You can always extend the GenericDao class to include your own method(s) other than the generic CRUD methods.

Working from the list and reviewing remember the milk

0
i've been reading the pragamtic programmer series for the last few years now. i've been trying to incorporate their ideas into my daily work routine whenever i get a chance.

i was reminded of one this week when i realized my todo list at work was getting a little out of control and consisted of a piece of paper with my ugly hand writing on it. Having a todo list is definitely the first step in getting organized, but i was not doing one thing correctly. One of the rules (from Pragmatic Programmers: Ship It!), was that the list must be publically available and easy to update/publish. So, here I have this massive list of things to do, and my team wasn't aware of it.

to correct this grave mistake, i signed myself up for a Remember the Milk account. It is a simple to do list manager that allows multiple lists, tagging, notes, calendar integration, rss feeds, sync-ing with smart devices (if u pay for pro) on top of the standard to do list features. so far, i've found this quite easy to pick up. i'm still poking around, so i'm a little slow at putting in my massive list into the system, but there are a lot of keyboard shortcuts that I'm sure will make things lightning fast when i manage to remember them. One other cool thing is that it supports Google Gears! the only thing that i dont like about right now is... when i add a priority to an item, it automatically updates the list to keep it sorted (the default sort is by priority). however, i feel like i "lost" my item, b/c i dont know where it is in my list anymore. i would much rather that I have a manual refresh button that i could click when i'm ready to re-sort the list.

i guess a simple test of the product's effectiveness is if i'm still using it 4 wks later? stay tuned to find out!!!

By the way...here are the tips for maintaining a good list as per the author of "Ship it!".

Tips:
  • Organize whatever daily task list you do have into a formal copy of The List.
  • Prioritize your work and add rough time estimates.
  • Start working on the highest-priority item on The List. no cheating! If some crisis forces a lower-priority item higher, record it. You should be using your list to help you determine what you are working on next.
  • Add all new work to The List, make sure it is an accurate reflection of your current tasks.
  • Move items to your finished list as you complete tasks (this makes surviving status reports and "witch-hunts" much easier).
  • Review The List every morning (aka updated daily)
  • Make sure the list is publically available
  • Maintaining The List should not require too much effort.
Signs you are doing it wrong
  • You're too busy to update the list or it takes too long.
  • The list gets outdated because you don't update it frequently enough.
  • It takes a long time to complete one item on the list (the items are too large)
  • No one else knows about your list or there are mulitple versions

getting an HTTP 405 on IIS

0
i was trying to set up this web application to connect to a HTTP server (happened to be IIS) that is serving some pre-generated report files. The offshore developer that had been working on this had some problems getting it going, so it was left to me to deal with it. The web application was using Apache HttpClient to connect to the http server using some standard http client code below:

<snip>

HttpClient client = new HttpClient();

PostMethod method = new PostMethod(filePath);
method.setRequestHeader("Content-type", "text/html");
client.executeMethod(method);
input = method.getResponseBodyAsStream();
responseBean.setInputStream(input);

</snip>


that resulted in IIS throwing this at us......

The page cannot be displayed
The page you are looking for cannot be displayed because an invalid method (HTTP verb) was used to attempt access.

Please try the following:

Contact the Web site administrator if you believe that this request should be allowed.
Make sure that the Web site address displayed in the address bar of your browser is spelled and formatted correctly.

HTTP Error 405 - The HTTP verb used to access this page is not allowed.
Internet Information Services (IIS)

Technical Information (for support personnel)

Go to Microsoft Product Support Services and perform a title search for the words HTTP and 405.
Open IIS Help, which is accessible in IIS Manager (inetmgr),
and search for topics titled Setting Application Mappings, Securing Your Site with Web Site Permissions, and About Custom Error Messages.



So basically what was happening was that IIS didn't like the POST method that was being used. (HTTP 405 --> Method Not Allowed). The fix? quite simple, use a GET! =) It is easy to forget that POST's primary objective is to post data to the server, not to obtain data from it.

As web devs, we see HTTP 404s a lot...and the occasional 403. it's not everyday you see a 405!

Using different log4j proerties for different environment in spring 2

1
Default location of log4j properties is in /WEB-INF/classes/logj4.properties. There are ways to point log4j to different properties. In spring, we can do something like this.


<!-- log4j setting -->
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>log4j.properties</value>
</list>
</property>
</bean>


where initLogging takes (String location), you can use absolute path or relative path here. But a more elegant way is to use a variable for the application root. like this


<value>${webapp.root}/${log4j.properties.location}</value>


You can get the ${webapp.root} from webAppRootKey. To bring it to the next level we can group all configs into 1 properties file and that will make the build process easier.

The full setup looks something like this

/WEB-INF/web.xml

<listener>
<listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>webapp.root</param-value>
</context-param>


/WEB-INF/applicationContext.xml

<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/spring-config/dev.properties</value>
</list>
</property>
</bean>
<!-- log4j setting -->
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="org.springframework.util.Log4jConfigurer"/>
<property name="targetMethod" value="initLogging"/>
<property name="arguments">
<list>
<value>${webapp.root}/${log4j.properties.location}</value>
</list>
</property>
</bean>


/WEB-INF/spring-config/dev.properties

#log4j setting
log4j.properties.location=WEB-INF/log4j-config/log4j.dev.properties


/WEB-INF/log4j-config/log4j.dev.properties

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=DEBUG
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

log4j.rootLogger=DEBUG, stdout

/WEB-INF/log4j-config/log4j.prod.properties

# Configuration for receiving e-mails when ERROR messages occur.
log4j.appender.mail=org.apache.log4j.net.SMTPAppender
log4j.appender.mail.To=to@mydomain.com
log4j.appender.mail.From=from@mydomain.com
log4j.appender.mail.SMTPHost=smtp.mydomain.com
log4j.appender.mail.Threshold=ERROR
log4j.appender.mail.BufferSize=1
log4j.appender.mail.Subject=An application error occured
log4j.appender.mail.layout=org.apache.log4j.HTMLLayout

# Standrd System.out appender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

log4j.rootLogger=INFO, stdout, mail

Accessing Context/System (Application Root) properties in Spring

0
In the last post I talked about how to parameterize the applicationContext.xml with a properties file. But sometime we would like to access system/context properties in the applicationContext.xml (for example, you want to reference a file in your webapp, but the class only takes absolute path). The spring PropertyPlaceholderConfigurer class would do the work for you as well.

By default, the system property mode is set to use fall back (SYSTEM_PROPERTIES_MODE_FALLBACK), which means if a property is not in our properties file that we supply, the property will be filled with the one in the context/system.

One good use would be getting the application root and use it to reference a config file.

For example

${webapp.root}/WEB-INF/velocity


(In reference to Spring documentation velocity properties chapter)

In order to use ${webapp.root} you will need to setup WebAppRootListener in web.xml



org.springframework.web.util.WebAppRootListener



and assign it to a context param



webAppRootKey
webapp.root


Parameterize Spring applicationContext with properties file

0
Spring has a very useful class called PropertyPlaceholderConfigurer that helps you to parameterize your applicationContext.xml file. In order to use this, you will need to add the bean in spring like this




/WEB-INF/spring-config/dev.properties




where the property location points to the list of properties files.

I use this primarily becasue
1. easier to maintain properties in a properties file than applicationContext
2. switch between different environments, e.g. development vs. staging vs. production

An example of the use of this would be

/WEB-INF/web.xml


org.springframework.web.context.ContextLoaderListener



contextConfigLocation
/WEB-INF/applicationContext.xml



/WEB-INF/spring-config/dev.properties

# Dev DB Setting
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://dev.mydomain.com:3306/
mysql.username=devuser
mysql.password=xxx

/WEB-INF/spring-config/prod.properties

# Product DB Setting
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://prod.mydomain.com:3306/
mysql.username=produser
mysql.password=xxx

/WEB-INF/applicationContext.xml




/WEB-INF/spring-config/dev.properties













To switch between environments, all you have to update is


/WEB-INF/spring-config/prod.properties

in the applicationContext.xml

To make it fancier, of course you can supply the properties to an ant script when you build your application.

Setup log4j to send email when an application error occur

7
Apache log4j is an excellent logging facility to log application information. It is extremely easy to setup and it is very powerful. It comes with an email appender by default which you can config it to sends email when you log.

Example: Logs message to standard system.out on INFO and Sends email when an application error occurs


# Configuration for receiving e-mails when ERROR messages occur.
log4j.appender.mail=org.apache.log4j.net.SMTPAppender
log4j.appender.mail.To=to@mydomain.com
log4j.appender.mail.From=from@mydomain.com
log4j.appender.mail.SMTPHost=smtp.mydomain.com
log4j.appender.mail.Threshold=ERROR
log4j.appender.mail.BufferSize=1
log4j.appender.mail.Subject=An application error occured
log4j.appender.mail.layout=org.apache.log4j.HTMLLayout

# Standrd System.out appender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

log4j.rootLogger=INFO, stdout, mail


This is pretty simple. The only setting that controls what to send is the Threshold property of the appender.