You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2018/05/03 23:49:41 UTC
groovy git commit: GROOVY-3867: Allow methodMissing/propertyMissing
to be defined through category(closes #693)
Repository: groovy
Updated Branches:
refs/heads/master c2404180a -> ad664b181
GROOVY-3867: Allow methodMissing/propertyMissing to be defined through category(closes #693)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/ad664b18
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/ad664b18
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/ad664b18
Branch: refs/heads/master
Commit: ad664b181249c4b8e8821003d7e750632943ce36
Parents: c240418
Author: Ruben Laguna <ru...@gmail.com>
Authored: Fri May 4 07:46:14 2018 +0800
Committer: sunlan <su...@apache.org>
Committed: Fri May 4 07:48:54 2018 +0800
----------------------------------------------------------------------
src/main/groovy/groovy/lang/MetaClassImpl.java | 35 ++++++++++++++-
src/test/groovy/CategoryTest.groovy | 50 ++++++++++++++++++++-
2 files changed, 83 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/ad664b18/src/main/groovy/groovy/lang/MetaClassImpl.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/MetaClassImpl.java b/src/main/groovy/groovy/lang/MetaClassImpl.java
index c798f76..66abb2d 100644
--- a/src/main/groovy/groovy/lang/MetaClassImpl.java
+++ b/src/main/groovy/groovy/lang/MetaClassImpl.java
@@ -945,6 +945,14 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
onInvokeMethodFoundInHierarchy(method);
return method.invoke(instance, invokeMethodArgs);
}
+
+ // last resort look in the category
+ if (method == null && GroovyCategorySupport.hasCategoryInCurrentThread()) {
+ method = getCategoryMethodMissing(instanceKlazz);
+ if (method != null) {
+ return method.invoke(instance, new Object[]{methodName, arguments});
+ }
+ }
}
if (methodMissing != null) {
@@ -1866,11 +1874,18 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
}
}
+ // check for propertyMissing provided through a category
+ Object[] arguments = EMPTY_ARGUMENTS;
+ if (method == null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInCurrentThread()) {
+ method = getCategoryMethodGetter(sender, "propertyMissing", true);
+ if (method != null) arguments = new Object[]{name};
+ }
+
+
//----------------------------------------------------------------------
// generic get method
//----------------------------------------------------------------------
// check for a generic get method provided through a category
- Object[] arguments = EMPTY_ARGUMENTS;
if (method == null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInCurrentThread()) {
method = getCategoryMethodGetter(sender, "get", true);
if (method != null) arguments = new Object[]{name};
@@ -2097,6 +2112,24 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
return new Tuple2<MetaMethod, MetaProperty>(method, mp);
}
+
+ private static MetaMethod getCategoryMethodMissing(Class sender) {
+ List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods("methodMissing");
+ if (possibleGenericMethods != null) {
+ for (Iterator iter = possibleGenericMethods.iterator(); iter.hasNext();) {
+ MetaMethod mmethod = (MetaMethod) iter.next();
+ 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 MetaMethod getCategoryMethodGetter(Class sender, String name, boolean useLongVersion) {
List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(name);
if (possibleGenericMethods != null) {
http://git-wip-us.apache.org/repos/asf/groovy/blob/ad664b18/src/test/groovy/CategoryTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/CategoryTest.groovy b/src/test/groovy/CategoryTest.groovy
index b6cb8e8..efec30c 100644
--- a/src/test/groovy/CategoryTest.groovy
+++ b/src/test/groovy/CategoryTest.groovy
@@ -228,12 +228,60 @@ class CategoryTest extends GroovyTestCase {
}
'''
}
+ // GROOVY-3867
+ void testPropertyMissing() {
+ def x = new X()
+
+ shouldFail(MissingPropertyException) {
+ assert x.baz != "works" // accessing x.baz should throw MPE
+ }
+
+ use(XCat4) {
+ assert x.baz == "works"
+ }
+
+ shouldFail(MissingPropertyException) {
+ assert x.baz != "works" // accessing x.baz should throw MPE
+ }
+ }
+
+ // GROOVY-3867
+ void testMethodMissing() {
+ def x = new X()
+ assert foo(x) == 1
+ use (XCat3) {
+ assert foo(x) == 1 // regular foo() is not affected by methodMissing in category
+ assert x.baz() == 4 // XCat3.methodMissing is called
+ }
+ assert foo(x) == 1
+ def t = Thread.start {use (XCat3){assert x.baz()==4}}
+ t.join()
+ assert foo(x) == 1
+ shouldFail(MissingMethodException) {
+ x.baz()
+ }
+ }
+
+ // GROOVY-3867
+ void testMethodMissingNoStatic() {
+ def x = new X()
+ use (XCat3) {
+ assert x.baz() == 4 // XCat3.methodMissing is called for instance
+ shouldFail(MissingMethodException) {
+ assert X.baz() != 4 // XCat3.methodMissing should not be called for static method of X
+ }
+ }
+ }
+
+
}
class X{ def bar(){1}}
class XCat{ static bar(X x){2}}
class XCat2{ static bar(X x){3}}
+class XCat3{ static methodMissing(X x, String name, args) {4}}
+class XCat4{ static propertyMissing(X x, String name) {"works"}}
class StringCategory {
static String lower(String string) {
@@ -261,4 +309,4 @@ class CategoryTestHelperPropertyReplacer {
private static aVal = "anotherValue"
static getaProperty(CategoryTestHelper self) { return aVal }
static void setaProperty(CategoryTestHelper self, newValue) { aVal = newValue }
-}
+}
\ No newline at end of file