2010-06-30

Integration testing your Spring 3 & JPA 2.0 application

In my previous posts, I explained the following:

Now, one thing that is missing in this picture is...


Testing DAO classes


There is a presentation by Rod Johnson of Spring on testing with Spring that explains you what unit testing and what integration testing is, what mock objects are and some of the best practices. The presentation itself is from 2007 and while the general ideas haven't changed, the implementation techniques have.

Therefore in this article I will show you how to integration test your DAO classes. I am going to use a JPA project for this, but the same test code will work for Hibernate as well.


Integration Testing principles


Integration testing is another level of tests; while unit tests test pieces of code in separation, integration tests test the bigger picture. Unit tests don't go to data sources, they are fast and simple. Integration tests hit the data sources and test multiple modules together.

So, you should have a database set up, in a well known state. This should not be the production database! But it should be identical (or as close as possible).

On this database you perform the tests. This is better than mock objects, because although you can simulate certain behaviors with mock objects, it's nothing compared to using a real database, with its triggers, views, stored procedures etc.


How does it, uhm, how does it work?


Integration testing that involves a data source, whether you use Spring or, say, DBUnit, often works according to the same schema.

You mess around with the database, add, update, remove. Then all the changes are reverted.

With Spring, they are rolled back.


Integration testing with Spring 3


Prior to Spring 3 the recommended way of testing JPA was to use AbstractJpaTests - but not anymore; now it's deprecated. The official documentation suggests you use (extend) AbstractJUnit38SpringContextTests. You would rather use AbstractJUnit4SpringContextTests if you use JUnit 4. But both strategies require extending and Java allows for inheritance only (which is good), so I will show you an alternative way of doing it.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/test/resources/applicationContext-test.xml" })
@TransactionConfiguration(transactionManager = "myTransactionManager", defaultRollback = true)
@Transactional
public class DogsDaoImplTest {
// ...

Alright! Let's explain these annotations, one by one.

  • @RunWith(SpringJUnit4ClassRunner.class) - this means that JUnit will enable the functionality of the Spring TextContext Framework. That makes it possible for you to use Spring goodies (annotations like @Autowired etc.) in the tests
  • @ContextConfiguration - tells Spring where the beans files are. Note the format. This way it works within Eclipse, within Ant, within Maven, from Hudson etc.
  • @TransactionConfiguration - here we configure the transaction. We specify the manager to use and if rollback should be the default thing to do when a transaction ends (a bit explicit - the default is true anyhow)
  • @Transactional - all methods must run in transactions so that their effects can be rolled back

NOTE: Some configurations also use this annotation:
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class,
        TransactionalTestExecutionListener.class })
But the code works without it... I don't see why it should be used. Perhaps someone can clarify on that.

And now a test method.

@Autowired
    private DogsDao dogsDaoImpl;

    @Test
    public void testPersistDog() {
        long dogsBefore = dogsDaoImpl.retrieveNumberOfDogs();

        Dog dog = new Dog();
        dog.setName("Fluffy");
        dogsDaoImpl.persistDog(dog);
        long dogsAfter = dogsDaoImpl.retrieveNumberOfDogs();

        assertEquals(dogsBefore + 1, dogsAfter);
    }


Dependencies


In the previous posts I screwed up dependencies - yes. I imported spring-dao, version 2.0.8 - WRONG. Here's the correct dependency set for the whole project:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>me.m1key</groupId>
    <artifactId>springtx</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>3.3.0.ga</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>3.5.3-Final</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>1.8.0.7</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.1</version>
            <type>jar</type>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <id>r.j.o-groups-public</id>
            <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
    </repositories>
</project>

Previously I was getting this:
java.lang.NoSuchMethodError:
org.springframework.transaction.interceptor.
TransactionAttribute.getQualifier()Ljava/lang/String;
Now it's fixed.


Other possibilities


Apart from JUnit traditional annotations, such as @Before and @BeforeClass, you can also use:
  • @BeforeTransaction (org.springframework.test.context.transaction.BeforeTransaction)
  • @AfterTransaction (org.springframework.test.context.transaction.AfterTransaction)


Summary


In this article I showed you how to integration test DAO classes with Spring 3.

Download source code for this article

2010-06-28

Spring transaction management: org.hibernate.SessionException: Session is closed!

If you got this exception:

Exception in thread "main"
javax.persistence.PersistenceException:
org.hibernate.SessionException:
Session is closed!

... and you are using Spring transaction management, then the reason might be that your DAO method (the method that threw it and that uses persistence context) is not transactional and it should be:

import org.springframework.transaction.annotation.Transactional;
//...
    @Transactional(readOnly = true)
    public List<Dog> retrieveAllDogs() {
        return em.createQuery("from Dog").getResultList();
    }
//...

See my article on correct setup of Spring 3 & JPA 2.0.

2010-06-27

Removing JpaTemplate in favor of injected @PersistenceContext

In the previous two articles (Spring, JPA 2.0 & Maven and Spring transaction management) I showed you how to create a project that utilizes Spring 3, JPA 2.0 and Maven, that does not require a server and that offers transaction handling.

However, I used Spring's JpaTemplate which got some attention from Tomek Nurkiewicz who pointed out that this is not really a recommended way of doing it.

The recommended way of handling JPA in your DAO classes is to use an EntityManager injected with JEE's @PersistenceContext annotation.

Let's see what the configuration looks like.


Your Spring beans file


  1. Remove the jpaTemplate bean declaration.
  2. Remove the jpaTemplate bean references.
  3. Add PersistenceAnnotationBeanPostProcessor.

Here's the whole file:
<?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:p="http://www.springframework.org/schema/p"
    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.xsd
        http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd
           http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="Dogs" />
    </bean>

    <bean id="dogsDao" class="me.m1key.springtx.dao.DogsDaoImpl" />

    <bean id="dogsBean" class="me.m1key.springtx.beans.DogsBean"
        scope="singleton">
        <property name="dogsDao" ref="dogsDao" />
    </bean>

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

    <bean id="myTransactionManager"
            class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <bean
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>




Your DAO class


  1. Remove extending JpaDaoSupport.
  2. Add @PersistenceContext injected EntityManager.
  3. Replace getJpaTemplate() with the EntityManager (that's not always a non-brainer).
  4. Make each DAO method @Transactional (you can set its readOnly attribute to true if the method only reads data).


package me.m1key.springtx.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.transaction.annotation.Transactional;

import me.m1key.springtx.entities.Dog;

public class DogsDaoImpl implements DogsDao {

    @PersistenceContext
    private EntityManager em;

    @SuppressWarnings("unchecked")
    @Transactional(readOnly = true)
    public List<Dog> retrieveAllDogs() {
        return em.createQuery("from Dog").getResultList();
    }

    @Transactional(readOnly = true)
    public Long retrieveNumberOfDogs() {
        System.out.println(em);
        return (Long) em.createQuery(
             "select count(d) from Dog d")
                .getSingleResult();
    }

    @Transactional(readOnly = false)
    public void persistDog(Dog dog) {
        em.persist(dog);
    }

}



Summary


We removed an additional thin layer of JpaTemplate.

Many sites (e.g. the official Hibernate site) will tell you you cannot use @PersistenceContext in Java SE applications - well we just did, thanks to Spring (thanks to PersistenceAnnotationBeanPostProcessor).

I got some of the information from the blog by Łukasz.

Download source code for this article

Spring 3 transaction management

In this article I will show you how to handle transaction management with Spring.


Benefits of Spring Transaction Management


  • Very easy to use, does not require any underlying transaction API knowledge
  • Your transaction management code will be independent of the transaction technology
  • Both annotation- and XML-based configuration
  • It does not require to run on a server - no server needed

Great! Let's begin with some basic information you may want to skip if you already know about transactions.


Overview


Transactions ensure that the data in your application (in the data source) stays consistent. You should also be familiar with the ACID concept.

Now, in Java you can handle transactions with plain SQL, with plain JDBC (a bit higher level), using Hibernate (or any other ORM library), or on an even higher level - with EJB or, finally, Spring!

EJBs require an application server, but our application presented here - doesn't.


Programmatic vs. Declarative


Spring offers two ways of handling transactions: programmatic and declarative. If you are familiar with EJB transaction handling, this corresponds to bean-managed and container-managed transaction management.

Programmatic means you have transaction management code surrounding your business code. That gives you extreme flexibility, but is difficult to maintain and, well, boilerplate.

Declarative means you separate transaction management from the business code. You only use annotations or XML based configuration.

We say that:
  • programmatic management is more flexible during development time but less flexible during application life
  • declarative management is less flexible during development time but more flexible during application life


In this article...


We will focus on declarative management.

OK, a small description of what we want to achieve and how.

The goals:
  • A desktop application (i.e. it doesn't need a server)
  • Declarative transaction management with minimum XML

The means:
  • A Maven project created in Eclipse and making use of SpringIDE
  • Spring transaction management
  • Java with annotations enabled (I'm going to use Java 6)
  • JPA 2.0

We are going to build on the project I used in my previous post on Spring & JPA 2.0.


Transaction Manager


We must first specify that we want to use annotation driven transaction management.

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

And, of course, the transaction manager itself:
    <bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

What we are using here is the JpaTransactionManager. There are more managers available:

It references a bean called entityManagerFactory. Here it is:

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="Dogs" />
    </bean>


Annotation based


@Transactional is the annotation you can use on any method of any bean and on the bean itself.

import org.springframework.transaction.annotation.Transactional;
// ...
@Transactional
public void doSomething(...
// ...

If you apply the annotation on the bean (i.e. on the class level), every public method will be transactional.

Note: Remember that it affects only Spring managed data sources (in our example whatever comes from the entity manager factory). If you get your data source outside of Spring, the @Transactional annotation will have no effect.


Where to put @Transactional


You should put this annotation on your business logic methods (service methods), not on DAO methods (unless you know what you're doing) - that's a rule of thumb. Normally a business method will call many DAO methods and those calls make only sense when made together, every single one or none (atomicity).


Transaction Propagation


Whenever a transactional method is called, a decision is made - what to do with the transaction. Create a new one? Use an existing one if it exists, otherwise create a new one? Use an existing one only if it exists, otherwise fail?

To make it possible for you to specify this, propagation behaviors exist.

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
// ...
@Transactional(propagation = Propagation.REQUIRED)
public void doSomething(...
// ...

See the behaviors:
  • REQUIRED - uses the existing transaction. If it doesn't exist, creates a new one
  • REQUIRES_NEW - must start a new transaction. If there's an existing one, it should be suspended
  • SUPPORTS - if there is a transaction, runs in it. If there isn't, it just runs outside transaction context
  • NOT_SUPPORTED - must not run in a transaction. If there's an existing one, it should be suspended
  • MANDATORY - must run in a transaction. If there isn't one, it throws an exception
  • NEVER - must not run in a transaction. If there's an existing one, an exception will be thrown
  • NESTED - if there is a transaction, it runs withing the nested transaction of it. Otherwise it runs in its own

It is up to you to decide which behavior is best for each method. REQUIRED is the default one.

Note: If you are using the XML setup for transactions, you can also configure these behaviors there instead of Java code.


Transaction Isolation


Concurrent transactions cause problems that might be difficult to investigate.
  • Lost update - two transactions both update a row, the second transaction aborts, both changes are lost
  • Dirty read - reading changes that are not yet committed
  • Unrepeatable read - a transactions read twice the same row, getting different data each time
  • Phantom read - similar to the previous one, except that the number of rows changed

Now, the perfect solution to these problems is maximum isolation, but in reality this would cost too much resources and could lead to deadlocks. So, instead, you will set one of five isolation levels (where the fifth one is actually the maximum isolation level):

  • DEFAULT - uses the default database isolation level
  • READ_UNCOMMITTED - dirty read, unrepeatable read, phantom read problems may occur, but not lost update
  • READ_COMMITTED - unrepeatable read, phantom read problems my occur
  • REPEATABLE_READ - phantom read problems my occur
  • SERIALIZABLE - all problems avoided! But performance is low

The default choice is DEFAULT.

HSQLDB 2.0 supports READ_COMMITTED and SERIALIZABLE levels (HSQLDB FAQ).


... and roll...back! Transaction Rollback


With Spring transaction management the default behavior for automatic rollback is this: Only unchecked exceptions cause a rollback. Unchecked exceptions are RuntimeExceptions and Errors.

import org.springframework.transaction.annotation.Transactional;
// ...
@Transactional
public void doSomething(...
// ...
Think about it for a second! Are you sure you understand what it does?
  • If the doSomething method terminates its execution naturally, with no exceptions, the transaction is committed
  • If the doSomething method or any other method it calls throws any kind of exception that is caught within doSomething or this other method and not rethrown, the transaction is committed
  • If the doSomething method or any other method it calls throws any kind of checked exception that is not caught or is caught and rethrown, the transaction is committed (so everything up to the moment of the exception being thrown is persisted)
  • If the doSomething method or any other method it calls throws any kind of unchecked exception that is not caught, the transaction is rolled back (so nothing saved in this transaction is persisted)

That's the default behavior. However, you may want to change it for certain cases:
@Transactional(rollbackFor = IOException.class, noRollbackFor = RuntimeException.class)
public void doSomething(...
Here I asked the transaction manager to rollback for IOExceptions and not to rollback for RuntimeExceptions.

Note: If you are using the XML setup for transactions, you can also configure these rules there instead of Java code.


Our sample application


Spring beans file

You've seen it before.
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    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.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

...

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

<bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="Dogs" />
</bean>

...


Using transactions

import org.springframework.transaction.annotation.Transactional;
// ...
@Transactional
public void doSomething(...
// ...

That's all!


What if you...


What if you are using Spring 1.x?

You have to use the classic AOP approach. org.springframework.transaction.interceptor.TransactionProxyFactoryBean might be your starting point.

What if you want to declare transactions in XML and not in the code?

You may want to go for something like this:

    <tx:advice id="dogsTxAdvice" transaction-manager="myTransactionManager">
        <tx:attributes>
            <tx:method name="persistDog" />
        </tx:attributes>
    </tx:advice>
    
    <aop:config>
        <aop:pointcut id="dogsOperation"
            expression="execution(* me.m1key.springtx.beans.DogsBean.*(..))" />
        <aop:advisor advice-ref="dogsTxAdvice" pointcut-ref="dogsOperation" />
    </aop:config>


Summary


That's it! Although the transactions themselves are by no means a trivial topic, Spring makes at least handling them easy.

I got my knowledge mostly from this book:
Spring Recipes: A Problem-Solution Approach
It helps me run this website if you buy this book through this link, thanks!

A brief intro to HSQLDB and how to use it in this app (Note that the project in that article is NOT a Maven project, but an Eclipse JPA one, so the project creating part doesn't matter)?

Read on: Remove JpaTemplate in favor of @PersistenceContext.

Download the source code for this article

2010-06-24

Spring, JPA 2.0 & Maven - Hello World

In this article I will show you how to create a
  • Spring 3.0.3.RELEASE application
  • that is a desktop application (no application server/servlet container required) but might be deployed to a server too
  • and that connects to a database (HSQLDB)
  • using JPA 2.0
  • without using provider specific code (such as Hibernate) in Java files
  • and that allows for declarative transaction management (next article).

You can download the source code and you are free to use it in your projects. I'm using Eclipse 3.5.2 for this.


JPA persistence file - persistence.xml


This file should be located in a folder called META-INF in the root of your classpath. It is a standard JPA configuration file where you put data source specific configuration.

Here's the content:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="Dogs">
        <class>me.m1key.springtx.entities.Dog</class>

        <properties>
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />

            <property name="hibernate.connection.driver_class"
                    value="org.hsqldb.jdbcDriver" />
            <property name="hibernate.connection.url"
                    value="jdbc:hsqldb:hsql://localhost/dogsdb" />

            <property name="hibernate.connection.username"
                    value="sa" />

            <property name="hibernate.c3p0.min_size" value="5" />
            <property name="hibernate.c3p0.max_size" value="20" />
            <property name="hibernate.c3p0.timeout" value="300" />
            <property name="hibernate.c3p0.max_statements"
                    value="50" />
            <property name="hibernate.c3p0.idle_test_period"
                    value="3000" />

            <property name="hibernate.dialect"
                    value="org.hibernate.dialect.HSQLDialect" />

            <property name="hibernate.hbm2ddl.auto" value="create" />
        </properties>
    </persistence-unit>

</persistence>

Things to note:
  • JPA is only an API that requires a concrete implementation - we are using Hibernate here; you can use anything you want though as long as it is JPA 2.0 compliant. There are going to be no references to Hibernate in Java code
  • Persistence unit name is Dogs
  • hibernate.hbm2ddl.auto is set to create so that tables are only dropped when the application starts (and not where it shuts down) - you can investigate the content after shutdown (see how)

If you are looking for more information on HSQLDB, I wrote an article on HSQLDB and Eclipse where you can find some basic information (and this project has it set up exactly the same way).


Maven pom.xml


Compile the project using Java 6

...
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
...

Add a repository

This is for the latest Hibernate distribution.

...
    <repositories>
        <repository>
            <id>r.j.o-groups-public</id>
            <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
    </repositories>
...

Correct dependencies

...
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>3.3.0.ga</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>3.5.3-Final</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>1.8.0.7</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jpa</artifactId>
            <version>2.0.8</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
    </dependencies>
...


Spring beans file - applicationContext.xml


This file is located directly in the classpath, I put it in src/main/resources (a Maven convention).

Entity Manager Factory

This is the JPA way of doing things in Spring. You do not declare a data source in your Spring beans file (it is declared in persistence.xml), but an entity manager factory instead. You give it the persistence unit name ("Dogs").

...
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="Dogs" />
    </bean>
...

JPA template

We are going to use JPA template from our DAO classes. It makes DAO operations a bit easier (and sometimes it doesn't). Note that Hibernate Template also exists and has methods that are easier to use than those of JPA template, but I promised no Hibernate in the code.

...
    <bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
...

A DAO class

DogsDao is our only DAO class and it needs the JPA Template.

...
    <bean id="dogsDao" class="me.m1key.springtx.dao.DogsDaoImpl">
        <property name="jpaTemplate" ref="jpaTemplate" />
    </bean>
...

An alternative approach would be to inject the entity manager factory directly, thus eliminating the need to use JPA templates at all.

A business logic class

Here's a business logic class and it receives the DAO class, setter-injected.

...
    <bean id="dogsBean" class="me.m1key.springtx.beans.DogsBean"
        scope="singleton">
        <property name="dogsDao" ref="dogsDao" />
    </bean>
...

Transaction management

The next article will tell you more about transaction management. For now, just use this (it is required by JPA).

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

    <bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
...


Java code


The DAO class

package me.m1key.springtx.dao;

import java.util.List;

import me.m1key.springtx.entities.Dog;

import org.springframework.orm.jpa.support.JpaDaoSupport;
import org.springframework.transaction.annotation.Transactional;

public class DogsDaoImpl extends JpaDaoSupport implements DogsDao {

    @SuppressWarnings("unchecked")
    public List<Dog> retrieveAllDogs() {
        return getJpaTemplate().find("from Dog");
    }

    public Long retrieveNumberOfDogs() {
        return (Long) getJpaTemplate().getEntityManagerFactory()
                .createEntityManager()
                .createQuery("select count(d) from Dog d").getSingleResult();
    }

    @Transactional
    public void persistDog(Dog dog) {
        getJpaTemplate().persist(dog);
    }

}
It extends JpaDaoSupport which gives us access to the getJpaTemplate() method. You don't have to extend this class - if you don't, just provide a getter and setter for the jpaTemplate property.

The first method retrieves all dogs and, sadly, needs a SuppressWarning annotation (collection cast).

The second method demonstrates how you can get access to the entity manager, if you need it. That kind of query (that returns a number) is called reporting query.

The third method persists an object. The @Transactional annotation is actually a requirement - without it no insertion occurs.

The DAO class

package me.m1key.springtx.dao;

import java.util.List;

import me.m1key.springtx.entities.Dog;

public interface DogsDao {

    List<Dog> retrieveAllDogs();

    Long retrieveNumberOfDogs();

    void persistDog(Dog dog);

}

The business logic class

A very basic sample that should give you an idea.

package me.m1key.springtx.beans;

import me.m1key.springtx.dao.DogsDao;
import me.m1key.springtx.entities.Dog;

public class DogsBean {

    private DogsDao dogsDao;

    /**
     * Returns true if there is at least one dog in the database.
     *
     * @return true if there is a dog in the database
     */
    public boolean containsDogs() {
        return dogsDao.retrieveNumberOfDogs() > 0;
    }

    /**
     * Persists the dog to the database.
     *
     * @param dog
     *            dog to persist
     */
    public void persistDog(Dog dog) {
        dogsDao.persistDog(dog);
    }

    protected DogsDao getDogsDao() {
        return dogsDao;
    }

    public void setDogsDao(DogsDao dogsDao) {
        this.dogsDao = dogsDao;
    }

}

The entity class

This is out Dog entity. No Hibernate, as promised.

package me.m1key.springtx.entities;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "DOGS")
public class Dog {

    private Long id;
    private String name;
    private static final long serialVersionUID = 1L;
    private List<String> nicknames = new ArrayList<String>();

    public Dog() {
        super();
    }

    @Id
    @GeneratedValue
    @Column(name = "DOG_ID")
    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "DOG_NAME")
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ElementCollection(fetch = FetchType.EAGER)
    public List<String> getNicknames() {
        return nicknames;
    }

    public void setNicknames(List<String> nicknames) {
        this.nicknames = nicknames;
    }

    @Override
    public String toString() {
        return "[" + id + ", " + name + "]";
    }

}

Let's launch it!

Finally, here's how you can see whether it works.

// ...
    public static void main(String[] args) {
        ApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] { "applicationContext.xml" });
        DogsBean dogsBean = appContext.getBean("dogsBean", DogsBean.class);

        Dog doggie = new Dog();
        doggie.setName("Sega");

        System.out.println("Any dogs: " + dogsBean.containsDogs());
        dogsBean.persistDog(doggie);
        System.out.println("Any dogs: " + dogsBean.containsDogs());
    }
// ...
It should first print false, then true - and lots of useful (or not) logs.


I hope this gives you an idea how to build such an application.

Issues and Solutions


Missing artifact org.hibernate:hibernate:jar:3.5.3-Final:compile

It happened to me that Maven was unable to fetch this lib - hibernate-3.5.3-Final.jar. If it happens to you, just download the correct (3.5.3-Final) Hibernate distribution ZIP/TAR file and put the missing file (it might be called hibernate3.jar) into your local repository manually (or your company corporate repository).

Caused by: java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist

Might happen when you run your application from Eclipse before you packaged it with Maven. That's a classpath issue. Just do Maven -> Clean and Maven -> Package, and then launch the application again.


I got my knowledge from here: Java Persistence with Hibernate

It helps me run this website when you buy the book via this link - thanks!

Download source code for this article

Sega

No Persistence provider for EntityManager named X

Did you get this error too?

Exception in thread "main"
javax.persistence.PersistenceException:
No Persistence provider for
EntityManager named helloworld
[Line breaks added for readability]

There can be at least three different causes, one not so obvious.

  • Your persistence.xml file cannot be found - it does not reside in a folder called META-INF that is located in classpath root
  • Your persistence.xml file does not contain a persistence-unit with the given name (helloworld in this case)
  • The tricky one - you have a problem with dependencies

I had problem #3. The error message suggested something different, but actually my dependencies were screwed up. Here's an example of correct dependencies (hibernate-entitymanager was the one causing problems).

...
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>3.3.0.ga</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>3.5.3-Final</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>1.8.0.7</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jpa</artifactId>
            <version>2.0.8</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
    </dependencies>
...

When Spring's jpaTemplate persist does not save

Just a quick one...

If you have code similar to this:

public void persistDog(Dog dog) {
        getJpaTemplate().persist(dog);
    }

... and if nothing is persisted to database (and you don't see the insert in logs), don't panic. ;)


Enable transactions!


This will do the trick:

import org.springframework.transaction.annotation.Transactional;
    // ...
    @Transactional
    public void persistDog(Dog dog) {
        getJpaTemplate().persist(dog);
    }
    // ...

Your pom.xml file may need this:

...
    <dependencies>
        ...
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <repositories>
        ...
        <repository>
            <id>r.j.o-groups-public</id>
            <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
    </repositories>
    ...

And your Spring beans file:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    ...

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

    <bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    ...

Enjoy.

org.hibernate.MappingException: Could not determine type for: java.util.List, at table exception

In case someone got an error similar to this one:

Caused by: org.hibernate.MappingException:
Could not determine type for: java.util.List,
at table: DOGS, for columns:
[org.hibernate.mapping.Column(nicknames)]
[Line breaks added for readability]

... I found the solution.

It was caused by:
import javax.persistence.ElementCollection;
    // ...
    @ElementCollection(fetch = FetchType.EAGER)
    public List<String> getNicknames() {
        return nicknames;
    }
    // ...

If you are getting this error in a similar situation, the reason is a bug in your Hibernate implementation and you should get a newer one (I recommend 3.5.3-Final or later).

Here's my pom.xml file.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>me.m1key</groupId>
    <artifactId>springtx</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.5.3-Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>3.3.0.ga</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>3.5.3-Final</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>1.8.0.7</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jpa</artifactId>
            <version>2.0.8</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>3.0.3.RELEASE</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <id>JBoss Repo</id>
            <url>http://repository.jboss.com/maven2</url>
        </repository>
        <repository>
            <id>r.j.o-groups-public</id>
            <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
    </repositories>
</project>

Please note it may also happen for java.util.Collection, java.util.Map and java.util.Set.

2010-06-23

Eclipse JPA with Hibernate & HSQLDB. Part 2

Did you see Part 1 of the series where I explained how to create an Eclipse JPA project?

In this part of the series I will show some basic functionalities of Eclipse JPA as we create a very simple project.


Creating an entity class


It is easy to create an entity class. Right click on a package, New -> Entity.
Creating an entity class

Note: In our scenario we are not using a legacy database, so we will let Hibernate create all tables in the database for our entities.

Now you can specify the entity name:
Fill entity name

You can add properties:
Adding a property

Access type
  • Field - annotate the field itself (e.g. with @Id)
  • Property - annotate the getter

You can also provide an alternative name for the table (other than the one derived from the class name):
Table name - DOGS

It's better to use the property one.

Let's see the generated code.

package me.m1key.dogs.dao;

import java.io.Serializable;
import java.lang.Long;
import java.lang.String;
import javax.persistence.*;

/**
 * Entity implementation class for Entity: Dog
 *
 */
@Entity
@Table(name = "DOGS")
public class Dog implements Serializable {

    private Long id;
    private String name;
    private static final long serialVersionUID = 1L;

    public Dog() {
        super();
    }

    @Id
    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }
    //... Omitted for brevity.
}

You have a no-argument constructor (that's a JPA requirement). You have an ID annotated with @Id, the class is annotated with @Entity and you have the @Table annotation so that an alternative table name can be specified.

Note that in the peristence.xml file content was created automatically. It should look more or less like this.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
    xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    
    <persistence-unit name="Dogs">
        <class>me.m1key.dogs.entities.Dog</class>
    </persistence-unit>
    
</persistence>


Eclipse JPA validation


At this moment, if connected to your HSQLDB server, you might get the following error:
Table "DOGS" cannot be resolved
Table cannot be resolved

That's right, the table does not exist because we are not using a legacy database. We should let Hibernate create this table for us.


What is missing?


We specified the ID column, but we did not specify how to get its value. Use the @GeneratedValue annotation.
import javax.persistence.GeneratedValue;

    // ...

    @Id
    @GeneratedValue
    public Long getId() {
        return this.id;
    }

    // ...

Compared to the project from the first part of the tutorial, you also need to add a dependency to slf4j-simple-1.5.8.jar.

One more thing we must add is database specific stuff in persistence.xml. Eclipse knows how to connect to the database, but your project doesn't.

...
    <persistence-unit name="Dogs">
        <class>me.m1key.dogs.entities.Dog</class>

        <properties>
            <property name="hibernate.archive.autodetecion" value="class, hbm" />

            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />

            <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
            <property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost/dogsdb" />

            <property name="hibernate.connection.username" value="sa" />

            <property name="hibernate.c3p0.min_size" value="5" />
            <property name="hibernate.c3p0.max_size" value="20" />
            <property name="hibernate.c3p0.timeout" value="300" />
            <property name="hibernate.c3p0.max_statements" value="50" />
            <property name="hibernate.c3p0.idle_test_period" value="3000" />

            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />

            <property name="hibernate.hbm2ddl.auto" value="create" />
        </properties>
    </persistence-unit>
...

The hibernate.hbm2ddl.auto paramater is set to create because it is more convenient for us in this situation. It means that the database is dropped and recreated on application start-up, but is not dropped after it shuts down, so that you can investigate the content of it after the application has run.


DAO


Let's create simple DAO classes, namely a generic DAO and DogDAO.

package me.m1key.dogs.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 * Generic DAO for other DAOs to extend.
 *
 * @author Michal
 *
 */
public abstract class GenericDAO {

    private static EntityManagerFactory emf = Persistence
            .createEntityManagerFactory("Dogs");

    public EntityManager createEntityManager() {
        return emf.createEntityManager();
    }

    public static void closeEntityManager() {
        emf.close();
    }

}
This is a simple generic DAO. All it does is it allows for using its createEntityManager method from extending classes. This is temporary design, not a recommended way of doing it, mind you.

Now, look at the createEntityManagerFactory method - it specifies the persistence unit name. It is the very same name which is specified in our persistence.xml file.

Let's create the DogDAO then.

package me.m1key.dogs.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;

import me.m1key.dogs.entities.Dog;

/**
 * Dog DAO.
 *
 * @author MichalH
 *
 */
public class DogDAO extends GenericDAO {

    public void persistDog(Dog dog) {
        EntityManager em = createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        em.persist(dog);

        tx.commit();
        em.close();
    }

    @SuppressWarnings("unchecked")
    public List getAllDogs() {
        EntityManager em = createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        Query allDogsQuery = em.createQuery("select d from Dog d");

        List allDogs = allDogsQuery.getResultList();

        tx.commit();
        em.close();

        return allDogs;
    }

}

Two simple methods, one for saving dogs in the database, and one for retrieving all of them.


Let it run


Below, sample code that uses those DAO classes.

package me.m1key.dogs;

import java.util.ArrayList;
import java.util.List;

import me.m1key.dogs.dao.DogDAO;
import me.m1key.dogs.dao.GenericDAO;
import me.m1key.dogs.entities.Dog;

/**
 * Launches the simple JPA demonstration application.
 *
 * @author MichalH
 *
 */
public class Launcher {

    /**
     * @param args
     */
    public static void main(String[] args) {
        DogDAO dogDao = new DogDAO();

        Dog michalsDog = new Dog();
        michalsDog.setName("Sega");

        Dog someOtherDog = new Dog();
        // http://www.fundognames.com/male-dog-names-p-9.html
        someOtherDog.setName("Assan");

        try {
            dogDao.persistDog(michalsDog);
        } catch (Exception e) {
            System.err.println("Exception while saving dog: " + michalsDog);
            System.err.println(e);
            e.printStackTrace();
        }

        try {
            dogDao.persistDog(someOtherDog);
        } catch (Exception e) {
            System.err.println("Exception while saving dog: " + someOtherDog);
            System.err.println(e);
            e.printStackTrace();
        }

        List<Dog> allDogs = dogDao.getAllDogs();
        for (Dog doggie : allDogs) {
            System.out.println(doggie);
        }

        GenericDAO.closeEntityManager();
    }

}

It's very very basic at this point. But what happens if you run it?

[1, Sega]
[2, Assan]
Alright! Something got saved in the database and was successfully retrieved. Note that each persisting operation and retrieval occur in separate transactions. If you don't like that, there are several solutions available:
  • Create business classes instead of DAO classes that handle persistence AND business logic
  • Use sf.getCurrentSession().beginTransaction() where sf is session factory - but that makes you use Hibernate directly, not just under the hood
  • Use JTA UserTransaction class
  • Use EJBs transaction propagation. (requires an application server)
  • Use Spring Transaction Management

And, if you refresh/clean the project now, you should see that the previous error (Table "DOGS" cannot be resolved) is now gone. You may have to do more Eclipse magic, like closing the database connection and opening it again etc.


Creating an entity from an existing database table


You can create entities from existing database tables, but it doesn't work so well, as I will show.

Imagine you already have an existing table in the database. Or, better, let's create one.

CREATE TABLE toys
(
TOY_ID BIGINT NOT NULL PRIMARY KEY,
TOY_NAME VARCHAR(128) NOT NULL,
DOG_ID BIGINT NOT NULL
)
That's simple SQL code (compatible with HSQLDB) creates a table called toys with a single column primary key and a toy name. There's also a column DOG_ID which we are going to make a foreign key.

ALTER TABLE toys
ADD FOREIGN KEY (DOG_ID)
REFERENCES DOGS (ID)
ON DELETE CASCADE

That's the foreign key. ON DELETE CASCADE means that if a dog is deleted - all its toys are deleted too. If a toy is deleted - the dog stays. Dogs don't share toys in our application.

Simply refreshing your database connection in Eclipse may not work (didn't work for me), so you may have to close it and open it again.

Now, right-click the entities package and select "New -> Entities From Tables":

New -> Entities From Tables

Here, select our new table:

Select tables to generate entities from

In the next window of the wizard it is possible to specify the associations. Please look at the following screenshot:

Select tables to generate entities from

It is smart enough to suggest the right columns:

Join columns

Now it's time to specify the kind of association. In our case, each dog has many toys.

Join columns

If you now click Finish, there's a surprise waiting for you. The list of associations remains empty.

No associations

I don't understand why. The class it generates doesn't even compile, and has no track of the relationship. Even when I created the relationship in JPA myself:

    @ManyToOne
    public Dog getDog() {
        return this.dog;
    }

... and let it create the table in the database, and then from this Hibernate-made table I repeated the procedure - I got the same disappointing result. What am I missing here?


Hand-written associations


I gave up generating entities using Eclipse JPA, I wrote them myself. Look at the previous code sample. This gives a one way association from a toy to a dog. A dog entity is unaware of its toys. You would need a separate DAO (ToysDAO) to even save toys.

We can change this by making the association bidirectional. In the Dog class:

// ...
    private List<Toy> toys = new ArrayList<Toy>();
    // ...
    @OneToMany(mappedBy = "dog", cascade = CascadeType.ALL)
    public List<Toy> getToys() {
        return toys;
    }

    public void setToys(List<Toy> toys) {
        this.toys = toys;
    }

CascadeType.ALL (javax.persistence.CascadeType) does the trick.

If you do not provide the mappedBy attribute, JPA will expect you to have another class just to "join" two tables together and you will get a validation error from Eclipse JPA:

Join table "DOGS_TOYS" cannot be resolved.

Cool.


Mapping a collection of Strings


Sometimes you want to map a collection of plain Objects and not entities. In our case, a dog can have some nicknames.

import javax.persistence.ElementCollection;
// ...
    @ElementCollection(fetch = FetchType.EAGER)
    public List<String> getNicknames() {
        return nicknames;
    }
// ...

An additional table is created:
DOG_NICKNAMES

You need JPA 2.0 for this; prior to JPA 2.0 you'd have to use Hibernate explicitly:

org.hibernate.annotations.CollectionOfElements

But not anymore, now you can use @ElementCollection like shown above.

Download source code for this article

2010-06-22

Eclipse JPA with Hibernate & HSQLDB. Part 1

In this tutorial I will show you how to create an Eclipse JPA project for a desktop application, avoiding some common pitfalls. You're going to need Eclipse Galileo 3.5.2 for this (the JEE edition) but other versions should work too (the UI may look different). I am also going to use HSQLDB, Java-based database. Note that my application doesn't use Maven.


Step #1: Open the Eclipse JPA project wizard


Open the Eclipse JPA project wizard

The first step is to open the Eclipse JPA project wizard. If it doesn't show up in the menu (as shown in the screenshot above), simply go to File -> New -> Other... and then under JPA there should be a "JPA Project" to select. If it isn't, you probably aren't using the correct version of Eclipse.


Step #2: Project name and runtime configuration


Project name and runtime configuration

Give the project a name (I called mine "Dogs"). I did not select a target runtime because the application is supposed to be a desktop one. I also selected the Default Configuration.


Step #3: Source folders


Source folders

We're going to leave this with the default value.


Step #4: Platform, JPA implementation


Platform, JPA implementation

This part gave me a bit of a headache. As a long time Maven user I could not agree to referencing project libraries from my local disk ("C:\Michal\Development\Libs\...") - it would never work for anyone else and not even for me on a different computer. And that's exactly what the wizard suggests you do!

So just select the "Hibernate" platform and "Disable Library Configuration" for JPA implementation. Eclipse displays a neat warning as if it suspected we didn't know what we are doing.

Now it's time to set up the connection.


Step #5: Adding the connection


Adding the connection

Click "Add connection...". Give it a name and click next.

Adding the connection

Fill in the data. We are using HSQLDB in the Server mode, so the DB location is hsql://localhost/dogsdb and it makes the URL become jdbc:hsqldb:hsql://localhost/dogsdb.

Note: HSQLDB in Server mode means that you need to explicitly start the server, it won't work if you just run the application (unlike the non-server file based and memory modes).

The server isn't up yet, so you will get an error when trying to connect:

Connection error

I would not check "Add driver library to build path".

Click "Finish".


Step #6: The HSQLDB


If the connection error annoyed you, no worries. We will take care of that. Create a folder called "lib" in your project and drop hsqldb-1.8.0.7.jar in there. You can get it from HSQLDB Download site (a newer version like 1.8.1.12 is fine, an older one should be OK too).

Now, let's add two batch files (or shell files; I am Windows based here at the moment) to the project root. Let's call them startDb.bat (startDb.sh for Unix based systems) and startManager.bat (startManager.sh). Here's the content.

startDb.bat
java -cp lib/hsqldb-1.8.0.7.jar
org.hsqldb.Server
-database.0
file:db\dogsdb -dbname.0 DOGSDB
[Line breaks added for readability] See how the database name corresponds with what you provided earlier?

If you run this, a folder called db will be created and database files put there. The java command must be in system PATH.

Note: You should run it from your system explorer (Windows Explorer, Finder etc.) and not from Eclipse. If you run it from Eclipse it is bound to fail because Eclipse runs it from its own root folder (where it is installed) and not from the project root.

HSQLDB server running

If you test the connection from Eclipse, it's going to be just fine.

Ping succeeded

You should also connect now from the Eclipse Data Source Explorer.

Connecting from Eclipse Data Source Explorer

startManager.bat
java -classpath lib/hsqldb-1.8.0.7.jar
org.hsqldb.util.DatabaseManagerSwing
[Line breaks added for readability] Now, this is for the Database Manager from HSQLDB. If you run this, you should set connection parameters as follows and it will let you in.

HSQLDB Database Manager


Step #7: Project classpath


You must add some libs to the project - namely Hibernate libs with certain dependencies. You can get them from the official distribution. Just drop them in the lib folder where hsqldb already is. Select them all (except for hsqldb) and right click them. Then Build path -> Add to build path.

Dependencies

You need the following jar files in the classpath:
  • antlr-2.7.6.jar
  • commons-collections-3.1.jar
  • dom4j-1.6.1.jar
  • hibernate3.jar
  • hibernate-jpa-2.0-api-1.0.0.Final.jar
  • javassist-3.9.0.jar
  • jta-1.1.jar
  • slf4j-api-1.5.8.jar

Now, you might get the following warning:

Classpath entry /Dogs/lib/dom4j-1.6.1.jar will not be exported or published. Runtime ClassNotFoundExceptions may result
Classpath entry /Dogs/lib/dom4j-1.6.1.jar
will not be exported or published.
Runtime ClassNotFoundExceptions may result
[Line breaks added for readability]

The only thing I could do about it was to click each of those issues (one per jar in classpath) and go for the quick fix (right click it and select "Quick Fix"; or select it and hit Ctrl+1). Then I would select "Exclude the associated raw classpath entry from the set of potential publish/export dependencies." Selecting the other option ("Mark the associated raw classpath entry as a publish/export dependency") would give me another warning that I couldn't fix.

Exclude the associated raw classpath entry from the set of potential publish/export dependencies.

If you plan to export your application with the Eclipse Export tool you might want to add hsqldb-1.8.0.7.jar to the build path too and it will not be exported.

Summary


In this tutorial we created a simple Eclipse JPA project thanks to which we can benefit from Eclipse JPA support. What is important, the project itself has all the dependencies it needs, so they are not referenced from an external location. In the next part we will create some simple JPA code.

Download source code for this article

2010-06-08

Porto Lifesavers - photos

The second album with pictures from Porto is different; there are no sights - instead you can see lifesavers in action near Castelo do Queijo.

Porto Lifesavers