Skip to content

Commit 4252d60

Browse files
authored
Remove Generated Array Instantiation (#366)
* remove array instantiation * Update Processor.java * Update SimpleModuleWriter.java * more javadoc changes * Update README.md * Update README.md * Update SimpleModuleWriter.java * Update README.md * java highlighting * add dependency class * Update README.md
1 parent aebe6ae commit 4252d60

File tree

5 files changed

+111
-23
lines changed

5 files changed

+111
-23
lines changed

README.md

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![Discord](https://img.shields.io/discord/1074074312421683250?color=%237289da&label=discord)](https://discord.gg/Qcqf9R27BR)
66

77
# [Avaje-Inject](https://avaje.io/inject)
8-
APT based dependency injection for server side developers - https://avaje.io/inject
8+
APT-based dependency injection for server-side developers - https://avaje.io/inject
99
## Quick Start
1010
#### 1. Add avaje-inject as a dependency.
1111
```xml
@@ -31,7 +31,7 @@ public class Example {
3131

3232
private DependencyClass d1;
3333
private DependencyClass2 d2;
34-
34+
3535
// Dependencies must be annotated with singleton,
3636
// or else be provided from another class annotated with @Factory
3737
public Example(DependencyClass d1, DependencyClass2 d2) {
@@ -45,19 +45,20 @@ Example factory class:
4545
@Factory
4646
public class ExampleFactory {
4747
@Bean
48-
public DependencyClass2() {
48+
public DependencyClass2 bean() {
4949
return new DependencyClass2();
5050
}
5151
}
5252
```
5353

54-
#### 4. Use BeanScope to wire and retrieve the beans and use however you wish.
54+
#### 4. Use BeanScope to wire and retrieve the beans and use them however you wish.
5555
```java
5656
BeanScope beanScope = BeanScope.builder().build()
5757
Example ex = beanScope.get(Example.class);
5858
```
5959

60-
### Example module use
60+
### Java Module Usage
61+
When working with Java modules you need to add a `provides` statement in your `module-info.java` with the generated class.
6162
```java
6263
import io.avaje.inject.spi.Module;
6364

@@ -69,23 +70,108 @@ module org.example {
6970
}
7071
```
7172

72-
## Similar to Dagger (https://google.github.io/dagger/)
73+
## Similar to [Dagger](https://google.github.io/dagger/)
7374

7475
- Uses Java annotation processing for dependency injection
7576
- Generates source code
7677
- Avoids any use of reflection or classpath scanning (so low overhead and fast startup)
77-
- A `Library only` (a DI library and that's it. ~25k in size)
78-
7978

8079
## Differences to Dagger
8180

82-
- Aimed specifically for server side development (rather than Andriod)
81+
- Aimed specifically for server-side development (rather than Android)
8382
- Supports lifecycle methods with `@PostConstruct` and `@PreDestory`
8483
- Supports `@Factory` and `@Bean`
8584
- Provides API to obtain all bean instances that implement an interface
8685
- Provides API to obtain all bean instances that have an annotation
87-
- Integration with server side web frameworks Javalin, Helidon
86+
- Integration with server-side web frameworks Javalin, Helidon
8887

8988
## Spring DI
9089

9190
For comparison with Spring DI look at https://avaje.io/inject/#spring
91+
92+
93+
## Generated Code
94+
95+
### DI classes
96+
97+
DI classes will be generated to call the constructors for annotated type/factory methods. Below is the class generated for the `Example` class in the above quickstart.
98+
99+
```java
100+
@Generated("io.avaje.inject.generator")
101+
public final class Example$DI {
102+
103+
/**
104+
* Create and register Example.
105+
*/
106+
public static void build(Builder builder) {
107+
if (builder.isAddBeanFor(Example.class)) {
108+
var bean = new Example(builder.get(DependencyClass.class,"!d1"), builder.get(DependencyClass2.class,"!d2"));
109+
builder.register(bean);
110+
// depending on the type of bean, callbacks for field/method injection, and lifecycle support will be generated here as well.
111+
}
112+
}
113+
}
114+
```
115+
116+
### Generated Wiring Class
117+
The inject annotation processor determines the dependency wiring order and generates a `Module` class that calls all the generated DI classes.
118+
119+
```java
120+
@Generated("io.avaje.inject.generator")
121+
@InjectModule
122+
public final class ExampleModule implements Module {
123+
124+
private Builder builder;
125+
126+
@Override
127+
public Class<?>[] classes() {
128+
return new Class<?>[] {
129+
org.example.DependencyClass.class,
130+
org.example.DependencyClass2.class,
131+
org.example.Example.class,
132+
org.example.ExampleFactory.class,
133+
};
134+
}
135+
136+
/**
137+
* Creates all the beans in order based on constructor dependencies. The beans are registered
138+
* into the builder along with callbacks for field/method injection, and lifecycle
139+
* support.
140+
*/
141+
@Override
142+
public void build(Builder builder) {
143+
this.builder = builder;
144+
// create beans in order based on constructor dependencies
145+
// i.e. "provides" followed by "dependsOn"
146+
build_example_ExampleFactory();
147+
build_example_DependencyClass();
148+
build_example_DependencyClass2();
149+
build_example_Example();
150+
}
151+
152+
@DependencyMeta(type = "org.example.ExampleFactory")
153+
private void build_example_ExampleFactory() {
154+
ExampleFactory$DI.build(builder);
155+
}
156+
157+
@DependencyMeta(type = "org.example.DependencyClass")
158+
private void build_example_DependencyClass() {
159+
DependencyClass$DI.build(builder);
160+
}
161+
162+
@DependencyMeta(
163+
type = "org.example.DependencyClass2",
164+
method = "org.example.ExampleFactory$DI.build_bean", // factory method
165+
dependsOn = {"org.example.ExampleFactory"}) //factory beans naturally depend on the factory
166+
private void build_example_DependencyClass2() {
167+
ExampleFactory$DI.build_bean(builder);
168+
}
169+
170+
@DependencyMeta(
171+
type = "org.example.Example",
172+
dependsOn = {"org.example.DependencyClass", "org.example.DependencyClass2"})
173+
private void build_example_Example() {
174+
Example$DI.build(builder);
175+
}
176+
}
177+
```

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,10 @@ private static Set<TypeElement> importedElements(RoundEnvironment roundEnv) {
133133
}
134134

135135
private static Map<String, AspectImportPrism> importedAspects(RoundEnvironment roundEnv) {
136-
return roundEnv.getElementsAnnotatedWith(element(AspectImportPrism.PRISM_TYPE)).stream()
136+
return Optional.ofNullable(element(AspectImportPrism.PRISM_TYPE))
137+
.map(roundEnv::getElementsAnnotatedWith)
138+
.stream()
139+
.flatMap(Set::stream)
137140
.map(AspectImportPrism::getInstanceOn)
138141
.collect(Collectors.toMap(p -> p.value().toString(), p -> p));
139142
}

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@ void writeModule() {
234234
}
235235
return;
236236
}
237-
MetaDataOrdering ordering = new MetaDataOrdering(meta, this);
238-
int remaining = ordering.processQueue();
237+
final MetaDataOrdering ordering = new MetaDataOrdering(meta, this);
238+
final int remaining = ordering.processQueue();
239239
if (remaining > 0) {
240240
ordering.logWarnings();
241241
}
@@ -364,7 +364,7 @@ void buildAtInjectModule(Append writer) {
364364
if (leadingComma) {
365365
writer.append(", ");
366366
}
367-
writer.append("customScopeType=\"%s\"", annotationType.getQualifiedName().toString());
367+
writer.append("customScopeType = \"%s\"", annotationType.getQualifiedName().toString());
368368
}
369369
writer.append(")").eol();
370370
}
@@ -373,9 +373,9 @@ private void attributeClasses(boolean leadingComma, Append writer, String prefix
373373
if (leadingComma) {
374374
writer.append(", ");
375375
}
376-
writer.append("%s={", prefix);
376+
writer.append("%s = {", prefix);
377377
int c = 0;
378-
for (String value : classNames) {
378+
for (final String value : classNames) {
379379
if (c++ > 0) {
380380
writer.append(",");
381381
}
@@ -399,7 +399,7 @@ void buildProvides(Append writer) {
399399
private void buildProvidesMethod(Append writer, String fieldName, Set<String> types) {
400400
writer.append(" @Override").eol();
401401
writer.append(" public Class<?>[] %s() {\n return %s;\n }", fieldName, fieldName).eol();
402-
writer.append(" private final Class<?>[] %s = new Class<?>[]{", fieldName).eol();
402+
writer.append(" private final Class<?>[] %s = {", fieldName).eol();
403403
for (final String rawType : types) {
404404
writer.append(" %s.class,", trimGenerics(rawType)).eol();
405405
}
@@ -446,7 +446,7 @@ void readModuleMetaData(TypeElement moduleType) {
446446
}
447447

448448
private void readFactoryMetaData(TypeElement moduleType) {
449-
List<? extends Element> elements = moduleType.getEnclosedElements();
449+
final List<? extends Element> elements = moduleType.getEnclosedElements();
450450
if (elements != null) {
451451
for (Element element : elements) {
452452
if (ElementKind.METHOD == element.getKind()) {

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ final class SimpleModuleWriter {
1818

1919
private static final String CODE_COMMENT_FACTORY =
2020
"/**\n" +
21-
" * Generated source - avaje inject module for %s.\n" +
21+
" * Avaje Inject module for %s.\n" +
2222
" * \n" +
23-
" * With the Java module system, this generated class should be explicitly\n" +
23+
" * When using the Java module system, this generated class should be explicitly\n" +
2424
" * registered in module-info via a <code>provides</code> clause like:\n" +
2525
" * \n" +
2626
" * <pre>{@code\n" +
@@ -37,11 +37,9 @@ final class SimpleModuleWriter {
3737

3838
private static final String CODE_COMMENT_CREATE_CONTEXT =
3939
" /**\n" +
40-
" * Create the beans.\n" +
41-
" * <p>\n" +
4240
" * Creates all the beans in order based on constructor dependencies.\n" +
4341
" * The beans are registered into the builder along with callbacks for\n" +
44-
" * field injection, method injection and lifecycle support.\n" +
42+
" * field/method injection, and lifecycle support.\n" +
4543
" */";
4644

4745
private final String modulePackage;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ default Class<?>[] autoProvidesAspects() {
6363
default Class<?>[] autoRequires() {
6464
return EMPTY_CLASSES;
6565
}
66+
6667
/**
6768
* These are the apects that this module requires whose implementations are provided by other external
6869
* modules (that are in the classpath at compile time).

0 commit comments

Comments
 (0)