From: <hib...@li...> - 2006-03-04 00:23:54
|
Author: ste...@jb... Date: 2006-03-03 19:23:51 -0500 (Fri, 03 Mar 2006) New Revision: 9544 Added: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/TransformingClassLoader.java Modified: trunk/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java trunk/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java trunk/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java Log: HHH-1435 : lazy="no-proxy" on many/one-to-one associations; use of ~transforming class loaders~ for runtime instrumentation of domain objects for testing purposes Modified: trunk/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java 2006-03-04 00:22:05 UTC (rev 9543) +++ trunk/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java 2006-03-04 00:23:51 UTC (rev 9544) @@ -14,6 +14,35 @@ */ public ProxyFactoryFactory getProxyFactoryFactory(); + /** + * Retrieve the ReflectionOptimizer delegate for this provider + * capable of generating reflection optimization components. + * + * @param clazz The class to be reflected upon. + * @param getterNames Names of all property getters to be accessed via reflection. + * @param setterNames Names of all property setters to be accessed via reflection. + * @param types The types of all properties to be accessed. + * @return The reflection optimization delegate. + */ public ReflectionOptimizer getReflectionOptimizer(Class clazz, String[] getterNames, String[] setterNames, Class[] types); + /** + * Generate a ClassLoader capable of performing dynamic bytecode manipulation + * on classes as they are loaded for the purpose of field-level interception. + * The returned ClassLoader is used for run-time bytecode manipulation as + * opposed to the more common build-time manipulation, since here we get + * into SecurityManager issues and such. + * <p/> + * Currently used only from the Hibernate test suite, although conceivably + * (SecurityManager concerns aside) could be used somehow in running systems. + * + * @param parent The parent classloader + * @param classpath The classpath to be searched + * @param packages can be null; use to limnit the packages to be loaded + * via this classloader (and transformed). + * @return The appropriate ClassLoader. + */ + public ClassLoader generateDynamicFieldInterceptionClassLoader(ClassLoader parent, String[] classpath, String[] packages); + + public void releaseDynamicFieldInterceptionClassLoader(ClassLoader classLoader); } Modified: trunk/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java 2006-03-04 00:22:05 UTC (rev 9543) +++ trunk/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java 2006-03-04 00:23:51 UTC (rev 9544) @@ -6,9 +6,16 @@ import org.hibernate.util.StringHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.objectweb.asm.Type; import net.sf.cglib.reflect.FastClass; import net.sf.cglib.beans.BulkBean; import net.sf.cglib.beans.BulkBeanException; +import net.sf.cglib.transform.TransformingClassLoader; +import net.sf.cglib.transform.ClassFilter; +import net.sf.cglib.transform.ClassTransformerFactory; +import net.sf.cglib.transform.ClassTransformer; +import net.sf.cglib.transform.impl.InterceptFieldTransformer; +import net.sf.cglib.transform.impl.InterceptFieldFilter; import java.lang.reflect.Modifier; @@ -76,4 +83,53 @@ return null; } } + + public ClassLoader generateDynamicFieldInterceptionClassLoader( + ClassLoader parent, + String[] classpath, + String[] packages) { + return new TransformingClassLoader( + parent, + new ClassLoaderClassFilter( packages ), + new ClassTransformerFactory() { + public ClassTransformer newInstance() { + return new InterceptFieldTransformer( + new InterceptFieldFilter() { + public boolean acceptRead(Type owner, String name) { + return true; + } + public boolean acceptWrite(Type owner, String name) { + return true; + } + } + ); + } + } + ); + } + + public void releaseDynamicFieldInterceptionClassLoader(ClassLoader classLoader) { + } + + private static class ClassLoaderClassFilter implements ClassFilter { + private final String[] packages; + + public ClassLoaderClassFilter(String[] packages) { + this.packages = packages; + } + + public boolean accept(String className) { + if ( packages == null ) { + return true; + } + else { + for ( int i = 0; i < packages.length; i++ ) { + if ( className.startsWith( packages[i] ) ) { + return true; + } + } + return false; + } + } + } } Modified: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java 2006-03-04 00:22:05 UTC (rev 9543) +++ trunk/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java 2006-03-04 00:23:51 UTC (rev 9544) @@ -73,4 +73,15 @@ return null; } } + + public ClassLoader generateDynamicFieldInterceptionClassLoader(ClassLoader parent, String[] classpath, String[] packages) { + return new TransformingClassLoader( parent, classpath ); + } + + public void releaseDynamicFieldInterceptionClassLoader(ClassLoader classLoader) { + if ( ! TransformingClassLoader.class.isAssignableFrom( classLoader.getClass() ) ) { + return; + } + ( ( TransformingClassLoader ) classLoader ).release(); + } } Added: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/TransformingClassLoader.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/javassist/TransformingClassLoader.java 2006-03-04 00:22:05 UTC (rev 9543) +++ trunk/Hibernate3/src/org/hibernate/bytecode/javassist/TransformingClassLoader.java 2006-03-04 00:23:51 UTC (rev 9544) @@ -0,0 +1,57 @@ +package org.hibernate.bytecode.javassist; + +import javassist.ClassPool; +import javassist.NotFoundException; +import javassist.CtClass; +import javassist.CannotCompileException; +import org.hibernate.HibernateException; + +import java.io.IOException; +import java.util.ArrayList; + +/** + * @author Steve Ebersole + */ +public class TransformingClassLoader extends ClassLoader { + private ClassLoader parent; + private ClassPool classPool; + + /*package*/ TransformingClassLoader(ClassLoader parent, String[] classpath) { + this.parent = parent; + classPool = new ClassPool( true ); + for ( int i = 0; i < classpath.length; i++ ) { + try { + classPool.appendClassPath( classpath[i] ); + } + catch ( NotFoundException e ) { + throw new HibernateException( + "Unable to resolve requested classpath for transformation [" + + classpath[i] + "] : " + e.getMessage() + ); + } + } + } + + protected Class findClass(String name) throws ClassNotFoundException { + try { + CtClass cc = classPool.get( name ); + // todo : modify the class definition if not already transformed... + byte[] b = cc.toBytecode(); + return defineClass( name, b, 0, b.length ); + } + catch ( NotFoundException e ) { + throw new ClassNotFoundException(); + } + catch ( IOException e ) { + throw new ClassNotFoundException(); + } + catch ( CannotCompileException e ) { + throw new ClassNotFoundException(); + } + } + + public void release() { + classPool = null; + parent = null; + } +} |