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 2017/04/24 14:12:35 UTC

[1/3] groovy git commit: refactor(idea): do not add blank line after Copyright

Repository: groovy
Updated Branches:
  refs/heads/GROOVY_2_6_X b84d25803 -> 3e7d63d13


refactor(idea): do not add blank line after Copyright


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/34eada61
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/34eada61
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/34eada61

Branch: refs/heads/GROOVY_2_6_X
Commit: 34eada61e111237758948617df0be8c0d204dcec
Parents: b84d258
Author: John Wagenleitner <jw...@apache.org>
Authored: Sat Apr 22 08:22:30 2017 -0700
Committer: paulk <pa...@asert.com.au>
Committed: Tue Apr 25 00:12:20 2017 +1000

----------------------------------------------------------------------
 gradle/idea.gradle | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/34eada61/gradle/idea.gradle
----------------------------------------------------------------------
diff --git a/gradle/idea.gradle b/gradle/idea.gradle
index 510a9cc..21af30f 100644
--- a/gradle/idea.gradle
+++ b/gradle/idea.gradle
@@ -68,7 +68,12 @@ idea {
                           <option name="myName" value="ASL2" />
                           <option name="myLocal" value="true" />
                       </copyright>
-                ''')
+                    ''')
+                    appendNode(copyrightManager, '''
+                        <LanguageOptions name="__TEMPLATE__">
+                            <option name="addBlankAfter" value="false" />
+                        </LanguageOptions>
+                    ''')
                 }
 
                 def compilerConfig = node.component.find { it.@name == 'CompilerConfiguration' }


[3/3] groovy git commit: GROOVY-7579: Improve docs for invokeMethod (closes #528)

Posted by pa...@apache.org.
GROOVY-7579: Improve docs for invokeMethod (closes #528)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/3e7d63d1
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/3e7d63d1
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/3e7d63d1

Branch: refs/heads/GROOVY_2_6_X
Commit: 3e7d63d131434efe1ca32ca5741dc663b9cc1c46
Parents: 4835f80
Author: John Wagenleitner <jw...@apache.org>
Authored: Sun Apr 23 16:06:13 2017 -0700
Committer: paulk <pa...@asert.com.au>
Committed: Tue Apr 25 00:12:21 2017 +1000

----------------------------------------------------------------------
 src/spec/doc/core-metaprogramming.adoc | 43 +++++++++++++++++------------
 1 file changed, 25 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/3e7d63d1/src/spec/doc/core-metaprogramming.adoc
----------------------------------------------------------------------
diff --git a/src/spec/doc/core-metaprogramming.adoc b/src/spec/doc/core-metaprogramming.adoc
index 52344fd..4609d7f 100644
--- a/src/spec/doc/core-metaprogramming.adoc
+++ b/src/spec/doc/core-metaprogramming.adoc
@@ -21,19 +21,19 @@
 
 = Metaprogramming
 
-The Groovy language supports two flavors of metaprogramming: runtime metaprogramming and compile-time metaprogramming.
-The first one allows altering the class model and the behavior of a program at runtime, while the second only occurs
-at compile-time. Both have pros and cons, that we will detail in this section.
+The Groovy language supports two flavors of metaprogramming: runtime and compile-time.
+The first allows altering the class model and the behavior of a program at runtime while the second only occurs
+at compile-time. Both have pros and cons that we will detail in this section.
 
 == Runtime metaprogramming
-With runtime metaprogramming we can postpone to runtime the decision to intercept, inject and even synthesize methods of classes and interfaces. For a deep understanding of Groovy MOP we need to understand Groovy objects and Groovy's method handling.
-In Groovy we work with three kinds of objects: POJO, POGO and Groovy Interceptors. Groovy allows metaprogramming for all types of objects but in different manner.
+With runtime metaprogramming we can postpone to runtime the decision to intercept, inject and even synthesize methods of classes and interfaces. For a deep understanding of Groovy's metaobject protocol (MOP) we need to understand Groovy objects and Groovy's method handling.
+In Groovy we work with three kinds of objects: POJO, POGO and Groovy Interceptors. Groovy allows metaprogramming for all types of objects but in a different manner.
 
-- POJO - A regular Java object, whose class can be written in Java or any other language for the JVM.
-- POGO - A Groovy object, whose class is written in Groovy. It extends `java.lang.Object` and implements the gapi:groovy.lang.GroovyObject[] interface by default.
-- Groovy Interceptor - A Groovy object that implements the gapi:groovy.lang.GroovyInterceptable[] interface and has method-interception capability, which we'll discuss in the <<core-metaprogramming.adoc#_groovyinterceptable,GroovyInterceptable>> section.
+- POJO - A regular Java object whose class can be written in Java or any other language for the JVM.
+- POGO - A Groovy object whose class is written in Groovy. It extends `java.lang.Object` and implements the gapi:groovy.lang.GroovyObject[] interface by default.
+- Groovy Interceptor - A Groovy object that implements the gapi:groovy.lang.GroovyInterceptable[] interface and has method-interception capability which is discussed in the <<core-metaprogramming.adoc#_groovyinterceptable,GroovyInterceptable>> section.
 
-For every method call Groovy checks whether the object is a POJO or a POGO. For POJOs, Groovy fetches it's `MetaClass` from the gapi:groovy.lang.MetaClassRegistry[] and delegates method invocation to it. For POGOs, Groovy takes more steps, as illustrated in the following figure:
+For every method call Groovy checks whether the object is a POJO or a POGO. For POJOs, Groovy fetches its `MetaClass` from the gapi:groovy.lang.MetaClassRegistry[] and delegates method invocation to it. For POGOs, Groovy takes more steps, as illustrated in the following figure:
 
 .Groovy interception mechanism
 image::assets/img/GroovyInterceptions.png[align="center"]
@@ -62,14 +62,21 @@ public interface GroovyObject {
 
 ==== invokeMethod
 
-According to the schema in <<core-metaprogramming.adoc#_runtime_metaprogramming,Runtime Metaprogramming>> this method is called when the method you called is not present on a Groovy object.
-Here is a simple example using a overridden `invokeMethod()` method:
+This method is primarily intended to be used in conjunction with the <<core-metaprogramming.adoc#_groovyinterceptable,GroovyInterceptable>>
+interface or an object's `MetaClass` where it will intercept all method calls.
+
+It is also invoked when the method called is not present on a Groovy object. Here is a simple example using an
+overridden `invokeMethod()` method:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/metaprogramming/GroovyObjectTest.groovy[tags=groovy_invoke_method,indent=0]
 ----
 
+However, the use of `invokeMethod` to intercept missing methods is discouraged.  In cases where the intent is to only
+intercept method calls in the case of a failed method dispatch use <<core-metaprogramming.adoc#_methodmissing,methodMissing>>
+instead.
+
 ==== get/setProperty
 
 Every read access to a property can be intercepted by overriding the `getProperty()` method of the current object.
@@ -90,7 +97,7 @@ include::{projectdir}/src/spec/test/metaprogramming/GroovyObjectTest.groovy[tags
 
 ==== get/setMetaClass
 
-You can a access an object's `metaClass` or set your own `MetaClass` implementation for changing the default interception mechanism. For example you can write your own implementation of the `MetaClass` interface and assign to it to objects and accordingly change the interception mechanism:
+You can a access an object's `metaClass` or set your own `MetaClass` implementation for changing the default interception mechanism. For example, you can write your own implementation of the `MetaClass` interface and assign it to objects in order to change the interception mechanism:
 
 [source,groovy]
 ----
@@ -106,7 +113,7 @@ You can find an additional example in the <<core-metaprogramming.adoc#_groovyint
 
 === get/setAttribute
 
-This functionality is related to the `MetaClass` implementation. In the default implementation you can access fields without invoking their getters and setters. The examples below demonstrate this approach:
+This functionality is related to the `MetaClass` implementation. In the default implementation you can access fields without invoking their getters and setters. The examples below demonstrates this approach:
 
 [source, groovy]
 ----
@@ -121,7 +128,7 @@ include::{projectdir}/src/spec/test/metaprogramming/GroovyObjectTest.groovy[tags
 === methodMissing
 
 Groovy supports the concept of `methodMissing`. This method differs from `invokeMethod` in that it
-is only invoked in case of a failed method dispatch, when no method can be found for the given name and/or the
+is only invoked in the case of a failed method dispatch when no method can be found for the given name and/or the
 given arguments:
 
 [source,groovy]
@@ -131,7 +138,7 @@ include::{projectdir}/src/spec/test/metaprogramming/MethodPropertyMissingTest.gr
 
 Typically when using `methodMissing` it is possible to cache the result for the next time the same method is called.
 
-For example consider dynamic finders in GORM. These are implemented in terms of `methodMissing`. The code resembles
+For example, consider dynamic finders in GORM. These are implemented in terms of `methodMissing`. The code resembles
 something like this:
 
 [source,groovy]
@@ -194,7 +201,7 @@ package groovy.lang;
 public interface GroovyInterceptable extends GroovyObject {
 }
 ----
-When a Groovy object implements the `GroovyInterceptable` interface, it's `invokeMethod()` is called for any method calls. Below you can see a simple example of a object of this type:
+When a Groovy object implements the `GroovyInterceptable` interface, its `invokeMethod()` is called for any method calls. Below you can see a simple example of a object of this type:
 
 [source,groovy]
 ----
@@ -209,9 +216,9 @@ include::{projectdir}/src/spec/test/metaprogramming/InterceptableTest.groovy[tag
 ----
 
 [NOTE]
-We cannot use default groovy methods like `println` because these methods are injected into all groovy objects so they will be intercepted too.
+We cannot use default groovy methods like `println` because these methods are injected into all Groovy objects so they will be intercepted too.
 
-If we want to intercept all methods call but do not want to implement the `GroovyInterceptable` interface we can implement `invokeMethod()` on an object's `MetaClass`.
+If we want to intercept all method calls but do not want to implement the `GroovyInterceptable` interface we can implement `invokeMethod()` on an object's `MetaClass`.
 This approach works for both POGOs and POJOs, as shown by this example:
 
 [source,groovy]


[2/3] groovy git commit: GROOVY-8127: Access to Trait$Trait$Helper#$self is forbidden (closes #529)

Posted by pa...@apache.org.
GROOVY-8127: Access to Trait$Trait$Helper#$self is forbidden (closes #529)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/4835f80a
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/4835f80a
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/4835f80a

Branch: refs/heads/GROOVY_2_6_X
Commit: 4835f80a7c97711ea69539702449ef3b17bffc4e
Parents: 34eada6
Author: paulk <pa...@asert.com.au>
Authored: Mon Apr 24 18:02:34 2017 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Tue Apr 25 00:12:21 2017 +1000

----------------------------------------------------------------------
 .../transform/trait/TraitASTTransformation.java | 22 ++++----
 .../groovy/transform/trait/TraitComposer.java   |  7 +--
 src/test/groovy/bugs/Groovy8127Bug.groovy       | 53 ++++++++++++++++++++
 3 files changed, 70 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/4835f80a/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java b/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
index 8222056..4ac7753 100644
--- a/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
@@ -73,9 +73,13 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
 import static org.codehaus.groovy.transform.trait.SuperCallTraitTransformer.UNRESOLVED_HELPER_CLASS;
 
 /**
- * Handles generation of code for the @Trait annotation. A class annotated with @Trait will generate, instead: <ul>
- * <li>an <i>interface</i> with the same name</li> <li>an utility inner class that will be used by the compiler to
- * handle the trait</li> </ul>
+ * Handles generation of code for the traits (trait keyword is equivalent to using the @Trait annotation).
+ * A class annotated with @Trait will generate, instead:
+ * <ul>
+ * <li>an <i>interface</i> with the same name</li>
+ * <li>a utility inner class that will be used by the compiler to implement the trait</li>
+ * <li>potentially a utility inner class to assist with implementing trait fields</li>
+ * </ul>
  *
  * @author Cedric Champeau
  */
@@ -415,21 +419,21 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
         Expression initialExpression = field.getInitialExpression();
         MethodNode selectedMethod = field.isStatic()?staticInitializer:initializer;
         if (initialExpression != null) {
+            VariableExpression thisObject = new VariableExpression(selectedMethod.getParameters()[0]);
+            ExpressionStatement initCode = new ExpressionStatement(initialExpression);
+            processBody(thisObject, initCode, trait, helper, fieldHelper, knownFields);
             if (field.isFinal()) {
                 String baseName = field.isStatic() ? Traits.STATIC_INIT_METHOD : Traits.INIT_METHOD;
                 MethodNode fieldInitializer = new MethodNode(
                         baseName + Traits.remappedFieldName(trait, field.getName()),
                         ACC_STATIC | ACC_PUBLIC | ACC_SYNTHETIC,
                         field.getOriginType(),
-                        Parameter.EMPTY_ARRAY,
+                        new Parameter[]{createSelfParameter(trait, field.isStatic())},
                         ClassNode.EMPTY_ARRAY,
-                        returnS(initialExpression)
+                        returnS(initCode.getExpression())
                 );
                 helper.addMethod(fieldInitializer);
             }
-            VariableExpression thisObject = new VariableExpression(selectedMethod.getParameters()[0]);
-            ExpressionStatement initCode = new ExpressionStatement(initialExpression);
-            processBody(thisObject, initCode, trait, helper, fieldHelper, knownFields);
             BlockStatement code = (BlockStatement) selectedMethod.getCode();
             MethodCallExpression mce;
             if (field.isStatic()) {
@@ -480,7 +484,7 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
                 ACC_STATIC | ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC,
                 field.getOriginType(),
                 fieldHelper,
-                field.isFinal() ? initialExpression : null
+                null
         );
         // copy annotations from field to dummy field
         List<AnnotationNode> copied = new LinkedList<AnnotationNode>();

http://git-wip-us.apache.org/repos/asf/groovy/blob/4835f80a/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java b/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
index 1025e61..b97f480 100644
--- a/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
+++ b/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
@@ -71,6 +71,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
+import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
@@ -257,13 +258,13 @@ public abstract class TraitComposer {
                             List<AnnotationNode> copied = new LinkedList<AnnotationNode>();
                             List<AnnotationNode> notCopied = new LinkedList<AnnotationNode>();
                             GeneralUtils.copyAnnotatedNodeAnnotations(helperField, copied, notCopied);
-                            FieldNode fieldNode = cNode.addField(fieldName, fieldMods, returnType, (fieldMods & Opcodes.ACC_FINAL) == 0 ? null : helperField.getInitialExpression());
+                            FieldNode fieldNode = cNode.addField(fieldName, fieldMods, returnType, null);
                             fieldNode.addAnnotations(copied);
                             // getInitialExpression above will be null if not in same source unit
                             // so instead set within (static) initializer
-                            if (fieldNode.isFinal() && !(helperClassNode instanceof InnerClassNode)) {
+                            if (fieldNode.isFinal()) {
                                 String baseName = fieldNode.isStatic() ? Traits.STATIC_INIT_METHOD : Traits.INIT_METHOD;
-                                Expression mce = callX(helperClassNode, baseName + fieldNode.getName());
+                                Expression mce = callX(helperClassNode, baseName + fieldNode.getName(), args(varX("this")));
                                 Statement stmt = stmt(assignX(varX(fieldNode.getName(), fieldNode.getType()), mce));
                                 if (isStatic == 0) {
                                     cNode.addObjectInitializerStatements(stmt);

http://git-wip-us.apache.org/repos/asf/groovy/blob/4835f80a/src/test/groovy/bugs/Groovy8127Bug.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/bugs/Groovy8127Bug.groovy b/src/test/groovy/bugs/Groovy8127Bug.groovy
new file mode 100644
index 0000000..842390e
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy8127Bug.groovy
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.bugs
+
+import gls.CompilableTestSupport
+
+class Groovy8127Bug extends CompilableTestSupport {
+    void testTraitWithClosureReferencingField() {
+        assertScript """
+        trait BarTrait {
+            String result = ''
+            public final Runnable bar = { result = 'changeme' } as Runnable
+            void doRun() { bar.run() }
+        }
+
+        class Bar implements BarTrait {}
+
+        def b = new Bar()
+        b.doRun()
+        assert b.result == 'changeme'
+        """
+    }
+
+    void testTraitWithCompileStaticAndCoercedClosure() {
+        shouldCompile """
+        @groovy.transform.CompileStatic
+        trait FooTrait {
+            public final Runnable foo = { println new Date() } as Runnable
+            void doRun() { foo.run() }
+        }
+
+        class Foo implements FooTrait { }
+
+        new Foo().doRun()
+        """
+    }
+}