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

Reply via email to