Skip to content

Commit f74aaec

Browse files
committed
#262 - ENH: Simplify multi-module compilation and wiring but auto detecting provides and requires
- Adds autoProvides() and autoProvidesAspects() - Next step is autoRequires()
1 parent 3d4316c commit f74aaec

File tree

12 files changed

+189
-28
lines changed

12 files changed

+189
-28
lines changed

blackbox-test-inject/src/main/java/org/example/myapp/config/AppConfig.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,12 @@ public Provider provider() {
6565

6666
@Bean
6767
public MyGen<String> myGen() {
68-
return new MyGen<String>();
68+
return new MyGen<>();
69+
}
70+
71+
@Bean
72+
MyInterface myInterface2() {
73+
return new MyInterface() {};
6974
}
7075

7176
public static class Builder {
@@ -88,6 +93,10 @@ public static class MyGen<T> {
8893

8994
}
9095

96+
public interface MyInterface {
97+
98+
}
99+
91100
public static class MyPrim {
92101
public final String val;
93102
public MyPrim(String val) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ List<String> getProvides() {
115115
return typeReader.getProvides();
116116
}
117117

118+
String autoProvides() {
119+
return typeReader.autoProvides();
120+
}
121+
118122
Set<GenericType> getGenericTypes() {
119123
return typeReader.getGenericTypes();
120124
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ final class MetaData {
3131
* The list of dependencies with optional and named.
3232
*/
3333
private List<Dependency> dependsOn;
34+
35+
/**
36+
* Type deemed to be candidate for providing to another external module.
37+
*/
38+
private String autoProvides;
3439
private boolean generateProxy;
3540

3641
MetaData(DependencyMeta meta) {
@@ -40,6 +45,7 @@ final class MetaData {
4045
this.method = meta.method();
4146
this.provides = asList(meta.provides());
4247
this.dependsOn = Stream.of(meta.dependsOn()).map(Dependency::new).collect(Collectors.toList());
48+
this.autoProvides = meta.autoProvides();
4349
}
4450

4551
MetaData(String type, String name) {
@@ -113,6 +119,7 @@ private List<String> asList(String[] content) {
113119
void update(BeanReader beanReader) {
114120
this.provides = beanReader.getProvides();
115121
this.dependsOn = beanReader.getDependsOn();
122+
this.autoProvides = beanReader.autoProvides();
116123
this.generateProxy = beanReader.isGenerateProxy();
117124
}
118125

@@ -128,6 +135,10 @@ List<Dependency> getDependsOn() {
128135
return dependsOn;
129136
}
130137

138+
String getAutoProvides() {
139+
return autoProvides;
140+
}
141+
131142
/**
132143
* Return the top level package for the bean and the interfaces it implements.
133144
*/
@@ -164,6 +175,9 @@ void buildMethod(Append append) {
164175
if (!dependsOn.isEmpty()) {
165176
appendProvides(append, "dependsOn", dependsOn.stream().map(Dependency::dependsOn).collect(Collectors.toList()));
166177
}
178+
if (autoProvides != null && !autoProvides.isEmpty()) {
179+
append.append(", autoProvides=\"").append(autoProvides).append("\"");
180+
}
167181
append.append(")").append(NEWLINE);
168182
append.append(" private void build_").append(getBuildName()).append("() {").append(NEWLINE);
169183
if (hasMethod()) {
@@ -205,4 +219,7 @@ void setMethod(String method) {
205219
this.method = method;
206220
}
207221

222+
void setAutoProvides(String autoProvides) {
223+
this.autoProvides = autoProvides;
224+
}
208225
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ MetaData createMeta() {
134134
}
135135
metaData.setDependsOn(dependsOn);
136136
metaData.setProvides(typeReader == null ? Collections.emptyList() : typeReader.getProvides());
137+
metaData.setAutoProvides(typeReader == null ? null : typeReader.autoProvides());
137138
return metaData;
138139
}
139140

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

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -395,18 +395,43 @@ private void buildClassArray(Append writer, Set<String> values) {
395395
}
396396

397397
void buildFields(Append writer) {
398-
writer.append(" private final Class<?>[] provides = ");
399-
buildClassArray(writer, provides);
400-
writer.append(";").eol();
401-
writer.append(" private final Class<?>[] requires = ");
402-
buildClassArray(writer, requires);
403-
writer.append(";").eol();
404-
writer.append(" private final Class<?>[] requiresPackages = ");
405-
buildClassArray(writer, requiresPackages);
406-
writer.append(";").eol();
398+
if (!provides.isEmpty()) {
399+
writer.append(" private final Class<?>[] provides = ");
400+
buildClassArray(writer, provides);
401+
writer.append(";").eol();
402+
}
403+
if (!requires.isEmpty()) {
404+
writer.append(" private final Class<?>[] requires = ");
405+
buildClassArray(writer, requires);
406+
writer.append(";").eol();
407+
}
408+
if (!requiresPackages.isEmpty()) {
409+
writer.append(" private final Class<?>[] requiresPackages = ");
410+
buildClassArray(writer, requiresPackages);
411+
writer.append(";").eol();
412+
}
407413
writer.append(" private Builder builder;").eol().eol();
408414
}
409415

416+
void buildProvides(Append writer) {
417+
if (!provides.isEmpty()) {
418+
buildProvidesMethod(writer, "provides");
419+
}
420+
if (!requires.isEmpty()) {
421+
buildProvidesMethod(writer, "requires");
422+
}
423+
if (!requiresPackages.isEmpty()) {
424+
buildProvidesMethod(writer, "requiresPackages");
425+
}
426+
}
427+
428+
private void buildProvidesMethod(Append writer, String fieldName) {
429+
writer.append(" @Override").eol();
430+
writer.append(" public Class<?>[] %s() {", fieldName).eol();
431+
writer.append(" return %s;", fieldName).eol();
432+
writer.append(" }").eol().eol();
433+
}
434+
410435
void readModuleMetaData(TypeElement moduleType) {
411436
InjectModule module = moduleType.getAnnotation(InjectModule.class);
412437
details(module.name(), moduleType);

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

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ void write(ScopeInfo.Type scopeType) throws IOException {
6565
writer = new Append(createFileWriter());
6666
writePackage();
6767
writeStartClass();
68+
writeAutoProvides();
6869
writeClassesMethod();
6970
writeBuildMethod();
7071
writeBuildMethods();
@@ -89,12 +90,42 @@ private void writeServicesFile(ScopeInfo.Type scopeType) {
8990
}
9091
}
9192

93+
private void writeAutoProvides() {
94+
Set<String> autoProvidesAspects = new TreeSet<>();
95+
Set<String> autoProvides = new TreeSet<>();
96+
97+
for (MetaData metaData : ordering.ordered()) {
98+
String forExternal = metaData.getAutoProvides();
99+
if (forExternal != null && !forExternal.isEmpty()) {
100+
if (Util.isAspectProvider(forExternal)) {
101+
autoProvidesAspects.add(Util.extractAspectType(forExternal));
102+
} else if (!forExternal.contains("<")) {
103+
autoProvides.add(forExternal);
104+
}
105+
}
106+
}
107+
if (!autoProvides.isEmpty()) {
108+
writer.append(" @Override").eol();
109+
writer.append(" public Class<?>[] autoProvides() {").eol();
110+
writeReturnClassArray(autoProvides);
111+
}
112+
if (!autoProvidesAspects.isEmpty()) {
113+
writer.append(" @Override").eol();
114+
writer.append(" public Class<?>[] autoProvidesAspects() {").eol();
115+
writeReturnClassArray(autoProvidesAspects);
116+
}
117+
}
118+
92119
private void writeClassesMethod() {
93120
Set<String> allClasses = distinctPublicClasses();
94121
writer.append(" @Override").eol();
95122
writer.append(" public Class<?>[] classes() {").eol();
123+
writeReturnClassArray(new TreeSet<>(allClasses));
124+
}
125+
126+
private void writeReturnClassArray(Set<String> types) {
96127
writer.append(" return new Class<?>[]{").eol();
97-
for (String rawType : new TreeSet<>(allClasses)) {
128+
for (String rawType : types) {
98129
writer.append(" %s.class,", rawType).eol();
99130
}
100131
writer.append(" };").eol();
@@ -178,20 +209,7 @@ private void writeStartClass() {
178209
if (scopeInfo.addModuleConstructor()) {
179210
writeConstructor();
180211
}
181-
writer.append(" @Override").eol();
182-
writer.append(" public Class<?>[] provides() {").eol();
183-
writer.append(" return provides;").eol();
184-
writer.append(" }").eol().eol();
185-
186-
writer.append(" @Override").eol();
187-
writer.append(" public Class<?>[] requires() {").eol();
188-
writer.append(" return requires;").eol();
189-
writer.append(" }").eol().eol();
190-
191-
writer.append(" @Override").eol();
192-
writer.append(" public Class<?>[] requiresPackages() {").eol();
193-
writer.append(" return requiresPackages;").eol();
194-
writer.append(" }").eol().eol();
212+
scopeInfo.buildProvides(writer);
195213
}
196214

197215
private void writeWithBeans() {

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

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

33
import javax.lang.model.element.Element;
4+
import javax.lang.model.element.ElementKind;
45
import javax.lang.model.element.Modifier;
56
import javax.lang.model.element.TypeElement;
67
import javax.lang.model.type.TypeMirror;
@@ -22,6 +23,7 @@ final class TypeExtendsReader {
2223
private final List<String> providesTypes = new ArrayList<>();
2324
private final String beanSimpleName;
2425
private final String baseTypeRaw;
26+
private final boolean baseTypeIsInterface;
2527
private boolean closeable;
2628
/**
2729
* The implied qualifier name based on naming convention.
@@ -35,6 +37,7 @@ final class TypeExtendsReader {
3537
this.extendsInjection = new TypeExtendsInjection(baseType, context, factory, importTypes);
3638
this.beanSimpleName = baseType.getSimpleName().toString();
3739
this.baseTypeRaw = Util.unwrapProvider(baseGenericType.toString());
40+
this.baseTypeIsInterface = baseType.getKind() == ElementKind.INTERFACE;
3841
}
3942

4043
GenericType getBaseType() {
@@ -73,6 +76,16 @@ MethodReader getConstructor() {
7376
return extendsInjection.getConstructor();
7477
}
7578

79+
String autoProvides() {
80+
if (baseTypeIsInterface) {
81+
return baseTypeRaw;
82+
}
83+
if (!interfaceTypes.isEmpty()) {
84+
return interfaceTypes.get(0);
85+
}
86+
return null;
87+
}
88+
7689
List<String> getProvides() {
7790
return providesTypes;
7891
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ List<String> getProvides() {
4141
return extendsReader.getProvides();
4242
}
4343

44+
String autoProvides() {
45+
return extendsReader.autoProvides();
46+
}
47+
4448
boolean isClosable() {
4549
return extendsReader.isCloseable();
4650
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99

1010
final class Util {
1111

12+
static final String ASPECT_PROVIDER_PREFIX = "io.avaje.inject.aop.AspectProvider<";
1213
static final String PROVIDER_PREFIX = "jakarta.inject.Provider<";
1314
private static final String OPTIONAL_PREFIX = "java.util.Optional<";
1415
private static final String NULLABLE = "Nullable";
1516
private static final int PROVIDER_LENGTH = PROVIDER_PREFIX.length();
17+
private static final int ASPECT_PROVIDER_LENGTH = ASPECT_PROVIDER_PREFIX.length();
1618

1719
static boolean isVoid(String type) {
1820
return "void".equalsIgnoreCase(type);
@@ -141,6 +143,10 @@ static UtilType determineType(TypeMirror rawType) {
141143
return UtilType.of(rawType.toString());
142144
}
143145

146+
static boolean isAspectProvider(String rawType) {
147+
return rawType.startsWith(ASPECT_PROVIDER_PREFIX);
148+
}
149+
144150
static boolean isProvider(String rawType) {
145151
return rawType.startsWith(PROVIDER_PREFIX);
146152
}
@@ -149,6 +155,10 @@ private static String extractProviderType(String rawType) {
149155
return rawType.substring(PROVIDER_LENGTH, rawType.length() - 1);
150156
}
151157

158+
static String extractAspectType(String rawType) {
159+
return rawType.substring(ASPECT_PROVIDER_LENGTH, rawType.length() - 1);
160+
}
161+
152162
/**
153163
* Return the common parent package.
154164
*/

inject-generator/src/test/java/io/avaje/inject/generator/UtilTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,26 @@ void commonParent() {
3434
assertEquals(Util.commonParent("org.foo.web.foo", "org.foo.service.blah"), "org.foo");
3535
}
3636

37+
@Test
38+
void isAspectProvider() {
39+
assertTrue(Util.isAspectProvider("io.avaje.inject.aop.AspectProvider<org.Foo>"));
40+
assertTrue(Util.isAspectProvider("io.avaje.inject.aop.AspectProvider<org.one.Bar"));
41+
}
42+
43+
@Test
44+
void isAspectProvider_not() {
45+
assertFalse(Util.isAspectProvider("not.avaje.inject.aop.AspectProvider<org.Foo>"));
46+
assertFalse(Util.isAspectProvider("io.avaje.inject.not.AspectProvider<org.one.Bar"));
47+
assertFalse(Util.isAspectProvider("io.avaje.inject.aop.NotAspectProvider<org.one.Bar"));
48+
assertFalse(Util.isAspectProvider("io.avaje.inject.aop.NotAspectProvider"));
49+
}
50+
51+
@Test
52+
void extractAspectType() {
53+
assertEquals(Util.extractAspectType("io.avaje.inject.aop.AspectProvider<org.Foo>"), "org.Foo");
54+
assertEquals(Util.extractAspectType("io.avaje.inject.aop.AspectProvider<org.one.Bar>"), "org.one.Bar");
55+
}
56+
3757
@Test
3858
void unwrapProvider() {
3959
assertEquals(Util.unwrapProvider("jakarta.inject.Provider<org.Foo<com.Bazz>>"), "org.Foo<com.Bazz>");

inject/src/main/java/io/avaje/inject/spi/DependencyMeta.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,11 @@
3737
*/
3838
String[] dependsOn() default {};
3939

40+
/**
41+
* Type deemed to be reasonable to provide to external module.
42+
* <p>
43+
* Used to support multiple module wiring automatically (as alternative to using explicit InjectModule annotation).
44+
*/
45+
String autoProvides() default "";
46+
4047
}

0 commit comments

Comments
 (0)