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
commit 4dbda66ab4cffeee9bf726a01a7ca295b2500b5c Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Wed Jul 16 14:26:31 2025 -0500 GROOVY-8283: propagate sender class for `setGroovyObjectProperty` --- src/main/java/groovy/lang/MetaClassImpl.java | 20 +++++++++-------- .../groovy/runtime/ScriptBytecodeAdapter.java | 26 +++++++++++++++------- src/test/groovy/bugs/Groovy8283.groovy | 4 ---- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java index 01307b3df8..414de5606a 100644 --- a/src/main/java/groovy/lang/MetaClassImpl.java +++ b/src/main/java/groovy/lang/MetaClassImpl.java @@ -138,9 +138,9 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { private static final String GET_PROPERTY_METHOD = "getProperty"; private static final String SET_PROPERTY_METHOD = "setProperty"; - private static final Class[] METHOD_MISSING_ARGS = new Class[]{String.class, Object.class}; - private static final Class[] GETTER_MISSING_ARGS = new Class[]{String.class}; - private static final Class[] SETTER_MISSING_ARGS = METHOD_MISSING_ARGS; + private static final Class<?>[] GETTER_MISSING_ARGS = {String.class}; + private static final Class<?>[] SETTER_MISSING_ARGS = {String.class,Object.class}; + private static final Class<?>[] METHOD_MISSING_ARGS = {String.class,Object.class}; private static final MetaMethod AMBIGUOUS_LISTENER_METHOD = new DummyMetaMethod(); private static final Comparator<CachedClass> CACHED_CLASS_NAME_COMPARATOR = Comparator.comparing(CachedClass::getName); private static final boolean PERMISSIVE_PROPERTY_ACCESS = SystemUtil.getBooleanSafe("groovy.permissive.property.access"); @@ -265,9 +265,11 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { */ @Override public List<MetaMethod> respondsTo(final Object obj, final String name) { - final Object o = getMethods(getTheClass(), name, false); + Object o = getMethods(getTheClass(), name, false); if (o instanceof FastArray) { - return ((FastArray) o).toList(); + @SuppressWarnings("unchecked") + List<MetaMethod> l = ((FastArray) o).toList(); + return l; } return Collections.singletonList((MetaMethod) o); } @@ -974,7 +976,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { * @return The value in the case of a getter or a MissingPropertyException */ protected Object invokeStaticMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter) { - MetaClass mc = instance instanceof Class ? registry.getMetaClass((Class) instance) : this; + MetaClass mc = instance instanceof Class ? registry.getMetaClass((Class<?>) instance) : this; if (isGetter) { MetaMethod propertyMissing = mc.getMetaMethod(STATIC_PROPERTY_MISSING, GETTER_MISSING_ARGS); if (propertyMissing != null) { @@ -988,7 +990,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { } if (instance instanceof Class) { - throw new MissingPropertyException(propertyName, (Class) instance); + throw new MissingPropertyException(propertyName, (Class<?>) instance); } throw new MissingPropertyException(propertyName, theClass); } @@ -2089,7 +2091,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { * Object#getClass and Map#isEmpty */ private boolean isSpecialProperty(final String name) { - return "class".equals(name) || (isMap && ("empty".equals(name))); + return "class".equals(name) || (isMap && "empty".equals(name)); } private boolean isVisibleProperty(final MetaProperty field, final MetaMethod method, final Class<?> sender) { @@ -2107,7 +2109,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { return !owner.isAssignableFrom(method.getDeclaringClass().getTheClass()) && !method.getDeclaringClass().isInterface(); } - private Tuple2<MetaMethod, MetaProperty> createMetaMethodAndMetaProperty(final Class sender, final String name, final boolean useSuper, final boolean isStatic) { + private Tuple2<MetaMethod, MetaProperty> createMetaMethodAndMetaProperty(final Class<?> sender, final String name, final boolean useSuper, final boolean isStatic) { MetaMethod method = null; MetaProperty mp = getMetaProperty(sender, name, useSuper, isStatic); if ((mp == null || mp instanceof CachedField) && !name.isEmpty() && isUpperCase(name.charAt(0)) && (name.length() < 2 || !isUpperCase(name.charAt(1))) && !"Class".equals(name) && !"MetaClass".equals(name)) { diff --git a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java index 5860340946..93d5720064 100644 --- a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java +++ b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java @@ -541,14 +541,19 @@ public class ScriptBytecodeAdapter { // -------------------------------------------------------- public static Object getGroovyObjectProperty(Class senderClass, GroovyObject receiver, String messageName) throws Throwable { + Class<?> receiverClass = receiver.getClass(); try { - return receiver.getProperty(messageName); - } catch (GroovyRuntimeException gre) { - if (gre instanceof MissingPropertyException && senderClass!=receiver.getClass() && senderClass.isInstance(receiver)) { - return receiver.getMetaClass().getProperty(senderClass, receiver, messageName, false, false); +// if (!receiverClass.getMethod("getProperty", String.class).isDefault()) { + return receiver.getProperty(messageName); +// } + } catch (MissingPropertyException mpe) { + if (senderClass == receiverClass || !senderClass.isInstance(receiver)) { + throw unwrap(mpe); } + } catch (GroovyRuntimeException gre) { throw unwrap(gre); } + return receiver.getMetaClass().getProperty(senderClass, receiver, messageName, false, false); } public static Object getGroovyObjectPropertySafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable { @@ -570,15 +575,20 @@ public class ScriptBytecodeAdapter { // -------------------------------------------------------- public static void setGroovyObjectProperty(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable { + Class<?> receiverClass = receiver.getClass(); try { - receiver.setProperty(messageName, messageArgument); - } catch (GroovyRuntimeException gre) { // GROOVY-3142: retry with super sender class? - if (gre instanceof MissingPropertyException && senderClass != receiver.getClass() && senderClass.isInstance(receiver)) { - receiver.getMetaClass().setProperty(senderClass, receiver, messageName, messageArgument, false, false); + if (!receiverClass.getMethod("setProperty", String.class, Object.class).isDefault()) { + receiver.setProperty(messageName, messageArgument); return; } + } catch (MissingPropertyException mpe) { + if (senderClass == receiverClass || !senderClass.isInstance(receiver)) { + throw unwrap(mpe); + } + } catch (GroovyRuntimeException gre) { throw unwrap(gre); } + receiver.getMetaClass().setProperty(senderClass, receiver, messageName, messageArgument, false, false); } public static void setGroovyObjectPropertySafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable { diff --git a/src/test/groovy/bugs/Groovy8283.groovy b/src/test/groovy/bugs/Groovy8283.groovy index 5afbe01d3f..2ff3e75f29 100644 --- a/src/test/groovy/bugs/Groovy8283.groovy +++ b/src/test/groovy/bugs/Groovy8283.groovy @@ -331,12 +331,10 @@ final class Groovy8283 { assert fooB == null } void test2() { - /* TODO this.foo = null assert !setter assert fooA != null assert fooB == null - */ } void test3() { this.@foo = null @@ -352,14 +350,12 @@ final class Groovy8283 { } void test5() { def that = new E() - /* TODO that.foo = null assert !that.setter assert that.fooA != null assert that.fooB == null that = new E() - */ that.@foo = null assert !that.setter assert that.fooA != null