Filed under: J2EE, Java, — Tags: HSQL, Hibernate, Maven, Spring, TDD — Thomas Sundberg — 2009-04-09
We will create a small Java application that connects to a database using Hibernate. We will use Spring to wire stuff together and Maven to build it.
Step 0 - Setting the stage
Step 1 - Creating unit tests to verify our Java code
Step 2 - Annotate the entities using EJB3 annotations
Step 3 - Create the database schema for the annotated entities with Maven
Step 4 - Connect the Data Access Objects, dao, to Hibernate using Spring for the wiring
Step 5 - Start Hypersonic SQL, HSQL
Step 6 - Run the integration tests to verify the entire setup using a database
The problem we will solve is to create a small project that uses Spring to wire stuff together, Hibernate to communicate with a database and build everything using Maven.
I tried to get a similar setup to work and didn't find any solutions on the net. Or the solutions that I found was either incomplete or didn't solve the problem the way I wanted it to be solved.
I found a lot of un answered questions on mailing list and for some reason nobody wanted to describe something that I felt like a valid solution. Hopefully I will be able to solve some issues and clarify some things I have discovered.
I will use Maven so the file structure will be the standard maven setup like this:
src -------+- main ----+- java ------ | | | +- resources - | +- test ---+- java ------- | +- resources -- pom.xml
Create the first version of the pom.xml with this content:
<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>com.agical.experimental</groupId> <artifactId>spring-hibernate-maven</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>SpringHibernateMaven</name> <url>http://www.agical.com</url> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-idea-plugin</artifactId> <configuration> <downloadJavadocs>true</downloadJavadocs> <downloadSources>true</downloadSources> <jdkLevel>1.5</jdkLevel> <jdkName>1.5</jdkName> </configuration> </plugin> </plugins> </build> </project>
The heading is a normal Maven heading
I define two things in the build section. First I want the project to be created for Java 1.5 so we can use
annotations later.
Then I define how the maven-idea-plugin pluging should create project files for Intellij Idea. Note that I set both
downloadJavadocs and downloadSources to true. this will enable me to browse the source code from Idea if I want to
and get Javadocs automatic.
Somebody using Eclipse may want to do something similar. I don't use Eclispe unless I have to so I don't really care
how this should be done.
We should now be able to create the first version of the projects files so we can do the rest of the editing in Idea. Create the project files for Idea with the command
mvn idea:idea
Any stuff needed to be downloaded will be downloaded and if everything goes well we should have a successful build.
>mvn idea:idea [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'idea'. [INFO] ------------------------------------------------------------------------ [INFO] Building SpringHibernateMaven [INFO] task-segment: [idea:idea] [INFO] ------------------------------------------------------------------------ [INFO] Preparing idea:idea [INFO] No goals needed for project - skipping [INFO] [idea:idea] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1 second [INFO] Finished at: Mon Dec 15 22:25:33 CET 2008 [INFO] Final Memory: 3M/6M [INFO] ------------------------------------------------------------------------
So, now we can launch Idea with our new project files and continue with something more interesting then setting up the project.
Lets start with adding a dependency to JUnit. Add the dependency below to the pom.
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> </dependencies>
The new pom should look something like this.
<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>com.agical.experimental</groupId> <artifactId>spring-hibernate-maven</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>SpringHibernateMaven</name> <url>http://www.agical.com</url> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-idea-plugin</artifactId> <configuration> <downloadJavadocs>true</downloadJavadocs> <downloadSources>true</downloadSources> <jdkLevel>1.5</jdkLevel> <jdkName>1.5</jdkName> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.5</version> <scope>test</scope> </dependency> </dependencies> </project>
Recreate the project files for Idea with mvn idea:idea
as above.
We should now be able to create our test unit tests. To start with, lets create one to test a Data Access Object, dao. This will be the only class we test in this project. The other classes will be entities with simple setter and getters that can be generated. I don't see any point in testing generated source code if you don't build the tool generating them. The tests we create will be running using a database. I claim that this is by definition not a unit test but rather an integration test. At this stage it doesn't really matter, we will be using a in memory database so he performance impact will not be significant.
Create the class com.agical.experimental.SubscriptionDaoTest My test class looks like the one below:
package com.agical.experimental.dao; import com.agical.experimental.entity.DefaultSubscription; import com.agical.experimental.entity.FixedLineSubscription; import com.agical.experimental.entity.Subscription; import static junit.framework.Assert.assertNull; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import org.junit.Test; import org.junit.Ignore; public class SubscriptionDaoTest { @Test @Ignore public void saveReadUpdateAndDeleteADefaultSubscription() { SubscriptionDao subscriptionDao = new SubscriptionDaoImpl(); Subscription subscription = new DefaultSubscription(); String subscriberName = "Marie"; subscription.setSubscriberName(subscriberName); subscriptionDao.saveSubscription(subscription); Subscription fetchedSubscription = subscriptionDao.getSubscription(subscription); assertThat(fetchedSubscription.getSubscriberName(), is(subscriberName)); String newSubscriberName = "Klara"; fetchedSubscription.setSubscriberName(newSubscriberName); subscriptionDao.updateSubscription(fetchedSubscription); fetchedSubscription = subscriptionDao.getSubscription(subscription); assertThat(fetchedSubscription.getSubscriberName(), is(newSubscriberName)); subscriptionDao.deleteSubscription(subscription); fetchedSubscription = subscriptionDao.getSubscription(subscription); assertNull(fetchedSubscription); } @Test @Ignore public void saveReadUpdateAndDeleteAFixedLineSubscription() { SubscriptionDao subscriptionDao = new SubscriptionDaoImpl(); Subscription subscription = new FixedLineSubscription(); String subscriberName = "Lena"; subscription.setSubscriberName(subscriberName); subscriptionDao.saveSubscription(subscription); Subscription fetchedSubscription = subscriptionDao.getSubscription(subscription); assertThat(fetchedSubscription.getSubscriberName(), is(subscriberName)); assertThat(fetchedSubscription.getSubscriberName(), is(subscriberName)); subscriptionDao.deleteSubscription(subscription); fetchedSubscription = subscriptionDao.getSubscription(subscription); assertNull(fetchedSubscription); } }
If you enjoy TDD, test driven development, then you already know that defining a test like the one above is a great way to define the classes that we should implement. Only the stuff defined in the test will be implemented and if the tests define what we need, we will not create any waste since we will use everything we create and nothing more.
I will use Ideas great support to create the interfaces and the classes defined in the test. You should be able to compile everything when you have created all interfaces and classes. The code will not run properly since we implemented the production code. This is the next steps.
You created all the interfaces and classes needed in the previous step. We need to annotate the entity classes so we can use Hibernate to handle the database communication.
To start, we need to add more stuff to our pom so we can get access to some Hibernate stuff, lets add the dependency javax.persistence below.
<dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> </dependency>
Your pom should look something like this by now:
<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>com.agical.experimental</groupId> <artifactId>spring-hibernate-maven</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>SpringHibernateMaven</name> <url>http://www.agical.com</url> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-idea-plugin</artifactId> <configuration> <downloadJavadocs>true</downloadJavadocs> <downloadSources>true</downloadSources> <jdkLevel>1.5</jdkLevel> <jdkName>1.5</jdkName> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.5</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> </dependency> </dependencies> </project>
Recreate the Idea project files.
We are now in the position that we can annotate the classes we want to persist. I plan to use a single table to persist the data for both the DefaultDescription and the FixedLineSubscription. The reason isn't more complicated then it is enough for this example. The difference between these entities will only be how they use there internal data, which we will not see anything of. The values persisted will be the same for both type of subscriptions.
Lets start to annotate the DefaultSubscription class.
package com.agical.experimental.entity; import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.Table; @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn( name = "subscriptionType", discriminatorType = DiscriminatorType.STRING ) @DiscriminatorValue("subdscription") @Table(name = "subscriptions") public class DefaultSubscription implements Subscription { private String subscriberName; private Long id; @Id @GeneratedValue(strategy = GenerationType.AUTO) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public void setSubscriberName(String subscriberName) { this.subscriberName = subscriberName; } public String getSubscriberName() { return subscriberName; } }
The class is annotated with these annotations:
The @Entity
annotation tells us that this is an entity class.
We will use a single table strategy to handle inheritance, @Inheritance(strategy =
InheritanceType.SINGLE_TABLE)
We will differ the rows in the table using a column called subscriptionType
that will be a called
name = "subscriptionType"
and be of the type String
For the DefaultSubscription we use the value @DiscriminatorValue("subdscription")
And finally, we will store the rows in a table called @Table(name = "subscriptions")
Then we want to define a primary key for the table. In this example I will create a surrogate key that will be an integer and doesn't have any connection to the data stored. It can be argued that this is a pretty bad solution, but in order to keep the example as small as possible I will accept this.
The annotation @Id
tells us that this will be the Id column for this table.
It will be created automatically @GeneratedValue(strategy = GenerationType.AUTO)
Next we want to annotate the FixedLineSubscription class. It will be significant less annotations.
package com.agical.experimental.entity; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; @Entity @DiscriminatorValue("fixedline") public class FixedLineSubscription extends DefaultSubscription { }
We have the @Entity
annotation to define that this is an entity.
We have to add the discriminator value @DiscriminatorValue("fixedline")
The rest is handled through the inheritance system in Java.
We should now be done with some of the preparations and ready to add some more stuff the the pom so we can create the database schema.
We need some hibernate tools. Add the hibernate3-maven-plugin
and configure it as below:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.1</version> <configuration> <components> <component> <name>hbm2ddl</name> <implementation>annotationconfiguration</implementation> </component> </components> <componentProperties> <drop>true</drop> <jdk5>true</jdk5> <outputfilename>schema.sql</outputfilename> <skip>${maven.test.skip}</skip> <hibernate.dialect>org.hibernate.dialect.HSQLDialect</hibernate.dialect> <!-- Connection properties May be used or not by the plugin, when it will recreate the annotated tables every time it is executed --> <hibernate.connection.driver_class>org.hsqldb.jdbcDriver</hibernate.connection.driver_class> <hibernate.connection.url>jdbc:hsqldb:mem:spring-hibernate-maven</hibernate.connection.url> <hibernate.connection.username>sa</hibernate.connection.username> <hibernate.connection.password></hibernate.connection.password> <!-- /Connection properties --> </componentProperties> </configuration> <executions> <execution> <phase>process-test-resources</phase> <goals> <goal>hbm2ddl</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency> </dependencies> </plugin>
We have a dependency to org.hibernate.dialect.HSQLDialect so we need to one more dependency. Add the dependency:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.4.0.GA</version> </dependency>
A working pom should look something like this:
<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>com.agical.experimental</groupId> <artifactId>spring-hibernate-maven</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>SpringHibernateMaven</name> <url>http://www.agical.com</url> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.1</version> <configuration> <components> <component> <name>hbm2ddl</name> <implementation>annotationconfiguration</implementation> </component> </components> <componentProperties> <drop>true</drop> <jdk5>true</jdk5> <outputfilename>schema.sql</outputfilename> <skip>${maven.test.skip}</skip> <hibernate.dialect>org.hibernate.dialect.HSQLDialect</hibernate.dialect> <!-- Connection properties May be used or not by the plugin, when it will recreate the annotated tables every time it is executed --> <hibernate.connection.driver_class>org.hsqldb.jdbcDriver</hibernate.connection.driver_class> <hibernate.connection.url>jdbc:hsqldb:mem:spring-hibernate-maven</hibernate.connection.url> <hibernate.connection.username>sa</hibernate.connection.username> <hibernate.connection.password></hibernate.connection.password> <!-- /Connection properties --> </componentProperties> </configuration> <executions> <execution> <phase>process-test-resources</phase> <goals> <goal>hbm2ddl</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency> </dependencies> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-idea-plugin</artifactId> <configuration> <downloadJavadocs>true</downloadJavadocs> <downloadSources>true</downloadSources> <jdkLevel>1.5</jdkLevel> <jdkName>1.5</jdkName> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.4.0.GA</version> </dependency> </dependencies> </project>
We want to configure a dependency to hsqldb
se we can generate a schema and update the database when we
run the process-test-resources
, which we do every time we run the test from Maven.
The hibernate plugin is dependant of a hibernate configuration file called hibernate.cfg.xml
. Create it
in /src/main/resources/hibernate.cfg.xml
.
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.show_sql">false</property> <property name="hibernate.format_sql">true</property> <property name="use_sql_comments">true</property> <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property> <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="hibernate.connection.url">jdbc:hsqldb:hsql://localhost</property> <property name="hibernate.connection.username">sa</property> <property name="hibernate.connection.password"></property> <!-- add classes to map from here --> <mapping class="com.agical.experimental.entity.DefaultSubscription"/> <mapping class="com.agical.experimental.entity.FixedLineSubscription"/> </session-factory> </hibernate-configuration>
Recreate the idea project files, mvn idea:idea
to get the resources missing and make sure that Idea
knows about the last dependency we added.
We want to connect the different parts we have. The goal here is to use Springs IoC, Inversion of Control, container
for the wiring. We will create two configuration files. The first one should be src/main/resources/applicationContext.xml
.
It should contain some bean definitions like below:
<?xml version="1.0" encoding="ISO-8859-1"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> <property name="dataSource" ref="dataSource"/> </bean> <bean id="recordDao" class="com.agical.experimental.dao.RecordDaoImpl"> <property name="sessionFactory" ref="sessionFactory"/> </bean> </beans>
We refer to a bean called sessionFactory. It need to be defined as well, define it in
src/main/resources/sessionFactory.xml
below:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="url" value="jdbc:hsqldb:hsql://localhost"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean> <!-- Hibernate session factory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> <prop key="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</prop> <prop key="hibernate.connection.url">jdbc:hsqldb:hsql://localhost</prop> <prop key="hibernate.connection.username">sa</prop> </props> </property> <property name="annotatedClasses"> <list> <value>com.agical.experimental.entity.DefaultSubscription</value> <value>com.agical.experimental.entity.FixedLineSubscription</value> </list> </property> </bean> </beans>
Finally we need to add some more dependencies to the pom. We have introduced some spring stuff above as well as a DataSource implementation. So lets add the dependencies below:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency>
A working pom should look like this by now:
<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>com.agical.experimental</groupId> <artifactId>spring-hibernate-maven</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>SpringHibernateMaven</name> <url>http://www.agical.com</url> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.1</version> <configuration> <components> <component> <name>hbm2ddl</name> <implementation>annotationconfiguration</implementation> </component> </components> <componentProperties> <drop>true</drop> <jdk5>true</jdk5> <outputfilename>schema.sql</outputfilename> <skip>${maven.test.skip}</skip> <hibernate.dialect>org.hibernate.dialect.HSQLDialect</hibernate.dialect> <!-- Connection properties May be used or not by the plugin, when it will recreate the annotated tables every time it is executed --> <hibernate.connection.driver_class>org.hsqldb.jdbcDriver</hibernate.connection.driver_class> <hibernate.connection.url>jdbc:hsqldb:mem:spring-hibernate-maven</hibernate.connection.url> <hibernate.connection.username>sa</hibernate.connection.username> <hibernate.connection.password></hibernate.connection.password> <!-- /Connection properties --> </componentProperties> </configuration> <executions> <execution> <phase>process-test-resources</phase> <goals> <goal>hbm2ddl</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency> </dependencies> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-idea-plugin</artifactId> <configuration> <downloadJavadocs>true</downloadJavadocs> <downloadSources>true</downloadSources> <jdkLevel>1.5</jdkLevel> <jdkName>1.5</jdkName> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.4.0.GA</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> </dependencies> </project>
You have downloaded HSQL when you updated the pom earlier. A simple way to start it is to locate the downloaded hsqldb-1.8.0.7.jar and issue the command below.
java -cp hsqldb-1.8.0.7.jar org.hsqldb.Server
You may want to shut it down without loosing your data. Do so from the DatabaseManager. To launch the DatabaseManager issue the command:
java -cp hsqldb-1.8.0.7.jar org.hsqldb.util.DatabaseManager
But remember that you don't want to shut down the database for the rest of this tutorial. If you do, the parts that want to connect to the database will fail.
The final step should be to run Maven and have it to perform the unit/integration tests so we can verify that the table has been created and that we can add stuff to it. Run the Maven command below:
mvn clean install
A successful build could produce this output:
[INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Building SpringHibernateMaven [INFO] task-segment: [clean, install] [INFO] ------------------------------------------------------------------------ [INFO] [clean:clean] [INFO] Deleting directory C:projectsAgicalMavenHibernateAnnotationssandboxstep4target [INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:compile] [INFO] Compiling 5 source files to C:projectsAgicalMavenHibernateAnnotationssandboxstep4targetclasses [INFO] [resources:testResources] [INFO] Using default encoding to copy filtered resources. [INFO] Preparing hibernate3:hbm2ddl [WARNING] Removing: hbm2ddl from forked lifecycle, to prevent recursive invocation. [INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [INFO] [hibernate3:hbm2ddl {execution: default}] [INFO] Configuration XML file loaded: file:/C:/projects/Agical/MavenHibernateAnnotations/sandbox/step4/src/main/resources/hibernate.cfg.xml 20:44:38,718 INFO org.hibernate.cfg.annotations.Version - Hibernate Annotations 3.3.0.GA 20:44:38,734 INFO org.hibernate.cfg.Environment - Hibernate 3.2.5 20:44:38,734 INFO org.hibernate.cfg.Environment - hibernate.properties not found 20:44:38,734 INFO org.hibernate.cfg.Environment - Bytecode provider name : cglib 20:44:38,734 INFO org.hibernate.cfg.Environment - using JDK 1.4 java.sql.Timestamp handling [INFO] Configuration XML file loaded: file:/C:/projects/Agical/MavenHibernateAnnotations/sandbox/step4/src/main/resources/hibernate.cfg.xml 20:44:38,796 INFO org.hibernate.cfg.Configuration - configuring from url: file:/C:/projects/Agical/MavenHibernateAnnotations/sandbox/step4/src/main/r esources/hibernate.cfg.xml 20:44:38,890 INFO org.hibernate.cfg.Configuration - Configured SessionFactory: null [INFO] src/main/resources/database.properties not found within the project. Trying absolute path. [INFO] No hibernate properties file loaded. 20:44:38,968 INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.agical.experimental.entity.DefaultSubscription 20:44:39,000 INFO org.hibernate.cfg.annotations.EntityBinder - Bind entity com.agical.experimental.entity.DefaultSubscription on table subscriptions 20:44:39,031 INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.agical.experimental.entity.FixedLineSubscription 20:44:39,062 INFO org.hibernate.validator.Version - Hibernate Validator 3.0.0.GA 20:44:39,078 INFO org.hibernate.dialect.Dialect - Using dialect: org.hibernate.dialect.HSQLDialect 20:44:39,171 INFO org.hibernate.tool.hbm2ddl.SchemaExport - Running hbm2ddl schema export 20:44:39,171 INFO org.hibernate.tool.hbm2ddl.SchemaExport - writing generated schema to file: C:projectsAgicalMavenHibernateAnnotationssandboxst ep4targethibernate3sqlschema.sql 20:44:39,171 INFO org.hibernate.tool.hbm2ddl.SchemaExport - exporting generated schema to database 20:44:39,171 INFO org.hibernate.connection.DriverManagerConnectionProvider - Using Hibernate built-in connection pool (not for production use!) 20:44:39,171 INFO org.hibernate.connection.DriverManagerConnectionProvider - Hibernate connection pool size: 20 20:44:39,171 INFO org.hibernate.connection.DriverManagerConnectionProvider - autocommit mode: false 20:44:39,171 INFO org.hibernate.connection.DriverManagerConnectionProvider - using driver: org.hsqldb.jdbcDriver at URL: jdbc:hsqldb:hsql://localhost 20:44:39,171 INFO org.hibernate.connection.DriverManagerConnectionProvider - connection properties: {user=sa, password=****} drop table subscriptions if exists; create table subscriptions (subscriptionType varchar(31) not null, id bigint generated by default as identity (start with 1), subscriberName varchar(2 55), primary key (id)); 20:44:39,234 INFO org.hibernate.tool.hbm2ddl.SchemaExport - schema export complete 20:44:39,234 INFO org.hibernate.connection.DriverManagerConnectionProvider - cleaning up connection pool: jdbc:hsqldb:hsql://localhost [INFO] [compiler:testCompile] [INFO] Compiling 1 source file to C:projectsAgicalMavenHibernateAnnotationssandboxstep4targettest-classes 20:44:39,968 INFO org.hibernate.connection.DriverManagerConnectionProvider - cleaning up connection pool: jdbc:hsqldb:hsql://localhost [INFO] [surefire:test] [INFO] Surefire report directory: C:projectsAgicalMavenHibernateAnnotationssandboxstep4targetsurefire-reports ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.agical.experimental.dao.SubscriptionDaoTest Tests run: 2, Failures: 0, Errors: 0, Skipped: 2, Time elapsed: 0.141 sec Results : Tests run: 2, Failures: 0, Errors: 0, Skipped: 2 [INFO] [jar:jar] [INFO] Building jar: C:projectsAgicalMavenHibernateAnnotationssandboxstep4targetspring-hibernate-maven-1.0-SNAPSHOT.jar [INFO] [install:install] [INFO] Installing C:projectsAgicalMavenHibernateAnnotationssandboxstep4targetspring-hibernate-maven-1.0-SNAPSHOT.jar to C:Documents and Settin gsThomas.m2repositorycomagicalexperimentalspring-hibernate-maven1.0-SNAPSHOTspring-hibernate-maven-1.0-SNAPSHOT.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 9 seconds [INFO] Finished at: Mon Dec 22 20:44:42 CET 2008 [INFO] Final Memory: 14M/26M [INFO] ------------------------------------------------------------------------
BUILD SUCCESSFUL
indicates that we are happy and that the configuration we have created works.