Skip to content

Commit 12e9928

Browse files
committed
#97 - Refactor to register using explicit types rather than bean.getClass() canonical name
Plus - #96 Case insensitive qualifier names - #98 Support @singleton that extends another concrete @singleton
1 parent 9e23624 commit 12e9928

31 files changed

+681
-240
lines changed

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

Lines changed: 14 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,11 @@
33
import io.avaje.inject.Bean;
44
import io.avaje.inject.Primary;
55
import io.avaje.inject.Secondary;
6-
76
import jakarta.inject.Inject;
87
import jakarta.inject.Named;
9-
import jakarta.inject.Qualifier;
10-
import javax.lang.model.element.AnnotationMirror;
11-
import javax.lang.model.element.Element;
12-
import javax.lang.model.element.ElementKind;
13-
import javax.lang.model.element.ExecutableElement;
14-
import javax.lang.model.element.TypeElement;
15-
import javax.lang.model.type.DeclaredType;
16-
import javax.lang.model.type.TypeMirror;
17-
import java.util.ArrayList;
18-
import java.util.Collections;
19-
import java.util.List;
20-
import java.util.Set;
21-
import java.util.TreeSet;
8+
9+
import javax.lang.model.element.*;
10+
import java.util.*;
2211

2312
class BeanReader {
2413

@@ -32,31 +21,20 @@ class BeanReader {
3221
private String name;
3322

3423
private MethodReader injectConstructor;
35-
3624
private final List<MethodReader> otherConstructors = new ArrayList<>();
37-
3825
private final List<MethodReader> factoryMethods = new ArrayList<>();
3926

4027
private Element postConstructMethod;
41-
4228
private Element preDestroyMethod;
4329

4430
private final List<FieldReader> injectFields = new ArrayList<>();
45-
4631
private final List<MethodReader> injectMethods = new ArrayList<>();
47-
48-
private final List<String> interfaceTypes = new ArrayList<>();
49-
50-
private String addForType;
51-
5232
private final Set<String> importTypes = new TreeSet<>();
53-
5433
private final BeanRequestParams requestParams;
5534

35+
private final TypeReader typeReader;
5636
private MethodReader constructor;
5737

58-
private String registrationTypes;
59-
6038
private boolean writtenToFile;
6139

6240
/**
@@ -72,6 +50,7 @@ class BeanReader {
7250
this.shortName = shortName(beanType);
7351
this.context = context;
7452
this.requestParams = new BeanRequestParams(type);
53+
this.typeReader = new TypeReader(beanType, context, importTypes);
7554
init();
7655
}
7756

@@ -81,55 +60,11 @@ public String toString() {
8160
}
8261

8362
private void init() {
84-
StringBuilder sb = new StringBuilder();
85-
86-
for (TypeMirror anInterface : beanType.getInterfaces()) {
87-
String type = Util.unwrapProvider(anInterface.toString());
88-
if (Constants.isBeanLifecycle(type)) {
89-
beanLifeCycle = true;
90-
} else if (type.indexOf('.') == -1) {
91-
context.logWarn("skip when no package on interface " + type);
92-
} else {
93-
interfaceTypes.add(type);
94-
if (!GenericType.isGeneric(type)) {
95-
importTypes.add(type);
96-
sb.append(", ").append(Util.shortName(type)).append(".class");
97-
}
98-
}
99-
}
100-
if (interfaceTypes.size() == 1) {
101-
String ifaceType = interfaceTypes.get(0);
102-
if (!GenericType.isGeneric(ifaceType)) {
103-
// only register for non-generic interfaces for the moment
104-
addForType = Util.addForInterface(ifaceType);
105-
}
106-
}
107-
108-
// get class level annotations (that are not Named and Singleton)
109-
for (AnnotationMirror annotationMirror : beanType.getAnnotationMirrors()) {
110-
111-
DeclaredType annotationType = annotationMirror.getAnnotationType();
112-
Qualifier qualifier = annotationType.asElement().getAnnotation(Qualifier.class);
113-
String annType = annotationType.toString();
114-
if (qualifier != null) {
115-
this.name = Util.shortName(annType);
116-
} else if (annType.indexOf('.') == -1) {
117-
context.logWarn("skip when no package on annotation " + annType);
118-
} else {
119-
if (IncludeAnnotations.include(annType)) {
120-
importTypes.add(annType);
121-
sb.append(", ").append(Util.shortName(annType)).append(".class");
122-
}
123-
}
124-
}
125-
Named named = beanType.getAnnotation(Named.class);
126-
if (named != null) {
127-
this.name = named.value();
128-
}
129-
63+
typeReader.process();
64+
beanLifeCycle = typeReader.isBeanLifeCycle();
65+
name = typeReader.getName();
13066
primary = (beanType.getAnnotation(Primary.class) != null);
13167
secondary = !primary && (beanType.getAnnotation(Secondary.class) != null);
132-
registrationTypes = sb.toString();
13368
}
13469

13570
TypeElement getBeanType() {
@@ -220,18 +155,7 @@ List<MethodReader> getFactoryMethods() {
220155
}
221156

222157
List<String> getInterfaces() {
223-
return interfaceTypes;
224-
}
225-
226-
/**
227-
* Return all the interfaces and annotations associated with this bean.
228-
* <p>
229-
* The bean is made a 'member' of the list of beans that implement the interface or have the
230-
* annotation.
231-
* </p>
232-
*/
233-
String getInterfacesAndAnnotations() {
234-
return registrationTypes;
158+
return typeReader.getInterfaces();
235159
}
236160

237161
private void readConstructor(Element element) {
@@ -361,10 +285,8 @@ void buildAddFor(Append writer) {
361285
if (name != null) {
362286
writer.append("\"%s\", ", name);
363287
}
364-
if (addForType != null) {
365-
writer.append(addForType).append(".class, ");
366-
}
367-
writer.append(shortName).append(".class)) {").eol();
288+
writer.append(typeReader.getTypesRegister());
289+
writer.append(")) {").eol();
368290
}
369291

370292
void buildRegister(Append writer) {
@@ -375,12 +297,12 @@ void buildRegister(Append writer) {
375297
String flags = primary ? "Primary" : secondary ? "Secondary" : "";
376298
writer.append("builder.register%s(bean, ", flags);
377299
if (name == null) {
378-
writer.append("null");
300+
writer.append("null, ");
379301
} else {
380-
writer.append("\"%s\"", name);
302+
writer.append("\"%s\", ", name);
381303
}
382304
// add interfaces and annotations
383-
writer.append(getInterfacesAndAnnotations()).append(");").eol();
305+
writer.append(typeReader.getTypesRegister()).append(");").eol();
384306
}
385307

386308
void buildAddLifecycle(Append writer) {

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

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.avaje.inject.Bean;
44

55
import jakarta.inject.Named;
6+
67
import javax.lang.model.element.*;
78
import javax.lang.model.type.TypeMirror;
89
import java.util.ArrayList;
@@ -19,17 +20,17 @@ class MethodReader {
1920
private final String factoryType;
2021
private final String methodName;
2122
private final TypeMirror returnType;
23+
private final TypeElement returnElement;
2224
private final String returnTypeRaw;
2325
private final String shortName;
2426
private final boolean isVoid;
2527
private final List<MethodParam> params = new ArrayList<>();
26-
private final List<String> interfaceTypes = new ArrayList<>();
2728
private final String factoryShortName;
2829
private final boolean isFactory;
2930
private final String initMethod;
3031
private final String destroyMethod;
3132
private final String name;
32-
private String addForType;
33+
private final TypeReader typeReader;
3334
private boolean beanLifeCycle;
3435

3536
MethodReader(ProcessingContext context, ExecutableElement element, TypeElement beanType) {
@@ -50,32 +51,18 @@ class MethodReader {
5051
this.initMethod = (bean == null) ? null : bean.initMethod();
5152
this.destroyMethod = (bean == null) ? null : bean.destroyMethod();
5253
this.name = (named == null) ? null : named.value();
53-
initInterfaces();
54-
}
55-
56-
String getName() {
57-
return methodName;
54+
this.returnElement = baseTypeElement(context.asElement(returnType));
55+
if (returnElement == null) {
56+
this.typeReader = null;
57+
} else {
58+
this.typeReader = new TypeReader(returnElement, context);
59+
typeReader.process();
60+
beanLifeCycle = typeReader.isBeanLifeCycle();
61+
}
5862
}
5963

60-
private void initInterfaces() {
61-
Element element = context.asElement(returnType);
62-
if (element instanceof TypeElement) {
63-
TypeElement te = (TypeElement) element;
64-
if (te.getKind() == ElementKind.INTERFACE) {
65-
interfaceTypes.add(te.getQualifiedName().toString());
66-
}
67-
for (TypeMirror anInterface : te.getInterfaces()) {
68-
if (Constants.isBeanLifecycle(anInterface.toString())) {
69-
// directly implements BeanLifecycle
70-
beanLifeCycle = true;
71-
} else {
72-
interfaceTypes.add(anInterface.toString());
73-
}
74-
}
75-
if (interfaceTypes.size() == 1) {
76-
addForType = interfaceTypes.get(0);
77-
}
78-
}
64+
TypeElement baseTypeElement(Element element) {
65+
return element instanceof TypeElement ? (TypeElement) element : null;
7966
}
8067

8168
void read() {
@@ -85,13 +72,15 @@ void read() {
8572
}
8673
}
8774

75+
String getName() {
76+
return methodName;
77+
}
78+
8879
List<MethodParam> getParams() {
8980
return params;
9081
}
9182

92-
9383
MetaData createMeta() {
94-
9584
MetaData metaData = new MetaData(returnTypeRaw, name);
9685
metaData.setMethod(fullBuildMethod());
9786

@@ -138,12 +127,12 @@ void builderBuildAddBean(Append writer) {
138127
}
139128
writer.append("builder.register(bean, ");
140129
if (name == null) {
141-
writer.append("null");
130+
writer.append("null, ");
142131
} else {
143-
writer.append("\"%s\"", name);
132+
writer.append("\"%s\", ", name);
144133
}
145-
for (String anInterface : interfaceTypes) {
146-
writer.append(", ").append(Util.shortName(anInterface)).append(".class");
134+
if (typeReader != null) {
135+
writer.append(typeReader.getTypesRegister());
147136
}
148137
writer.append(");").eol();
149138

@@ -173,22 +162,24 @@ void addImports(Set<String> importTypes) {
173162
if (beanLifeCycle || hasLifecycleMethods()) {
174163
importTypes.add(Constants.BEAN_LIFECYCLE);
175164
}
176-
importTypes.addAll(interfaceTypes);
165+
if (typeReader != null) {
166+
typeReader.addImports(importTypes);
167+
}
177168
}
178169

179170
void buildAddFor(Append writer) {
180171
writer.append(" if (builder.isAddBeanFor(");
181-
if (name != null) {
182-
writer.append("\"%s\", ", name);
183-
}
184-
if (addForType != null) {
185-
writer.append(addForType).append(".class, ");
186-
}
187172
if (isVoid) {
188-
writer.append("Void.class)) {").eol();
173+
writer.append("Void.class");
189174
} else {
190-
writer.append(shortName).append(".class)) {").eol();
175+
if (name != null) {
176+
writer.append("\"%s\", ", name);
177+
}
178+
if (typeReader != null) {
179+
writer.append(typeReader.getTypesRegister());
180+
}
191181
}
182+
writer.append(")) {").eol();
192183
}
193184

194185
/**
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package io.avaje.inject.generator;
2+
3+
import jakarta.inject.Qualifier;
4+
5+
import javax.lang.model.element.AnnotationMirror;
6+
import javax.lang.model.element.TypeElement;
7+
import javax.lang.model.type.DeclaredType;
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
/**
12+
* Read the annotations on the type.
13+
*/
14+
class TypeAnnotationReader {
15+
16+
private final TypeElement beanType;
17+
private final ProcessingContext context;
18+
private final List<String> annotationTypes = new ArrayList<>();
19+
private String qualifierName;
20+
21+
TypeAnnotationReader(TypeElement beanType, ProcessingContext context) {
22+
this.beanType = beanType;
23+
this.context = context;
24+
}
25+
26+
List<String> getAnnotationTypes() {
27+
return annotationTypes;
28+
}
29+
30+
boolean hasQualifierName() {
31+
return qualifierName != null;
32+
}
33+
34+
String getQualifierName() {
35+
return qualifierName;
36+
}
37+
38+
void process() {
39+
for (AnnotationMirror annotationMirror : beanType.getAnnotationMirrors()) {
40+
DeclaredType annotationType = annotationMirror.getAnnotationType();
41+
Qualifier qualifier = annotationType.asElement().getAnnotation(Qualifier.class);
42+
String annType = annotationType.toString();
43+
if (qualifier != null) {
44+
qualifierName = Util.shortName(annType);
45+
} else if (annType.indexOf('.') == -1) {
46+
context.logWarn("skip when no package on annotation " + annType);
47+
} else {
48+
if (IncludeAnnotations.include(annType)) {
49+
annotationTypes.add(annType);
50+
}
51+
}
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)