Skip to content

Commit f5a161f

Browse files
committed
GROOVY-7937: CLONE - same linkedlist code different behavior between groovy and java (fix priority of DGM methods vs actual methods on an object) (closes groovy#418)
1 parent 14266ad commit f5a161f

File tree

2 files changed

+56
-3
lines changed

2 files changed

+56
-3
lines changed

src/main/groovy/lang/MetaClassImpl.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494

9595
import static org.codehaus.groovy.ast.tools.GeneralUtils.inSamePackage;
9696
import static org.codehaus.groovy.ast.tools.GeneralUtils.isDefaultVisibility;
97+
import static org.codehaus.groovy.reflection.ReflectionCache.isAssignableFrom;
9798

9899
/**
99100
* Allows methods to be dynamically added to existing classes at runtime
@@ -625,10 +626,26 @@ private void inheritInterfaceNewMetaMethods(Set<CachedClass> interfaces) {
625626
for (CachedClass cls : interfaces) {
626627
MetaMethod methods[] = getNewMetaMethods(cls);
627628
for (MetaMethod method : methods) {
628-
if (!newGroovyMethodsSet.contains(method)) {
629-
newGroovyMethodsSet.add(method);
629+
boolean skip = false;
630+
// skip DGM methods on an interface if the class already has the method
631+
// but don't skip for GroovyObject-related methods as it breaks things :-(
632+
if (method instanceof GeneratedMetaMethod && !isAssignableFrom(GroovyObject.class, method.getDeclaringClass().getTheClass())) {
633+
for (Method m : theClass.getMethods()) {
634+
if (method.getName().equals(m.getName())
635+
// below not true for DGM#push and also co-variant return scenarios
636+
//&& method.getReturnType().equals(m.getReturnType())
637+
&& MetaMethod.equal(method.getParameterTypes(), m.getParameterTypes())) {
638+
skip = true;
639+
break;
640+
}
641+
}
642+
}
643+
if (!skip) {
644+
if (!newGroovyMethodsSet.contains(method)) {
645+
newGroovyMethodsSet.add(method);
646+
}
647+
addMetaMethodToIndex(method, mainClassMethodHeader);
630648
}
631-
addMetaMethodToIndex(method, mainClassMethodHeader);
632649
}
633650
}
634651
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
class Groovy7937Bug extends GroovyTestCase {
22+
void testMethodsWithinAnInstanceShouldBeChosenAheadOfDGMMethodsOnAnInterface() {
23+
assertScript """
24+
class MyList extends LinkedList<String> {
25+
MyList(Collection c) { super(c) }
26+
String pop() {
27+
'foo'
28+
}
29+
}
30+
MyList stack1 = new MyList(1..3)
31+
assert stack1.pop() == 'foo'
32+
def stack2 = 1..3 as LinkedList
33+
assert stack2.pop() == 1
34+
"""
35+
}
36+
}

0 commit comments

Comments
 (0)