Thursday, December 8, 2011

A way of preventing state of persistent object from becoming "Hollow" when using Wicket + Guice + Apache Cayenne

I'm using wicket-guice to inject ObjectContext to Page by Guice.
In this case, persistent object become "hollow" state when I click the back button of browser.

Persistent object don't serialize value to the session. DataContext object sets values in persistent object when it is deserialized.
But the processing of DataContext deserialization doesn't work because the serialized object is a proxy object when wicket-guice is used.
The proxy object always create a new object. Therefore DataContext object cannot deserialize persistent object, and the state of persistent object become "hollow".


A simple method of solving is written here.
http://cayenne.195.n3.nabble.com/Conditions-when-PersistenceState-gets-quot-hollow-quot-td691334.html
But, this method needs to add the code of checking persistent state to all models.


Another method is to add the following code to Application.java.
        getComponentInstantiationListeners().add(
            new GuiceComponentInjector(
                this, Guice.createInjector(
                    usesDeploymentConfig() ? Stage.PRODUCTION : Stage.DEVELOPMENT, new GuiceModule()), false));
This method needs to modify all injected objects to serializable. You will need a lot of corrections if you are already using service class of not serializable.



If you want to change deserialization processing, you need copying and changing source code of wicket-guice.
I changed the source code of wicket-guice as shown as follows.

GuiceCayenneComponentInjector.java
    public GuiceCayenneComponentInjector(final Application app, final Injector injector,
        final boolean wrapInProxies)
    {
        app.setMetaData(GuiceInjectorHolder.INJECTOR_KEY, new GuiceInjectorHolder(injector));
        fieldValueFactory = new GuiceCayenneFieldValueFactory(wrapInProxies);
        app.getBehaviorInstantiationListeners().add(this);
        bind(app);
    }

GuiceCayenneFieldValueFactory.java
 public class GuiceCayenneFieldValueFactory implements IFieldValueFactory
{
    private final boolean wrapInProxies;

    private boolean wrapClass(Class<?> type) {
        if (!type.getPackage().getName().startsWith("org.apache.cayenne"))
            return true;
        if (type.getName().endsWith("ObjectContext") ||
                type.getName().endsWith("DataContext"))
            return false;
        return true;
    }

    ... (snip)

    public Object getFieldValue(final Field field, final Object fieldOwner)

        ... (snip)

                    if (wrapInProxies && wrapClass(field.getType()))
                    {
                        target = LazyInitProxyFactory.createProxy(field.getType(), locator);
                    }
                    else
                    {
                        target = locator.locateProxyTarget();
                    }

A object is serialized and deserialized without using proxy by this code when injected object is DataContext.





No comments:

Post a Comment