This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 1eeb735e30 GROOVY-11639: include super interface fields in face's
property index
1eeb735e30 is described below
commit 1eeb735e303fdb230feb03ea3b3f44f7e7750e66
Author: Eric Milles <[email protected]>
AuthorDate: Sat Apr 26 17:59:57 2025 -0500
GROOVY-11639: include super interface fields in face's property index
---
src/main/java/groovy/lang/MetaClassImpl.java | 49 +++++++++++-----------
.../codehaus/groovy/reflection/CachedClass.java | 2 +-
.../groovy/lang/DefaultInterfaceMethodsTest.groovy | 27 +++++++++++-
3 files changed, 52 insertions(+), 26 deletions(-)
diff --git a/src/main/java/groovy/lang/MetaClassImpl.java
b/src/main/java/groovy/lang/MetaClassImpl.java
index 495639eac8..168c781216 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -2310,24 +2310,15 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
*/
private void setUpProperties(final PropertyDescriptor[]
propertyDescriptors) {
if (theCachedClass.isInterface) {
- CachedClass superClass = ReflectionCache.OBJECT_CLASS;
- List<CachedClass> superInterfaces = new
ArrayList<>(theCachedClass.getInterfaces());
- superInterfaces.remove(theCachedClass); // always includes
interface theCachedClass
- // sort interfaces so that we may ensure a deterministic behaviour
in case of
- // ambiguous fields -- class implementing two interfaces using the
same field
- if (superInterfaces.size() > 1) {
- superInterfaces.sort(CACHED_CLASS_NAME_COMPARATOR);
+ for (CachedClass iface : theCachedClass.getInterfaces()) { //
includes theCachedClass
+ classPropertyIndex.computeIfAbsent(iface, x -> {
+ var index = new LinkedHashMap<String, MetaProperty>();
+ addConsts(iface, index);
+ return index;
+ });
}
-
- Map<String, MetaProperty> iPropertyIndex =
classPropertyIndex.computeIfAbsent(theCachedClass, x -> new LinkedHashMap<>());
- for (CachedClass sInterface : superInterfaces) {
- Map<String, MetaProperty> sPropertyIndex =
classPropertyIndex.computeIfAbsent(sInterface, x -> new LinkedHashMap<>());
- copyNonPrivateFields(sPropertyIndex, iPropertyIndex, null);
- addFields(sInterface, iPropertyIndex);
- }
- addFields(theCachedClass, iPropertyIndex);
-
applyPropertyDescriptors(propertyDescriptors);
+ CachedClass superClass = ReflectionCache.OBJECT_CLASS;
applyStrayPropertyMethods(superClass,
classPropertyIndex.computeIfAbsent(superClass, x -> new LinkedHashMap<>()),
true);
} else {
List<CachedClass> superClasses = getSuperClasses();
@@ -2339,7 +2330,7 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
}
if (theCachedClass.isArray) { // add the special read-only
"length" property
- LinkedHashMap<String, MetaProperty> map = new
LinkedHashMap<>();
+ var map = new LinkedHashMap<String, MetaProperty>();
map.put("length", arrayLengthProperty);
classPropertyIndex.put(theCachedClass, map);
}
@@ -2437,12 +2428,15 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
}
private void inheritStaticInterfaceFields(List<CachedClass> superClasses,
Iterable<CachedClass> interfaces) {
- for (CachedClass iclass : interfaces) {
- LinkedHashMap<String, MetaProperty> iPropertyIndex =
classPropertyIndex.computeIfAbsent(iclass, k -> new LinkedHashMap<>());
- addFields(iclass, iPropertyIndex);
+ for (CachedClass iface : interfaces) {
+ LinkedHashMap<String, MetaProperty> iPropertyIndex =
classPropertyIndex.computeIfAbsent(iface, x -> {
+ var index = new LinkedHashMap<String, MetaProperty>();
+ addConsts(iface, index);
+ return index;
+ });
for (CachedClass superClass : superClasses) {
- if
(!iclass.getTheClass().isAssignableFrom(superClass.getTheClass())) continue;
- LinkedHashMap<String, MetaProperty> sPropertyIndex =
classPropertyIndex.computeIfAbsent(superClass, k -> new LinkedHashMap<>());
+ if
(!iface.getTheClass().isAssignableFrom(superClass.getTheClass())) continue;
+ LinkedHashMap<String, MetaProperty> sPropertyIndex =
classPropertyIndex.computeIfAbsent(superClass, x -> new LinkedHashMap<>());
copyNonPrivateFields(iPropertyIndex, sPropertyIndex, null);
}
}
@@ -2462,9 +2456,16 @@ public class MetaClassImpl implements MetaClass,
MutableMetaClass {
}
}
- private static void addFields(CachedClass klass, Map<String, MetaProperty>
propertyIndex) {
+ private static void addConsts(final CachedClass iface, final Map<String,
MetaProperty> index) {
+ for (CachedClass superInterface : iface.getDeclaredInterfaces()) { //
GROOVY-11639
+ addConsts(superInterface, index);
+ }
+ addFields(iface, index);
+ }
+
+ private static void addFields(final CachedClass klass, final Map<String,
MetaProperty> index) {
for (CachedField field : klass.getFields()) {
- propertyIndex.put(field.getName(), field);
+ index.put(field.getName(), field);
}
}
diff --git a/src/main/java/org/codehaus/groovy/reflection/CachedClass.java
b/src/main/java/org/codehaus/groovy/reflection/CachedClass.java
index cc9a27b3df..5a89b1a0fc 100644
--- a/src/main/java/org/codehaus/groovy/reflection/CachedClass.java
+++ b/src/main/java/org/codehaus/groovy/reflection/CachedClass.java
@@ -174,7 +174,7 @@ public class CachedClass {
@Override
public Set<CachedClass> initValue() {
Class[] classes = getTheClass().getInterfaces();
- Set<CachedClass> res = new HashSet<>(classes.length);
+ Set<CachedClass> res = new LinkedHashSet<>(classes.length);
for (Class cls : classes) {
res.add(ReflectionCache.getCachedClass(cls));
}
diff --git a/src/test/groovy/groovy/lang/DefaultInterfaceMethodsTest.groovy
b/src/test/groovy/groovy/lang/DefaultInterfaceMethodsTest.groovy
index 82e3ab4ea3..bcd1bab7db 100644
--- a/src/test/groovy/groovy/lang/DefaultInterfaceMethodsTest.groovy
+++ b/src/test/groovy/groovy/lang/DefaultInterfaceMethodsTest.groovy
@@ -18,7 +18,7 @@
*/
package groovy.lang
-import org.junit.Test
+import org.junit.jupiter.api.Test
import static groovy.test.GroovyAssert.assertScript
@@ -58,4 +58,29 @@ final class DefaultInterfaceMethodsTest {
assert new C().m() == 'Bon jour'
'''
}
+
+ // GROOVY-11639
+ @Test
+ void testDefaultMethodUsesSuperProperty() {
+ assertScript '''
+ interface I {
+ String FOO = 'foo'
+ }
+
+ interface J extends I {
+ default m() {
+ return FOO + 'bar'
+ }
+ }
+
+ class C implements J {
+ def xx() {
+ return m() + 'baz'
+ }
+ }
+
+ String result = new C().xx()
+ assert result == 'foobarbaz'
+ '''
+ }
}