Skip to content

Commit 4750bdd

Browse files
committed
solve with regex
1 parent 6ae275d commit 4750bdd

File tree

17 files changed

+297
-61
lines changed

17 files changed

+297
-61
lines changed

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

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
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 {
@@ -14,27 +18,15 @@ public static void copyAnnotations(Append writer, Element element, boolean newLi
1418
copyAnnotations(writer, element, "", newLines);
1519
}
1620

17-
public static void copyAnnotations(Append writer, Element element, String indent, boolean newLines) {
21+
public static void copyAnnotations(
22+
Append writer, Element element, String indent, boolean newLines) {
1823
for (final AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
1924
final var type = annotationMirror.getAnnotationType().asElement().asType().toString();
2025
if (type.startsWith("io.avaje.inject.Assist")) {
2126
continue;
2227
}
23-
final String annotationName = annotationMirror.getAnnotationType().toString();
24-
final StringBuilder sb = new StringBuilder(indent).append("@").append(annotationName).append("(");
25-
boolean first = true;
2628

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-
}
35-
36-
sb.append(")");
37-
final String annotationString = sb.toString();
29+
final String annotationString = getAnnotationString(indent, annotationMirror, false);
3830
writer.append(annotationString);
3931

4032
if (newLines) {
@@ -45,8 +37,45 @@ public static void copyAnnotations(Append writer, Element element, String indent
4537
}
4638
}
4739

40+
static String getSimpleAnnotationString(AnnotationMirror annotationMirror) {
41+
return Util.trimAnnotationString(getAnnotationString("", annotationMirror, true)).substring(1);
42+
}
43+
44+
static String getAnnotationString(
45+
String indent, AnnotationMirror annotationMirror, boolean simpleEnums) {
46+
final String annotationName = annotationMirror.getAnnotationType().toString();
47+
48+
final StringBuilder sb =
49+
new StringBuilder(indent).append("@").append(annotationName).append("(");
50+
boolean first = true;
51+
52+
for (final var entry : sortedValues(annotationMirror)) {
53+
if (!first) {
54+
sb.append(", ");
55+
}
56+
sb.append(entry.getKey().getSimpleName()).append("=");
57+
writeVal(sb, entry.getValue(), simpleEnums);
58+
first = false;
59+
}
60+
61+
return sb.append(")").toString().replace("()", "");
62+
}
63+
64+
private static List<Entry<? extends ExecutableElement, ? extends AnnotationValue>> sortedValues(
65+
AnnotationMirror annotationMirror) {
66+
return APContext.elements().getElementValuesWithDefaults(annotationMirror).entrySet().stream()
67+
.sorted(
68+
(e1, e2) ->
69+
e1.getKey()
70+
.getSimpleName()
71+
.toString()
72+
.compareTo(e2.getKey().getSimpleName().toString()))
73+
.collect(toList());
74+
}
75+
4876
@SuppressWarnings("unchecked")
49-
private static void writeVal(final StringBuilder sb, final AnnotationValue annotationValue) {
77+
private static void writeVal(
78+
final StringBuilder sb, final AnnotationValue annotationValue, boolean simpleEnums) {
5079
final var value = annotationValue.getValue();
5180
if (value instanceof List) {
5281
// handle array values
@@ -56,7 +85,7 @@ private static void writeVal(final StringBuilder sb, final AnnotationValue annot
5685
if (!first) {
5786
sb.append(", ");
5887
}
59-
writeVal(sb, listValue);
88+
writeVal(sb, listValue, first);
6089
first = false;
6190
}
6291
sb.append("}");
@@ -65,7 +94,8 @@ private static void writeVal(final StringBuilder sb, final AnnotationValue annot
6594
// Handle enum values
6695
final var element = (VariableElement) value;
6796
final var type = element.asType();
68-
sb.append(type.toString() + "." + element);
97+
final var str = simpleEnums ? element : type.toString() + "." + element;
98+
sb.append(str);
6999

70100
} else if (value instanceof AnnotationMirror) {
71101
// handle annotation values
@@ -74,12 +104,12 @@ private static void writeVal(final StringBuilder sb, final AnnotationValue annot
74104
sb.append("@").append(annotationName).append("(");
75105
boolean first = true;
76106

77-
for (final var entry : mirror.getElementValues().entrySet()) {
107+
for (final var entry : sortedValues(mirror)) {
78108
if (!first) {
79109
sb.append(", ");
80110
}
81111
sb.append(entry.getKey().getSimpleName()).append("=");
82-
writeVal(sb, entry.getValue());
112+
writeVal(sb, entry.getValue(), first);
83113
first = false;
84114
}
85115
sb.append(")");

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

Lines changed: 25 additions & 2 deletions
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,7 +135,23 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
128135
return false;
129136
}
130137

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

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import javax.lang.model.element.AnnotationMirror;
99
import javax.lang.model.element.TypeElement;
1010
import javax.lang.model.type.DeclaredType;
11-
import javax.lang.model.util.ElementFilter;
1211

1312
/**
1413
* Read the annotations on the type.
@@ -42,13 +41,10 @@ void process() {
4241

4342
if (QualifierPrism.isPresent(annotationType.asElement())) {
4443

45-
final var shortName = Util.shortName(annotationType.toString());
46-
var fqn = APContext.asTypeElement(annotationType).getQualifiedName().toString();
44+
var shortName = Util.shortName(annotationType.toString());
4745
qualifierName =
48-
annotationMirror
49-
.toString()
50-
.substring(1)
51-
.replace(fqn, shortName)
46+
AnnotationCopier.getSimpleAnnotationString(annotationMirror)
47+
.replaceFirst(annotationType.toString(), shortName)
5248
.replace("\"", "\\\"")
5349
.toLowerCase();
5450

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();

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

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

33
import java.util.Optional;
4+
import java.util.regex.Matcher;
5+
import java.util.regex.Pattern;
46

57
import javax.lang.model.element.AnnotationMirror;
68
import javax.lang.model.element.Element;
79
import javax.lang.model.type.DeclaredType;
810
import javax.lang.model.type.TypeKind;
911
import javax.lang.model.type.TypeMirror;
10-
import javax.lang.model.util.ElementFilter;
1112

1213
final class Util {
1314
static final String ASPECT_PROVIDER_PREFIX = "io.avaje.inject.aop.AspectProvider<";
@@ -274,13 +275,10 @@ public static String getNamed(Element p) {
274275
final DeclaredType annotationType = annotationMirror.getAnnotationType();
275276
final var hasQualifier = QualifierPrism.isPresent(annotationType.asElement());
276277
if (hasQualifier) {
277-
final var shortName = Util.shortName(annotationType.toString());
278+
var shortName = Util.shortName(annotationType.toString());
278279

279-
var fqn = APContext.asTypeElement(annotationType).getQualifiedName().toString();
280-
return annotationMirror
281-
.toString()
282-
.substring(1)
283-
.replace(fqn, shortName)
280+
return AnnotationCopier.getSimpleAnnotationString(annotationMirror)
281+
.replaceFirst(annotationType.toString(), shortName)
284282
.replace("\"", "\\\"")
285283
.toLowerCase();
286284
}
@@ -317,4 +315,11 @@ public static String addForInterface(String interfaceType) {
317315
public static String trimMethod(String method) {
318316
return shortMethod(method).replace('.', '_').replace(Constants.DI, "");
319317
}
318+
319+
private static final Pattern ANNOTATION_TYPE_PATTERN = Pattern.compile("@([\\w.]+)\\.");
320+
321+
public static String trimAnnotationString(String input) {
322+
323+
return ANNOTATION_TYPE_PATTERN.matcher(input).replaceAll("@");
324+
}
320325
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.avaje.inject.generator.models.valid.qualifier;
2+
3+
import io.avaje.inject.generator.models.valid.qualifier.TempQualifier.Scale;
4+
import jakarta.inject.Singleton;
5+
6+
@Singleton
7+
@TempQualifier(value = Scale.FAHRENHEIT, someOtherString = "far")
8+
public class ImperialMeter implements Thermometer {
9+
10+
@Override
11+
public boolean freezing(float temp) {
12+
return temp <= 32;
13+
}
14+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.avaje.inject.generator.models.valid.qualifier;
2+
3+
import io.avaje.inject.generator.models.valid.qualifier.TempQualifier.Scale;
4+
import jakarta.inject.Singleton;
5+
6+
@Singleton
7+
public class Meters {
8+
9+
Thermometer imperial;
10+
11+
Thermometer metric;
12+
13+
public Meters(
14+
@TempQualifier(value = Scale.FAHRENHEIT, someOtherString = "far") Thermometer imperial,
15+
@TempQualifier(value = Scale.CELSIUS, someOtherString = "celsi") Thermometer metric) {
16+
this.imperial = imperial;
17+
this.metric = metric;
18+
}
19+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.avaje.inject.generator.models.valid.qualifier;
2+
3+
import io.avaje.inject.generator.models.valid.qualifier.TempQualifier.Scale;
4+
import jakarta.inject.Singleton;
5+
6+
@Singleton
7+
@TempQualifier(value = Scale.CELSIUS, someOtherString = "celsi")
8+
public class MetricMeter implements Thermometer {
9+
10+
@Override
11+
public boolean freezing(float temp) {
12+
return temp <= 0;
13+
}
14+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.avaje.inject.generator.models.valid.qualifier;
2+
3+
import java.lang.annotation.Retention;
4+
import java.lang.annotation.RetentionPolicy;
5+
6+
import jakarta.inject.Inject;
7+
import jakarta.inject.Qualifier;
8+
9+
@Qualifier
10+
@Retention(RetentionPolicy.RUNTIME)
11+
public @interface TempQualifier {
12+
Scale[] value();
13+
14+
String someOtherString();
15+
16+
int defaultVal() default 0;
17+
18+
NestedAnnotation[] inject() default {@NestedAnnotation()};
19+
20+
enum Scale {
21+
CELSIUS,
22+
FAHRENHEIT,
23+
}
24+
25+
@interface NestedAnnotation {
26+
27+
Inject[] inject() default {};
28+
}
29+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package io.avaje.inject.generator.models.valid.qualifier;
2+
3+
public interface Thermometer {
4+
5+
boolean freezing(float temp);
6+
}

0 commit comments

Comments
 (0)