Skip to content

Commit

Permalink
GROOVY-9541
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Nov 21, 2022
1 parent f3616f0 commit 51ed232
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ private void checkForDuplicateAnnotations(AnnotatedNode node, Map<String, List<A
}
if (repeatable != null) {
AnnotationNode collector = new AnnotationNode(repeatable);
/* GRECLIPSE edit
/* GRECLIPSE edit -- GROOVY-4156, GROOVY-9541, et al.
if (repeatable.isResolved()) {
Class repeatableType = repeatable.getTypeClass();
Retention retAnn = (Retention) repeatableType.getAnnotation(Retention.class);
Expand All @@ -214,8 +214,7 @@ private void checkForDuplicateAnnotations(AnnotatedNode node, Map<String, List<A
collector.setClassRetention(repeatee.hasClassRetention());
collector.setRuntimeRetention(repeatee.hasRuntimeRetention());
// GRECLIPSE end

List<Expression> annos = new ArrayList<Expression>();
List<Expression> annos = new ArrayList<>();
for (AnnotationNode an : next.getValue()) {
annos.add(new AnnotationConstantExpression(an));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
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.expr.PropertyExpression;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.control.AnnotationConstantsVisitor;
Expand All @@ -42,14 +42,15 @@
import groovyjarjarasm.asm.Opcodes;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;
import static org.codehaus.groovy.ast.ClassHelper.makeCached;
import static org.codehaus.groovy.ast.tools.GeneralUtils.getInterfacesAndSuperInterfaces;
import static org.codehaus.groovy.ast.tools.GeneralUtils.listX;
import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
Expand Down Expand Up @@ -191,10 +192,10 @@ protected void visitAnnotations(AnnotatedNode node, int target) {
}

private void checkForDuplicateAnnotations(AnnotatedNode node, Map<String, List<AnnotationNode>> nonSourceAnnotations) {
for (Map.Entry<String, List<AnnotationNode>> next : nonSourceAnnotations.entrySet()) {
if (next.getValue().size() > 1) {
for (Map.Entry<String, List<AnnotationNode>> entry : nonSourceAnnotations.entrySet()) {
if (entry.getValue().size() > 1) {
ClassNode repeatable = null;
AnnotationNode repeatee = next.getValue().get(0);
AnnotationNode repeatee = entry.getValue().get(0);
for (AnnotationNode anno : repeatee.getClassNode().getAnnotations()) {
if (anno.getClassNode().getName().equals("java.lang.annotation.Repeatable")) {
Expression value = anno.getMember("value");
Expand All @@ -206,29 +207,32 @@ private void checkForDuplicateAnnotations(AnnotatedNode node, Map<String, List<A
}
if (repeatable != null) {
if (nonSourceAnnotations.containsKey(repeatable.getName())) {
addError("Cannot specify duplicate annotation on the same member. Explicit " + repeatable.getName()
+ " found when creating implicit container for " + next.getKey(), node);
addError("Cannot specify duplicate annotation on the same member. Explicit " + repeatable.getName() + " found when creating implicit container for " + entry.getKey(), node);
}
AnnotationNode collector = new AnnotationNode(repeatable);
if (repeatee.hasRuntimeRetention()) {
if (repeatee.hasClassRetention()) {
collector.setClassRetention(true);
} else if (repeatee.hasRuntimeRetention()) {
collector.setRuntimeRetention(true);
} else if (repeatable.hasClass()) { // GRECLIPSE edit
Class<?> repeatableType = repeatable.getTypeClass();
Retention retention = repeatableType.getAnnotation(Retention.class);
collector.setRuntimeRetention(retention != null && retention.value().equals(RetentionPolicy.RUNTIME));
} else {
for (AnnotationNode annotation : repeatable.getAnnotations()) {
if (annotation.getClassNode().getName().equals("java.lang.annotation.Retention")) {
Expression value = annotation.getMember("value"); assert value != null;
Object retention = evaluateExpression(value, source.getConfiguration());
collector.setRuntimeRetention(retention != null && retention.toString().equals("RUNTIME"));
break;
} else { // load retention policy from annotation definition
List<AnnotationNode> retention = repeatable.getAnnotations(makeCached(Retention.class));
if (!retention.isEmpty()) {
Object policy;
Expression value = retention.get(0).getMember("value");
if (value instanceof PropertyExpression) {
policy = ((PropertyExpression) value).getPropertyAsString();
} else { // NOTE: it is risky to evaluate the expression from repeatable's source this way:
policy = evaluateExpression(value, source.getConfiguration(), source.getClassLoader());
}
if ("CLASS".equals(policy)) {
collector.setClassRetention(true);
} else if ("RUNTIME".equals(policy)) {
collector.setRuntimeRetention(true);
}
}
}
collector.addMember("value", new ListExpression(next.getValue().stream()
.map(AnnotationConstantExpression::new).collect(Collectors.toList())));
node.getAnnotations().removeAll(next.getValue());
collector.addMember("value", listX(entry.getValue().stream().map(AnnotationConstantExpression::new).collect(toList())));
node.getAnnotations().removeAll(entry.getValue());
node.addAnnotation(collector);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
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.expr.PropertyExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
Expand All @@ -44,14 +44,13 @@
import groovyjarjarasm.asm.Opcodes;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;
import static org.codehaus.groovy.ast.AnnotationNode.ANNOTATION_TARGET;
import static org.codehaus.groovy.ast.AnnotationNode.CONSTRUCTOR_TARGET;
import static org.codehaus.groovy.ast.AnnotationNode.FIELD_TARGET;
Expand All @@ -63,7 +62,9 @@
import static org.codehaus.groovy.ast.AnnotationNode.TYPE_PARAMETER_TARGET;
import static org.codehaus.groovy.ast.AnnotationNode.TYPE_TARGET;
import static org.codehaus.groovy.ast.AnnotationNode.TYPE_USE_TARGET;
import static org.codehaus.groovy.ast.ClassHelper.makeCached;
import static org.codehaus.groovy.ast.tools.GeneralUtils.getInterfacesAndSuperInterfaces;
import static org.codehaus.groovy.ast.tools.GeneralUtils.listX;
import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
Expand Down Expand Up @@ -349,10 +350,10 @@ private boolean isTypeUseScenario(AnnotationNode visited, int target) {
}

private void processDuplicateAnnotationContainers(AnnotatedNode node, Map<String, List<AnnotationNode>> nonSourceAnnotations) {
for (Map.Entry<String, List<AnnotationNode>> next : nonSourceAnnotations.entrySet()) {
if (next.getValue().size() > 1) {
for (Map.Entry<String, List<AnnotationNode>> entry : nonSourceAnnotations.entrySet()) {
if (entry.getValue().size() > 1) {
ClassNode repeatable = null;
AnnotationNode repeatee = next.getValue().get(0);
AnnotationNode repeatee = entry.getValue().get(0);
for (AnnotationNode anno : repeatee.getClassNode().getAnnotations()) {
if (anno.getClassNode().getName().equals("java.lang.annotation.Repeatable")) {
Expression value = anno.getMember("value");
Expand All @@ -364,29 +365,32 @@ private void processDuplicateAnnotationContainers(AnnotatedNode node, Map<String
}
if (repeatable != null) {
if (nonSourceAnnotations.containsKey(repeatable.getName())) {
addError("Cannot specify duplicate annotation on the same member. Explicit " + repeatable.getName()
+ " found when creating implicit container for " + next.getKey(), node);
addError("Cannot specify duplicate annotation on the same member. Explicit " + repeatable.getName() + " found when creating implicit container for " + entry.getKey(), node);
}
AnnotationNode collector = new AnnotationNode(repeatable);
if (repeatee.hasRuntimeRetention()) {
if (repeatee.hasClassRetention()) {
collector.setClassRetention(true);
} else if (repeatee.hasRuntimeRetention()) {
collector.setRuntimeRetention(true);
} else if (repeatable.hasClass()) { // GRECLIPSE edit
Class<?> repeatableType = repeatable.getTypeClass();
Retention retention = repeatableType.getAnnotation(Retention.class);
collector.setRuntimeRetention(retention != null && retention.value().equals(RetentionPolicy.RUNTIME));
} else {
for (AnnotationNode annotation : repeatable.getAnnotations()) {
if (annotation.getClassNode().getName().equals("java.lang.annotation.Retention")) {
Expression value = annotation.getMember("value"); assert value != null;
Object retention = evaluateExpression(value, source.getConfiguration());
collector.setRuntimeRetention(retention != null && retention.toString().equals("RUNTIME"));
break;
} else { // load retention policy from annotation definition
List<AnnotationNode> retention = repeatable.getAnnotations(makeCached(Retention.class));
if (!retention.isEmpty()) {
Object policy;
Expression value = retention.get(0).getMember("value");
if (value instanceof PropertyExpression) {
policy = ((PropertyExpression) value).getPropertyAsString();
} else { // NOTE: it is risky to evaluate the expression from repeatable's source this way:
policy = evaluateExpression(value, source.getConfiguration(), source.getClassLoader());
}
if ("CLASS".equals(policy)) {
collector.setClassRetention(true);
} else if ("RUNTIME".equals(policy)) {
collector.setRuntimeRetention(true);
}
}
}
collector.addMember("value", new ListExpression(next.getValue().stream()
.map(AnnotationConstantExpression::new).collect(Collectors.toList())));
node.getAnnotations().removeAll(next.getValue());
collector.addMember("value", listX(entry.getValue().stream().map(AnnotationConstantExpression::new).collect(toList())));
node.getAnnotations().removeAll(entry.getValue());
node.addAnnotation(collector);
}
}
Expand Down

0 comments on commit 51ed232

Please sign in to comment.