Java Persistence API (JPA)

Enumeration collection assignment

The following example shows the required annotations to assign a collection of roles (defined as enum class) to a user entity.

@Entity
@Table(name = "t_user")
public class User {

  @Id
  private String id;

  @ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
  @CollectionTable(name = "t_userrole", joinColumns = @JoinColumn(name = "userid"))
  @Column(name = "role", nullable = false)
  @Enumerated(EnumType.STRING)
  private Set<Role> roles = new TreeSet<Role>();

  ...
}

Common JPA annotations

Use the annotation @Temporal to store java.util.Date fields into database.

@Entity
public class Journal extends Literature {

  @Temporal(TemporalType.DATE)
  private java.util.Date publicationDate;

  @Enumerated(EnumType.STRING)
  private PublicationType pubType;

}

JPQL Constructor Expressions

If you want to create DTOs on-the-fly without iterating your query result list you can use JPQL constructor expressions.

SELECT NEW com.patternbox.tangocalendar.location.application.data.LocationData(
  l.identifier, l.name, l.address.country, l.address.state, l.address.town, 
  l.address.postalCode, l.address.street) FROM Location l

Separating Query Logic

In order to separate database query logic from my domain model I annotated my JPA repositories with @NamedQueries. Unfortunately it does not work because JPA only parses classes that are mentioned in the persistence.xml configuration. Annotating the repository with @MappedSuperclass overcomes this problem.

Java-Class

@MappedSuperclass
@NamedQueries({
  @NamedQuery(name = "findAll", query = "...") })
public class JpaLiteratureRepository { 
  ... 
}

persistence.xml

<persistence-unit name="LocationPU">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <jta-data-source>java:jboss/datasources/TangocalendarDS</jta-data-source>
  <class>[...].JpaLiteratureRepository </class>
</persistence-unit>

OptimisticLockException

Concurrent write access to JPA Entity with optimistic locking might cause a OptimisticLockException wrapped in an EJBException. The following code checks whether at least one of the exception causes is instance of OptimisticLockException. Otherwise the orignal EJBException will be re-thrown.

private void checkOptimisticLockException(EJBException ex) {
  Throwable cause = ex;
  while(cause.getCause() != null) {
  cause = cause.getCause();
  if (cause instanceof OptimisticLockException) {
    return;
  }
  }

  throw ex;
}