JPA 2: Multiple Fetch Joins for One-To-Many Relations

While working on Lireparp, I tried to write a function to fetch multiple one-to-many relations using JPA's criteria API. It turns out, that when using Java's List to represent one-to-many relations one gets a nasty exception which is caused by a lack of implementation in Hibernate (see):

Aug 08, 2014 4:48:23 PM org.apache.openejb.core.transaction.EjbTransactionUtil handleSystemException
Schwerwiegend: EjbTransactionUtil.handleSystemException: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
javax.persistence.PersistenceException: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
  at org.hibernate.ejb.AbstractEntityManagerImpl.convert
(AbstractEntityManagerImpl.java:1377)
 
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
 
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:516)
 
at org.hibernate.ejb.criteria.CriteriaQueryCompiler.compile(CriteriaQueryCompiler.java:221)
 
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:633)
 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 
at java.lang.reflect.Method.invoke(Unknown Source)
 
at org.apache.openejb.persistence.JtaEntityManager.createQuery(JtaEntityManager.java:331)
 
at org.apache.openejb.persistence.JtaEntityManager.typedProxyIfNoTx(JtaEntityManager.java:326)
 
at org.apache.openejb.persistence.JtaEntityManager.createQuery(JtaEntityManager.java:385)
 
at de.starwit.lirejarp.ejb.impl.AbstractServiceImpl.findByIdWithRelations(AbstractServiceImpl.java:119)
 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 
at java.lang.reflect.Method.invoke(Unknown Source)


The code that leads to this exception can be found here. So a workaround is necessary and this article describes two ways I came up so far to address this problem. Unfortunately both ideas have some drawbacks and therefore any help is appreciated ;)

Possibility 1

If one uses Set instead of List to model relations in entities then you won't get aforementioned exception. Although this is working you however have to be careful, as lists have properties that sets have not. For example you will obviously loose any sorting done DB. Also changing the result type for entity attributes will have great impact for code that uses those entities. So if you do that implementation of the relation method can be used unchanged and therefore look like that:

  public E findByIdWithRelations(Long id, String... relations) {
   
Class<E> clazz = getParentClass();
    CriteriaBuilder cb = getEntityManager
().getCriteriaBuilder();
    CriteriaQuery<E> criteria = cb.createQuery
(clazz);
    Root<E> r = criteria.from
(clazz);
   
for (String attributeName : relations) {
     
r.fetch(attributeName, JoinType.LEFT);
   
}
   
criteria.where(cb.equal(r.get("id"), id));
    criteria.select
(r);
    TypedQuery<E> query = getEntityManager
().createQuery(criteria);
   
return query.getSingleResult();
 
}


Possibility 2

The second idea is to force loading of related lists. This can be done by calling the getter method for every attribute representing a relation in database. So if you call the getter methods, according select statements will be executed to populate lists. You will end up with one select-statement for each attribute. Major drawback of that workaround is that for item in your result list ALL selected attributes will be read from database. This is obviously pretty bad in terms of memory, network I/O and CPU usage.

  public E findByIdWithRelations(Long id, String... relations) {
   
Class<E> clazz = getParentClass();
    CriteriaBuilder cb = getEntityManager
().getCriteriaBuilder();
    CriteriaQuery<E> criteria = cb.createQuery
(clazz);
    Root<E> root = criteria.from
(clazz);

    criteria.where
(cb.equal(root.get("id"), id));
    criteria.select
(root);
    TypedQuery<E> query = getEntityManager
().createQuery(criteria);
    E result = query.getSingleResult
();
   
   
for (String attributeName : relations) {
     
try {
       
Collection<?> value = (Collection<?>) PropertyUtils.getProperty(result, attributeName);
        value.size
();
     
} catch (IllegalAccessException | InvocationTargetException
          | NoSuchMethodException e
) {
       
LOG.error("Method for class " + clazz + " of property" + attributeName + " could not be resolved.", e);
     
}
    }
   
return result;
 
}


Conclusion:

Try to avoid fetching multiple one-to-many relations if you can. You can create an new Object and fill in the result of a JPA-Query to get only the attributes you need of each Entity.

Complete sourcecode can be found here

There is a really useful article about the problem: JPA 2 | Fetch Joins and whether we should use them

Lightweight REST JEE Arch Pattern

Motivation

Creating modern software always requires a number of things to do. One of these things is to persist data and to access persisted data. Within the Java Enterprise ecosystem this basic task evolved up to a point where using objects in Java as representations of data in a database, has become an easy to use commodity. With RESTful web services (added to JEE in version 5) attached to these entities, even network access to persisted data has become very easy. 
Yet still a lot of boiler plate code needs to be written and creating JEE application quickly remains a challenge. Therefore approach described in this article shall provide a guide in how to setup an architecture implementing persistence and a RESTful interface layer. To do that properly a (reusable) pattern of inheritance + generic data types is proposed. This (yet unnamed) pattern is applied in persistence, Enterprise Java Beans and in RESTful web service implementation and therefore proved to be quite flexible.
A fully working example application of this pattern can be found on Sourceforge. Besides using described pattern it also contains an Javascript based client application that serves a UI to the Java based back end. This rigorous separation of UI is also intended as it helps to demonstrate architecture approach without mixing with UI issues.

Sourcecode

Lightweight REST JEE Arch Pattern

Purpose

You have a group of objects which are different in its structure but should implement the same basic behavior.

Scenario

You have a lots of data objects in your application for whom the standard CRUD-functionality should be provided.

Description

E.g. you are using JPA for data access and you have create several entities. It should be possible to do simple CRUD-operations with all the objects. Using an AbstractDao is a common way to handle the implementation of the basic stuff. An AbstractEntity is created as base class for all entities. In the AbstractDao general CRUD functions are implemented using the AbstractEntity. E.g. http://sidaof.sourceforge.net/sidaof/ is a project, which implements an AbstractDao-class binding the concrete entity to the AbstractDao.

The architecture presented here goes further and uses this pattern through all layers of the entire architecture: business services (EJBs), restful webservices, junit-tests. Data objects extends the class "AbstractEntity". Each kind of service (EJB, restful webservice, jUnit-testclass) implements the general functionality around the data objects in an abstract class. For each data object and each kind of service contreted service-implementations are added. To prevent class-casts, Generics ensure the usage of concrete data object in the abstract part of the implementation.

The following class-diagram provides an overview of the architecture. The description afterwards is given a better understanding of the diagramm.

Advantage

You are really fast on creating or extending the backend of small JEE-application. You avoid to write boiler-plate code because you do not have to implement general functionality in each part of the architecture. You just have to implement additional stuff like special queries. For instance you have an News Entity and you want to diplay all news of the day. Because it is implement only once, all methods doing the same have the same names. Class-casts form abstract to concrete classes are prevented by using Generics.

Disadvantage

Everywhere abstract classes are used, the risk of deep class hirarchies occures. This can be avoided by using composition or transfer logic in sperate classes.

Example Implementation

Data Objects

complete code

Abstract Data Objects

In the example news and categories should be created, deleted and diplayed. The news have to be assigned to a category. At first the base data class "AbstractEntity" is written.

package de.starwit.lirejarp.entity;
import java.io.Serializable;
...

@MappedSuperclass 
public abstract class AbstractEntity implements Serializable {
 
 
private static final long serialVersionUID = 1L;
 
private Long id;

 
@Id
  @GeneratedValue
(strategy=GenerationType.IDENTITY)
 
@Column(name="id")
 
public Long getId() {
   
return id;
 
}

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

}

Concrete Data Objects

The entities "CategryEntity" and "NewsEntity" are created and inherit the base-class "AbstractEntity".

package de.starwit.lirejarp.entity;
import java.util.List;
...

@Entity
@Table
(name = "CATEGORY")
public class CategoryEntity extends AbstractEntity {
 
 
private static final long serialVersionUID = -1458424080034108665L;

 
@NotNull
  @Size
(max = 20)
 
private String name;
   
 
private List<NewsEntity> news;

 
@Column(name="NAME", nullable = false, length=100)
 
public String getName() {
   
return name;
 
}

 
public void setName(String name) {
   
this.name = name;
 
}
 
 
@XmlTransient
  @OneToMany
(mappedBy="category")
 
public List<NewsEntity> getNews() {
   
return news;
 
}

 
public void setNews(List<NewsEntity> news) {
   
this.news = news;
 
}
}

package de.starwit.lirejarp.entity;
import java.util.Date;
...

@XmlRootElement
@Entity
@Table
(name="NEWS")
public class NewsEntity extends AbstractEntity {
 
 
private static final long serialVersionUID = -3717230832637971328L;
 
 
@NotBlank
  @Size
(max = 100)
 
private String title;

 
@NotNull
 
private Date publishedAt;
 
 
@NotBlank
  @Size
(max = 100)
 
private String publishedBy;
 
 
@NotBlank
  @Size
(max = 1000)
 
private String content;
 
 
@NotNull
 
private CategoryEntity category;
 
 
@Column(name="TITLE", nullable = false, length=100)
 
public String getTitle() {
   
return title;
 
}

 
public void setTitle(String title) {
   
this.title = title;
 
}
 
 
@Column(name="PUBLISHED_BY", nullable = false, length=100)
 
public String getPublishedBy() {
   
return publishedBy;
 
}

 
public void setPublishedBy(String publishedBy) {
   
this.publishedBy = publishedBy;
 
}

 
@Column(name="CONTENT", nullable = false, length=1000)
 
public String getContent() {
   
return content;
 
}

 
public void setContent(String content) {
   
this.content = content;
 
}

 
@Column(name = "PUBLISHED_AT", nullable = false)
 
@Temporal(TemporalType.TIMESTAMP)
 
public Date getPublishedAt() {
   
return publishedAt;
 
}

 
public void setPublishedAt(Date publishedAt) {
   
this.publishedAt = publishedAt;
 
}
 
 
@ManyToOne
  @JoinColumn
(name = "CATEGORY_ID", nullable = false)
 
public CategoryEntity getCategory() {
   
return category;
 
}

 
public void setCategory(CategoryEntity category) {
   
this.category = category;
 
}
 
 
}

Data Access Services

complete code

Abstract Data Access Services

All starts again with an AbstractService providing CRUD-functionality for all data access services. To ensure correct transaction handling Enterprise Java Beans are taken. For that reason an interface "AbstractService" and the implementation "AbstractServiceImpl" exist.
Abstract Interface
package de.starwit.lirejarp.ejb;
import java.util.List;
...

public interface AbstractService<E extends AbstractEntity> {
 
 
E create(E entity);
 
 
void delete(Long id) throws EntityNotFoundException;
 
  E update
(E entity);
 
  E findById
(Long id);
 
  List<E> findAll
();
 
 
E findByIdWithRelations(Long id, String... attributeName);
 
 
  EntityManager getEntityManager
();

 
void setEntityManager(EntityManager em);

}
Abtract Implementation
package de.starwit.lirejarp.ejb.impl;
import java.lang.reflect.ParameterizedType;
...

public class AbstractServiceImpl<E extends AbstractEntity> implements AbstractService<E> {
 
 
private static Logger LOG = Logger.getLogger(AbstractServiceImpl.class);

 
@PersistenceContext(unitName = "MeineJpaPU")
 
private EntityManager em;

 
private E parentClass;

 
@SuppressWarnings("unchecked")
 
public Class<E> getParentClass() {
   
... 
 
}

 
public EntityManager getEntityManager() {
   
return em;
 
}

 
public E create(E entity) {
   
em.persist(entity);
    em.flush
();
   
return entity;
 
}

 
public void delete(Long id) throws EntityNotFoundException {
   
E entity = em.find(getParentClass(), id);
   
if (entity == null) {
     
throw new EntityNotFoundException(id, getParentClass().getName());
   
}
   
em.remove(entity);
 
}

 
public E update(E entity) {
   
em.merge(entity);
    em.flush
();
   
return entity;
 
}
 
 
public List<E> findAll() {
   
...
 
}
 
 
public List<E> findAll(int firstResult, int maxResult) {
   
...
 
}
 
 
public Long countAll() {
   
...
 
}

 
public E findById(Long id) {
   
return em.find(getParentClass(), id);
 
}

 
public E findByIdWithRelations(Long id, String... relations) {
   
...
 
}
 
 
public E findByIdOrThrowException(Long id)
     
throws IllegalIdException, EntityNotFoundException {
   
...
 
}

 
public void setEntityManager(EntityManager em) {
   
this.em = em;
 
}

}

Concrete Data Access Services

The concrete service interfaces and implementations are using the the concrete entities in the interface-definition and service-implementation-definition. If you do need additional stuff, you can add some functions. Otherwise, it is enough just to create the classes and interfaces without any method. Only the services for the NewsEntity are presented below.
NewsService Interface
package de.starwit.lirejarp.ejb;
import java.io.Serializable;
...

@Local
public interface NewsService extends Serializable, AbstractService<NewsEntity> {

 
List<NewsEntity> findToday();
 
  List<NewsEntity> findByCategory
(Long id);
}
NewsService Implementation
package de.starwit.lirejarp.ejb.impl;
import java.util.Calendar;
...

@Stateless(name="NewsService")
public class NewsServiceImpl extends AbstractServiceImpl<NewsEntity> implements NewsService {
 
 
private static final long serialVersionUID = -1034640519269748512L;

 
@Override
 
public List<NewsEntity> findToday() {
   
Calendar calBefore = Calendar.getInstance();
    calBefore.setTime
(new Date());
    calBefore.set
(Calendar.HOUR_OF_DAY, 0);
    calBefore.set
(Calendar.MINUTE, 0);
    calBefore.set
(Calendar.SECOND, 0);
    calBefore.set
(Calendar.MILLISECOND, 0);

    Calendar calAfter = Calendar.getInstance
();
    calAfter.setTime
(calBefore.getTime());
    calAfter.add
(Calendar.DATE, 1);

    String sql =
"select distinct news from NewsEntity news where news.publishedAt > :dateBefore and news.publishedAt < :dateAfter order by news.publishedAt desc";

    TypedQuery<NewsEntity> query = getEntityManager
().createQuery(
       
sql, NewsEntity.class);
    query.setParameter
("dateBefore", calBefore.getTime());
    query.setParameter
("dateAfter", calAfter.getTime());
   
return query.getResultList();
 
}
 
 
public List<NewsEntity> findByCategory(Long id) {
   
String sql = "select news from NewsEntity news where news.category.id = :id";
    TypedQuery<NewsEntity> query = getEntityManager
().createQuery(
       
sql, NewsEntity.class);
    query.setParameter
("id", id);
   
return query.getResultList();
 
}
 
}

Restful Webservices for User Interface

complete code

In our example, the User Interface is based upon AngularJS and html. Restful webservices are providing the connection between User Interface and the data access layer. The implementation follows the same pattern we used before. With JAXB, some problems occured by using generic types. Hence we switched to Jackson as JSON-Parser. But also Jackson has some limitation handling generic types, additional concrete functions had to be added.

Abstract Restful Webservice

package de.starwit.lirejarp.api.rest;
import java.util.List;
...

public abstract class AbstractRest<E extends AbstractEntity> {
 
 
private static final Logger LOG = Logger.getLogger("fileAppender");

 
/**
   * Deserialisation of JSON is not working. Implement abstract method instead:
   ****************************************************************************  
    @PUT
    @Override
    public ResultStateWrapper create(E entity) {
      return super.createGeneric(entity);
    }
   ****************************************************************************
   *
@param entity
   *
@return
  
*/
 
public abstract ResultWrapper<E> create(E entity);
 
 
/**
   * Deserialisation of JSON is not working. Implement abstract method instead:
   ****************************************************************************  
    @POST
    @Override
    public ResultStateWrapper update(E entity) {
      return super.updateGeneric(entity);
    }
   ****************************************************************************
   *
@param entity
   *
@return
  
*/
 
public abstract ResultStateWrapper update(E entity);
 

 
/**
   * Typify persistence service
   */
 
protected abstract AbstractService<E> getService();
 
 
public ResultWrapper<E> createGeneric(E entity) {
   
LOG.debug("************ FrontendService create for " + getService().getClass().getSimpleName());
    E interalEntity = getService
().create(entity);
    ResultWrapper<E> result =
new ResultWrapper<E>();
    result.setResult
(interalEntity);
    result.setResultState
(ResultValidator.savedResultExists(interalEntity));
   
return result;
 
}
 
 
//Update
 
@POST
 
public ResultStateWrapper updateGeneric(E entity) {
   
E interalEntity = getService().update(entity);
   
return ResultValidator.savedResultExists(interalEntity);
 
}

 
/**
   * returns a flat entity with NO associated entities
   *
   *
@param id
   *
@return
  
*/
 
@Path("/{entityId}")
 
@GET
 
public ResultWrapper<E> getById(@PathParam("entityId") Long id) {
   
E entity = getService().findById(id);
    ResultWrapper<E> rw =
new ResultWrapper<E>(entity);
   
return rw;
 
}
 
 
//Delete
 
@Path("/{entityId}")
 
@DELETE
 
public ResultStateWrapper delete(@PathParam("entityId") Long id) {
   
ResultStateWrapper resultState = new ResultStateWrapper();
   
try {
     
getService().delete(id);
      resultState.setState
(ResultState.OK);
      resultState.setMessage
("Der Eintrag wurde gelöscht.");
   
} catch (EntityNotFoundException e) {
     
resultState.setState(ResultState.NOT_DELETE);
      resultState.setMessage
("Der Eintrag konnte nicht gelöscht werden. " + e.getMessage());
   
}
   
return resultState;
 
}
 
 
 
protected ListResultWrapper<E> genericGetAll() {
   
List<E> entities = getService().findAll();
    ListResultWrapper<E> resultWrapper =
new ListResultWrapper<E>(entities);
    ResultStateWrapper resultStateWrapper = ResultValidator.isNotEmpty
(resultWrapper.getResult());
    resultWrapper.setResultState
(resultStateWrapper);
   
return resultWrapper;
 
}
}

Concrete Restfuls Webservices

package de.starwit.lirejarp.api.rest;
import java.util.Date;
...

@Path("/news")
@Consumes("application/json")
@Produces("application/json")
public class NewsRest extends AbstractRest<NewsEntity> {
 
 
@Inject
 
protected NewsService service;
 
 
@Override
 
protected NewsService getService() {
   
return service;
 
}
 
 
//Create
 
@PUT
  @Override
 
public ResultWrapper<NewsEntity> create(NewsEntity entity) {
   
System.out.println("Category Id: " + entity.getCategory().getId());
    System.out.println
("Category name: " + entity.getCategory().getName());
    entity.setPublishedAt
(new Date());
   
return super.createGeneric(entity);
 
}

 
//Update
 
@POST
  @Override
 
public ResultStateWrapper update(NewsEntity entity) {
   
System.out.println("Category Id: " + entity.getCategory().getId());
    System.out.println
("Category name: " + entity.getCategory().getName());
    entity.setPublishedAt
(new Date());
   
return super.updateGeneric(entity);
 
}
 
 
@Path("/all")
 
@GET
 
public ListResultWrapper<NewsEntity> getAll() {
   
return super.genericGetAll();
 
}
 
 
@Path("/ext/today")
 
@GET
 
public ListResultWrapper<NewsEntity> getToday() {
   
List<NewsEntity> entities = service.findToday();
    ListResultWrapper<NewsEntity> resultWrapper =
new ListResultWrapper<NewsEntity>(entities);
    ResultStateWrapper resultStateWrapper = ResultValidator.isNotEmpty
(resultWrapper.getResult());
    resultWrapper.setResultState
(resultStateWrapper);
   
return resultWrapper; 
 
}
 
 
@Path("/ext/category/{catedoryId}")
 
@GET
 
public ListResultWrapper<NewsEntity> getByCategory(@PathParam("catedoryId") Long id) {
   
List<NewsEntity> entities = service.findByCategory(id);
    ListResultWrapper<NewsEntity> resultWrapper =
new ListResultWrapper<NewsEntity>(entities);
    ResultStateWrapper resultStateWrapper = ResultValidator.isNotEmpty
(resultWrapper.getResult());
    resultWrapper.setResultState
(resultStateWrapper);
   
return resultWrapper; 
 
}
 
}

Test of JEE Applications with Arquillian - Configuration with TomEE

Links and sources

TomEE and Arquillian
persistence extension

How To

POM files and project setup

To understand the following notes for configuring arquillian, some explanations of the project structure should be made. The application code is parted in two subprojects. The web-subproject contains all html and frontend stuff whereas the persistence-subproject contains ejb-services for the database-access and some business-logic. All projects are maven projects and has a pom-file to manage the build-process and dependencies.

mainproject
   > web-subproject
   > persistence-subproject

For running the application, a war-archive is created and deployed on TomEE application server.

Configuration of the pom.xml in the main-project

In the pom.xml of the mainproject, the aquillian dependencies have to be added. This can be done by taking each reference seperately or by using the bom:
<dependency>
    <groupid>org.jboss.arquillian</groupid>
    <artifactid>arquillian-bom</artifactid>
    <version>1.1.2.Final</version>
    <scope>import</scope>
    <type>pom</type>
</dependency>
It is also essential to have a container which implements CDI / EJB. For this example, the TomEE embedded container is used, because the TomEE server was chosen to run the JEE appication.
<dependency>
     <groupid>org.apache.openejb</groupid>
     <artifactid>arquillian-tomee-embedded</artifactid>
     <version>1.0.0</version>
</dependency>
And, of course, JUnit (or TestNG) is nessecary for writing tests.
 <dependency>
    <groupid>junit</groupid>
    <artifactid>junit</artifactid>
    <version>4.11</version>
    <scope>test</scope>
</dependency>
OPTIONAL: The surfire plugin is used with the following system properties to execute the test.
<plugin>
    <groupid>org.apache.maven.plugins</groupid>
    <artifactid>maven-surefire-plugin</artifactid>
    <version>2.16</version>
</plugin>
I took another extension to have only one deployment for several JUnit tests. A deployment is a creation of a test-jar which can be executed in the maven-build-process.
<dependency>
    <groupId>org.eu.ingwar.tools</groupId>
    <artifactId>arquillian-suite-extension</artifactId>
    <version>1.0.6</version>
</plugin>

Configuration of the pom.xml in a sub-project

If you are using sub-projects, add the following dependencies for junit and aquillian in the pom of the sub-project.
<dependency>
    <groupId>org.apache.openejb</groupId>
    <artifactId>openejb-core</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupid>junit</groupid>
    <artifactid>junit</artifactid>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.jboss.arquillian.junit</groupId>
    <artifactId>arquillian-junit-container</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
     <groupid>org.eu.ingwar.tools</groupid>
     <artifactid>arquillian-suite-extension</artifactid>
    <scope>test</scope>
</dependency>  
<dependency>
     <groupid>org.apache.openejb</groupid>
     <artifactid>arquillian-tomee-embedded</artifactid>
    <scope>test</scope>
</dependency>  

!IMPORTANT! 
  • the arquillian-tomee-embedded has to be the last entry of the dependencies.

Add a persistence-configuration for tests

under src/test/resources/META-INF, you can define a JPA-configuration (persistence.xml) especially for tests. For avoiding to start an external database before running the tests, h2 can be used as embedded database. Be careful with property "hibernate.hbm2ddl.auto". If the value is configured as "create", all tables will be droped and created again before test execution.

<?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=
"MeineJpaPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <
class>de.starwit.lirejarp.entity.CategoryEntity</class>
    <
class>de.starwit.lirejarp.entity.NewsEntity</class>

    <properties>
        <property name=
"hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name=
"hibernate.connection.url" value="jdbc:h2:~/test"/>
            <property name=
"hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
            <property name=
"hibernate.connection.username" value="sa"/>
            <property name=
"hibernate.connection.password" value=""/>
             <property name=
"hibernate.temp.use_jdbc_metadata_defaults" value="false" />
             <property name=
"hibernate.hbm2ddl.auto" value="create" />
             <property name=
"hibernate.show_sql" value="true" />
      <property name=
"hibernate.format_sql" value="false" />
    </properties>

  </persistence-unit>
</persistence>


Create an arquillian test-deployment

At first, you should configure the Deployment. If you are using the arquillian-suite-extension, you can create a class for it, e.g. Deployment.java.

package de.starwit.lirejarp.ejb;

import org.eu.ingwar.tools.arquillian.extension.suite.annotations.ArquillianSuiteDeployment;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;

/**
* For description https://github.com/ingwarsw/arquillian-suite-extension
*
*
@author Anett
*
*/
@ArquillianSuiteDeployment
public class Deployments {

 
@Deployment
 
public static Archive<?> createTestArchive() {
   
return ShrinkWrap.create(JavaArchive.class, "test.jar").addPackages(true, "de/starwit/lirejarp")
                 
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")
                 
.addAsResource("META-INF/persistence.xml", "META-INF/persistence.xml");
 
}

}

In this case, I create an jar-file named "test.jar" which contains all tests of package "de.starwit.lirejarp" in the maven-test-folder. For working with cdi, you need to add a beans.xml to your meta-inf directory. .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") automatically creates one. At least, the persistence-configuration from the test/resources folder should be added.

Test of JEE Applications with Arquillian - Implementation of a Test with a generic Service

Create a generic abstract class for features available in all test-classes

An abstract class provides standard-functionality for transaction handling. The generic-abstract-class pattern forces the developer to define the EJB-service under test.

package de.starwit.lirejarp.ejb;

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

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;

@SuppressWarnings("rawtypes")
public abstract class AbstractServiceTest<E extends AbstractService> {
 
 
protected static EntityManager em;
 
protected static EntityManagerFactory emf;
 
protected E service;

   
@BeforeClass
   
public static void setupBeforeClass() {
       
emf = Persistence.createEntityManagerFactory("MeineJpaPU");
        em = emf.createEntityManager
();
   
}

 
@AfterClass
   
public static void TearDownAfterClass() {
       
emf.close();
   
}
 
   
@Before
   
public void setup() {
     
if (getService().getEntityManager() == null) {
       
getService().setEntityManager(em);
     
}
     
beginTransaction();
   
}
   
   
@After
   
public void tearDown() {  
     
closeTransaction();
   
}

   
public void beginTransaction() {
       
em.getTransaction().begin();
   
}
   
   
public void closeTransaction() {
       
if (em.getTransaction().isActive()) {
           
em.getTransaction().rollback();
       
}

       
if (em.isOpen()) {
           
em.close();
       
}
    }

 
@Inject
   
public abstract void setService(E service);

   
public E getService() {
   
return service;
 
}
  
}

Implement a test

For instance you want to test the "create"-methode of a CategoryService-EJB.

package de.starwit.lirejarp.ejb;

import org.jboss.arquillian.junit.Arquillian;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

import de.starwit.lirejarp.entity.CategoryEntity;

@RunWith(Arquillian.class)
public class CategoryServiceTest extends AbstractServiceTest<CategoryService> {


 
@Override
 
public void setService(CategoryService service) {
   
this.service = service;
 
}
 
 
@Test
 
public void addCategory() {
   
CategoryEntity category = new CategoryEntity();
    category.setName
("Politics");
    category = getService
().create(category);
    Assert.assertNotNull
(category.getId());
 
}
 
}