Cambridge Technology PartnersCommunity Documentation
With the CDI Query Module, it is possible to make a DAO out of basically any abstract class or interface (using a concrete class will work too, but you won't be able to use most of the CDI Query features). All that is required is to mark the type as such with a simple annotation:
@Dao(Person.class)
public abstract class PersonDao {
...
}
@Dao(Person.class)
public interface PersonDao {
...
}
The @Dao
annotation tells CDI Query that this is a DAO for the Person entity. Any method defined on the DAO
will be processed by the framework. The annotation does not require to set the entity class (we'll see later why)
but if there are just plain classes or interfaces this is the only way to tell the framework what entity
the DAO relates to. In order to simplify this, CDI Query provides several base types.
Although mainly intended to hold complex query logic, working with both a DAO and an entity manager in the service layer might unnecessarily clutter code. In order to avoid this for the most common cases, CDI Query provides base types which can be used to replace the entity manager.
The top base type is the EntityDao
interface, providing common methods used with an entity manager.
The following code shows the most important methods of the interface:
public interface EntityDao<E, PK extends Serializable> {
E save(E entity);
E saveAndFlush(E entity);
void remove(E entity);
E findBy(PK primaryKey);
List<E> findAll();
Long count();
}
The concrete DAO can then extend this basic interface. For our person DAO, this might look like the following:
@Dao
public interface PersonDao extends EntityDao<Person, Long> {
Person findBySsn(String ssn);
}
Annotations on interfaces do not inherit. If the EntityDao
interface is extended by
another interface adding some more common methods, it is not possible to simply add the annotation there.
It needs to go on each concrete DAO. The same is not true if a base class is introduced, as we see in the
next chapter.
This class is an implementation of the EntityDao
interface and provides additional
functionality when custom query logic needs also to be implemented in the DAO (note that your DAOs do not
support injection). The class also provides additional support with regards to the JPA 2 criteria API.
public abstract class PersonDao extends AbstractEntityDao<Person, Long> {
public Person findBySSN(String ssn) {
return getEntityManager()
.createQuery("select p from Person p where p.ssn = ?1", Person.class)
.setParameter(1, ssn)
.getResultList();
}
public List<Person> findByCriteria(String name, Integer ageFrom, Integer ageTo) {
return criteria()
.eq(Person_.name, name)
.between(Person_.age, ageFrom, ageTo)
.createQuery()
.getResultList();
}
}
More details on using the JPA criteria support API are outlined in Chapter 5, JPA Criteria API Support.
While most applications will run just fine with a single EntityManager
, there might be setups
where multiple data sources are used. Similar to the default case, CDI Query requires to have producers for
each EntityManager
to be used, and to distinguish them over a CDI qualifier.
@Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
public @interface CustomerData {
}
public class CustomerDataSourceProducer {
...
@Produces @CustomerData
public EntityManager create(){
return emf.createEntityManager();
}
}
The @CustomerData
is a CDI qualifier - all available EntityManager
have to
be exposed similar with a different qualifier. The link to the Query DAO happens then over a custom annotation
on the DAO:
@Dao
@WithEntityManager(CustomerData.class)
public interface CustomerDao extends EntityDao<Customer, Long> {
...
}
Qualifiers in CDI can also use attributes. This is not supported with the @WithEntityManager annotation, it can only be qualified over a plain annotation.
If a more granular qualifier support is required, the AbstractEntityDao
class can be extended.
The class provides a getEntityManager
method, which can be overridden and annotated with
the appropriate qualifiers:
@Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
public @interface CustomerData {
CustomerType value();
}
public abstract class CustomerDao extends AbstractEntityDao<Customer, Long> {
@Override @CustomerData(CRM)
protected abstract EntityManager getEntityManager();
...
}