2011-11-30 44 views
5

我正在研究一個使用Wicket 1.5和Hibernate/JPA 2的大型Java應用程序。Wicket有一個標準規則,存儲在會話中的對象必須實現Serializable。我們有一個額外的規則,即JPA管理的對象不得存儲在會話中。相反,JPA託管對象通過可拆卸模型加載到每個請求上。擴展Wicket的序列化測試

使事情複雜化,在會話中存儲實體對象是合理的,只要它尚未被持久化。因此,我們的一些課程已經實施了Serializable

如果我想擴展Wicket的序列化測試來檢測JPA擁有的對象,我會怎麼做呢?這可能沒有Wicket的本地分叉?

回答

5

在我的$ dayjob我們使用你描述的東西,以及我擁有的東西presented at several meetups(請參見幻燈片23及以上)。你不必爲此分叉Wicket。

基本上你要做的就是複製序列化程序檢查器代碼,並修改它以包含你的檢查以及檢查序列化錯誤。然後在請求週期的最後階段,在受影響的頁面上運行自己的序列化程序檢查器。

我們創建的檢查檢查我們的通用基類,而不管實體是否持續存在。如果是這樣,我們就失敗了。另外,我們在基本頁面中有一個Ajax回調,用於檢查會話屬性以查看是否存在序列化錯誤。如果是這樣,我們重定向到序列化失敗的錯誤頁面,以確保開發人員不會忽略頁面層次結構中的實體。

這是我們檢查的肉類(從檢票的串行檢查改寫check法):

private void check(Object obj) 
{ 
    if (obj == null || obj.getClass().isAnnotationPresent(Deprecated.class) 
     || obj.getClass().isAnnotationPresent(SkipClass.class)) 
    { 
     return; 
    } 

    Class<?> cls = obj.getClass(); 
    nameStack.add(simpleName); 
    traceStack.add(new TraceSlot(obj, fieldDescription)); 

    if (!(obj instanceof Serializable) && (!Proxy.isProxyClass(cls))) 
    { 
     throw new WicketNotSerializableException(toPrettyPrintedStack(obj.getClass().getName()) 
      .toString(), exception); 
    } 
    if (obj instanceof IdObject) 
    { 
     Serializable id = ((IdObject) obj).getIdAsSerializable(); 
     if (id != null && !(id instanceof Long && ((Long) id) <= 0)) 
     { 
      throw new WicketContainsEntityException(toPrettyPrintedStack(
       obj.getClass().getName()).toString(), exception); 
     } 
    } 
    if (obj instanceof LoadableDetachableModel) 
    { 
     LoadableDetachableModel<?> ldm = (LoadableDetachableModel<?>) obj; 
     if (ldm.isAttached()) 
     { 
      throw new WicketContainsAttachedLDMException(toPrettyPrintedStack(
       obj.getClass().getName()).toString(), exception); 
     } 
    } 

檢票1.5,我們創建了自己的PageStoreManager執行這些檢查(和很多其他的東西,比如使我們的用戶的服務器端瀏覽記錄)。

class DetachCheckingRequestAdapter extends RequestAdapter 
{ 
    public DetachCheckingRequestAdapter(IPageManagerContext context) 
    { 
     super(context); 
    } 

    @Override 
    protected void storeTouchedPages(List<IManageablePage> touchedPages) 
    { 
     super.storeTouchedPages(touchedPages); 
     if (Application.get().usesDevelopmentConfig()) 
     { 
      for (IManageablePage curPage : touchedPages) 
      { 
       if (!((Page) curPage).isErrorPage()) 
        testDetachedObjects(curPage); 
      } 
     } 
    } 

    private void testDetachedObjects(final IManageablePage page) 
    { 
     try 
     { 
      NotSerializableException exception = new NotSerializableException(); 
      EntityAndSerializableChecker checker = new EntityAndSerializableChecker(exception); 
      checker.writeObject(page); 
     } 
     catch (Exception ex) 
     { 
      log.error("Couldn't test/serialize the Page: " + page + ", error: " + ex); 
      Session.get().setDetachException(ex); 
     } 
    } 
} 
+0

我在我的應用程序中實現這一點,它的工作原理就像一個魅力。如果Wicket對會話檢查有一個方便的連接點,這將是一個整潔的,但這是相當可維護的。謝謝。 –

+1

不客氣。您可以自由提交功能請求。不幸的是,我們不能做這個通用的檢查,但能夠以更明顯的方式擴展框架將是很好的。 –

0

一個非常簡單的方法是自定義實體的系列化:

public Object writeReplace() throws ObjectStreamException { 
    if (!isTransient()) { 
    throw new NotSerializableException("persistent objects must not be serialized"); 
    } 
    return this; 
} 

我們已經把這個片段到所有我們通過重寫PageStoreManager#newRequestAdapter(IPageManagerContext context),做在適配器的系列化檢查提供我們自己的RequestAdapter我們的實體(實際上是一個名爲AbstractPersistentObject的公共基類),它工作得很好。它唯一複雜的是編輯具有持久屬性的持久化實體或瞬態實體:不允許序列化髒/編輯/修改的對象。