Skip to content

Commit 1c46a3d

Browse files
SentryManrbygrave
andauthored
Support qualifiers with members (#488)
* start * Support qualifiers with members * Revert "Support qualifiers with members" This reverts commit 1888f86. * separate tests * Create SpyMeterTest.java * Update jdk-ea.yml * gotta figure out something else * solve with regex * format * Update AnnotationReader.java * no longer strip `@` from qualifiers * Update AnnotationCopier.java * Update Aspect.java * Revert "no longer strip `@` from qualifiers" This reverts commit e08e45e. * Format and remove some dead code, remove public modifiers * Remove unused import only --------- Co-authored-by: Rob Bygrave <[email protected]>
1 parent 22165f7 commit 1c46a3d

File tree

20 files changed

+446
-58
lines changed

20 files changed

+446
-58
lines changed

.github/workflows/jdk-ea.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
strategy:
1717
fail-fast: false
1818
matrix:
19-
java_version: [GA,22-ea,EA] ## valhalla (fails javadoc)
19+
java_version: [GA,EA] ## valhalla (fails javadoc)
2020
os: [ubuntu-latest]
2121

2222
steps:

inject-generator/src/main/java/io/avaje/inject/generator/AnnotationCopier.java

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,31 @@
11
package io.avaje.inject.generator;
22

3+
import static java.util.stream.Collectors.toList;
4+
35
import java.util.List;
6+
import java.util.Map.Entry;
47

58
import javax.lang.model.element.AnnotationMirror;
69
import javax.lang.model.element.AnnotationValue;
710
import javax.lang.model.element.Element;
11+
import javax.lang.model.element.ExecutableElement;
812
import javax.lang.model.element.VariableElement;
913

1014
final class AnnotationCopier {
1115
private AnnotationCopier() {}
1216

13-
public static void copyAnnotations(Append writer, Element element, boolean newLines) {
17+
static void copyAnnotations(Append writer, Element element, boolean newLines) {
1418
copyAnnotations(writer, element, "", newLines);
1519
}
1620

17-
public static void copyAnnotations(Append writer, Element element, String indent, boolean newLines) {
21+
static void copyAnnotations(Append writer, Element element, String indent, boolean newLines) {
1822
for (final AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
1923
final var type = annotationMirror.getAnnotationType().asElement().asType().toString();
2024
if (type.startsWith("io.avaje.inject.Assist")) {
2125
continue;
2226
}
23-
final String annotationName = annotationMirror.getAnnotationType().toString();
24-
final StringBuilder sb = new StringBuilder(indent).append("@").append(annotationName).append("(");
25-
boolean first = true;
26-
27-
for (final var entry : annotationMirror.getElementValues().entrySet()) {
28-
if (!first) {
29-
sb.append(", ");
30-
}
31-
sb.append(entry.getKey().getSimpleName()).append("=");
32-
writeVal(sb, entry.getValue());
33-
first = false;
34-
}
3527

36-
sb.append(")");
37-
final String annotationString = sb.toString();
28+
final String annotationString = toAnnotationString(indent, annotationMirror, false);
3829
writer.append(annotationString);
3930

4031
if (newLines) {
@@ -45,8 +36,41 @@ public static void copyAnnotations(Append writer, Element element, String indent
4536
}
4637
}
4738

39+
static String toSimpleAnnotationString(AnnotationMirror annotationMirror) {
40+
return Util.trimAnnotationString(toAnnotationString("", annotationMirror, true)).substring(1);
41+
}
42+
43+
static String toAnnotationString(String indent, AnnotationMirror annotationMirror, boolean simpleEnums) {
44+
final String annotationName = annotationMirror.getAnnotationType().toString();
45+
46+
final StringBuilder sb = new StringBuilder(indent).append("@").append(annotationName).append("(");
47+
boolean first = true;
48+
49+
for (final var entry : sortedValues(annotationMirror)) {
50+
if (!first) {
51+
sb.append(", ");
52+
}
53+
sb.append(entry.getKey().getSimpleName()).append("=");
54+
writeVal(sb, entry.getValue(), simpleEnums);
55+
first = false;
56+
}
57+
58+
return sb.append(")").toString().replace("()", "");
59+
}
60+
61+
private static List<Entry<? extends ExecutableElement, ? extends AnnotationValue>> sortedValues(AnnotationMirror annotationMirror) {
62+
return APContext.elements().getElementValuesWithDefaults(annotationMirror).entrySet().stream()
63+
.sorted(AnnotationCopier::compareBySimpleName)
64+
.collect(toList());
65+
}
66+
67+
private static int compareBySimpleName(Entry<? extends ExecutableElement, ? extends AnnotationValue> entry1,
68+
Entry<? extends ExecutableElement, ? extends AnnotationValue> entry2) {
69+
return entry1.getKey().getSimpleName().toString().compareTo(entry2.getKey().getSimpleName().toString());
70+
}
71+
4872
@SuppressWarnings("unchecked")
49-
private static void writeVal(final StringBuilder sb, final AnnotationValue annotationValue) {
73+
private static void writeVal(final StringBuilder sb, final AnnotationValue annotationValue, boolean simpleEnums) {
5074
final var value = annotationValue.getValue();
5175
if (value instanceof List) {
5276
// handle array values
@@ -56,7 +80,7 @@ private static void writeVal(final StringBuilder sb, final AnnotationValue annot
5680
if (!first) {
5781
sb.append(", ");
5882
}
59-
writeVal(sb, listValue);
83+
writeVal(sb, listValue, simpleEnums);
6084
first = false;
6185
}
6286
sb.append("}");
@@ -65,7 +89,8 @@ private static void writeVal(final StringBuilder sb, final AnnotationValue annot
6589
// Handle enum values
6690
final var element = (VariableElement) value;
6791
final var type = element.asType();
68-
sb.append(type.toString() + "." + element);
92+
final var str = simpleEnums ? element : type.toString() + "." + element;
93+
sb.append(str);
6994

7095
} else if (value instanceof AnnotationMirror) {
7196
// handle annotation values
@@ -74,12 +99,12 @@ private static void writeVal(final StringBuilder sb, final AnnotationValue annot
7499
sb.append("@").append(annotationName).append("(");
75100
boolean first = true;
76101

77-
for (final var entry : mirror.getElementValues().entrySet()) {
102+
for (final var entry : sortedValues(mirror)) {
78103
if (!first) {
79104
sb.append(", ");
80105
}
81106
sb.append(entry.getKey().getSimpleName()).append("=");
82-
writeVal(sb, entry.getValue());
107+
writeVal(sb, entry.getValue(), simpleEnums);
83108
first = false;
84109
}
85110
sb.append(")");

inject-generator/src/main/java/io/avaje/inject/generator/Processor.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import javax.lang.model.element.AnnotationMirror;
99
import javax.lang.model.element.Element;
1010
import javax.lang.model.element.ElementKind;
11+
import javax.lang.model.element.ExecutableElement;
1112
import javax.lang.model.element.TypeElement;
1213
import javax.lang.model.util.ElementFilter;
1314
import javax.lang.model.util.Elements;
@@ -35,7 +36,8 @@
3536
Constants.TESTSCOPE,
3637
Constants.CONTROLLER,
3738
ImportPrism.PRISM_TYPE,
38-
AspectImportPrism.PRISM_TYPE
39+
AspectImportPrism.PRISM_TYPE,
40+
QualifierPrism.PRISM_TYPE
3941
})
4042
public final class Processor extends AbstractProcessor {
4143

@@ -103,6 +105,11 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
103105

104106
readBeans(delayedElements());
105107
addImportedAspects(importedAspects(roundEnv));
108+
maybeElements(roundEnv, QualifierPrism.PRISM_TYPE).stream()
109+
.flatMap(Set::stream)
110+
.flatMap(e -> ElementFilter.methodsIn(e.getEnclosedElements()).stream())
111+
.forEach(this::validateQualifier);
112+
106113
maybeElements(roundEnv, ScopePrism.PRISM_TYPE).ifPresent(this::readScopes);
107114
maybeElements(roundEnv, FactoryPrism.PRISM_TYPE).ifPresent(this::readFactories);
108115

@@ -128,6 +135,19 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
128135
return false;
129136
}
130137

138+
private void validateQualifier(ExecutableElement method) {
139+
var type = APContext.asTypeElement(method.getReturnType());
140+
if (type == null || type.getKind() != ElementKind.ANNOTATION_TYPE) {
141+
return;
142+
}
143+
144+
var enclosedMethods = ElementFilter.methodsIn(type.getEnclosedElements());
145+
if (enclosedMethods.size() > 1) {
146+
APContext.logError(method, "Qualifier annotation members can only have a single attribute");
147+
}
148+
enclosedMethods.forEach(this::validateQualifier);
149+
}
150+
131151
// Optional because these annotations are not guaranteed to exist
132152
private static Optional<? extends Set<? extends Element>> maybeElements(RoundEnvironment round, String name) {
133153
return Optional.ofNullable(typeElement(name)).map(round::getElementsAnnotatedWith);

inject-generator/src/main/java/io/avaje/inject/generator/TypeAnnotationReader.java

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,23 @@
11
package io.avaje.inject.generator;
22

3-
import static io.avaje.inject.generator.APContext.logWarn;
4-
5-
import java.util.ArrayList;
6-
import java.util.List;
7-
83
import javax.lang.model.element.AnnotationMirror;
94
import javax.lang.model.element.TypeElement;
105
import javax.lang.model.type.DeclaredType;
116

7+
import static io.avaje.inject.generator.APContext.logWarn;
8+
129
/**
1310
* Read the annotations on the type.
1411
*/
1512
final class TypeAnnotationReader {
1613

1714
private final TypeElement beanType;
18-
private final List<String> annotationTypes = new ArrayList<>();
1915
private String qualifierName;
2016

2117
TypeAnnotationReader(TypeElement beanType) {
2218
this.beanType = beanType;
2319
}
2420

25-
List<String> annotationTypes() {
26-
return annotationTypes;
27-
}
2821

2922
boolean hasQualifierName() {
3023
return qualifierName != null;
@@ -38,13 +31,16 @@ void process() {
3831
for (AnnotationMirror annotationMirror : beanType.getAnnotationMirrors()) {
3932
DeclaredType annotationType = annotationMirror.getAnnotationType();
4033
String annType = annotationType.toString();
41-
34+
4235
if (QualifierPrism.isPresent(annotationType.asElement())) {
43-
qualifierName = Util.shortName(annType).toLowerCase();
36+
var shortName = Util.shortName(annotationType.toString());
37+
qualifierName = AnnotationCopier.toSimpleAnnotationString(annotationMirror)
38+
.replaceFirst(annotationType.toString(), shortName)
39+
.replace("\"", "\\\"")
40+
.toLowerCase();
41+
4442
} else if (annType.indexOf('.') == -1) {
4543
logWarn("skip when no package on annotation " + annType);
46-
} else if (IncludeAnnotations.include(annType)) {
47-
annotationTypes.add(annType);
4844
}
4945
}
5046
}

inject-generator/src/main/java/io/avaje/inject/generator/TypeExtendsReader.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
package io.avaje.inject.generator;
22

33
import static io.avaje.inject.generator.APContext.logWarn;
4-
import static io.avaje.inject.generator.APContext.typeElement;
54
import static io.avaje.inject.generator.APContext.types;
65
import static io.avaje.inject.generator.ProcessingContext.asElement;
7-
import static java.util.stream.Collectors.toList;
8-
96
import java.lang.annotation.Annotation;
107
import java.util.ArrayList;
118
import java.util.List;
@@ -33,7 +30,6 @@ final class TypeExtendsReader {
3330
private final List<UType> interfaceTypes = new ArrayList<>();
3431
private final List<UType> providesTypes = new ArrayList<>();
3532
private final String beanSimpleName;
36-
private final String baseTypeRaw;
3733
private final boolean baseTypeIsInterface;
3834
private final boolean publicAccess;
3935
private final boolean autoProvide;
@@ -50,7 +46,6 @@ final class TypeExtendsReader {
5046
this.baseType = baseType;
5147
this.extendsInjection = new TypeExtendsInjection(baseType, factory, importTypes);
5248
this.beanSimpleName = baseType.getSimpleName().toString();
53-
this.baseTypeRaw = Util.unwrapProvider(baseUType.toString());
5449
this.baseTypeIsInterface = baseType.getKind() == ElementKind.INTERFACE;
5550
this.publicAccess = baseType.getModifiers().contains(Modifier.PUBLIC);
5651
this.autoProvide = autoProvide();

0 commit comments

Comments
 (0)