2011-11-30 12 views
5

Estoy trabajando en una gran aplicación Java que usa Wicket 1.5 junto con Hibernate/JPA 2. Wicket tiene una regla estándar que los objetos almacenados en la sesión deben implementar Serializable. Tenemos una regla adicional de que los objetos administrados por JPA no deben almacenarse en la sesión. En cambio, los objetos gestionados JPA se cargan en cada solicitud a través de modelos desmontables.Extender la prueba de serialización de Wicket

Para complicar las cosas, es legítimo almacenar un objeto Entity en la sesión siempre que no se haya conservado todavía. Como resultado, algunas de nuestras clases ya implementan Serializable.

Si quisiera extender la prueba de serialización de Wicket para detectar objetos propiedad de JPA, ¿cómo lo haría? ¿Es esto posible sin un tenedor local de Wicket?

Respuesta

5

En mi $ dayjob utilizamos algo que usted describe, y lo que tengo presented at several meetups (vea la diapositiva 23 y sucesivamente). No tienes que bifurcar Wicket por eso.

Básicamente, lo que debes hacer es copiar el código del verificador de serializadores y modificarlo para incluir tu cheque y también para verificar si hay errores de serialización. Luego, en la última fase del ciclo de solicitud, ejecuta su propio verificador de serializador en las páginas afectadas.

El cheque que creamos verifica nuestra clase base común, y si la entidad persistió o no. Si es así, fallamos la solicitud. Además, tenemos una devolución de llamada Ajax en nuestra página base que verifica un atributo de sesión para ver si hubo un error de serialización. Si es así, redirigiremos a la página de error con la falla de serialización, para garantizar que los desarrolladores no ignoren la entidad en la jerarquía de páginas.

Aquí está la carne de nuestra corrector (el método check reescrito desde cheque serializador de 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); 
     } 
    } 

Por Wicket 1,5 creamos nuestra propia PageStoreManager que realiza estas comprobaciones (y un montón de otras cosas, como permitir un historial de navegación del lado del servidor para nuestros usuarios). Proporcionamos nuestro propio RequestAdapter anulando PageStoreManager#newRequestAdapter(IPageManagerContext context) y hacer el cheque serialización en el adaptador:

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

He implementado esto en mi solicitud, y funciona como un encanto. Sería un poco mejor si Wicket tuviera un punto de conexión conveniente para las verificaciones de la sesión, pero esto es bastante fácil de mantener. Gracias. –

+1

De nada. Usted es libre de enviar una solicitud de función. Desafortunadamente no podemos hacer de esto una verificación genérica, pero sería bueno ampliar el marco de una manera más obvia. –

0

Un enfoque muy fácil es la personalización de la serialización de sus entidades:

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

Hemos puesto este fragmento en toda de nuestras entidades (bueno, de hecho en una clase base común llamada AbstractPersistentObject) y funciona bastante bien. Lo único que complica es editar entidades persistentes o entidades transitorias con propiedades persistentes: no se permite serializar objetos sucios/editados/modificados.