ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "MCCORMICK, Paul" <Paul.McCORM...@doir.wa.gov.au>
Subject RE: Lazy loading issues
Date Mon, 19 Mar 2007 02:02:19 GMT

I'll give you some of the sudo code that I used to overcome lazy loading
of 1 to 1 relationships.  I had to write extra code to allow lazy loaded
objects to be serializable and cloneable.  The code has nothing to do
with lazy loading of lists.

All objects loaded from the database implement the IBaseDomain
interface. 

interface IBaseDomain {
    Integer id              // The primary key which is never null
    Integer versionId  // Used of optomistic locking
    boolean setNewCalled // Used when the id and versionId have been set
to null by client code.
}


Here is the ResultObjectFactory used.  Quite simple,  just enhances
anything that implements IBaseDomain.
public final class EmitsResultObjectFactory implements
ResultObjectFactory {

    public final Object createInstance(String arg0, Class clazz) throws
InstantiationException, IllegalAccessException {
   
        if (IBaseDomain.class.isAssignableFrom(clazz)) {          
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz);

enhancer.setCallbackFilter(EnhancedBaseDomainCallbackFilter.instance);

enhancer.setCallbacks(EnhancedBaseDomainCallbackFilter.callbacks);
            return enhancer.create();
        } else {
            return null;
        }

    }

    public void setProperty(String arg0, String arg1) {}
}


-----------------------------------------------------------

public final class EnhancedBaseDomainCallbackFilter implements
CallbackFilter, MethodInterceptor, Serializable {

    private EnhancedBaseDomainCallbackFilter() {

    }

    public static final EnhancedBaseDomainCallbackFilter instance = new
EnhancedBaseDomainCallbackFilter();

    public static final Callback[] callbacks = { NoOpCallback.INSTANCE,
instance };

    public final int accept(Method method) {

        if (method.getName().startsWith("get") &&
method.getParameterTypes().length == 0 &&
IBaseDomain.class.isAssignableFrom(method.getReturnType())) {
            return 1; // BaseDomain return types are intercepted.
        }
        return 0; // the No operation interceptor. Does nothing.
    }

    /**
     * Allows using the enhancementEnabled ibatis option. This option
allows the lazy loading of single objects ( and not just Lists ).
     *
     * e.g the following method can be lazy loaded: public Party
getParty();
     *
     * A problem occurs if calling the "public Party getParty()" should
return null. Instead of null being returned a 'wrapped null' is
returned. This MethodInterceptor fixes this
     * feature/bug.
     */
    public final Object intercept(final Object object, final Method
method, final Object[] args, final MethodProxy proxy) throws Throwable {

        Object obj = proxy.invokeSuper(object, args);
        if ((obj == null) || (!(obj instanceof IBaseDomain))) {
            return obj;
        }

        IBaseDomain baseDomain = (IBaseDomain) obj;
       
        // All Enhanced objects implement Factory.
        if (baseDomain instanceof Factory) {
            // If the primary key is null then the object is null unless
the client code called setNew()
            if (baseDomain.getId() == null) {
                try {
                    // If baseDomain.setNew() is called then the object
is valid.  If not then its a return null instead of the proxy.
                    if (!baseDomain.isSetNewCalled()) {
                        return null;
                    }
                // There is a bug in cg lib that can cause a Null
Pointer to be thrown on a cloned enhanced object.  Don't know why but
this is a temp fix.
                } catch (NullPointerException e) {
                    Log log =
LogFactory.getLog(EnhancedBaseDomainCallbackFilter.class);


log.debug("EnhancedBaseDomainCallbackFilter.intercept caught
NullPointerException on method " + method.getName() + " object:" +
baseDomain.getClass().getName());
                    return null;
                }
            }
        }
       
        return baseDomain;

    }

    private interface NoOpCallback extends NoOp, Serializable {
        /**
         * A thread-safe singleton instance of the
<code>NoOpCallback</code> callback.
         */
        public static final NoOpCallback INSTANCE = new NoOpCallback() {
        };
    }

}

-----------------------------------------------------------
I changed the Ibatis class EnhancedLazyResultLoader.
1) I had to make an inner class Serializable.  This involved making the
field that links to the jdbc connection transient.  I then had to put my
application code into this class to set this transient field.  Thats a
hack that you may want to improve on.

2) Changed the EnhancedLazyResultLoaderImpl.loadResult() method to only
create proxy objects for IBaseDomain results ( that are not abstract).
The reason for not lazy loading abstract classes is because the
instanceof does not work as expected when comparing to a concrete class.
Here is the method code.  I'll attach a file of the whole class also but
most of it is not relevent.
    public Object loadResult() throws SQLException {
      if (...)
            ....
      } else if (Collection.class.isAssignableFrom(targetType)) {
       .....
        // This is my custom code for lazy loading 1 to 1 relationships.

      } else if ( IBaseDomain.class.isAssignableFrom(targetType)  &&
!Modifier.isAbstract(targetType.getModifiers())) {
          return  Enhancer.create(targetType, new Class[] {
IBaseDomain.class } , this);
      } else {
     loadObject();
  return resultObject;
      }
    }

I hope this helps,
Paul


________________________________

From: Wouter Roose [mailto:wouter.roose@guest.minfin.fed.be]
Sent: Friday, 16 March 2007 6:13 PM
To: user-java@ibatis.apache.org
Subject: RE: Lazy loading issues



Anybody?



________________________________

Van: Wouter Roose [mailto:wouter.roose@guest.minfin.fed.be]
Verzonden: maandag 12 maart 2007 8:49
Aan: user-java@ibatis.apache.org
Onderwerp: Lazy loading issues



Hello



Concerning

http://opensource.atlassian.com/confluence/oss/display/IBATIS/Lazy+loadi
ng+issues
<http://opensource.atlassian.com/confluence/oss/display/IBATIS/Lazy+load
ing+issues>



I encountered the second problem. Could somebody be so kind to add some
coding examples to the solution on the wiki? especially the one with the
ResultObjectFactory. As I'm not an expert iBATIS developer it is
difficult to implement this solution based on this explanation

Regards,
Wouter




________________________________

Disclaimer <http://www.minfin.fgov.be/disclaimer.htm>


________________________________

Disclaimer <http://www.minfin.fgov.be/disclaimer.htm>



"DISCLAIMER: This email, including any attachments, is intended only for use by the addressee(s)
and may contain confidential and/or personal information and may also be the subject of legal
privilege. If you are not the intended recipient, you must not disclose or use the information
contained in it. In this case, please let me know by return email, delete the message permanently
from your system and destroy any copies.

Before you take any action based upon advice and/or information contained in this email you
should carefully consider the advice and information and consider obtaining relevant independent
advice.
Mime
View raw message