Skip to content

Commit 4695a35

Browse files
committed
GROOVY-9873: use class loader of SAM type for proxy creation
3_0_X backport
1 parent a249a1b commit 4695a35

File tree

3 files changed

+150
-20
lines changed

3 files changed

+150
-20
lines changed

src/main/java/org/codehaus/groovy/vmplugin/v8/TypeTransformers.java

+10-13
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ protected static MethodHandle addTransformer(MethodHandle handle, int pos, Objec
142142
}
143143

144144
/**
145-
* creates a method handle able to transform the given Closure into a SAM type
146-
* if the given parameter is a SAM type
145+
* Creates a method handle that transforms the given Closure into the given
146+
* parameter type, if it is a SAM type.
147147
*/
148-
private static MethodHandle createSAMTransform(Object arg, Class<?> parameter) {
148+
private static MethodHandle createSAMTransform(Object closure, Class<?> parameter) {
149149
Method method = CachedSAMClass.getSAMMethod(parameter);
150150
if (method == null) return null;
151151
// TODO: have to think about how to optimize this!
@@ -165,17 +165,14 @@ private static MethodHandle createSAMTransform(Object arg, Class<?> parameter) {
165165
}
166166
// the following code will basically do this:
167167
// return Proxy.newProxyInstance(
168-
// arg.getClass().getClassLoader(),
168+
// parameter.getClassLoader(),
169169
// new Class[]{parameter},
170-
// new ConvertedClosure((Closure) arg));
170+
// new ConvertedClosure((Closure)closure, method.getName()));
171171
// TO_REFLECTIVE_PROXY will do that for us, though
172-
// input is the closure, the method name, the class loader and the
173-
// class[]. All of that but the closure must be provided here
172+
// input is the closure, the method name, the class loader and the
173+
// class array. All of that but the closure must be provided here.
174174
MethodHandle ret = TO_REFLECTIVE_PROXY;
175-
ret = MethodHandles.insertArguments(ret, 1,
176-
method.getName(),
177-
arg.getClass().getClassLoader(),
178-
new Class[]{parameter});
175+
ret = MethodHandles.insertArguments(ret, 1, method.getName(), parameter.getClassLoader(), new Class[]{parameter});
179176
return ret;
180177
} else {
181178
// the following code will basically do this:
@@ -208,8 +205,8 @@ public static MethodHandle applyUnsharpFilter(MethodHandle handle, int pos, Meth
208205
}
209206

210207
/**
211-
* returns a transformer later applied as filter to transform one
212-
* number into another
208+
* Returns a transformer later applied as filter to transform one
209+
* number into another.
213210
*/
214211
private static MethodHandle selectNumberTransformer(Class<?> param, Object arg) {
215212
param = TypeHelper.getWrapperClass(param);
+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package groovy.bugs
20+
21+
import org.codehaus.groovy.control.CompilerConfiguration
22+
import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
23+
import org.junit.Test
24+
25+
import static groovy.test.GroovyAssert.assertScript
26+
27+
final class Groovy9873 {
28+
29+
@Test
30+
void testCoerceClosure1() {
31+
assertScript '''
32+
@Grab('io.vavr:vavr:0.10.4;transitive=false')
33+
import io.vavr.control.Try
34+
class C { }
35+
C resolve() {new C()}
36+
Try.of(this::resolve)
37+
'''
38+
}
39+
40+
@Test
41+
void testCoerceClosure2() {
42+
def config = new CompilerConfiguration().tap {
43+
jointCompilationOptions = [memStub: true]
44+
targetDirectory = File.createTempDir()
45+
}
46+
File parentDir = File.createTempDir()
47+
try {
48+
def c = new File(parentDir, 'C.groovy')
49+
c.write '''
50+
class C<T> {
51+
private T t
52+
C(T item) {
53+
t = item
54+
}
55+
static <U> C<U> of(U item) {
56+
new C<U>(item)
57+
}
58+
def <V> C<V> map(F<? super T, ? super V> func) {
59+
new C<V>(func.apply(t))
60+
}
61+
}
62+
'''
63+
def d = new File(parentDir, 'D.groovy')
64+
d.write '''
65+
class D {
66+
static <W> Set<W> wrap(W o) {
67+
Collections.singleton(o)
68+
}
69+
}
70+
'''
71+
def f = new File(parentDir, 'F.groovy')
72+
f.write '''
73+
interface F<X,Y> {
74+
Y apply(X x)
75+
}
76+
'''
77+
def g = new File(parentDir, 'G.groovy')
78+
g.write '''
79+
def c = C.of(123)
80+
def d = c.map(D.&wrap)
81+
def e = d.map(x -> x.first().intValue())
82+
'''
83+
84+
def loader = new GroovyClassLoader(this.class.classLoader)
85+
def cu = new JavaAwareCompilationUnit(config, loader)
86+
cu.addSources(c, d, f, g)
87+
cu.compile()
88+
89+
loader.loadClass('G').main()
90+
} finally {
91+
parentDir.deleteDir()
92+
config.targetDirectory.deleteDir()
93+
}
94+
}
95+
96+
@Test
97+
void testCoerceClosure3() {
98+
def config = new CompilerConfiguration().tap {
99+
jointCompilationOptions = [memStub: true]
100+
targetDirectory = File.createTempDir()
101+
}
102+
File parentDir = File.createTempDir()
103+
try {
104+
def f = new File(parentDir, 'F.groovy')
105+
f.write '''
106+
class FInfo extends EventObject {
107+
FInfo() { super(null) }
108+
}
109+
interface FListener extends EventListener {
110+
void somethingHappened(FInfo i)
111+
}
112+
'''
113+
def g = new File(parentDir, 'G.groovy')
114+
g.write '''
115+
class H {
116+
void addFListener(FListener f) {
117+
f.somethingHappened(null)
118+
}
119+
void removeFListener(FListener f) {
120+
}
121+
}
122+
123+
new H().somethingHappened = { info -> }
124+
'''
125+
126+
def loader = new GroovyClassLoader(this.class.classLoader)
127+
def cu = new JavaAwareCompilationUnit(config, loader)
128+
cu.addSources(f, g)
129+
cu.compile()
130+
131+
loader.loadClass('G').main()
132+
} finally {
133+
parentDir.deleteDir()
134+
config.targetDirectory.deleteDir()
135+
}
136+
}
137+
}

src/test/groovy/transform/stc/GenericsSTCTest.groovy

+3-7
Original file line numberDiff line numberDiff line change
@@ -2722,13 +2722,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
27222722
}
27232723
}
27242724
2725-
void test() {
2726-
def c = C.of(42)
2727-
def d = c.map($toSet)
2728-
def e = d.map(x -> x.first().intValue())
2729-
}
2730-
2731-
test()
2725+
def c = C.of(42)
2726+
def d = c.map($toSet)
2727+
def e = d.map(x -> x.first().intValue())
27322728
"""
27332729
}
27342730
}

0 commit comments

Comments
 (0)