You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/10/12 20:16:21 UTC

[groovy] branch GROOVY_2_5_X updated: GROOVY-8244, GROOVY-10717: proxy method if abstract or no other abstract

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new 7ff5cb5291 GROOVY-8244, GROOVY-10717: proxy method if abstract or no other abstract
7ff5cb5291 is described below

commit 7ff5cb5291fa58c1a5b374dc454e220624ed91c5
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Oct 12 14:26:27 2022 -0500

    GROOVY-8244, GROOVY-10717: proxy method if abstract or no other abstract
    
    2_5_X backport
---
 .../groovy/runtime/ProxyGeneratorAdapter.java      | 172 +++++++++++----------
 src/spec/test/CoercionTest.groovy                  |  31 +++-
 .../traitx/TraitASTTransformationTest.groovy       |   2 -
 3 files changed, 117 insertions(+), 88 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java b/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
index 5ef57edc7c..cb761c04b8 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
@@ -45,8 +45,6 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -82,14 +80,14 @@ import java.util.concurrent.atomic.AtomicLong;
  *
  * @since 2.0.0
  */
+@SuppressWarnings("rawtypes")
 public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
     private static final Map<String, Boolean> EMPTY_DELEGATECLOSURE_MAP = Collections.emptyMap();
-    private static final Set<String> EMPTY_STRING_SET = Collections.emptySet();
+    private static final Object[] EMPTY_ARGS = new Object[0];
 
     private static final String CLOSURES_MAP_FIELD = "$closures$delegate$map";
     private static final String DELEGATE_OBJECT_FIELD = "$delegate";
-    private static final AtomicLong pxyCounter = new AtomicLong();
-    private static final Object[] EMPTY_ARGS = new Object[0];
+    private static final AtomicLong proxyCounter = new AtomicLong();
 
     private static List<Method> OBJECT_METHODS = getInheritedMethods(Object.class, new ArrayList<Method>());
     private static List<Method> GROOVYOBJECT_METHODS = getInheritedMethods(GroovyObject.class, new ArrayList<Method>());
@@ -102,22 +100,20 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         GROOVYOBJECT_METHOD_NAMES = Collections.unmodifiableSet(names);
     }
 
+    private final String proxyName;
     private final Class superClass;
     private final Class delegateClass;
-    private final InnerLoader loader;
-    private final String proxyName;
-    private final LinkedHashSet<Class> classList;
+    private final InnerLoader innerLoader;
+    private final Set<Class > implClasses;
+    private final Set<Object> visitedMethods;
+    private final Set<String> objectDelegateMethods;
     private final Map<String, Boolean> delegatedClosures;
 
-    // if emptyBody == true, then we generate an empty body instead throwing error on unimplemented methods
+    // if emptyBody is true, then we generate an empty body instead throwing error on unimplemented methods
     private final boolean emptyBody;
     private final boolean hasWildcard;
     private final boolean generateDelegateField;
-    private final Set<String> objectDelegateMethods;
 
-    private final Set<Object> visitedMethods;
-
-    // cached class
     private final Class cachedClass;
     private final Constructor cachedNoArgConstructor;
 
@@ -141,7 +137,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
             final boolean emptyBody,
             final Class delegateClass) {
         super(CompilerConfiguration.ASM_API_VERSION, new ClassWriter(0));
-        this.loader = proxyLoader != null ? createInnerLoader(proxyLoader, interfaces) : findClassLoader(superClass, interfaces);
+        this.innerLoader = proxyLoader != null ? createInnerLoader(proxyLoader, interfaces) : findClassLoader(superClass, interfaces);
         this.visitedMethods = new LinkedHashSet<Object>();
         this.delegatedClosures = closureMap.isEmpty() ? EMPTY_DELEGATECLOSURE_MAP : new HashMap<String, Boolean>();
         boolean wildcard = false;
@@ -158,7 +154,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         // 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.objectDelegateMethods = generateDelegateField ? createDelegateMethodList(fixedSuperClass, delegateClass, interfaces) : Collections.<String>emptySet();
         this.delegateClass = delegateClass;
 
         // a proxy is supposed to be a concrete class, so it cannot extend an interface.
@@ -166,15 +162,15 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         // and add this interface to the list of implemented interfaces
         this.superClass = fixedSuperClass;
 
-        // create the base list of classes which have possible methods to be overloaded
-        this.classList = new LinkedHashSet<Class>();
-        this.classList.add(superClass);
+        // collect classes which have possible methods to be overloaded
+        implClasses = new LinkedHashSet<Class>();
+        implClasses.add(superClass);
         if (generateDelegateField) {
-            classList.add(delegateClass);
-            Collections.addAll(this.classList, delegateClass.getInterfaces());
+            implClasses.add(delegateClass);
+            Collections.addAll(implClasses, delegateClass.getInterfaces()); // TODO: filter sealed
         }
         if (interfaces != null) {
-            Collections.addAll(this.classList, interfaces);
+            Collections.addAll(implClasses, interfaces);
         }
         this.proxyName = proxyName();
         this.emptyBody = emptyBody;
@@ -183,8 +179,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         ClassWriter writer = (ClassWriter) cv;
         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 = innerLoader.defineClass(proxyName.replace('/', '.'), b);
         // cache no-arg constructor
         Class[] args = generateDelegateField ? new Class[]{Map.class, delegateClass} : new Class[]{Map.class};
         Constructor constructor;
@@ -209,9 +204,9 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         if (!traits.isEmpty()) {
             String name = superClass.getName() + "$TraitAdapter";
             ClassNode cn = new ClassNode(name, ACC_PUBLIC | ACC_ABSTRACT, ClassHelper.OBJECT_TYPE, traits.toArray(ClassNode.EMPTY_ARRAY), null);
-            CompilationUnit cu = new CompilationUnit(loader);
+            CompilationUnit cu = new CompilationUnit(innerLoader);
             CompilerConfiguration config = new CompilerConfiguration();
-            SourceUnit su = new SourceUnit(name + "wrapper", "", config, loader, new ErrorCollector(config));
+            SourceUnit su = new SourceUnit(name + "wrapper", "", config, innerLoader, new ErrorCollector(config));
             cu.addSource(su);
             cu.compile(Phases.CONVERSION);
             su.getAST().addClass(cn);
@@ -220,7 +215,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
             List<GroovyClass> classes = cu.getClasses();
             for (GroovyClass groovyClass : classes) {
                 if (groovyClass.getName().equals(name)) {
-                    return loader.defineClass(name, groovyClass.getBytes());
+                    return innerLoader.defineClass(name, groovyClass.getBytes());
                 }
             }
         }
@@ -249,20 +244,21 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
     }
 
     private static InnerLoader createInnerLoader(final ClassLoader parent, final Class[] interfaces) {
-        return AccessController.doPrivileged(new PrivilegedAction<InnerLoader>() {
+        return java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<InnerLoader>() {
+            @Override
             public InnerLoader run() {
                 return new InnerLoader(parent, interfaces);
             }
         });
     }
 
-    private InnerLoader findClassLoader(Class clazz, Class[] interfaces) {
+    private InnerLoader findClassLoader(final Class clazz, final Class[] interfaces) {
         ClassLoader cl = clazz.getClassLoader();
         if (cl == null) cl = this.getClass().getClassLoader();
         return createInnerLoader(cl, interfaces);
     }
 
-    private static Set<String> createDelegateMethodList(Class superClass, Class delegateClass, Class[] interfaces) {
+    private static Set<String> createDelegateMethodList(final Class superClass, final Class delegateClass, final Class[] interfaces) {
         Set<String> selectedMethods = new HashSet<String>();
         List<Method> interfaceMethods = new ArrayList<Method>();
         List<Method> superClassMethods = new ArrayList<Method>();
@@ -290,7 +286,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         return selectedMethods;
     }
 
-    private static List<Method> getInheritedMethods(Class baseClass, List<Method> methods) {
+    private static List<Method> getInheritedMethods(final Class baseClass, final List<Method> methods) {
         Collections.addAll(methods, baseClass.getMethods());
         Class currentClass = baseClass;
         while (currentClass != null) {
@@ -306,18 +302,18 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         return methods;
     }
 
-    private static boolean containsEquivalentMethod(Collection<Method> publicAndProtectedMethods, Method candidate) {
+    private static boolean containsEquivalentMethod(final Collection<Method> publicAndProtectedMethods, final Method candidate) {
         for (Method method : publicAndProtectedMethods) {
             if (candidate.getName().equals(method.getName()) &&
                     candidate.getReturnType().equals(method.getReturnType()) &&
-                    hasMatchingParameterTypes(candidate, method)) {
+                    hasMatchingParameterTypes(method, candidate)) {
                 return true;
             }
         }
         return false;
     }
 
-    private static boolean hasMatchingParameterTypes(Method method, Method candidate) {
+    private static boolean hasMatchingParameterTypes(final Method method, final Method candidate) {
         Class[] candidateParamTypes = candidate.getParameterTypes();
         Class[] methodParamTypes = method.getParameterTypes();
         if (candidateParamTypes.length != methodParamTypes.length) return false;
@@ -331,13 +327,13 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
     public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
         Set<String> interfacesSet = new LinkedHashSet<String>();
         if (interfaces != null) Collections.addAll(interfacesSet, interfaces);
-        for (Class extraInterface : classList) {
+        for (Class extraInterface : implClasses) {
             if (extraInterface.isInterface()) interfacesSet.add(BytecodeHelper.getClassInternalName(extraInterface));
         }
         final boolean addGroovyObjectSupport = !GroovyObject.class.isAssignableFrom(superClass);
         if (addGroovyObjectSupport) interfacesSet.add("groovy/lang/GroovyObject");
         if (generateDelegateField) {
-            classList.add(GeneratedGroovyProxy.class);
+            implClasses.add(GeneratedGroovyProxy.class);
             interfacesSet.add("groovy/lang/GeneratedGroovyProxy");
         }
         super.visit(V1_5, ACC_PUBLIC, proxyName, signature, BytecodeHelper.getClassInternalName(superClass), interfacesSet.toArray(new String[0]));
@@ -346,7 +342,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         if (addGroovyObjectSupport) {
             createGroovyObjectSupport();
         }
-        for (Class clazz : classList) {
+        for (Class clazz : implClasses) {
             visitClass(clazz);
         }
     }
@@ -360,7 +356,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
     private void visitClass(final Class clazz) {
         Method[] methods = clazz.getDeclaredMethods();
         for (Method method : methods) {
-            Class<?>[] exceptionTypes = method.getExceptionTypes();
+            Class[] exceptionTypes = method.getExceptionTypes();
             String[] exceptions = new String[exceptionTypes.length];
             for (int i = 0; i < exceptions.length; i++) {
                 exceptions[i] = BytecodeHelper.getClassInternalName(exceptionTypes[i]);
@@ -374,7 +370,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         }
         Constructor[] constructors = clazz.getDeclaredConstructors();
         for (Constructor method : constructors) {
-            Class<?>[] exceptionTypes = method.getExceptionTypes();
+            Class[] exceptionTypes = method.getExceptionTypes();
             String[] exceptions = new String[exceptionTypes.length];
             for (int i = 0; i < exceptions.length; i++) {
                 exceptions[i] = BytecodeHelper.getClassInternalName(exceptionTypes[i]);
@@ -528,11 +524,22 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
             name = name.substring(1, name.length() - 1) + "_array";
         }
         int index = name.lastIndexOf('.');
-        if (index == -1) return name + pxyCounter.incrementAndGet() + "_groovyProxy";
-        return name.substring(index + 1) + pxyCounter.incrementAndGet() + "_groovyProxy";
+        if (index == -1) return name + proxyCounter.incrementAndGet() + "_groovyProxy";
+        return name.substring(index + 1) + proxyCounter.incrementAndGet() + "_groovyProxy";
     }
 
-    private static boolean isImplemented(Class clazz, String name, String desc) {
+    private boolean hasAbstractOverload(final String name) {
+        Method[] methods = superClass.getMethods();
+        for (Method method : methods) {
+            if (method.getName().equals(name)) {
+                if (Modifier.isAbstract(method.getModifiers()))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isImplemented(final Class clazz, final String name, final String desc) {
         Method[] methods = clazz.getDeclaredMethods();
         for (Method method : methods) {
             if (method.getName().equals(name)) {
@@ -547,40 +554,36 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
 
     @Override
     public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
+        // do not generate bytecode for final, native, private or synthetic methods
+        if ((access & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE | ACC_SYNTHETIC)) != 0) return null;
+
         Object key = Arrays.asList(name, desc);
-        if (visitedMethods.contains(key)) return null;
-        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 (!GROOVYOBJECT_METHOD_NAMES.contains(name)) {
-                if (Modifier.isAbstract(access)) {
-                    // prevents the proxy from being abstract
-                    accessFlags -= ACC_ABSTRACT;
-                }
-                if (delegatedClosures.containsKey(name) || (!"<init>".equals(name) && hasWildcard)) {
+        if (!visitedMethods.add(key)) return null;
+
+        boolean objectDelegate = objectDelegateMethods.contains(name + desc);
+        boolean closureDelegate = delegatedClosures.containsKey(name);
+        boolean wildcardDelegate = hasWildcard && !"<init>".equals(name);
+
+        if ((objectDelegate || closureDelegate || wildcardDelegate) && !Modifier.isStatic(access)) {
+            if (!GROOVYOBJECT_METHOD_NAMES.contains(name)
+                    // GROOVY-8244, GROOVY-10717: replace if abstract or no abstract overload exists
+                    && (!Modifier.isAbstract(superClass.getModifiers()) || !isImplemented(superClass, name, desc)
+                                        || ((objectDelegate || closureDelegate) && !hasAbstractOverload(name)))){
+
+                if (closureDelegate || wildcardDelegate || !(objectDelegate && generateDelegateField)) {
                     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);
+                    return makeDelegateToClosureCall(name, desc, signature, exceptions, access & ~ACC_ABSTRACT);
                 }
-                delegatedClosures.put(name, Boolean.TRUE);
-                return makeDelegateToClosureCall(name, desc, signature, exceptions, accessFlags);
+                return makeDelegateCall(name, desc, signature, exceptions, access & ~ACC_ABSTRACT);
             }
         } else if ("getProxyTarget".equals(name) && "()Ljava/lang/Object;".equals(desc)) {
             return createGetProxyTargetMethod(access, name, desc, signature, exceptions);
+
         } else if ("<init>".equals(name) && (Modifier.isPublic(access) || Modifier.isProtected(access))) {
             return createConstructor(access, name, desc, signature, exceptions);
-        } else if (Modifier.isAbstract(access) && !GROOVYOBJECT_METHOD_NAMES.contains(name)) {
-            if (isImplemented(superClass, name, desc)) {
-                return null;
-            }
-            accessFlags -= ACC_ABSTRACT;
-            MethodVisitor mv = super.visitMethod(accessFlags, name, desc, signature, exceptions);
+
+        } else if (Modifier.isAbstract(access) && !GROOVYOBJECT_METHOD_NAMES.contains(name) && !isImplemented(superClass, name, desc)) {
+            MethodVisitor mv = super.visitMethod(access & ~ACC_ABSTRACT, name, desc, signature, exceptions);
             mv.visitCode();
             Type[] args = Type.getArgumentTypes(desc);
             if (emptyBody) {
@@ -619,6 +622,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
             }
             mv.visitEnd();
         }
+
         return null;
     }
 
@@ -633,7 +637,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         return null;
     }
 
-    private static int registerLen(Type[] args) {
+    private static int registerLen(final Type[] args) {
         int i = 0;
         for (Type arg : args) {
             i += registerLen(arg);
@@ -680,7 +684,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         return null;
     }
 
-    private void initializeDelegateClosure(final MethodVisitor mv, Type[] args) {
+    private void initializeDelegateClosure(final MethodVisitor mv, final Type[] args) {
         int idx = 1 + getTypeArgsRegisterLength(args);
 
         mv.visitIntInsn(ALOAD, 0); // this
@@ -689,7 +693,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         mv.visitFieldInsn(PUTFIELD, proxyName, CLOSURES_MAP_FIELD, "Ljava/util/Map;");
     }
 
-    private void initializeDelegateObject(final MethodVisitor mv, Type[] args) {
+    private void initializeDelegateObject(final MethodVisitor mv, final Type[] args) {
         int idx = 2 + getTypeArgsRegisterLength(args);
 
         mv.visitIntInsn(ALOAD, 0); // this
@@ -739,8 +743,6 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
 
     protected MethodVisitor makeDelegateToClosureCall(final String name, final String desc, final String signature, final String[] exceptions, final int accessFlags) {
         MethodVisitor mv = super.visitMethod(accessFlags, name, desc, signature, exceptions);
-//        TraceMethodVisitor tmv = new TraceMethodVisitor(mv);
-//        mv = tmv;
         mv.visitCode();
         int stackSize = 0;
         // method body should be:
@@ -787,11 +789,10 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         unwrapResult(mv, desc);
         mv.visitMaxs(stackSize, arrayStore + 1);
         mv.visitEnd();
-//        System.out.println("tmv.getText() = " + tmv.getText());
         return null;
     }
 
-    private void boxPrimitiveType(MethodVisitor mv, int idx, Type arg) {
+    private void boxPrimitiveType(final MethodVisitor mv, final int idx, final Type arg) {
         if (isPrimitive(arg)) {
             mv.visitIntInsn(getLoadInsn(arg), idx);
             String wrappedType = getWrappedClassDescriptor(arg);
@@ -817,7 +818,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
     }
 
     @SuppressWarnings("unchecked")
-    public GroovyObject proxy(Map<Object, Object> map, Object... constructorArgs) {
+    public GroovyObject proxy(final 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 {
@@ -834,7 +835,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
     }
 
     @SuppressWarnings("unchecked")
-    public GroovyObject delegatingProxy(Object delegate, Map<Object, Object> map, Object... constructorArgs) {
+    public GroovyObject delegatingProxy(final Object delegate, final 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 {
@@ -857,25 +858,25 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
      * Do not trust IDEs, this method is used in bytecode.
      */
     @SuppressWarnings("unchecked")
-    public static Closure ensureClosure(Object o) {
+    public static Closure ensureClosure(final Object o) {
         if (o == null) throw new UnsupportedOperationException();
         if (o instanceof Closure) return (Closure) o;
         return new ReturnValueWrappingClosure(o);
     }
 
-    private static int getLoadInsn(Type type) {
+    private static int getLoadInsn(final Type type) {
         return TypeUtil.getLoadInsnByType(type);
     }
 
-    private static int getReturnInsn(Type type) {
+    private static int getReturnInsn(final Type type) {
         return TypeUtil.getReturnInsnByType(type);
     }
 
-    private static boolean isPrimitive(Type type) {
+    private static boolean isPrimitive(final Type type) {
         return TypeUtil.isPrimitiveType(type);
     }
 
-    private static String getWrappedClassDescriptor(Type type) {
+    private static String getWrappedClassDescriptor(final Type type) {
         return TypeUtil.getWrappedClassDescriptor(type);
     }
 
@@ -897,11 +898,13 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
             }
         }
 
-        public Class defineClass(String name, byte[] data) {
+        @Override
+        public Class defineClass(final String name, final byte[] data) {
             return super.defineClass(name, data, 0, data.length);
         }
 
-        public Class<?> loadClass(String name) throws ClassNotFoundException {
+        @Override
+        public Class<?> loadClass(final String name) throws ClassNotFoundException {
             // First check whether it's already been loaded, if so use it
             Class loadedClass = findLoadedClass(name);
 
@@ -948,7 +951,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         private static final long serialVersionUID = 1313135457715304501L;
         private final V value;
 
-        public ReturnValueWrappingClosure(V returnValue) {
+        public ReturnValueWrappingClosure(final V returnValue) {
             super(null);
             value = returnValue;
         }
@@ -958,5 +961,4 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
             return value;
         }
     }
-
 }
diff --git a/src/spec/test/CoercionTest.groovy b/src/spec/test/CoercionTest.groovy
index e0e114ca10..afca9ad1e0 100644
--- a/src/spec/test/CoercionTest.groovy
+++ b/src/spec/test/CoercionTest.groovy
@@ -16,7 +16,8 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-class CoercionTest extends GroovyTestCase {
+
+final class CoercionTest extends GroovyTestCase {
 
     void testStringToEnumValue() {
         assertScript '''
@@ -297,6 +298,34 @@ println iter.next()
 assert map.i==0
 // end::use_coerced_iterator[]
 '''
+        // "remove()" is an interface default method
+        assertScript '''import static groovy.test.GroovyAssert.shouldFail
+
+            def iter = [next: {->null}, hasNext: {->true}] as Iterator
+            shouldFail(UnsupportedOperationException) {
+                iter.remove()
+            }
+
+            iter = [next: {->null}, hasNext: {->true}, remove: {->}] as Iterator
+            iter.remove()
+        '''
+    }
+
+    // GROOVY-10717
+    void testCoerceMapToAbstract() {
+        assertScript '''import static groovy.test.GroovyAssert.shouldFail
+
+            abstract class A {
+                String b,c
+            }
+
+            def a = [getB: {->'bb'}, getX: {->'xx'}] as A
+            assert a.b == 'bb' // overrides accessor
+            assert a.c == null // generated accessor
+            shouldFail(MissingPropertyException) {
+                a.x
+            }
+        '''
     }
 
     void testCoerceThrowsNPE() {
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index ae6223f019..ff843d4f44 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -18,7 +18,6 @@
  */
 package org.codehaus.groovy.transform.traitx
 
-import groovy.transform.NotYetImplemented
 import groovy.transform.SelfType
 import org.codehaus.groovy.ast.ClassHelper
 import org.codehaus.groovy.ast.expr.ClassExpression
@@ -1212,7 +1211,6 @@ assert phone.speak() == 'My name is Galaxy S3\''''
     }
 
     // GROOVY-8244
-    @NotYetImplemented
     void testSAMCoercion6() {
         assertScript '''
             trait T {