El doble clic parece interrumpir la inyección Wicket-Spring

Nuestra aplicación utiliza un front-end de Wicket, con inyección de Spring para cargar nuestros DOA y administrar transacciones.

Hemos descubierto que varios de nuestros usuarios están haciendo doble clic en enlaces/botones y esto de alguna manera interrumpe la inyección de Spring, por lo que las llamadas posteriores a Dao.doStuff(obj) arrojan NPE. Esta aplicación se ejecuta en la red interna de nuestro cliente y, por ahora, Hemos solicitado amablemente que el cliente haga correr la voz entre su equipo de que los clics individuales funcionan en todas las funciones. Pero es evidente que esto se está convirtiendo en un problema para ellos.

Un caso de uso común implica una pantalla de "Búsqueda" que muestra una lista de todos los objetos Foo actualmente en el sistema, que se pueden filtrar a través de parámetros de búsqueda si se desea, y cuando se hace clic en un elemento, se lleva al usuario a una página de detalles para ese Foo específico. , inicialmente en un modo de solo lectura. A continuación, el usuario puede hacer clic en el botón "Editar" en la esquina para cambiar al modo de edición. Luego, el usuario puede hacer algunos cambios y hacer clic en "Guardar" (o posiblemente hacer clic en "Eliminar" para eliminar el elemento).

Este escenario implica llamadas DAO en hasta tres pasos: 1. En la página de búsqueda, cuando se hace clic en el elemento, para cargar los detalles básicos de ese elemento. 2. En la página de detalles en modo de solo lectura, cuando se hace clic en editar, para cargar los detalles completos de ese artículo. 3a. En la página de detalles en el modo de edición, cuando se hace clic en Guardar, para conservar los cambios. 3b. En la página de detalles en el modo de edición, cuando se hace clic en Eliminar, para eliminar.

En cualquiera de estos casos, si el usuario hace doble clic en el anterior paso, el siguiente paso produce el error. La reproducibilidad es de alrededor del 33% con algunas variaciones entre navegadores y sistemas operativos.

¿Alguna idea sobre cómo prevenir esto?


En los ejemplos a continuación, BasePage es nuestra extensión personalizada de la página web de Wicket que contiene nuestros menús y otros elementos comunes de la página, y PageType es una enumeración de los detalles CREAR, EDITAR y SOLO LEER.

Ejemplo de código para la página de búsqueda (se muestra Java, HTML es lo que espera):

import org.apache.wicket.spring.injection.annot.SpringBean;
// and other imports

public class FooManagerPage extends BasePage {

    @SpringBean
    private transient FooDao fooDao;

    public FooManagerPage() {
        SortableDataProvider<Foo> provider = new SortableDataProvider<Foo>(fooDao);

        add(new FeedbackPanel("feedback");

        final Form<Foo> searchFooForm = new Form<Foo>("searchFooForm",
            new CompoundPropertyModel<Foo>(new Foo()));

        // the form's search parameter's go here
        // with a 'search' button that filters table below

        add(searchFooForm)

        List<IColumn<Foo>> columns = new ArrayList<IColumn<Foo>>();
        columns.add(new PropertyColumn<Foo>(Model.of("Name"), "name", "name"));
        // a couple other columns here

        DataTable fooTable = new AjaxFallbackDefaultDataTable<Foo>("fooTable", columns, provider, 10){
            @Override
            protected Item<Foo> newRowItem(String id, int index, final IModel<Foo> model){
                Item<Foo> item = super.newRowItem(id, index, model);
                item.add(new AjaxEventBehavior ("onclick") {
                    @Override
                    protected void onEvent(AjaxRequestTarget target) {
                        Foo foo = fooDao.load(model.getObject().getId());
                        setResponsePage(new FooViewPage(foo, PageType.READ_ONLY));
                    }
                }); 
                return item;
            }
        };

        add(fooTable);
    }
}

Código de muestra para la página de visualización (se muestra Java, HTML es lo que espera):

// several imports, including Spring Bean
public class FooFormPage extends BasePage {

    @SpringBean
    private transient fooDao fooDao;

    public FooFormPage(final Foo foo, PageType type) {
        Form<Foo> fooForm = new Form<Foo>("fooForm",
            new CompoundPropertyModel<Foo>(foo));

        // all of Foo's input elements go here
        // are enabled or disabled and sometimes invisible based on PageType

        add(fooForm);

        SubmitLink submitButton = new SubmitLink("save", fooForm){
            @Override
            public void onSubmit() {
                super.onSubmit();
                //***** A double click on the Edit button can cause fooDao to be N.P.E. here *****
                fooDao.save(createInitiativeForm.getModelObject().getId());
                changePageType(PageType.VIEW, createFooForm.getModelObject());
            }
        };
        add(submitButton);

        AjaxLink<Void> editButton = new AjaxLink<Void>("edit"){
            @Override
            public void onClick(AjaxRequestTarget target) {
                // reload the item from DB
                //***** A double click on Search Page item will cause fooDao to be N.P.E. here *****
                Foo foo = fooDao.load(fooForm.getModelObject().getId());
                setResponsePage(new FooPage(foo, PageType.EDIT));
            }
        };
        add(editButton);

        // some stuff here that makes save button invisible in READ_ONLY, and Edit visible only in READ_ONLY
        // delete button is similar (visible only in CREATE)
    }
}

preguntado el 11 de junio de 12 a las 18:06

1 Respuestas

Los campos de dependencia no deben marcarse como transient, deben ser serializados a lo largo de la página. El wicket-spring El módulo inyecta proxies serializables en @SpringBean-campos anotados en el momento de la creación del componente/página, para que puedan serializarse de forma segura, sin preocuparse por serializar las dependencias en sí.

Respondido el 11 de junio de 12 a las 20:06

Entiendo lo que dices que el error puede estar ocurriendo porque el DAO no se serializó con la página. Sin embargo, estos DAO no son en sí mismos Seriablizable. - pato cobalto

No importa. El wicket-spring módulo creará un proxy serializable para el DAO, incluso si no implementa Serializable. El campo contendrá una referencia al proxy (que debe serializarse con la página), no al DAO. Buscará la referencia DAO real de Spring a pedido, en un LoadableDetachableModel-como manera. - tetsuo

¡Nooooooo! :) No necesita hacer que sus DAO se implementen Serializable. Las wicket-spring ¡La integración creará un proxy serializable para usted! Simplemente intente eliminar el transient calificador de los campos y ver si funciona. - tetsuo

Nuestros dos últimos comentarios se cruzaron. De hecho, lo estábamos probando con y sin serializable, y funciona en ambos sentidos, siempre que las instancias no sean transitorias. Así que gracias de nuevo. - pato cobalto

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.