Trasis Inc.

渋谷拠点のシステム開発会社

Maven+Spring+Hibernate+JPA+JUnit4環境構築

概要

今回は Maven + Spring Framework + Hibernate + JPA + JUnit の組み合わせで環境構築。

開発環境

項目
OS Windows XP Pro SP2
IDE 環境 Eclipse 3.3.2(Preiades All in One)
Java JDK 6 update 6
DB PostgreSQL 8.3

準備

次の手順までHibernateを使ったシンプルなJPA環境構築と同じように進める。

    • Maven プロジェクト作成
    • Java コンパイラー準拠レベルの設定
    • pom.xml を設定する
    • 設定ファイル作成
      •  META-INF/persistence.xml
         ehcache.xml
        log4j.properties
  • BaseEntity, User クラス作成

pom.xml 修正

次のように修正する。

<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>trasis-sample</groupId>
<artifactId>jpa1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.3-603.jdbc4</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.5</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.3.2.GA</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>2.5.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

src/main/resources ソース・フォルダ

META-INF/persistence.xml

次のように修正する。

<?xml version="1.0" encoding="UTF-8" ?>
<persistence 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"
version="1.0">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jar-file>.</jar-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.cache.provider_class"	value="org.hibernate.cache.EhCacheProvider" />
<property name="hibernate.cache.provider_configuration_file_resource_path" value="/ehcache.xml" />
<property name="hibernate.cache.use_query_cache"		value="true" />
<property name="hibernate.cache.use_second_level_cache"	value="true" />
<!-- none | update | create-drop -->
<property name="hibernate.hbm2ddl.auto"		value="update" />
<property name="hibernate.show_sql"			value="false" />
<property name="hibernate.format_sql"		value="true" />
<property name="hibernate.use_sql_comments" value="false" />
<property name="hibernate.max_fetch_depth" value="3" />
<property name="hibernate.jdbc.batch_size" value="100" />
</properties>
</persistence-unit>
</persistence>

Maven を使う場合、エンティティクラスは src/main/java に、META-INF/persistence.xml ファイルなどは src/main/resources フォルダに置く。
この環境で Spring Framework + Hibernate にうまくクラスのアノテーションをスキャンしてもらうために、次のように記述している。

<jar-file>.</jar-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>

applicationContext.xml

Spring Framework の設定。

<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans		http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop		http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx		http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/context	http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- アノテーション検索パッケージ  -->
<context:component-scan base-package="test.test" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
<context:annotation-config />
<!-- @Transactional: トランザクション自動開始 -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>

Spring Framework 2.5 からサポートされたいくつかの記述により、前のバージョンよりも記述が簡単になっている。

context:property-placeholder によって、jdbc.properties を読み込んでいる。
${jdbc.url} のように applicationContext.xml 内に記述すると置換される。

context:annotation-config によって、クラスをスキャンし、@Service などのアノテーションを解釈する。
<context:component-scan base-package=”test.test” /> によってスキャンするパッケージを明示的に指定している。

tx:annotation-driven によって、@Transactional アノテーションを解釈する。

jdbc.properties

新たに作成。applicationContext.xml の中で ${jdbc.driverClassName} などが置換される。

jdbc.driverClassName=org.postgresql.Driver
jdbc.url=jdbc:postgresql://localhost:5432/sandbox
jdbc.username=postgres
jdbc.password=postgres

Dao 作成

src/main/java フォルダの中で test.test.dao.UserDao クラスを作成する。

package test.test.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import test.test.entity.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class UserDao {
@PersistenceContext
private EntityManager entityManager;
public void persist(User user) {
entityManager.persist(user);
}
public void remove(User user) {
entityManager.remove(user);
}
public void remove(Long id) {
entityManager.createQuery("delete from Users c where id=?1")
.setParameter(1, id)
.executeUpdate();
}
public User find(Long id) {
return entityManager.find(User.class, id);
}
public User findByMailAddress(String mailAddress) {
return (User) entityManager
.createQuery("from Users c where mailAddress=?1")
.setParameter(1, mailAddress)
.getSingleResult();
}
@SuppressWarnings("unchecked")
public List<User> findAll() {
return entityManager.createQuery("from Users").getResultList();
}
}

@Service アノテーションを指定すると、Spring Framework のビーンとして解釈され、他のビーンから @Resource アノテーションなどによって呼び出せる。

@Transactional アノテーションによって、このクラスのメソッド呼び出し時に、トランザクションがまだオープンされていなければ、自動的にオープンする。

JUnit4 によるテスト

テストケースの作成

src/test/java フォルダの中で test.test.DBTest を作成する。

package test.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.List;
import javax.annotation.Resource;
import javax.persistence.NoResultException;
import test.test.dao.UserDao;
import test.test.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext.xml"})
@Transactional
public class DBTest {
private static final String MAIL_ADDRESS = "test3@example.com";
@Resource
private UserDao userDao;
@Test
public void test1() throws InterruptedException {
// 追加
{
User user = new User();
user.setMailAddress(MAIL_ADDRESS);
user.setPassword("test");
userDao.persist(user);
}
// 検索1
{
List<User> list = userDao.findAll();
assertEquals(1, list.size());
User user = list.get(0);
assertEquals(MAIL_ADDRESS, user.getMailAddress());
assertEquals("test", user.getPassword());
}
// 検索2
User user = userDao.findByMailAddress(MAIL_ADDRESS);
assertEquals(MAIL_ADDRESS, user.getMailAddress());
assertEquals("test", user.getPassword());
// 削除
userDao.remove(user);
try {
user = userDao.findByMailAddress(MAIL_ADDRESS);
fail();
} catch (NoResultException e) {
// ok
}
}
}

@RunWith(SpringJUnit4ClassRunner.class) アノテーションによって、@Transactional によってトランザクションをオープンしたり、@Resource によってビーンの注入を行った状態でテストを実行することが可能になる。

なお、テストを実行しても、トランザクションはデフォルトでは自動的にロールバックされる。
テストの結果、コミットされるようにするには、test1() メソッドに対して @Rollback(false) を宣言する。

テストスイートの作成

複数のテストケースを実行するテストスイート test.test.AllTests を作成する。

package test.test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
DBTest.class
})
public class AllTests {
}