Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The mystery of Java EE 6 annotations inheritance

I'm using inheritance with EJB in a few scenarios, sometimes with annotations in the super class like this generic entityDAO:

public class JpaDAO<T>{
    protected Class<T> entityClass;

    @PersistenceContext(unitName="CarrierPortalPU")
    protected EntityManager em;
    protected CriteriaBuilder cb;

    @PostConstruct
    private void init() {
        cb = em.getCriteriaBuilder();
    }

    public JpaDAO(Class<T> type) {
        entityClass = type;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void create(T entity) {
        em.persist(entity);
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public T find(Object id) {
        return em.find(entityClass, id);
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public List<T> findAll(){
        CriteriaQuery<T> cq = cb.createQuery(entityClass);
        Root<T> entity = cq.from(entityClass);
        cq.select(entity);
        return em.createQuery(cq).getResultList();
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void remove(T entity) {
        em.remove(em.merge(entity));
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public T edit(T entity) {
        return em.merge(entity);
    }

}

With an example subclass implemented like this:

@Stateless
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class DepartmentDAO extends JpaDAO<Department> {

    public DepartmentDAO() {
        super(Department.class);
    }

    public Department findByName(String name){
        CriteriaQuery<Department> cq = cb.createQuery(Department.class);
        Root<Department> department = cq.from(Department.class);
        cq.where(cb.equal(department.get(Department_.name), name));
        cq.select(department);
        try{
            return em.createQuery(cq).getSingleResult();
        }catch(Exception e){
            return null;
        }
    }
}

I recently read that java annotations are NOT inherited (source). This should cause my JpaDAO to throw a null pointer exception when accessing its entitymanager or its criteriabuilder (since both @PersistanceContext and @PostConstruct would be ignored), however this it not the case. Can someone clarify how this really works? I am abit worried about what happens to my @TransactionAttributes in the superclass, can I trust a REQUIRED to actually use transactions when called from the subclass, when the subclass has NOT_SUPPORTED as class default?

like image 938
Rasmus Franke Avatar asked Apr 04 '11 09:04

Rasmus Franke


1 Answers

Java annotations are not inherited, but the JavaEE specs change the rules to allow these attributes to work as expected. See the common annotations 1.1 spec. Section 2.1 even uses @TransactionAttribute as an example. EJB 3.1 section 13.3.7.1 also explicitly states the rules for @TransactionAttribute:

If the bean class has superclasses, the following additional rules apply.

  • transaction attribute specified on a superclass S applies to the business methods defined by S. If a class-level transaction attribute is not specified on S, it is equivalent to specification of TransactionAttribute(REQUIRED) on S.
  • A transaction attribute may be specified on a business method M defined by class S to override for method M the transaction attribute value explicitly or implicitly specified on the class S.
  • If a method M of class S overrides a business method defined by a superclass of S, the transaction attribute of M is determined by the above rules as applied to class S.

In short, for most JavaEE annotations, method-level annotations apply to that method unless a subclass overrides the method, and class-level annotations apply to all methods defined in that class only. The rule does not apply to "component-defining" class-level annotations, such as @Stateless (see the EJB 3.1 specification section 4.9.2.1)

like image 85
Brett Kail Avatar answered Oct 28 '22 19:10

Brett Kail