diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java index 480c5509803..4308fa98838 100644 --- a/src/main/java/groovy/lang/MetaClassImpl.java +++ b/src/main/java/groovy/lang/MetaClassImpl.java @@ -2676,11 +2676,13 @@ public void addMetaBeanProperty(MetaBeanProperty mp) { } /** - *
Retrieves a property on the given receiver for the specified arguments. The sender is the class that is requesting the property from the object. - * The MetaClass will attempt to establish the method to invoke based on the name and arguments provided. - * - *
The useSuper and fromInsideClass help the Groovy runtime perform optimisations on the call to go directly - * to the super class if necessary + * Writes a property on the given receiver for the specified arguments. The + * sender is the class that is requesting the property from the object. The + * MetaClass will attempt to establish the method to invoke based on the name + * and arguments provided. + *
+ * The useSuper and fromInsideClass help the runtime perform optimisations
+ * on the call to go directly to the super class if necessary
*
* @param sender The java.lang.Class instance that is mutating the property
* @param object The Object which the property is being set on
@@ -2751,10 +2753,13 @@ public void setProperty(final Class sender, final Object object, final String na
method = listeners.get(name);
ambiguousListener = (method == AMBIGUOUS_LISTENER_METHOD);
if (method != null && !ambiguousListener && newValue instanceof Closure) {
+ // bean.name = { -> } is short for bean.addSomeListener({ -> });
+ // where "name" derives from the SomeListener interface's method
+ var listener = method.getParameterTypes()[0].getTheClass();
Object proxy = Proxy.newProxyInstance(
- theClass.getClassLoader(),
- new Class[]{method.getParameterTypes()[0].getTheClass()},
- new ConvertedClosure((Closure) newValue, name));
+ listener.getClassLoader(),
+ new Class[]{listener},
+ new ConvertedClosure((Closure>) newValue, name));
arguments = new Object[]{proxy};
newValue = proxy;
} else {
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/TypeTransformers.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/TypeTransformers.java
index 55c77b65bd7..673cc756c0f 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/TypeTransformers.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/TypeTransformers.java
@@ -141,10 +141,10 @@ protected static MethodHandle addTransformer(MethodHandle handle, int pos, Objec
}
/**
- * creates a method handle able to transform the given Closure into a SAM type
- * if the given parameter is a SAM type
+ * Creates a method handle that transforms the given Closure into the given
+ * parameter type, if it is a SAM type.
*/
- private static MethodHandle createSAMTransform(Object arg, Class> parameter) {
+ private static MethodHandle createSAMTransform(Object closure, Class> parameter) {
Method method = CachedSAMClass.getSAMMethod(parameter);
if (method == null) return null;
// TODO: have to think about how to optimize this!
@@ -164,17 +164,14 @@ private static MethodHandle createSAMTransform(Object arg, Class> parameter) {
}
// the following code will basically do this:
// return Proxy.newProxyInstance(
- // arg.getClass().getClassLoader(),
+ // parameter.getClassLoader(),
// new Class[]{parameter},
- // new ConvertedClosure((Closure) arg));
+ // new ConvertedClosure((Closure)closure, method.getName()));
// TO_REFLECTIVE_PROXY will do that for us, though
// input is the closure, the method name, the class loader and the
- // class[]. All of that but the closure must be provided here
+ // class array. All of that but the closure must be provided here.
MethodHandle ret = TO_REFLECTIVE_PROXY;
- ret = MethodHandles.insertArguments(ret, 1,
- method.getName(),
- arg.getClass().getClassLoader(),
- new Class[]{parameter});
+ ret = MethodHandles.insertArguments(ret, 1, method.getName(), parameter.getClassLoader(), new Class[]{parameter});
return ret;
} else {
// the following code will basically do this:
@@ -207,8 +204,8 @@ public static MethodHandle applyUnsharpFilter(MethodHandle handle, int pos, Meth
}
/**
- * returns a transformer later applied as filter to transform one
- * number into another
+ * Returns a transformer later applied as filter to transform one
+ * number into another.
*/
private static MethodHandle selectNumberTransformer(Class> param, Object arg) {
param = TypeHelper.getWrapperClass(param);
diff --git a/src/test/groovy/bugs/Groovy9873.groovy b/src/test/groovy/bugs/Groovy9873.groovy
new file mode 100644
index 00000000000..65afad43ed9
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9873.groovy
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.bugs
+
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy9873 {
+
+ @Test
+ void testCoerceClosure1() {
+ assertScript '''
+ @Grab('io.vavr:vavr:0.10.4;transitive=false')
+ import io.vavr.control.Try
+ class C { }
+ C resolve() {new C()}
+ Try.of(this::resolve)
+ '''
+ }
+
+ @Test
+ void testCoerceClosure2() {
+ def config = new CompilerConfiguration().tap {
+ jointCompilationOptions = [memStub: true]
+ targetDirectory = File.createTempDir()
+ }
+ File parentDir = File.createTempDir()
+ try {
+ def c = new File(parentDir, 'C.groovy')
+ c.write '''
+ class C