From: <hib...@li...> - 2006-07-20 17:27:33
|
Author: scottmarlownovell Date: 2006-07-20 13:27:30 -0400 (Thu, 20 Jul 2006) New Revision: 10126 Modified: trunk/Hibernate3/src/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java Log: Fix for HHH-1293. Switched to using InvocationHandler. Modified: trunk/Hibernate3/src/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java 2006-07-19 14:11:50 UTC (rev 10125) +++ trunk/Hibernate3/src/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java 2006-07-20 17:27:30 UTC (rev 10126) @@ -4,16 +4,19 @@ import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.Enhancer; -import net.sf.cglib.proxy.Factory; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; +import net.sf.cglib.proxy.InvocationHandler; import net.sf.cglib.proxy.NoOp; import org.hibernate.HibernateException; +import org.hibernate.LazyInitializationException; import org.hibernate.proxy.pojo.BasicLazyInitializer; import org.hibernate.proxy.HibernateProxy; import org.hibernate.engine.SessionImplementor; @@ -25,11 +28,8 @@ /** * A <tt>LazyInitializer</tt> implemented using the CGLIB bytecode generation library */ -public final class CGLIBLazyInitializer extends BasicLazyInitializer implements MethodInterceptor { +public final class CGLIBLazyInitializer extends BasicLazyInitializer implements InvocationHandler { - - private static final Class[] CALLBACK_TYPES = new Class[]{ MethodInterceptor.class,NoOp.class }; - private static final CallbackFilter FINALIZE_FILTER = new CallbackFilter() { public int accept(Method method) { if ( method.getParameterTypes().length == 0 && method.getName().equals("finalize") ){ @@ -49,7 +49,7 @@ final Method setIdentifierMethod, AbstractComponentType componentIdType, final Serializable id, final SessionImplementor session) throws HibernateException { // note: interfaces is assumed to already contain HibernateProxy.class - + try { final CGLIBLazyInitializer instance = new CGLIBLazyInitializer( entityName, @@ -59,16 +59,13 @@ getIdentifierMethod, setIdentifierMethod, componentIdType, - session + session ); - - final HibernateProxy proxy = (HibernateProxy) Enhancer.create( - interfaces.length == 1 ? persistentClass : null, - interfaces, - FINALIZE_FILTER, - new Callback[]{ instance, NoOp.INSTANCE } - ); - + + final HibernateProxy proxy; + Class factory = getProxyFactory(persistentClass, interfaces); + Enhancer.registerCallbacks(factory, new Callback[]{ instance, null }); + proxy = (HibernateProxy)factory.newInstance(); instance.constructed = true; return proxy; } @@ -84,7 +81,7 @@ final Method getIdentifierMethod, final Method setIdentifierMethod, final AbstractComponentType componentIdType, final Serializable id, final SessionImplementor session) throws HibernateException { - + final CGLIBLazyInitializer instance = new CGLIBLazyInitializer( entityName, persistentClass, @@ -93,17 +90,17 @@ getIdentifierMethod, setIdentifierMethod, componentIdType, - session + session ); - + final HibernateProxy proxy; try { - proxy = (HibernateProxy) factory.newInstance(); + Enhancer.registerCallbacks(factory, new Callback[]{ instance, null }); + proxy = (HibernateProxy)factory.newInstance(); } catch (Exception e) { throw new HibernateException( "CGLIB Enhancement failed: " + persistentClass.getName(), e ); } - ( (Factory) proxy ).setCallback( 0, instance ); instance.constructed = true; return proxy; @@ -111,28 +108,17 @@ public static Class getProxyFactory(Class persistentClass, Class[] interfaces) throws HibernateException { - // note: interfaces is assumed to already contain HibernateProxy.class - - try { - - Enhancer en = new Enhancer(); - en.setUseCache( false ); - en.setInterceptDuringConstruction( false ); - - en.setCallbackTypes( CALLBACK_TYPES ); - en.setCallbackFilter( FINALIZE_FILTER ); - - en.setSuperclass( interfaces.length == 1 ? persistentClass : null ); - en.setInterfaces( interfaces ); - - return en.createClass(); - - } - catch (Throwable t) { - LogFactory.getLog( BasicLazyInitializer.class ) - .error( "CGLIB Enhancement failed: " + persistentClass.getName(), t ); - throw new HibernateException( "CGLIB Enhancement failed: " + persistentClass.getName(), t ); - } + Enhancer e = new Enhancer(); + e.setSuperclass( interfaces.length == 1 ? persistentClass : null ); + e.setInterfaces(interfaces); + e.setCallbackTypes(new Class[]{ + InvocationHandler.class, + NoOp.class, + }); + e.setCallbackFilter(FINALIZE_FILTER); + e.setUseFactory(false); + e.setInterceptDuringConstruction( false ); + return e.createClass(); } private CGLIBLazyInitializer(final String entityName, final Class persistentClass, @@ -146,48 +132,80 @@ getIdentifierMethod, setIdentifierMethod, componentIdType, - session + session ); this.interfaces = interfaces; } - public Object intercept(final Object proxy, final Method method, final Object[] args, - final MethodProxy methodProxy) throws Throwable { + private static boolean isCastable(Class caster, Class castee) { + if ( castee.equals( caster ) ) { + return true; + } + List list = addCheckingTypes( caster, new ArrayList() ); + for ( Iterator iter = list.iterator(); iter.hasNext(); ) { + Class cl = ( Class ) iter.next(); + if ( castee.equals( cl ) ) { + return true; + } + } + return false; + } + + private static List addCheckingTypes(final Class type, final List list) { + Class superclass = type.getSuperclass(); + if ( superclass != null ) { + list.add( superclass ); + addCheckingTypes( superclass, list ); + } + Class[] interfaces = type.getInterfaces(); + for ( int i = 0; i < interfaces.length; ++i ) { + list.add( interfaces[i] ); + addCheckingTypes( interfaces[i], list ); + } + return list; + } + + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { if ( constructed ) { - Object result = invoke( method, args, proxy ); if ( result == INVOKE_IMPLEMENTATION ) { Object target = getImplementation(); final Object returnValue; - if ( ReflectHelper.isPublic( persistentClass, method ) ) { - returnValue = methodProxy.invoke( target, args ); - } - else { - if ( !method.isAccessible() ) method.setAccessible( true ); - try { + try { + if ( ReflectHelper.isPublic( persistentClass, method ) ) { + if ( !isCastable( + target.getClass(), method + .getDeclaringClass() + ) ) { + throw new ClassCastException( + target.getClass() + .getName() + ); + } returnValue = method.invoke( target, args ); } - catch (InvocationTargetException ite) { - throw ite.getTargetException(); + else { + if ( !method.isAccessible() ) method.setAccessible( true ); + returnValue = method.invoke( target, args ); } + return returnValue == target ? proxy : returnValue; } - return returnValue == target ? proxy : returnValue; + catch (InvocationTargetException ite) { + throw ite.getTargetException(); + } } else { return result; } - } else { - // while constructor is running if ( method.getName().equals( "getHibernateLazyInitializer" ) ) { return this; } else { - return methodProxy.invokeSuper( proxy, args ); + throw new LazyInitializationException("unexpected case hit, method=" + method.getName()); } - } } |