2011-11-30 14 views
5

Sto lavorando a una grande applicazione Java che utilizza Wicket 1.5 insieme a Hibernate/JPA 2. Wicket ha una regola standard che gli oggetti memorizzati nella sessione devono implementare Serializable. Abbiamo una regola in più che gli oggetti gestiti da JPA non devono essere memorizzati nella sessione. Invece, gli oggetti gestiti JPA vengono caricati su ogni richiesta tramite modelli rimovibili.Estensione del test di serializzazione di Wicket

Per complicare le cose, è legittimo memorizzare un oggetto Entity nella sessione a condizione che non sia stato ancora persistuto. Di conseguenza, alcune delle nostre classi implementano già Serializable.

Se volevo estendere il test di serializzazione di Wicket per rilevare oggetti di proprietà di JPA, come potrei farlo? E 'possibile senza un fork locale di Wicket?

risposta

5

Al mio $ dayjob usiamo qualcosa che descrivi, e cosa ho presented at several meetups (vedi diapositiva 23 e on). Non devi perderti Wicket per quello.

Fondamentalmente ciò che si fa è copiare il codice di controllo del serializzatore e modificarlo per includere il controllo e controllare gli errori di serializzazione. Quindi nell'ultima fase del ciclo di richiesta si esegue il proprio correttore serializzatore sulle pagine interessate.

Il controllo che abbiamo creato assegni per la nostra classe di base comune, e che l'entità abbia o meno persistito. Se è così, falliamo la richiesta. Inoltre abbiamo un callback Ajax nella nostra pagina di base che controlla un attributo di sessione per vedere se c'è stato un errore di serializzazione. In tal caso, reindirizziamo alla pagina di errore con l'errore di serializzazione, per garantire che gli sviluppatori non ignorino l'entità nella gerarchia di pagine.

Ecco la carne del nostro controllo (il metodo check riscritta dal check serializzatore di Wicket):

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

Per Wicket 1.5 abbiamo creato il nostro PageStoreManager che esegue questi controlli (e un sacco di altre cose, come consentendo una cronologia di navigazione lato server per i nostri utenti). Abbiamo fornito il nostro RequestAdapter sovrascrivendo PageStoreManager#newRequestAdapter(IPageManagerContext context) e fare il check-serializzazione l'adattatore:

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

Ho implementato questo nella mia domanda, e funziona come un fascino. Sarebbe un po 'più ordinato se Wicket avesse un comodo punto di collegamento per i controlli di sessione, ma questo è abbastanza mantenibile. Grazie. –

+1

Prego. Sei libero di inviare una richiesta di funzionalità. Sfortunatamente non possiamo fare un controllo generico, ma essere in grado di estendere la struttura in un modo più ovvio sarebbe bello. –

0

Un approccio molto semplice è la personalizzazione serializzazione delle vostre entità:

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

Abbiamo messo questo frammento in tutto delle nostre entità (beh, in realtà in una classe base comune chiamata AbstractPersistentObject) e funziona piuttosto bene. L'unica cosa che complica è la modifica di entità persistenti o entità transitorie con proprietà persistenti: non è permesso serializzare oggetti sporchi/modificati/modificati.

Problemi correlati