Как отключить методы обратного вызова JPA 2 и прослушиватели сущностей - PullRequest
5 голосов
/ 23 марта 2011

У меня есть несколько классов (сущностей) с методами, аннотированными @PostLoad, @PrePersist и т. Д., И у классов есть аннотация @EntityListeners. Я хочу отключить обработку методов обратного вызова и слушателей в моей тестовой среде.

Удаление части кода невозможно, потому что тесты выполняются на сервере CI, и у меня нет никакой возможности изменить код только для тестов.

Есть ли возможность отключить методы обратного вызова и прослушиватели сущностей в конфигурации JPA 2? Я использую Hibernate.

Ответы [ 2 ]

6 голосов
/ 08 октября 2014

Если вы хотите удалить всех слушателей JPA из Hibernate 4.3.5 (единственного, который я тестировал), это можно сделать.Я не буду показывать, как получить EntityMangerFactory (emf в приведенном ниже коде), но после этого необходимо добавить / запустить приведенный ниже код.


Объяснение: похоже, существует очень центральный класс с именем org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl, который содержит все зарегистрированные прослушиватели и обратные вызовы для объектов.При замене реестра на пустой обратные вызовы выполняться не будут.

SessionFactoryImpl sessionFactory = (SessionFactoryImpl) ((EntityManagerFactoryImpl) emf).getSessionFactory();
EventListenerRegistry eventListenerRegistry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);

CallbackRegistryImpl emptyRegistry= new CallbackRegistryImpl();

for ( EventType eventType : EventType.values() ) {
  final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType );
  for ( Object listener : eventListenerGroup.listeners() ) {
    if ( CallbackRegistryConsumer.class.isInstance( listener ) ) {
      ( (CallbackRegistryConsumer) listener ).injectCallbackRegistry( emptyRegistry );
    }
  }
}
1 голос
/ 23 марта 2011

Я почти уверен, что это невозможно.Механизм аннотированных сущностей очень статичен, поэтому я перестал его использовать.

Вместо этого в аналогичных ситуациях я определил интерфейсы для реализуемых сущностей, что-то вроде этого:

interface UpdateValidation{
    void preUpdate();
}

interface PersistValidation{
    void prePersist();
}

// etc.

Теперь определите один EntityListener, который проверяет сущности на наличие вышеуказанных интерфейсов.В методе @PreUpdate проверьте UpdateValidation, в методе @PrePersist проверьте PersistValidation.Затем делегируйте методы объекта.

Таким образом, у вас будет один прослушиватель, который контролирует всю функциональность, и вы можете включить или отключить этот прослушиватель с помощью конфигурации XML.


Обновление Вот полная реализация:

public class DelegatingEntityListener{

    public interface PrePersistSupport{
        void prePersist();
    }

    public interface PostPersistSupport{
        void postPersist();
    }

    public interface PreRemoveSupport{
        void preRemove();
    }

    public interface PostRemoveSupport{
        void postRemove();
    }

    public interface PreUpdateSupport{
        void preUpdate();
    }

    public interface PostUpdateSupport{
        void postUpdate();
    }

    public interface PostLoadSupport{
        void postLoad();
    }

    @PrePersist
    public void prePersist(final Object entity){
        if(entity instanceof PrePersistSupport){
            ((PrePersistSupport) entity).prePersist();
        }
    }

    @PostPersist
    public void postPersist(final Object entity){
        if(entity instanceof PostPersistSupport){
            ((PostPersistSupport) entity).postPersist();
        }
    }

    @PreRemove
    public void preRemove(final Object entity){
        if(entity instanceof PreRemoveSupport){
            ((PreRemoveSupport) entity).preRemove();
        }
    }

    @PostRemove
    public void postRemove(final Object entity){
        if(entity instanceof PostRemoveSupport){
            ((PostRemoveSupport) entity).postRemove();
        }
    }

    @PreUpdate
    public void preUpdate(final Object entity){
        if(entity instanceof PreUpdateSupport){
            ((PreUpdateSupport) entity).preUpdate();
        }
    }

    @PostUpdate
    public void postUpdate(final Object entity){
        if(entity instanceof PostUpdateSupport){
            ((PostUpdateSupport) entity).postUpdate();
        }
    }

    @PostLoad
    public void postLoad(final Object entity){
        if(entity instanceof PostLoadSupport){
            ((PostLoadSupport) entity).postLoad();
        }
    }

}

И на случай, если вы удивитесь: нет, я не писал код вручную.Вот код, который написал этот код :-) Вы можете легко настроить его в соответствии со своими потребностями.

public static void main(final String[] args){

    final StringBuilder ib = new StringBuilder(); // interface builder
    final StringBuilder sb = new StringBuilder(); // method builder
    for(final Class<? extends Annotation> annotationType : Arrays
        .asList(
            // all lifecycle annotations:
            PrePersist.class, PostPersist.class, PreRemove.class,
            PostRemove.class, PreUpdate.class, PostUpdate.class,
            PostLoad.class)){

        final String annotationName = annotationType.getSimpleName();
        final String lower =
            annotationName
                .substring(0, 1)
                .toLowerCase()
                .concat(annotationName.substring(1));

        ib.append("public interface ")
            .append(annotationName)
            .append("Support{\n\tvoid ")
            .append(lower)
            .append("();\n}\n\n");

        sb.append('@')
            .append(annotationName)
            .append(" public void ")
            .append(lower)
            .append("(Object entity){\nif(entity instanceof ")
            .append(annotationName)
            .append("Support){((")
            .append(annotationName)
            .append("Support)entity).")
            .append(lower)
            .append("();}}\n\n");

    }
    System.out.println(ib.toString());
    System.out.println(sb.toString());

}

Недостатком является, конечно, то, что провайдер JPA не может кэшировать фактически используемые методы жизненного цикла,но я бы сказал, что это единственный способ получить то, что вы хотите / нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...