Тайна наследования аннотаций Java EE 6 - PullRequest
10 голосов
/ 04 апреля 2011

Я использую наследование с EJB в нескольких сценариях, иногда с аннотациями в суперклассе, как этот универсальный объект DAO:

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);
    }

}

С примером подкласса, реализованным так:

@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;
        }
    }
}

Я недавно прочитал, что Java-аннотации НЕ наследуются (источник) .Это должно заставить мой JpaDAO выдавать исключение нулевого указателя при доступе к его диспетчеру сущностей или его построителю критериев (так как и @PersistanceContext, и @PostConstruct будут игнорироваться), однако это не так.Может кто-нибудь уточнить, как это действительно работает?Я немного обеспокоен тем, что происходит с моими @TransactionAttributes в суперклассе. Могу ли я доверять НЕОБХОДИМОМУ фактическому использованию транзакций при вызове из подкласса, когда подкласс имеет NOT_SUPPORTED в качестве класса по умолчанию?

1 Ответ

21 голосов
/ 04 апреля 2011

Java-аннотации не наследуются, но спецификации JavaEE изменяют правила, чтобы позволить этим атрибутам работать должным образом.Смотрите общие аннотации 1.1 спец.В разделе 2.1 даже используется @TransactionAttribute в качестве примера.В разделе 13.3.7.1 EJB 3.1 также явно указаны правила для @TransactionAttribute:

Если у класса компонента есть суперклассы, применяются следующие дополнительные правила.

  • атрибут транзакции, указанный всуперкласс S применяется к бизнес-методам, определенным S. Если атрибут S на уровне класса не указан на S, это эквивалентно спецификации TransactionAttribute (REQUIRED) на S.
  • Может быть указан атрибут транзакциив бизнес-методе M, определенном классом S, для переопределения для метода M значения атрибута транзакции, явно или неявно указанного в классе S.
  • Если метод M класса S переопределяет бизнес-метод, определенный суперклассом Sатрибут транзакции M определяется вышеупомянутыми правилами применительно к классу S.

Короче говоря, для большинства аннотаций JavaEE к этому методу применяются аннотации уровня метода, если только подкласс не переопределяетметод и аннотации на уровне класса применяются to все методы, определенные только в этом классе.Правило не применяется к аннотациям на уровне класса, определяющим компоненты, таким как @Stateless (см. Раздел 4.9.2.1 спецификации EJB 3.1)

...