What is Spring or Hibernate in Java

Jump with JPA and Hibernate (tutorial)

This article is part of a (tutorial) series about the introduction to the Spring Framework and describes the use of JPA (Database access) and Hibernate (OR mapper) with the Spring Framework.

The structure of the project

This example builds on the previous Spring example using a simple example in version 2.0.x. The frameworks and tools used are described here. This example is a console application that implements driver management. This example introduces the following Spring Framework technologies:

  • The definition and usage of abstract and generic data access objects (DAO).
  • The specialization of data access objects for JPA.
  • The definition of entities with relations, Named queries and sequences.
  • Taking into account Special features of entities.
  • Creating an XML configuration for JPA.
  • Declaring a Data access object in the Spring Framework.
  • Providing a service in the Spring Framework with transactions.
  • Generate the database-specific configuration for the Spring Framework.
  • Create a JUnit test for database operations with the Spring Framework.

The following libraries are required:

The required libraries - dependencies (© Frank Rahn)

The reading recommendations for this example

The abstract and generic data access object

A DAO (D.ata A.ccess Object) serves to abstract from the concrete persistence technology and decouples the Business logic from Database access. The following interface of a data access object (DAO) is still independent of a specific access technology.

This interface defines the most elementary methods (CRUD) for data access. The class of the entity and the primary key (Primary key) Are defined.

/ ** * A generic DAO interface for an entity with a primary key. * @author Frank W. Rahn * @param The class of the entity * @param The class of the primary key * / public interface GenericDAO {/ ** * Deliver the primary key for the specified object. * @param persistentObject the persistent object * @return the primary key * / PrimaryKey getPrimaryKey (Entity persistentObject); / ** * Save the new object in the database. * @param newPersistentObject the new persistent object * @return the primary key * / PrimaryKey create (Entity newPersistentObject); / ** * Update the changed object in the database. * @param persistentObject the persistent object * / void save (Entity persistentObject); / ** * Delete the persistent object from the database. * @param persistentObject the persistent object * / void remove (Entity persistentObject); / ** * Delete the persistent object from the database. * @param key the primary key * / void remove (PrimaryKey key); / ** * Find the persistent object based on its primary key. * @param key the primary key * @return the persistent object * / Entity findByPrimaryKey (PrimaryKey key); }

An abstract implementation of this interface now follows. In this implementation ...

  • in line 21 the logger is defined and
  • in lines 30 to 41 in Object initializer the determination of the concrete classes of entity and des primary key carried out.
/ ** * An abstract implementation of the {@link GenericDAO} interface. * @author Frank W. Rahn * @param The class of the entity * @param The class of the primary key * / public abstract class AbstractGenericDAO implements GenericDAO {/ ** The central logger for the DAO's. * / protected final static Logger logger = getLogger (GenericDAO.class); / ** The class of the entity. * / protected final Class entityClass; / ** The class of the primary key. * / protected final Class primaryKeyClass; {ParameterizedType type = (ParameterizedType) getClass (). GetGenericSuperclass (); Type [] actualTypeArguments = type.getActualTypeArguments (); @SuppressWarnings ("unchecked") Class entityClass = (Class ) actualTypeArguments [0]; this.entityClass = entityClass; @SuppressWarnings ("unchecked") Class primaryKey = (Class ) actualTypeArguments [1]; this.primaryKeyClass = primaryKey; } / ** * {@inheritDoc} * @see GenericDAO # remove (java.io.Serializable) * / @Override public void remove (PrimaryKey key) {remove (findByPrimaryKey (key)); }}

The specialization of the Data Access Object for JPA

The basic interface of a data access object this time depends on the Java Persistence API access technology (JPA).

/ ** * An extension of the interface {@link GenericDAO} for JPA. * @author Frank W. Rahn * @param The class of the entity * @param The class of the primary key * @see de.rahn.db.dao.GenericDAO * / public interface GenericJpaDAO extends GenericDAO {// No special definitions yet. }

In the following abstract implementation of this interface, the JPA annotation used. This is then injected by the Spring Framework.

/ ** * An implementation of the interface {@link GenericJpaDAO} for JPA. * @author Frank W. Rahn * @param The class of the entity * @param The class of the primary key * @see de.rahn.db.dao.AbstractGenericDAO * / public abstract class AbstractGenericJpaDAO extends AbstractGenericDAO implements GenericJpaDAO {@PersistenceContext private EntityManager entityManager; / ** * @return Returns the {@link #entityManager} * / protected final EntityManager getEntityManager () {return entityManager; } / ** * {@inheritDoc} * @see GenericDAO # create (java.lang.Object) * / @Override public PrimaryKey create (Entity newPersistentObject) {entityManager.persist (newPersistentObject); return getPrimaryKey (newPersistentObject); } / ** * {@inheritDoc} * @see GenericDAO # save (java.lang.Object) * / @Override public void save (Entity persistentObject) {entityManager.merge (persistentObject); } / ** * {@inheritDoc} * @see GenericDAO # remove (java.lang.Object) * / @Override public void remove (Entity persistentObject) {entityManager.remove (persistentObject); } / ** * {@inheritDoc} * @see GenericDAO # findByPrimaryKey (java.io.Serializable) * / @Override public Entity findByPrimaryKey (PrimaryKey key) {return entityManager.find (entityClass, key); }}

In the following class diagram, the facts of the abstract generic JPA data access objects are shown graphically via UML.

Abstract generic data access objects for JPA (© Frank Rahn)

The definition of the service of driver management

First, the interface of this service is defined. This example is also kept relatively simple.

/ ** * The interface to the service driver. * @author Frank W. Rahn * / public interface Drivers {/ ** * Get all drivers. * @return the list of drivers * / List getDrivers (); / ** * Get a driver. * @param id the id of a driver * @return the driver * / Driver getDriver (Long id); / ** * Create a driver. * @param name the name of the driver * @param firstname the first name of the driver * @return the ID of the driver * / Long createDriver (String name, String firstname); / ** * Create a driver. * @param driver the driver * @return the id of the driver * / Long create (Driver driver); / ** * Save the driver. * @param driver the driver * / Driver save (Driver driver); / ** * Add a car to the driver. * @param id the id of the driver * @param car the car * @return the complete driver * / Driver addCarToDriver (Long id, Car car); }

The XML configuration for this module.

<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <description> Dieses ist die zentrale Konfiguration für den Service Drivers. </description> <!-- Scanne das Package nach Spring Beans --> <context:component-scan base-package="de.rahn.services.drivers" /> </beans>

The entities of the Driver Management service

Our driver management consists of drivers with their cars. Here a number of JPA annotations are used to define the data model.

  1. In lines 27 to 29, this class is defined as an entity with access at the attribute level. The database schema is also specified. The table name is generated from the class name.
  2. Line 30 is a static and named Query with JPQL Are defined. With this query all drivers can be selected. This rules out what is known as SQL injection, as these queries are used exclusively.
  3. Lines 37 through 41 define the primary key for this class. This identifier is used via a DB sequence automatically assigned.
  4. In line 54, a directed relation (1-to-n) is passed on with the CRUD operations (Cascade) defined to the car.
  5. In line 55 the column is defined in the table of the car. This is necessary because the car class does not know the driver - i.e. it has no driver attribute. If the attribute had been defined in the Auto class, the following statement was sufficient for the relation:
    .
/ ** * The class of a driver. * @author Frank W. Rahn * / @Entity @Table (schema = "rahn") @Access (AccessType.FIELD) @NamedQueries (@NamedQuery (name = Driver.FIND_ALL, query = "from Driver d")) public class Driver {/ ** Constant for the NamedQuery. * / public static final String FIND_ALL = "Driver.findAll"; / ** The identifier of the driver. * / @Id @GeneratedValue (strategy = GenerationType.SEQUENCE, generator = "DriverSEQ") @SequenceGenerator (name = "DriverSEQ", sequenceName = "DriverSEQ", schema = "rahn") @Basic (optional = false) private long id ; / ** The name of the driver. * / @Basic (optional = false) @Column (nullable = false) private String name; / ** The driver's first name. * / @Basic private string firstname; / ** The cars the driver drives. * / @OneToMany (cascade = CascadeType.ALL) @JoinColumn (name = "driver_id", nullable = false) private Set cars = new HashSet <> (); ...

The following section shows the methods generated by the Eclipse IDE for and. These methods must be overloaded because an entity has a unique identity that must be determined using the two methods.

Two entities that are actually the same are assessed as unequal if ...

  • the entities have been read by different ones or
  • the one entity via Eager loading (directly when executing the Select) and the other entity via Lazy loading (through a proxy when accessing the field).

The automatically generated key () is only set when the entities are saved. The two methods and must depend on the same significant attributes.

  • Lines 67 and 99 also check whether the cars have already been charged. If not, the entities of the car would load or throw an error if it was already closed.
/ ** * @see java.lang.Object # hashCode () * / @Override public int hashCode () {final int prime = 31; int result = 1; if (cars! = null && Persistence.getPersistenceUtil (). isLoaded (cars)) {result = prime * result + cars.hashCode (); } else {result = prime * result; } result = prime * result + (firstname == null? 0: firstname.hashCode ()); result = prime * result + (id == null? 0: id.hashCode ()); result = prime * result + (name == null? 0: name.hashCode ()); return result; } / ** * @see java.lang.Object # equals (java.lang.Object) * / @Override public boolean equals (Object obj) {if (this == obj) {return true; } if (obj == null) {return false; } if (! (obj instanceof Driver)) {return false; } Driver other = (Driver) obj; if (cars == null) {if (other.cars! = null) {return false; }} else {if (Persistence.getPersistenceUtil (). isLoaded (cars) && Persistence.getPersistenceUtil (). isLoaded (other.cars)) {if (! cars.equals (other.cars)) {return false; }}} if (firstname == null) {if (other.firstname! = null) {return false; }} else if (! firstname.equals (other.firstname)) {return false; } if (id == null) {if (other.id! = null) {return false; }} else if (! id.equals (other.id)) {return false; } if (name == null) {if (other.name! = null) {return false; }} else if (! name.equals (other.name)) {return false; } return true; } / ** * @see java.lang.Object # toString () * / @Override public String toString () {return new StringBuilder (). append ("Driver [id ="). append (id) .append (" , name = "). append (name) .append (", firstname = ") .append (firstname) .append ("] "). toString (); } ...

Next up is the class for the cars. The car does not know its driver, so there is no attribute for the driver in the class.

  • The primary key in line 22 is specified externally (identifier).
/ ** * The class of a car. * @author Frank W. Rahn * / @Entity @Table (schema = "rahn") @Access (AccessType.FIELD) public class Car {/ ** The identity of a registered car. * / @Id @Basic (optional = false) private string id; / ** The type of car. * / @Basic (optional = false) private String type; ...

The XML configuration for persistence, which is not very extensive, is still missing.

  • Line 11 indicates that the application should use the database transactions:

    In contrast to where the transaction manager of the Java EE container would be used:
<?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="test-spring-drivers" transaction-type="RESOURCE_LOCAL" /> </persistence>

The data access object for driver management

The definition of the specific data access object for the service of the driver administration.

  • In line 16 the annotation is used. This annotation makes this class a Spring Bean with persistence layer exception handling. These exceptions are translated into a subclass of.
  • From line 32 onwards, a method is implemented that loads all instances of this class via a defined query.
/ ** * A DAO for the driver. * @author Frank W. Rahn * @param The class of the entity * @param The class of the primary key * / @Repository public class DriverDAO extends AbstractGenericJpaDAO {/ ** * {@inheritDoc } * @see GenericDAO # getPrimaryKey (java.lang.Object) * / @Override public Long getPrimaryKey (Driver persistentObject) {return persistentObject.getId (); } / ** * Find all drivers. * @return all drivers * / public List findAll () {return getEntityManager (). createNamedQuery (Driver.FIND_ALL, Driver.class) .getResultList (); }}

Implementation of the driver management service

The standard implementation of driver management.

  • The annotation on line 19 defines this implementation as a Spring Bean with the name.
  • The data access object is used in line 24.
  • Line 20 defines that all methods are executed in one transaction.
  • In lines 31 and 41, the annotation indicates that these methods support an existing transaction, but do not require a transaction of their own.
/ ** * The standard implementation of the service {@link Drivers}. * @author Frank W. Rahn * / @Service ("drivers") @Transactional public class StandardDrivers implements Drivers {@Autowired private DriverDAO driverDAO; / ** * {@inheritDoc} * @see Drivers # getDrivers () * / @Override @Transactional (propagation = Propagation.SUPPORTS) public List getDrivers () {return driverDAO.findAll (); } / ** * {@inheritDoc} * @see Drivers # getDriver (Long) * / @Override @Transactional (propagation = Propagation.SUPPORTS) public Driver getDriver (Long id) {return driverDAO.findByPrimaryKey (id); } / ** * {@inheritDoc} * @see Drivers # createDriver (String, String) * / @Override public Long createDriver (String name, String firstname) {Driver driver = new Driver (); driver.setName (name); driver.setFirstname (firstname); return create (driver); } / ** * {@inheritDoc} * @see Drivers # create (Driver) * / @Override public Long create (Driver driver) {return driverDAO.create (driver); } / ** * {@inheritDoc} * @see Drivers # save (Driver) * / @Override public Driver save (Driver driver) {driverDAO.save (driver); return driver; } / ** * {@inheritDoc} * @see Drivers # addCarToDriver (Long, Car) * / @Override public Driver addCarToDriver (Long id, Car car) {Driver driver = driverDAO.findByPrimaryKey (id); driver.getCars (). add (car); return save (driver); }}

In the following picture the complete service is shown in a UML class diagram.

Jump with JPA and Hibernate (© Frank Rahn)

The application with logging

As in the Spring example, it is structured using a simple example. Only the application changes, the XML configuration and that remain the same. The changes to the are shown here.

/ ** * The application for calling up the driver management. * @author Frank W.Rahn * / @Component public class Application implements Runnable {private static final Logger logger = getLogger (Application.class); @Autowired (required = true) private Drivers drivers; / ** * {@inheritDoc} * @see Runnable # run () * / @Override public void run () {// Create a driver Long id = drivers.createDriver ("Rahn", "Frank"); logger.info ("A driver with the id '{}' created", id); // Get the driver back Driver driver = drivers.getDriver (id); logger.info ("Fetched the driver with the id '{}': {}", id, driver); // add a car Car car = new Car (); car.setId ("K-XX 4711"); car.setType ("Audi A6"); driver = drivers.addCarToDriver (id, car); logger.info ("Changed the driver with id '{}': {}", id, driver); // Select all drivers List listDrivers = drivers.getDrivers (); for (Driver driver2: listDrivers) {logger.info ("Driver: Id '{}' Name: {} {}", new Object [] {driver2.getId (), driver2.getFirstname (), driver2.getName () }); }}}

The XML configuration for accessing the application must be expanded to include the database and transaction definitions.

  • In line 27, the configuration with the Database and transaction definitions referenced in the same directory.
<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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd "> <description> Dieses ist die zentrale Konfiguration für die Anwendungen. </description> <!-- Enabling des AspectJ Support --> <aop:aspectj-autoproxy proxy-target-class="true" /> <!-- Das Verwenden von allgemeinen Annotationen ermöglichen --> <context:annotation-config /> <!-- Die projektspezifischen Konfigurationen laden --> <import resource="db.xml" /> <import resource="classpath:/de/rahn/services/drivers/drivers.xml" /> <import resource="classpath:/de/rahn/app/application.xml" /> </beans>

The database and transaction definitions are made in the following XML configuration. For the first time, the p namespace for setting Properties used.

The syntax is:
or

  • The definitions for database access () in lines 27 to 34 and the handling of transactions in lines 37 to 42.
  • In lines 22 to 24 a database is started and initialized by the specified script.
<!-- Starte die HSQL-Datenbank im Memory --> <jdbc:embedded-database id="dataSource" type="HSQL"> <jdbc:script location="classpath:/META-INF/spring/init.sql" /> </jdbc:embedded-database> <!-- Erzeuge die Persitence-Unit --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="dataSource" p:persistenceUnitName="test-spring-drivers"> <property name="jpaVendorAdapter"> <1bean p:generateDdl="true" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> </property> </bean> <!-- Einen Transaktionmanager erzeugen --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory" /> <!-- Das Verwenden von Annotationen für die Transaktionen ermöglichen --> <tx:annotation-driven proxy-target-class="true" /> </beans>

The script is shown in the following box. The SQL dialect is HSQL (HyperSQL Database). HSQLDB is a relational database written entirely in Java.

create SCHEMA rahn; create sequence DriverSEQ; create table rahn.Driver (id bigint not null, firstname varchar (255), name varchar (255) not null, primary key (id)); create table rahn.Car (id varchar (255) not null, type varchar (255) not null, driver_id bigint not null, primary key (id)); alter table rahn.Car add constraint FK107B45ADEE2FE foreign key (driver_id) references rahn.Driver; insert into rahn.Driver (firstname, name, id) values ​​('Martin', 'Rahn', next value for DriverSEQ);

The unit test

First, let's create a test for the class.

  • Line 25 refers to the XML configurations required by Spring. This is a special XML configuration for the test, it contains the configurations for the database access and the configuration for the driver management.
/ ** * The test class for {@link DriverDAO}. * @author Frank W. Rahn * / @RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (locations = {"/META-INF/spring/context-test.xml", "../drivers.xml"}) @Transactional public class DriverDAOTest {@Autowired private DriverDAO driverDAO; / ** * Test method for {@link DriverDAO # getPrimaryKey (Driver)}. * / @Test public void testGetPrimaryKey () {Driver driver = new Driver (); driver.setId (new Long (4711)); Long id = driverDAO.getPrimaryKey (driver); assertThat ("Primary key different", driver.getId (), is (id)); } / ** * Test method for {@link DriverDAO # findAll ()}. * / @Test public void testFindAll () {List drivers = driverDAO.findAll (); assertThat ("no result returned", drivers, notNullValue ()); assertThat ("Number of hits not equal", drivers.size (), is (1)); Driver driver = drivers.get (0); assertThat ("id not equal", driver.getId (), is (0L)); assertThat ("firstname not equal", driver.getFirstname (), is ("Martin")); assertThat ("name does not match", driver.getName (), is ("Rahn")); } / ** * Test method for * {@link de.rahn.db.jpa.dao.AbstractGenericJpaDAO # create (Object)}. * / @Test public void testCreate () {Driver driver = new Driver (); driver.setName ("Rahn"); driver.setFirstname ("Frank"); Long id = driverDAO.create (driver); assertThat ("no id supplied", id, notNullValue ()); assertThat ("unequal id", driver.getId (), is (id)); Driver driver2 = driverDAO.findByPrimaryKey (id); assertThat ("not saved after all", driver2, notNullValue ()); assertThat ("unequal driver", driver2, sameInstance (driver)); } / ** * Test method for * {@link de.rahn.db.jpa.dao.AbstractGenericJpaDAO # save (Object)}. * / @Test public void testSave () {Driver driver = driverDAO.findByPrimaryKey (0L); assertThat ("no driver found", driver, notNullValue ()); driver.setFirstname ("Peter"); driverDAO.save (driver); Driver driver2 = driverDAO.findByPrimaryKey (0L); assertThat ("no driver found", driver2, notNullValue ()); assertThat ("unequal driver", driver2, sameInstance (driver)); } / ** * Test method for * {@link de.rahn.db.jpa.dao.AbstractGenericJpaDAO # remove (Object)}. * / @Test public void testRemoveEntity () {List drivers = driverDAO.findAll (); assertThat ("Number of hits not equal", drivers.size (), is (1)); Driver driver = drivers.get (0); driverDAO.remove (driver); drivers = driverDAO.findAll (); assertThat ("Number of hits not equal", drivers.size (), is (0)); } / ** * Test method for * {@link de.rahn.db.jpa.dao.AbstractGenericJpaDAO # findByPrimaryKey (Serializable)} *. * / @Test public void testFindByPrimaryKey () {Driver driver = driverDAO.findByPrimaryKey (0L); assertThat ("no result returned", driver, notNullValue ()); assertThat ("id not equal", driver.getId (), is (0L)); assertThat ("firstname not equal", driver.getFirstname (), is ("Martin")); assertThat ("name not equal", driver.getName (), is ("Rahn")); } / ** * Test method for * {@link de.rahn.db.dao.AbstractGenericDAO # remove (Serializable)}. * / @Test public void testRemovePrimaryKey () {driverDAO.remove (0L); List drivers = driverDAO.findAll (); assertThat ("no result returned", drivers, notNullValue ()); assertThat ("Number of hits not equal", drivers.size (), is (0)); }}

A special XML configuration was created for the general Spring Beans. It only loads the configurations for database access.

<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <description> Dieses ist die zentrale Konfiguration für die Tests. </description> <!-- Das Verwenden von allgemeinen Annotationen ermöglichen --> <context:annotation-config /> <!-- Die projektspezifischen Konfigurationen laden --> <import resource="db.xml" /> </beans>

Now the only thing missing is the unit test for the driver administration service.

/ ** * The test class for {@link StandardDrivers}. * @author Frank W. Rahn * / @RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (locations = {"/META-INF/spring/context-test.xml", "../drivers.xml"}) @Transactional public class StandardDriversTest {/ ** CAR_TYPE * / private static final string CAR_TYPE = "Audi A6"; / ** CAR_ID * / private static final string CAR_ID = "K-XX 4711"; @Autowired private Drivers drivers; / ** * Test method for {@link StandardDrivers # getDriver (Long)}. * / @Test public void testGetDriver () {Driver driver = drivers.getDriver (0L); assertThat ("no driver supplied", driver, notNullValue ()); assertThat ("id not equal", driver.getId (), is (0L)); assertThat ("firstname not equal", driver.getFirstname (), is ("Martin")); assertThat ("name does not match", driver.getName (), is ("Rahn")); } / ** * Test method for {@link StandardDrivers # createDriver (String, String)}. * / @Test public void testCreateDriver () {Long id = drivers.createDriver ("Rahn", "Frank"); assertThat ("no id supplied", id, notNullValue ()); Driver driver = drivers.getDriver (id); assertThat ("not saved after all", driver, notNullValue ()); assertThat ("unequal id", driver.getId (), is (id)); assertThat ("firstname not equal", driver.getFirstname (), is ("Frank")); assertThat ("name does not match", driver.getName (), is ("Rahn")); } / ** * Test method for {@link StandardDrivers # addCarToDriver (Long, Car)}. * / @Test public void testAddCarToDriver () {Car car = new Car (); car.setId (CAR_ID); car.setType (CAR_TYPE); Driver driver = drivers.addCarToDriver (0L, car); assertThat ("not saved after all", driver, notNullValue ()); assertThat ("id not equal", driver.getId (), is (0L)); assertThat ("firstname not equal", driver.getFirstname (), is ("Martin")); assertThat ("name not equal", driver.getName (), is ("Rahn")); assertThat ("number of cars not equal", driver.getCars (). isEmpty (), not (true)); car = driver.getCars (). iterator (). next (); assertThat ("id not equal", car.getId (), is (CAR_ID)); assertThat ("type not equal to", car.getType (), is (CAR_TYPE)); }}

Here is the corresponding success message.

The success message from JUnit (© Frank Rahn)

The source code and download of the example

View source code on GitHub:
Jump with JPA and Hibernate

Download a ZIP file from GitHub:
Jump with JPA and Hibernate

The Maven Command

Recreate Eclipse configuration:

Build application:

Run application:

Update: Criteria API

A Maven plugin for generating the metamodel of the Criteria API recorded. This metamodel is generated in the directory. With the Criteria API database queries can be programmed object-oriented in the source code.

The following is the Maven configuration for generating the Criteria API with the JPA 2 Metamodel Generator from Hibernate.

org.bsc.maven maven-processor-plugin 22.2.1 process true true true org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor org.hibernate hibernate-jpamodelgen $ {hibernate-jpamodelgen-version} ...

In addition, a template was created based on the model of Spring. This means that the abstract and generic JPA data access object can take over the generation of the factory classes.

/ ** * A typical Spring template that delegates the creation of some necessary factory * classes for creating queries based on the Criteria API to the * {@link AbstractGenericJpaDAO}. * @author Frank W. Rahn * @param The class of the entity * @see AbstractGenericJpaDAO * / public interface CriteriaQueryTemplate {/ ** * This method is carried out by the {@link AbstractGenericJpaDAO} and * provides some standard components the Criteria API. * @param builder the {@link CriteriaBuilder} * @param query the query linked to the entity * @param rootEntity the projection variable of the FROM clause * / void doBuild (CriteriaBuilder builder, CriteriaQuery query, Root rootEntity) ; }

The abstract and generic JPA data access object is extended by the method.

/ ** * Generate a JPA query via the Criteria API. * @param template the builder * @return an executable JPA query * / protected TypedQuery buildQuery (CriteriaQueryTemplate template) {// Create a builder CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder (); // Create the query CriteriaQuery criteriaQuery = criteriaBuilder.createQuery (entityClass); // Create the reference to the main entity Root rootEntity = criteriaQuery.from (entityClass); // Execute the build template.doBuild (criteriaBuilder, criteriaQuery, rootEntity); // Create an executable JPA query return entityManager.createQuery (criteriaQuery); } ...

The data access object of the driver provides the method.

/ ** * Find all drivers by name. * @param name the name of the driver * @return the drivers found * / public List findByName (final String name) {return buildQuery (new CriteriaQueryTemplate () {@Override public void doBuild (CriteriaBuilder builder, CriteriaQuery < Driver> query, Root rootEntity) {// Create a logical expression Predicate predicate = builder.equal (rootEntity.get (Driver_.name), name); // Define the query query.select (rootEntity) .where ( predicate) .distinct (true);}}). getResultList (); } ...

Finally, of course, the test should not be missing.

/ ** * Criteria API test. * / @Test public void testCriteriaAPI () {List drivers = driverDAO.findByName ("Rahn"); assertThat ("no result returned", drivers, notNullValue ()); assertThat ("Number of hits not equal", drivers.size (), is (1)); Driver driver = drivers.get (0); assertThat ("id not equal", driver.getId (), is (0L)); assertThat ("firstname not equal", driver.getFirstname (), is ("Martin")); assertThat ("name does not match", driver.getName (), is ("Rahn")); } ...

Update on 09/28/2012

The following changes have been made to all projects.

  1. The projects have been moved from my local Apache Subversion repository to my public GitHub repositories.
  2. The following typical adjustments to Git were made on all projects.
    • deleted
    • added
    • added
    • added
    • A branch was created in each repository for each post in the series.

    Updates from 10/6/2012 to 10/14/2012

    The following changes have been made to all projects.

    1. Update of the OpenJDK to version 1.7.0.
    2. Update of the Eclipse development environment to version 4.2.1.
      The required plugins from the Eclipse Marketplace:
    3. Update of the file:
      • Adjustments to the OpenJDK version
      • Added GitHub entries (SCM and URL)
      • Update of the libraries to more recent versions (e.g. Spring version 3.1.2.RELEASE, Hibernate version 4.1.7.Final, JUnit version 4.10, mockito version 1.9.0, ...)
        For the more detailed versions, please refer to the respective on GitHub.
    Frank Rahn is a software architect. He supports the conception of software architectures with Java technology. Follow him on Facebook or Twitter.

    Do you need assistance? Contact him.

    Did you like this article? We look forward to your comment! Please use your real name.
    / 0 comments / by Frank RahnKeywords:Architecture, CRUD, DAO, DI, IoC, Java, Java SE, JPA, Open Source Software, POJO, Service Oriented, Spring, SQL, XML