GROOVY-7443: instantiating a class withTraits does not use the classloader of the trait (test and formatting - closes #34)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/3d7e2cae Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/3d7e2cae Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/3d7e2cae Branch: refs/heads/master Commit: 3d7e2cae3b0f86c4cefd995349268ac3be7f5d3c Parents: 03d3720 Author: paulk <pa...@asert.com.au> Authored: Wed Aug 3 11:55:52 2016 +1000 Committer: paulk <pa...@asert.com.au> Committed: Wed Aug 3 11:55:52 2016 +1000 ---------------------------------------------------------------------- .../groovy/runtime/ProxyGeneratorAdapter.java | 182 +++++++++---------- .../util/ProxyGeneratorAdapterTest.groovy | 18 ++ 2 files changed, 102 insertions(+), 98 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/3d7e2cae/src/main/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java b/src/main/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java index 2b09bdb..207a7ca 100644 --- a/src/main/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java +++ b/src/main/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java @@ -24,7 +24,6 @@ import groovy.lang.GroovyClassLoader; import groovy.lang.GroovyObject; import groovy.lang.GroovyRuntimeException; import groovy.transform.Trait; - import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.classgen.asm.BytecodeHelper; @@ -82,8 +81,6 @@ import java.util.concurrent.atomic.AtomicLong; * Internally, the proxy generator makes use of ASM to generate bytecode, for improved performance as compared * to the legacy proxy generation mechanism which made use of string templates. * - * @author Cedric Champeau - * * @since 2.0.0 */ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { @@ -130,13 +127,13 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { * Construct a proxy generator. This generator is used when we need to create a proxy object for a class or an * interface given a map of closures. * - * @param closureMap the delegates implementations - * @param superClass corresponding to the superclass class visitor - * @param interfaces extra interfaces the proxy should implement - * @param proxyLoader the class loader which should be used to load the generated proxy + * @param closureMap the delegates implementations + * @param superClass corresponding to the superclass class visitor + * @param interfaces extra interfaces the proxy should implement + * @param proxyLoader the class loader which should be used to load the generated proxy * @param delegateClass if not null, generate a delegate field with the corresponding class - * @param emptyBody if set to true, the unimplemented abstract methods will receive an empty body instead of - * throwing an {@link UnsupportedOperationException}. + * @param emptyBody if set to true, the unimplemented abstract methods will receive an empty body instead of + * throwing an {@link UnsupportedOperationException}. */ public ProxyGeneratorAdapter( final Map<Object, Object> closureMap, @@ -146,9 +143,9 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { final boolean emptyBody, final Class delegateClass) { super(Opcodes.ASM4, new ClassWriter(0)); - this.loader = proxyLoader!=null?createInnerLoader(proxyLoader, interfaces):findClassLoader(superClass, interfaces); + this.loader = proxyLoader != null ? createInnerLoader(proxyLoader, interfaces) : findClassLoader(superClass, interfaces); this.visitedMethods = new LinkedHashSet<Object>(); - this.delegatedClosures = closureMap.isEmpty()? EMPTY_DELEGATECLOSURE_MAP :new HashMap<String, Boolean>(); + this.delegatedClosures = closureMap.isEmpty() ? EMPTY_DELEGATECLOSURE_MAP : new HashMap<String, Boolean>(); boolean wildcard = false; for (Map.Entry<Object, Object> entry : closureMap.entrySet()) { String name = entry.getKey().toString(); @@ -162,8 +159,8 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { Class fixedSuperClass = adjustSuperClass(superClass, interfaces); // if we have to delegate to another object, generate the appropriate delegate field // and collect the name of the methods for which delegation is active - this.generateDelegateField = delegateClass!=null; - this.objectDelegateMethods = generateDelegateField?createDelegateMethodList(fixedSuperClass, delegateClass, interfaces):EMPTY_STRING_SET; + this.generateDelegateField = delegateClass != null; + this.objectDelegateMethods = generateDelegateField ? createDelegateMethodList(fixedSuperClass, delegateClass, interfaces) : EMPTY_STRING_SET; this.delegateClass = delegateClass; // a proxy is supposed to be a concrete class, so it cannot extend an interface. @@ -178,7 +175,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { classList.add(delegateClass); Collections.addAll(this.classList, delegateClass.getInterfaces()); } - if (interfaces!=null) { + if (interfaces != null) { Collections.addAll(this.classList, interfaces); } this.proxyName = proxyName(); @@ -189,9 +186,9 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { this.visit(Opcodes.V1_5, ACC_PUBLIC, proxyName, null, null, null); byte[] b = writer.toByteArray(); // CheckClassAdapter.verify(new ClassReader(b), true, new PrintWriter(System.err)); - cachedClass = loader.defineClass(proxyName.replace('/','.'), b); + cachedClass = loader.defineClass(proxyName.replace('/', '.'), b); // cache no-arg constructor - Class[] args = generateDelegateField?new Class[] { Map.class, delegateClass }:new Class[] { Map.class }; + Class[] args = generateDelegateField ? new Class[]{Map.class, delegateClass} : new Class[]{Map.class}; Constructor constructor; try { constructor = cachedClass.getConstructor(args); @@ -210,7 +207,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { Set<ClassNode> traits = new LinkedHashSet<ClassNode>(); // check if it's a trait collectTraits(superClass, traits); - if (interfaces!=null) { + if (interfaces != null) { for (Class anInterface : interfaces) { collectTraits(anInterface, traits); } @@ -220,7 +217,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { ClassNode cn = new ClassNode(name, ACC_PUBLIC | ACC_ABSTRACT, ClassHelper.OBJECT_TYPE, traits.toArray(new ClassNode[traits.size()]), null); CompilationUnit cu = new CompilationUnit(loader); CompilerConfiguration config = new CompilerConfiguration(); - SourceUnit su = new SourceUnit(name+"wrapper", "", config, loader, new ErrorCollector(config)); + SourceUnit su = new SourceUnit(name + "wrapper", "", config, loader, new ErrorCollector(config)); cu.addSource(su); cu.compile(Phases.CONVERSION); su.getAST().addClass(cn); @@ -229,7 +226,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { List<GroovyClass> classes = (List<GroovyClass>) cu.getClasses(); for (GroovyClass groovyClass : classes) { if (groovyClass.getName().equals(name)) { - return loader.defineClass(name,groovyClass.getBytes()); + return loader.defineClass(name, groovyClass.getBytes()); } } } @@ -238,7 +235,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { private static void collectTraits(final Class clazz, final Set<ClassNode> traits) { Annotation annotation = clazz.getAnnotation(Trait.class); - if (annotation!=null) { + if (annotation != null) { ClassNode trait = ClassHelper.make(clazz); traits.add(trait.getPlainNodeReference()); LinkedHashSet<ClassNode> selfTypes = new LinkedHashSet<ClassNode>(); @@ -261,7 +258,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { private InnerLoader findClassLoader(Class clazz, Class[] interfaces) { ClassLoader cl = clazz.getClassLoader(); - if (cl==null) cl = this.getClass().getClassLoader(); + if (cl == null) cl = this.getClass().getClassLoader(); return createInnerLoader(cl, interfaces); } @@ -270,13 +267,13 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { List<Method> interfaceMethods = new ArrayList<Method>(); List<Method> superClassMethods = new ArrayList<Method>(); Collections.addAll(superClassMethods, superClass.getDeclaredMethods()); - if (interfaces!=null) { + if (interfaces != null) { for (Class thisInterface : interfaces) { getInheritedMethods(thisInterface, interfaceMethods); } for (Method method : interfaceMethods) { if (!(containsEquivalentMethod(superClassMethods, method))) { - selectedMethods.add(method.getName()+Type.getMethodDescriptor(method)); + selectedMethods.add(method.getName() + Type.getMethodDescriptor(method)); } } } @@ -287,7 +284,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { if (!containsEquivalentMethod(interfaceMethods, method) && !containsEquivalentMethod(OBJECT_METHODS, method) && !containsEquivalentMethod(GROOVYOBJECT_METHODS, method)) { - selectedMethods.add(method.getName()+Type.getMethodDescriptor(method)); + selectedMethods.add(method.getName() + Type.getMethodDescriptor(method)); } } return selectedMethods; @@ -357,6 +354,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { /** * Visit every class/interface this proxy should implement, and generate the appropriate * bytecode for delegation if available. + * * @param clazz an class for which to generate bytecode */ private void visitClass(final Class clazz) { @@ -393,7 +391,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { visitClass(intf); } Class superclass = clazz.getSuperclass(); - if (superclass!=null) visitClass(superclass); + if (superclass != null) visitClass(superclass); // Ultimately, methods can be available in the closure map which are not defined by the superclass // nor the interfaces @@ -512,7 +510,6 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { mv.visitMaxs(2, 2); mv.visitEnd(); } - } /** @@ -521,7 +518,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { private void addDelegateFields() { visitField(ACC_PRIVATE + ACC_FINAL, CLOSURES_MAP_FIELD, "Ljava/util/Map;", null, null); if (generateDelegateField) { - visitField(ACC_PRIVATE+ACC_FINAL, DELEGATE_OBJECT_FIELD, BytecodeHelper.getTypeDescription(delegateClass), null, null); + visitField(ACC_PRIVATE + ACC_FINAL, DELEGATE_OBJECT_FIELD, BytecodeHelper.getTypeDescription(delegateClass), null, null); } } @@ -552,13 +549,13 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) { Object key = Arrays.asList(name, desc); if (visitedMethods.contains(key)) return null; - if (Modifier.isPrivate(access) || Modifier.isNative(access) || ((access&ACC_SYNTHETIC)!=0)) { + if (Modifier.isPrivate(access) || Modifier.isNative(access) || ((access & ACC_SYNTHETIC) != 0)) { // do not generate bytecode for private methods return null; } int accessFlags = access; visitedMethods.add(key); - if ((objectDelegateMethods.contains(name+desc) || delegatedClosures.containsKey(name) || (!"<init>".equals(name) && hasWildcard)) && !Modifier.isStatic(access) && !Modifier.isFinal(access)) { + if ((objectDelegateMethods.contains(name + desc) || delegatedClosures.containsKey(name) || (!"<init>".equals(name) && hasWildcard)) && !Modifier.isStatic(access) && !Modifier.isFinal(access)) { if (!GROOVYOBJECT_METHOD_NAMESS.contains(name)) { if (Modifier.isAbstract(access)) { // prevents the proxy from being abstract @@ -568,8 +565,8 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { delegatedClosures.put(name, Boolean.TRUE); return makeDelegateToClosureCall(name, desc, signature, exceptions, accessFlags); } - if (generateDelegateField && objectDelegateMethods.contains(name+desc)) { - return makeDelegateCall(name, desc, signature, exceptions, accessFlags); + if (generateDelegateField && objectDelegateMethods.contains(name + desc)) { + return makeDelegateCall(name, desc, signature, exceptions, accessFlags); } delegatedClosures.put(name, Boolean.TRUE); return makeDelegateToClosureCall(name, desc, signature, exceptions, accessFlags); @@ -588,24 +585,28 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { Type[] args = Type.getArgumentTypes(desc); if (emptyBody) { Type returnType = Type.getReturnType(desc); - if (returnType==Type.VOID_TYPE) { + if (returnType == Type.VOID_TYPE) { mv.visitInsn(RETURN); } else { int loadIns = getLoadInsn(returnType); switch (loadIns) { - case ILOAD: mv.visitInsn(ICONST_0); + case ILOAD: + mv.visitInsn(ICONST_0); break; - case LLOAD: mv.visitInsn(LCONST_0); + case LLOAD: + mv.visitInsn(LCONST_0); break; - case FLOAD: mv.visitInsn(FCONST_0); + case FLOAD: + mv.visitInsn(FCONST_0); break; - case DLOAD: mv.visitInsn(DCONST_0); + case DLOAD: + mv.visitInsn(DCONST_0); break; default: mv.visitInsn(ACONST_NULL); } mv.visitInsn(getReturnInsn(returnType)); - mv.visitMaxs(2, registerLen(args)+1); + mv.visitMaxs(2, registerLen(args) + 1); } } else { // for compatibility with the legacy proxy generator, we should throw an UnsupportedOperationException @@ -614,7 +615,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "()V", false); mv.visitInsn(ATHROW); - mv.visitMaxs(2, registerLen(args)+1); + mv.visitMaxs(2, registerLen(args) + 1); } mv.visitEnd(); } @@ -624,10 +625,10 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { private MethodVisitor createGetProxyTargetMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_FINAL, name, desc, signature, exceptions); mv.visitCode(); - mv.visitIntInsn(ALOAD,0); + mv.visitIntInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, proxyName, DELEGATE_OBJECT_FIELD, BytecodeHelper.getTypeDescription(delegateClass)); mv.visitInsn(ARETURN); - mv.visitMaxs(1,1); + mv.visitMaxs(1, 1); mv.visitEnd(); return null; } @@ -641,7 +642,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { } private static int registerLen(final Type arg) { - return arg== Type.DOUBLE_TYPE||arg==Type.LONG_TYPE?2:1; + return arg == Type.DOUBLE_TYPE || arg == Type.LONG_TYPE ? 2 : 1; } private MethodVisitor createConstructor(final int access, final String name, final String desc, final String signature, final String[] exceptions) { @@ -673,7 +674,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { } mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superClass), "<init>", desc, false); mv.visitInsn(RETURN); - int max = idx + 1 + (generateDelegateField?1:0); + int max = idx + 1 + (generateDelegateField ? 1 : 0); mv.visitMaxs(max, max); mv.visitEnd(); return null; @@ -696,9 +697,11 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { mv.visitFieldInsn(PUTFIELD, proxyName, DELEGATE_OBJECT_FIELD, BytecodeHelper.getTypeDescription(delegateClass)); } - private static int getTypeArgsRegisterLength(Type[] args) { + private static int getTypeArgsRegisterLength(Type[] args) { int length = 0; - for (Type type : args) { length += registerLen(type); } + for (Type type : args) { + length += registerLen(type); + } return length; } @@ -729,7 +732,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { } else { mv.visitVarInsn(ALOAD, idx); // load argument i } - size = Math.max(size, 5+registerLen(arg)); + size = Math.max(size, 5 + registerLen(arg)); idx += registerLen(arg); mv.visitInsn(AASTORE); // store value into array } @@ -749,7 +752,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { // method body should be: // this.$delegate$closure$methodName.call(new Object[] { method arguments }) Type[] args = Type.getArgumentTypes(desc); - int arrayStore = args.length+1; + int arrayStore = args.length + 1; BytecodeHelper.pushConstant(mv, args.length); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); // stack size = 1 stackSize = 1; @@ -768,7 +771,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { mv.visitVarInsn(ALOAD, idx); // load argument i } idx += registerLen(arg); - stackSize = Math.max(4, 3+registerLen(arg)); + stackSize = Math.max(4, 3 + registerLen(arg)); mv.visitInsn(AASTORE); // store value into array } mv.visitVarInsn(ASTORE, arrayStore); // store array @@ -795,7 +798,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { stackSize++; mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Closure", "call", "([Ljava/lang/Object;)Ljava/lang/Object;", false); // call closure unwrapResult(mv, desc); - mv.visitMaxs(stackSize, arrayStore+1); + mv.visitMaxs(stackSize, arrayStore + 1); mv.visitEnd(); // System.out.println("tmv.getText() = " + tmv.getText()); return null; @@ -803,7 +806,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { private static void unwrapResult(final MethodVisitor mv, final String desc) { Type returnType = Type.getReturnType(desc); - if (returnType==Type.VOID_TYPE) { + if (returnType == Type.VOID_TYPE) { mv.visitInsn(POP); mv.visitInsn(RETURN); } else { @@ -817,8 +820,8 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { } @SuppressWarnings("unchecked") - public GroovyObject proxy(Map<Object,Object> map, Object... constructorArgs) { - if (constructorArgs==null && cachedNoArgConstructor!=null) { + public GroovyObject proxy(Map<Object, Object> map, Object... constructorArgs) { + if (constructorArgs == null && cachedNoArgConstructor != null) { // if there isn't any argument, we can make invocation faster using the cached constructor try { return (GroovyObject) cachedNoArgConstructor.newInstance(map); @@ -830,16 +833,16 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { throw new GroovyRuntimeException(e); } } - if (constructorArgs==null) constructorArgs= EMPTY_ARGS; + if (constructorArgs == null) constructorArgs = EMPTY_ARGS; Object[] values = new Object[constructorArgs.length + 1]; System.arraycopy(constructorArgs, 0, values, 0, constructorArgs.length); - values[values.length-1] = map; + values[values.length - 1] = map; return DefaultGroovyMethods.<GroovyObject>newInstance(cachedClass, values); } @SuppressWarnings("unchecked") - public GroovyObject delegatingProxy(Object delegate,Map<Object,Object> map, Object... constructorArgs) { - if (constructorArgs==null && cachedNoArgConstructor!=null) { + public GroovyObject delegatingProxy(Object delegate, Map<Object, Object> map, Object... constructorArgs) { + if (constructorArgs == null && cachedNoArgConstructor != null) { // if there isn't any argument, we can make invocation faster using the cached constructor try { return (GroovyObject) cachedNoArgConstructor.newInstance(map, delegate); @@ -851,11 +854,11 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { throw new GroovyRuntimeException(e); } } - if (constructorArgs==null) constructorArgs= EMPTY_ARGS; + if (constructorArgs == null) constructorArgs = EMPTY_ARGS; Object[] values = new Object[constructorArgs.length + 2]; System.arraycopy(constructorArgs, 0, values, 0, constructorArgs.length); - values[values.length-2] = map; - values[values.length-1] = delegate; + values[values.length - 2] = map; + values[values.length - 1] = delegate; return DefaultGroovyMethods.<GroovyObject>newInstance(cachedClass, values); } @@ -866,7 +869,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { */ @SuppressWarnings("unchecked") public static Closure ensureClosure(Object o) { - if (o==null) throw new UnsupportedOperationException(); + if (o == null) throw new UnsupportedOperationException(); if (o instanceof Closure) return (Closure) o; return new ReturnValueWrappingClosure(o); } @@ -918,18 +921,17 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { throw new IllegalArgumentException("Unexpected type class [" + type + "]"); } - private static class InnerLoader extends GroovyClassLoader { - List<ClassLoader> internalClassLoaders = null; protected InnerLoader(final ClassLoader parent, final Class[] interfaces) { super(parent); - if(interfaces != null) { - for(Class c : interfaces) { - if(c.getClassLoader() != parent) { - if(internalClassLoaders == null) internalClassLoaders = new ArrayList<ClassLoader>(interfaces.length); - if( ! internalClassLoaders.contains(c.getClassLoader()) ) { + if (interfaces != null) { + for (Class c : interfaces) { + if (c.getClassLoader() != parent) { + if (internalClassLoaders == null) + internalClassLoaders = new ArrayList<ClassLoader>(interfaces.length); + if (!internalClassLoaders.contains(c.getClassLoader())) { internalClassLoaders.add(c.getClassLoader()); } } @@ -944,63 +946,47 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes { public Class<?> loadClass(String name) throws ClassNotFoundException { // First check whether it's already been loaded, if so use it Class loadedClass = findLoadedClass(name); - + if (loadedClass != null) return loadedClass; - - //check this class loader + // Check this class loader try { - loadedClass = findClass(name); - - } catch (ClassNotFoundException e) { } - - if(loadedClass != null) return loadedClass; + } catch (ClassNotFoundException ignore) { + } - - //check parent classloader, keep the exception for future use + if (loadedClass != null) return loadedClass; + + // Check parent classloader, keep the exception for future use ClassNotFoundException ex = null; try { loadedClass = super.loadClass(name); - } catch(ClassNotFoundException e) { + } catch (ClassNotFoundException e) { ex = e; } - + if (loadedClass != null) return loadedClass; - - - // Not loaded, try to load it - if(internalClassLoaders != null) { - for(ClassLoader i : internalClassLoaders) { + // Not loaded, try to load it + if (internalClassLoaders != null) { + for (ClassLoader i : internalClassLoaders) { try { // Ignore parent delegation and just try to load locally - loadedClass = i.loadClass(name); - - if(loadedClass != null) return loadedClass; - + if (loadedClass != null) return loadedClass; } catch (ClassNotFoundException e) { // Swallow exception - does not exist locally } - } - } - - //throw parent exception if exists, otherwise create a new exception - if(ex != null) throw ex; - + // Throw earlier exception from parent loader if it exists, otherwise create a new exception + if (ex != null) throw ex; throw new ClassNotFoundException(name); - } - } - - - private static class ReturnValueWrappingClosure<V> extends Closure<V>{ + private static class ReturnValueWrappingClosure<V> extends Closure<V> { private final V value; public ReturnValueWrappingClosure(V returnValue) { http://git-wip-us.apache.org/repos/asf/groovy/blob/3d7e2cae/src/test/groovy/util/ProxyGeneratorAdapterTest.groovy ---------------------------------------------------------------------- diff --git a/src/test/groovy/util/ProxyGeneratorAdapterTest.groovy b/src/test/groovy/util/ProxyGeneratorAdapterTest.groovy index 393dad4..a9d2fc9 100644 --- a/src/test/groovy/util/ProxyGeneratorAdapterTest.groovy +++ b/src/test/groovy/util/ProxyGeneratorAdapterTest.groovy @@ -172,6 +172,24 @@ class ProxyGeneratorAdapterTest extends GroovyTestCase { ''' } + static class ClassA {} + static trait Trait1 { def method1() { 'Trait1 method' } } + + // GROOVY-7443 + void testTraitFromDifferentClassloader() { + def aWith1 = new ClassA().withTraits(Trait1) + assert aWith1.method1() == 'Trait1 method' + GroovyClassLoader gcl = new GroovyClassLoader(Thread.currentThread().contextClassLoader) + Class classB = gcl.parseClass('class ClassB {}') + Class trait2 = gcl.parseClass('trait Trait2 { def method2() { "Trait2 method" } }') + def bWith1 = classB.newInstance().withTraits(Trait1) + assert bWith1.method1() == 'Trait1 method' + def bWith2 = classB.newInstance().withTraits(trait2) + assert bWith2.method2() == 'Trait2 method' + def aWith2 = new ClassA().withTraits(trait2) + assert aWith2.method2() == 'Trait2 method' + } + void testGetTypeArgsRegisterLength() { def types = { list -> list as org.objectweb.asm.Type[] } def proxyGeneratorAdapter = new ProxyGeneratorAdapter([:], Object, [] as Class[], null, false, Object)