You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/06/03 20:34:02 UTC

[groovy] branch master updated: GROOVY-5453: order category methods before taking first getter/setter

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 445e0f6  GROOVY-5453: order category methods before taking first getter/setter
445e0f6 is described below

commit 445e0f638432a0bdaa9d50a7d5485d9eafdec8aa
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jun 3 15:28:00 2021 -0500

    GROOVY-5453: order category methods before taking first getter/setter
---
 src/main/java/groovy/lang/MetaClassImpl.java       | 69 ++++++----------------
 .../groovy/runtime/GroovyCategorySupport.java      | 24 +++-----
 src/test/groovy/CategoryTest.groovy                | 34 +++++++----
 3 files changed, 50 insertions(+), 77 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index 639514c..2046b3e 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -2187,61 +2187,30 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         return tuple(method, mp);
     }
 
-    private static MetaMethod getCategoryMethodMissing(Class sender) {
-        List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(METHOD_MISSING);
-        if (possibleGenericMethods != null) {
-            for (Object possibleGenericMethod : possibleGenericMethods) {
-                MetaMethod mmethod = (MetaMethod) possibleGenericMethod;
-                if (!mmethod.getDeclaringClass().getTheClass().isAssignableFrom(sender))
-                    continue;
-
-                CachedClass[] paramTypes = mmethod.getParameterTypes();
-                if (paramTypes.length == 2 && paramTypes[0].getTheClass() == String.class) {
-                    return mmethod;
-                }
-            }
-        }
-        return null;
+    private static CategoryMethod getCategoryMethodMissing(final Class<?> sender) {
+        return findCategoryMethod(METHOD_MISSING, sender, params ->
+            params.length == 2 && params[0].getTheClass() == String.class
+        );
     }
 
-    private static MetaMethod getCategoryMethodGetter(Class sender, String name, boolean useLongVersion) {
-        List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(name);
-        if (possibleGenericMethods != null) {
-            for (Object possibleGenericMethod : possibleGenericMethods) {
-                MetaMethod mmethod = (MetaMethod) possibleGenericMethod;
-                if (!mmethod.getDeclaringClass().getTheClass().isAssignableFrom(sender))
-                    continue;
-
-                CachedClass[] paramTypes = mmethod.getParameterTypes();
-                if (useLongVersion) {
-                    if (paramTypes.length == 1 && paramTypes[0].getTheClass() == String.class) {
-                        return mmethod;
-                    }
-                } else {
-                    if (paramTypes.length == 0) return mmethod;
-                }
-            }
-        }
-        return null;
+    private static CategoryMethod getCategoryMethodGetter(final Class<?> sender, final String name, final boolean useLongVersion) {
+        return findCategoryMethod(name, sender, params ->
+            useLongVersion ? params.length == 1 && params[0].getTheClass() == String.class : params.length == 0
+        );
     }
 
-    private static MetaMethod getCategoryMethodSetter(Class sender, String name, boolean useLongVersion) {
-        List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(name);
-        if (possibleGenericMethods != null) {
-            for (Object possibleGenericMethod : possibleGenericMethods) {
-                MetaMethod mmethod = (MetaMethod) possibleGenericMethod;
-                if (!mmethod.getDeclaringClass().getTheClass().isAssignableFrom(sender))
-                    continue;
+    private static CategoryMethod getCategoryMethodSetter(final Class<?> sender, final String name, final boolean useLongVersion) {
+        return findCategoryMethod(name, sender, params ->
+            useLongVersion ? params.length == 2 && params[0].getTheClass() == String.class : params.length == 1
+        );
+    }
 
-                CachedClass[] paramTypes = mmethod.getParameterTypes();
-                if (useLongVersion) {
-                    if (paramTypes.length == 2 && paramTypes[0].getTheClass() == String.class) {
-                        return mmethod;
-                    }
-                } else {
-                    if (paramTypes.length == 1) return mmethod;
-                }
-            }
+    private static CategoryMethod findCategoryMethod(final String name, final Class<?> sender, final java.util.function.Predicate<CachedClass[]> paramFilter) {
+        List<CategoryMethod> categoryMethods = GroovyCategorySupport.getCategoryMethods(name);
+        if (categoryMethods != null) {
+            return categoryMethods.stream().filter(categoryMethod ->
+                categoryMethod.getDeclaringClass().isAssignableFrom(sender) && paramFilter.test(categoryMethod.getParameterTypes())
+            ).sorted().findFirst().orElse(null);
         }
         return null;
     }
diff --git a/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java b/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
index 5fb8396..adbfa33 100644
--- a/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
+++ b/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
@@ -230,28 +230,18 @@ public class GroovyCategorySupport {
         /**
          * Sort by most specific to least specific.
          *
-         * @param o the object to compare against
+         * @param that the object to compare against
          */
         @Override
-        public int compareTo(Object o) {
-            CategoryMethod thatMethod = (CategoryMethod) o;
+        public int compareTo(final Object that) {
             Class thisClass = metaClass;
-            Class thatClass = thatMethod.metaClass;
+            Class thatClass = ((CategoryMethod) that).metaClass;
+
             if (thisClass == thatClass) return 0;
-            if (isChildOfParent(thisClass, thatClass)) return -1;
-            if (isChildOfParent(thatClass, thisClass)) return 1;
-            return 0;
-        }
+            if (thisClass.isAssignableFrom(thatClass)) return 1;
+            if (thatClass.isAssignableFrom(thisClass)) return -1;
 
-        private boolean isChildOfParent(Class candidateChild, Class candidateParent) {
-            Class loop = candidateChild;
-            while(loop != null && loop != Object.class) {
-                loop = loop.getSuperclass();
-                if (loop == candidateParent) {
-                    return true;
-                }
-            }
-            return false;
+            return 0;
         }
     }
 
diff --git a/src/test/groovy/CategoryTest.groovy b/src/test/groovy/CategoryTest.groovy
index 1dbbb99..2a7f73f 100644
--- a/src/test/groovy/CategoryTest.groovy
+++ b/src/test/groovy/CategoryTest.groovy
@@ -180,15 +180,15 @@ final class CategoryTest extends GroovyTestCase {
         """
     }
 
-
     def foo(x){x.bar()}
+
     void testMethodHiding1() {
         def x = new X()
         assert foo(x) == 1
         use (XCat) {
-	        assert foo(x) == 2
-	        def t = Thread.start {assert foo(x)==1}
-	        t.join()
+            assert foo(x) == 2
+            def t = Thread.start {assert foo(x)==1}
+            t.join()
         }
         assert foo(x) == 1
         def t = Thread.start {use (XCat2){assert foo(x)==3}}
@@ -200,12 +200,12 @@ final class CategoryTest extends GroovyTestCase {
         def x = new X()
         assert foo(x) == 1
         use (XCat) {
-	        assert foo(x) == 2
-        	def t = Thread.start {use (XCat2){assert foo(x)==3}}
-        	t.join()
-        	assert foo(x) == 2
-	        t = Thread.start {assert foo(x)==1}
-	        t.join()
+            assert foo(x) == 2
+            def t = Thread.start {use (XCat2){assert foo(x)==3}}
+            t.join()
+            assert foo(x) == 2
+            t = Thread.start {assert foo(x)==1}
+            t.join()
         }
         assert foo(x) == 1
         def t = Thread.start {use (XCat2){assert foo(x)==3}}
@@ -248,6 +248,20 @@ final class CategoryTest extends GroovyTestCase {
         '''
     }
 
+    // GROOVY-5453
+    void testOverloadedGetterMethod() {
+        assertScript '''
+            class Cat {
+                static getFoo(String s) {'String'}
+                static getFoo(CharSequence s) {'CharSequence'}
+            }
+            use (Cat) {
+                assert 'abc'.getFoo() == 'String'
+                assert 'abc'.foo      == 'String'
+            }
+        '''
+    }
+
     // GROOVY-3867
     void testPropertyMissing() {
         def x = new X()