You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2016/04/22 07:37:04 UTC
[2/3] groovy git commit: implement delegation to method
implement delegation to method
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/87fe7865
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/87fe7865
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/87fe7865
Branch: refs/heads/master
Commit: 87fe7865e40718789ea9337e6b50c36f7e64dbc6
Parents: c7e6d4c
Author: oreissig <or...@gmail.com>
Authored: Mon Feb 15 20:12:25 2016 +0100
Committer: paulk <pa...@asert.com.au>
Committed: Fri Apr 22 15:35:25 2016 +1000
----------------------------------------------------------------------
src/main/groovy/lang/Delegate.java | 3 +-
.../transform/DelegateASTTransformation.java | 38 +++++++++++++++-----
.../transform/DelegateTransformTest.groovy | 20 +++++++++++
3 files changed, 52 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/87fe7865/src/main/groovy/lang/Delegate.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/lang/Delegate.java b/src/main/groovy/lang/Delegate.java
index e0e556a..aa61d85 100644
--- a/src/main/groovy/lang/Delegate.java
+++ b/src/main/groovy/lang/Delegate.java
@@ -26,6 +26,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+// TODO update javadoc for use on a getter method
/**
* Field annotation to automatically delegate part of the functionality of an owner class to the annotated field.
* <p>
@@ -128,7 +129,7 @@ import java.lang.annotation.Target;
*/
@java.lang.annotation.Documented
@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
+@Target({ElementType.FIELD, ElementType.METHOD})
@GroovyASTTransformationClass("org.codehaus.groovy.transform.DelegateASTTransformation")
public @interface Delegate {
/**
http://git-wip-us.apache.org/repos/asf/groovy/blob/87fe7865/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java b/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
index 5447acd..7434d8c 100644
--- a/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
@@ -49,6 +49,7 @@ import java.util.Set;
import static org.codehaus.groovy.ast.ClassHelper.make;
import static org.codehaus.groovy.ast.tools.GeneralUtils.assignS;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.getAllMethods;
import static org.codehaus.groovy.ast.tools.GeneralUtils.getAllProperties;
import static org.codehaus.groovy.ast.tools.GeneralUtils.getInterfacesAndSuperInterfaces;
@@ -96,25 +97,46 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
AnnotatedNode parent = (AnnotatedNode) nodes[1];
AnnotationNode node = (AnnotationNode) nodes[0];
+ DelegateDescription delegate = null;
if (parent instanceof FieldNode) {
FieldNode fieldNode = (FieldNode) parent;
- DelegateDescription delegate = new DelegateDescription();
+ delegate = new DelegateDescription();
delegate.delegate = fieldNode;
delegate.annotation = node;
- delegate.delegateName = fieldNode.getName();
+ delegate.name = fieldNode.getName();
delegate.type = fieldNode.getType();
delegate.owner = fieldNode.getOwner();
delegate.getOp = varX(fieldNode);
+ } else if (parent instanceof MethodNode) {
+ MethodNode methodNode = (MethodNode) parent;
+ delegate = new DelegateDescription();
+ delegate.delegate = methodNode;
+ delegate.annotation = node;
+ delegate.name = methodNode.getName();
+ delegate.type = methodNode.getReturnType();
+ delegate.owner = methodNode.getDeclaringClass();
+ delegate.getOp = callThisX(delegate.name);
+
+ if (methodNode.getParameters().length > 0) {
+ addError("You can only delegate to methods that take no parameters, but " +
+ delegate.name + " takes " + methodNode.getParameters().length +
+ " parameters.", parent);
+ return;
+ }
+ }
+
+ if (delegate != null) {
+ // TODO may also be a method
if (delegate.type.equals(ClassHelper.OBJECT_TYPE) || delegate.type.equals(GROOVYOBJECT_TYPE)) {
- addError(MY_TYPE_NAME + " field '" + delegate.delegateName + "' has an inappropriate type: " + delegate.type.getName() +
+ addError(MY_TYPE_NAME + " field '" + delegate.name + "' has an inappropriate type: " + delegate.type.getName() +
". Please add an explicit type but not java.lang.Object or groovy.lang.GroovyObject.", parent);
return;
}
if (delegate.type.equals(delegate.owner)) {
- addError(MY_TYPE_NAME + " field '" + delegate.delegateName + "' has an inappropriate type: " + delegate.type.getName() +
+ addError(MY_TYPE_NAME + " field '" + delegate.name + "' has an inappropriate type: " + delegate.type.getName() +
". Delegation to own type not supported. Please use a different type.", parent);
return;
}
@@ -251,7 +273,7 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
List<String> currentMethodGenPlaceholders = genericPlaceholderNames(candidate);
for (int i = 0; i < newParams.length; i++) {
ClassNode newParamType = correctToGenericsSpecRecurse(genericsSpec, params[i].getType(), currentMethodGenPlaceholders);
- Parameter newParam = new Parameter(newParamType, getParamName(params, i, delegate.delegateName));
+ Parameter newParam = new Parameter(newParamType, getParamName(params, i, delegate.name));
newParam.setInitialExpression(params[i].getInitialExpression());
if (memberHasValue(delegate.annotation, MEMBER_PARAMETER_ANNOTATIONS, true)) {
@@ -264,8 +286,8 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
boolean alsoLazy = !delegate.delegate.getAnnotations(LAZY_TYPE).isEmpty();
// addMethod will ignore attempts to override abstract or static methods with same signature on self
MethodCallExpression mce = callX(
- alsoLazy ? propX(varX("this"), delegate.delegateName.substring(1)) :
- varX(delegate.delegateName, correctToGenericsSpecRecurse(genericsSpec, delegate.type)),
+ // use propX when lazy, because lazy is only allowed on fields
+ alsoLazy ? propX(varX("this"), delegate.name.substring(1)) : delegate.getOp,
candidate.getName(),
args);
mce.setSourcePosition(delegate.delegate);
@@ -314,7 +336,7 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
static class DelegateDescription {
AnnotationNode annotation;
AnnotatedNode delegate;
- String delegateName;
+ String name;
ClassNode type;
ClassNode owner;
Expression getOp;
http://git-wip-us.apache.org/repos/asf/groovy/blob/87fe7865/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy b/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
index 61b6ab2..45218ed 100644
--- a/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
@@ -745,6 +745,15 @@ assert foo.dm.x == '123'
assert delegates.respondsTo('set$')
'''
}
+
+ void testDelegateToGetterMethod() {
+ // given:
+ def delegate = { new DelegateFooImpl() }
+ // when:
+ def foo = new FooToMethod(delegate)
+ // then:
+ assert foo.foo() == delegate().foo()
+ }
}
interface DelegateFoo {
@@ -784,6 +793,17 @@ class Foo4244 {
@Delegate Bar4244 bar = new Bar4244()
}
+class FooToMethod {
+ private final Closure<DelegateFoo> strategy
+
+ FooToMethod(Closure<DelegateFoo> strategy) {
+ this.strategy = strategy
+ }
+
+ @Delegate
+ DelegateFoo getStrategy() { strategy() }
+}
+
class Bar4244 {
String nonFinalBaz = "Initial value - nonFinalBaz"
final String finalBaz = "Initial value - finalBaz"