如何禁用JPA 2回调方法和实体侦听器

Koz*_*łek 8 java testing hibernate jpa-2.0

我有一些类(实体),其中的方法由@ PostLoad,@ PrePersist等注释,类有@EntityListeners注释.我想在我的测试环境中禁用回调方法和监听器的处理.

删除部分代码是不可能的,因为测试是在CI服务器上运行的,我没有任何可能只为测试更改代码.

是否有可能在JPA 2配置中关闭回调方法和实体侦听器?我使用Hibernate.

Kon*_*tin 6

如果你想从Hibernate 4.3.5(我测试过的唯一一个)中删除所有JPA监听器,就可以完成.我不会展示如何获取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 );
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Sea*_*oyd 1

我很确定这是不可能的。带注释的实体机制非常静态,这就是我停止使用它的原因。

在类似的情况下,我所做的是定义要实现的实体的接口,如下所示:

interface UpdateValidation{
    void preUpdate();
}

interface PersistValidation{
    void prePersist();
}

// etc.
Run Code Online (Sandbox Code Playgroud)

现在定义一个 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();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

如果您想知道:不,我没有手工编写代码。这是编写该代码的代码:-) 您可以轻松地根据自己的需要进行调整。

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

}
Run Code Online (Sandbox Code Playgroud)

当然,缺点是 JPA 提供程序无法缓存实际使用的生命周期方法,但我想说这是获得您想要/需要的内容的唯一方法。