2011-03-23 39 views
4

我有一些類(實體)的方法由@PostLoad,@PrePersist等註解,類有@EntityListeners註釋。我想在我的測試環境中禁用處理回調方法和偵聽器。如何禁用JPA 2回調方法和實體監聽器

刪除部分代碼是不可能的,因爲在CI服務器上運行測試,並且我沒有任何可能爲測試更改代碼。

有沒有可能在JPA 2配置中關閉回調方法和實體監聽器?我使用Hibernate。

回答

1

我很確定這是不可能的。註釋實體機制非常靜態,這就是爲什麼我停止使用它。

我做了什麼,而不是在類似情況下被定義實體接口來實現,這樣的事:

interface UpdateValidation{ 
    void preUpdate(); 
} 

interface PersistValidation{ 
    void prePersist(); 
} 

// etc. 

現在定義一個EntityListener來檢查上述接口的實體。在​​方法中,檢查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提供者不能緩存實際使用的生命週期方法的,但我會說這是得到你想要/需要什麼的唯一方式。

+0

這樣的編譯沒有()的嗎? PostUpdateSupport {而不是PostUpdateSupport(){? – 2011-03-23 17:30:37

+0

@Chris我不太瞭解你。隨意將代碼粘貼到IDE中並親自查看。上面的代碼*進行編譯,並且強制轉換(以及括號)是必需的。 – 2011-03-23 17:34:44

+0

肖恩,thx很多:D就是這樣。 – 2011-03-23 18:07:14

4

如果您想從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); 
    } 
    } 
}