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/07/14 03:30:08 UTC
[1/2] groovy git commit: GROOVY-8234: Add @Repeatable java8
annotation support (closes #567)
Repository: groovy
Updated Branches:
refs/heads/GROOVY_2_6_X 0bf5fb7b4 -> bd94384e4
GROOVY-8234: Add @Repeatable java8 annotation support (closes #567)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/8f958c23
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/8f958c23
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/8f958c23
Branch: refs/heads/GROOVY_2_6_X
Commit: 8f958c2348fc0876595f7b934dd447590dc4a6ef
Parents: 0bf5fb7
Author: paulk <pa...@asert.com.au>
Authored: Mon Jun 26 23:17:12 2017 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Fri Jul 14 13:26:19 2017 +1000
----------------------------------------------------------------------
.../groovy/classgen/ExtendedVerifier.java | 72 ++++++++++++++++++--
src/test/gls/annotations/AnnotationTest.groovy | 47 +++++++++++++
2 files changed, 113 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/8f958c23/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java b/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java
index bad5acc..5e13cd7 100644
--- a/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java
+++ b/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java
@@ -18,8 +18,24 @@
*/
package org.codehaus.groovy.classgen;
-import org.codehaus.groovy.ast.*;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.ast.tools.ParameterUtils;
@@ -34,6 +50,7 @@ import org.objectweb.asm.Opcodes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -135,21 +152,64 @@ public class ExtendedVerifier extends ClassCodeVisitorSupport {
addError("Annotations are not supported in the current runtime. " + JVM_ERROR_MESSAGE, node);
return;
}
+ Map<String, List<AnnotationNode>> runtimeAnnotations = new LinkedHashMap<String, List<AnnotationNode>>();
for (AnnotationNode unvisited : node.getAnnotations()) {
AnnotationNode visited = visitAnnotation(unvisited);
- boolean isTargetAnnotation = visited.getClassNode().isResolved() &&
- visited.getClassNode().getName().equals("java.lang.annotation.Target");
+ String name = visited.getClassNode().getName();
+ if (visited.hasRuntimeRetention()) {
+ List<AnnotationNode> seen = runtimeAnnotations.get(name);
+ if (seen == null) {
+ seen = new ArrayList<AnnotationNode>();
+ }
+ seen.add(visited);
+ runtimeAnnotations.put(name, seen);
+ }
+ boolean isTargetAnnotation = name.equals("java.lang.annotation.Target");
// Check if the annotation target is correct, unless it's the target annotating an annotation definition
// defining on which target elements the annotation applies
if (!isTargetAnnotation && !visited.isTargetAllowed(target)) {
- addError("Annotation @" + visited.getClassNode().getName()
- + " is not allowed on element " + AnnotationNode.targetToName(target),
- visited);
+ addError("Annotation @" + name + " is not allowed on element "
+ + AnnotationNode.targetToName(target), visited);
}
visitDeprecation(node, visited);
visitOverride(node, visited);
}
+ checkForDuplicateAnnotations(node, runtimeAnnotations);
+ }
+
+ private void checkForDuplicateAnnotations(AnnotatedNode node, Map<String, List<AnnotationNode>> runtimeAnnotations) {
+ for (Map.Entry<String, List<AnnotationNode>> next : runtimeAnnotations.entrySet()) {
+ if (next.getValue().size() > 1) {
+ ClassNode repeatable = null;
+ AnnotationNode repeatee = next.getValue().get(0);
+ List<AnnotationNode> repeateeAnnotations = repeatee.getClassNode().getAnnotations();
+ for (AnnotationNode anno : repeateeAnnotations) {
+ ClassNode annoClassNode = anno.getClassNode();
+ if (annoClassNode.getName().equals("java.lang.annotation.Repeatable")) {
+ Expression value = anno.getMember("value");
+ if (value instanceof ClassExpression) {
+ ClassExpression ce = (ClassExpression) value;
+ if (ce.getType() != null && ce.getType().isAnnotationDefinition()) {
+ repeatable = ce.getType();
+ break;
+ }
+ }
+ }
+ }
+ if (repeatable != null) {
+ AnnotationNode collector = new AnnotationNode(repeatable);
+ collector.setRuntimeRetention(true); // checked earlier
+ List<Expression> annos = new ArrayList<Expression>();
+ for (AnnotationNode an : next.getValue()) {
+ annos.add(new AnnotationConstantExpression(an));
+ }
+ collector.addMember("value", new ListExpression(annos));
+ node.addAnnotation(collector);
+ node.getAnnotations().removeAll(next.getValue());
+ }
+ }
+ }
}
private static void visitDeprecation(AnnotatedNode node, AnnotationNode visited) {
http://git-wip-us.apache.org/repos/asf/groovy/blob/8f958c23/src/test/gls/annotations/AnnotationTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/gls/annotations/AnnotationTest.groovy b/src/test/gls/annotations/AnnotationTest.groovy
index af32e9b..f4d3826 100644
--- a/src/test/gls/annotations/AnnotationTest.groovy
+++ b/src/test/gls/annotations/AnnotationTest.groovy
@@ -705,6 +705,53 @@ class AnnotationTest extends CompilableTestSupport {
'''
}
+ // GROOVY-8234
+ void testAnnotationWithRepeatableSupported() {
+ assertScript '''
+ import java.lang.annotation.*
+
+ class MyClass {
+ private static final expected = '@MyAnnotationArray(value=[@MyAnnotation(value=val1), @MyAnnotation(value=val2)])'
+
+ // control
+ @MyAnnotationArray([@MyAnnotation("val1"), @MyAnnotation("val2")])
+ String method1() { 'method1' }
+
+ // duplicate candidate for auto collection
+ @MyAnnotation(value = "val1")
+ @MyAnnotation(value = "val2")
+ String method2() { 'method2' }
+
+ static void main(String... args) {
+ MyClass myc = new MyClass()
+ assert 'method1' == myc.method1()
+ assert 'method2' == myc.method2()
+ assert checkAnnos(myc, "method1") == expected
+ assert checkAnnos(myc, "method2") == expected
+ }
+
+ 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()
+ }
+ }
+
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.RUNTIME)
+ @Repeatable(MyAnnotationArray)
+ @interface MyAnnotation {
+ String value() default "val0"
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface MyAnnotationArray {
+ MyAnnotation[] value()
+ }
+ '''
+ }
+
//Parametrized tests in Spock would allow to make it much more readable
private static String codeWithMetaAnnotationWithTarget(String targetElementTypeName) {
"""
[2/2] groovy git commit: GROOVY-8234: Add @Repeatable java8
annotation support (fix for jdk < 1.8)
Posted by pa...@apache.org.
GROOVY-8234: Add @Repeatable java8 annotation support (fix for jdk < 1.8)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/bd94384e
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/bd94384e
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/bd94384e
Branch: refs/heads/GROOVY_2_6_X
Commit: bd94384e401fb3c02948b055b503e084fefed26e
Parents: 8f958c2
Author: paulk <pa...@asert.com.au>
Authored: Fri Jul 14 13:29:39 2017 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Fri Jul 14 13:29:39 2017 +1000
----------------------------------------------------------------------
src/test/gls/annotations/AnnotationTest.groovy | 1 +
1 file changed, 1 insertion(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/bd94384e/src/test/gls/annotations/AnnotationTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/gls/annotations/AnnotationTest.groovy b/src/test/gls/annotations/AnnotationTest.groovy
index f4d3826..504f0e8 100644
--- a/src/test/gls/annotations/AnnotationTest.groovy
+++ b/src/test/gls/annotations/AnnotationTest.groovy
@@ -707,6 +707,7 @@ class AnnotationTest extends CompilableTestSupport {
// GROOVY-8234
void testAnnotationWithRepeatableSupported() {
+ if (System.getProperty('java.specification.version') < '1.8') return
assertScript '''
import java.lang.annotation.*