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 2018/04/25 13:56:25 UTC

groovy git commit: GROOVY-8559: CLONE - Add @Repeatable java8 annotation support (handle pre-compiled annotations)

Repository: groovy
Updated Branches:
  refs/heads/master 9bcdd74df -> ebebbb31f


GROOVY-8559: CLONE - Add @Repeatable java8 annotation support (handle pre-compiled annotations)


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

Branch: refs/heads/master
Commit: ebebbb31fb949ffbe515edc8bf5810aa2ae9a3b2
Parents: 9bcdd74
Author: Paul King <pa...@asert.com.au>
Authored: Wed Apr 25 23:55:12 2018 +1000
Committer: Paul King <pa...@asert.com.au>
Committed: Wed Apr 25 23:56:19 2018 +1000

----------------------------------------------------------------------
 .../java/org/codehaus/groovy/ast/ClassNode.java |  5 +--
 .../codehaus/groovy/control/ResolveVisitor.java | 18 +++++++--
 src/test/gls/annotations/AnnotationTest.groovy  | 39 ++++++++++++++++++++
 src/test/gls/annotations/Require.java           | 32 ++++++++++++++++
 src/test/gls/annotations/Requires.java          | 30 +++++++++++++++
 5 files changed, 118 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/ebebbb31/src/main/java/org/codehaus/groovy/ast/ClassNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassNode.java b/src/main/java/org/codehaus/groovy/ast/ClassNode.java
index e5d1f03..565e2f9 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassNode.java
@@ -1440,9 +1440,8 @@ public class ClassNode extends AnnotatedNode implements Opcodes {
     }
 
     public boolean isAnnotationDefinition() {
-        return redirect().isPrimaryNode &&
-               isInterface() &&
-               (getModifiers() & Opcodes.ACC_ANNOTATION)!=0;
+        return /* redirect().isPrimaryNode && */
+                isInterface() && (getModifiers() & Opcodes.ACC_ANNOTATION) != 0;
     }
 
     public List<AnnotationNode> getAnnotations() {

http://git-wip-us.apache.org/repos/asf/groovy/blob/ebebbb31/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
index 1bdf9b8..d5d0bf9 100644
--- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -63,6 +63,7 @@ import org.codehaus.groovy.syntax.Types;
 import org.codehaus.groovy.transform.trait.Traits;
 import org.objectweb.asm.Opcodes;
 
+import java.lang.annotation.Annotation;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.Modifier;
@@ -1222,12 +1223,13 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                 member.setValue(newValue);
                 checkAnnotationMemberValue(newValue);
             }
-            if(annType.isResolved()) {
+            if (annType.isResolved()) {
                 Class annTypeClass = annType.getTypeClass();
                 Retention retAnn = (Retention) annTypeClass.getAnnotation(Retention.class);
-                if (retAnn != null && retAnn.value().equals(RetentionPolicy.RUNTIME)) {
+                if (retAnn != null && retAnn.value().equals(RetentionPolicy.RUNTIME) && !isRepeatable(annTypeClass)) {
+                    // remember runtime/non-repeatable annos (auto collecting of Repeatable annotations is handled elsewhere)
                     AnnotationNode anyPrevAnnNode = tmpAnnotations.put(annTypeClass.getName(), an);
-                    if(anyPrevAnnNode != null) {
+                    if (anyPrevAnnNode != null) {
                         addError("Cannot specify duplicate annotation on the same member : " + annType.getName(), an);
                     }
                 }
@@ -1235,6 +1237,16 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         }
     }
 
+    private boolean isRepeatable(Class annTypeClass) {
+        Annotation[] annTypeAnnotations = annTypeClass.getAnnotations();
+        for (Annotation annTypeAnnotation : annTypeAnnotations) {
+            if (annTypeAnnotation.annotationType().getName().equals("java.lang.annotation.Repeatable")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     // resolve constant-looking expressions statically (do here as gets transformed away later)
     private Expression transformInlineConstants(Expression exp) {
         if (exp instanceof PropertyExpression) {

http://git-wip-us.apache.org/repos/asf/groovy/blob/ebebbb31/src/test/gls/annotations/AnnotationTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/gls/annotations/AnnotationTest.groovy b/src/test/gls/annotations/AnnotationTest.groovy
index be77a16..78aa260 100644
--- a/src/test/gls/annotations/AnnotationTest.groovy
+++ b/src/test/gls/annotations/AnnotationTest.groovy
@@ -755,6 +755,45 @@ class AnnotationTest extends CompilableTestSupport {
         '''
     }
 
+    void testAnnotationWithRepeatableSupportedPrecompiledJava() {
+        assertScript '''
+            import java.lang.annotation.*
+            import gls.annotations.*
+
+            class MyClass {
+                // TODO confirm the JDK9 behavior is what we expect
+                private static final List<String> expected = [
+                    '@gls.annotations.Requires(value=[@gls.annotations.Require(value=val1), @gls.annotations.Require(value=val2)])',    // JDK5-8
+                    '@gls.annotations.Requires(value={@gls.annotations.Require(value="val1"), @gls.annotations.Require(value="val2")})' // JDK9
+                ]
+
+                // control
+                @Requires([@Require("val1"), @Require("val2")])
+                String method1() { 'method1' }
+
+                // duplicate candidate for auto collection
+                @Require(value = "val1")
+                @Require(value = "val2")
+                String method2() { 'method2' }
+
+                static void main(String... args) {
+                    MyClass myc = new MyClass()
+                    assert 'method1' == myc.method1()
+                    assert 'method2' == myc.method2()
+                    assert expected.contains(checkAnnos(myc, "method1"))
+                    assert expected.contains(checkAnnos(myc, "method2"))
+                }
+
+                private static String checkAnnos(MyClass myc, String name) {
+                    def m = myc.getClass().getMethod(name)
+                    List annos = m.getAnnotations()
+                    assert annos.size() == 1
+                    annos[0].toString()
+                }
+            }
+        '''
+    }
+
     //Parametrized tests in Spock would allow to make it much more readable
     private static String codeWithMetaAnnotationWithTarget(String targetElementTypeName) {
         """

http://git-wip-us.apache.org/repos/asf/groovy/blob/ebebbb31/src/test/gls/annotations/Require.java
----------------------------------------------------------------------
diff --git a/src/test/gls/annotations/Require.java b/src/test/gls/annotations/Require.java
new file mode 100644
index 0000000..7d51cf2
--- /dev/null
+++ b/src/test/gls/annotations/Require.java
@@ -0,0 +1,32 @@
+/*
+ *  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 gls.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Repeatable(Requires.class)
+public @interface Require {
+    String value() default "";
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/ebebbb31/src/test/gls/annotations/Requires.java
----------------------------------------------------------------------
diff --git a/src/test/gls/annotations/Requires.java b/src/test/gls/annotations/Requires.java
new file mode 100644
index 0000000..b828a59
--- /dev/null
+++ b/src/test/gls/annotations/Requires.java
@@ -0,0 +1,30 @@
+/*
+ *  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 gls.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Requires {
+    Require[] value();
+}