Skip to content

Commit 398172b

Browse files
committed
#188 - ENH: Add support for prototype scope (add @prototype)
Field and method injection supported. PreDestroy lifecycle method is not supported and Closable is expected to be handled by application code. PostConstruct lifecycle method will be called.
1 parent db4fcad commit 398172b

File tree

5 files changed

+112
-12
lines changed

5 files changed

+112
-12
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,29 @@ void buildRegister(Append writer) {
186186
}
187187

188188
void addLifecycleCallbacks(Append writer, String indent) {
189-
if (postConstructMethod != null) {
189+
if (postConstructMethod != null && !prototype) {
190190
writer.append("%s builder.addPostConstruct($bean::%s);", indent, postConstructMethod.getSimpleName()).eol();
191191
}
192192
if (preDestroyMethod != null) {
193+
prototypeNotSupported(writer, "@PreDestroy");
193194
writer.append("%s builder.addPreDestroy($bean::%s);", indent, preDestroyMethod.getSimpleName()).eol();
194-
} else if (typeReader.isClosable()) {
195+
} else if (typeReader.isClosable() && !prototype) {
195196
writer.append("%s builder.addPreDestroy($bean);", indent).eol();
196197
}
197198
}
198199

200+
void prototypePostConstruct(Append writer, String indent) {
201+
if (postConstructMethod != null) {
202+
writer.append("%s bean.%s();", indent, postConstructMethod.getSimpleName()).eol();
203+
}
204+
}
205+
206+
private void prototypeNotSupported(Append writer, String lifecycle) {
207+
if (prototype) {
208+
writer.append(" // @Prototype scoped bean does not support %s lifecycle method", lifecycle).eol();
209+
}
210+
}
211+
199212
private Set<String> importTypes() {
200213
importTypes.add(Constants.GENERATED);
201214
importTypes.add(Constants.BUILDER);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ void addImports(Set<String> importTypes) {
2929
importTypes.add(fieldType);
3030
}
3131

32-
String builderGetDependency() {
32+
String builderGetDependency(String builder) {
3333
StringBuilder sb = new StringBuilder();
34-
sb.append("b.").append(type.getMethod(nullable));
34+
sb.append(builder).append(".").append(type.getMethod(nullable));
3535
sb.append(nm(fieldType)).append(".class");
3636
if (name != null) {
3737
sb.append(",\"").append(name).append("\"");

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

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class SimpleBeanWriter {
1616
private static final String CODE_COMMENT = "/**\n * Generated source - dependency injection builder for %s.\n */";
1717
private static final String CODE_COMMENT_FACTORY = "/**\n * Generated source - dependency injection factory for request scoped %s.\n */";
1818
private static final String CODE_COMMENT_BUILD = " /**\n * Create and register %s.\n */";
19+
private static final String CODE_COMMENT_BUILD_PROVIDER = " /**\n * Register %s provider.\n */";
1920

2021
private final BeanReader beanReader;
2122
private final ProcessingContext context;
@@ -146,6 +147,7 @@ private void writeAddFor(MethodReader constructor) {
146147
beanReader.buildAddFor(writer);
147148
if (beanReader.prototype()) {
148149
indent += " ";
150+
writer.append(" // prototype scope so register provider").eol();
149151
writer.append(" builder.registerProvider(() -> {", shortName, shortName).eol();
150152
}
151153
writeCreateBean(constructor);
@@ -155,6 +157,7 @@ private void writeAddFor(MethodReader constructor) {
155157
writeExtraInjection();
156158
}
157159
if (beanReader.prototype()) {
160+
beanReader.prototypePostConstruct(writer, indent);
158161
writer.append(" return bean;").eol();
159162
writer.append(" });", shortName, shortName).eol();
160163
}
@@ -163,7 +166,11 @@ private void writeAddFor(MethodReader constructor) {
163166

164167
private void writeBuildMethodStart(MethodReader constructor) {
165168
int providerIndex = 0;
166-
writer.append(CODE_COMMENT_BUILD, shortName).eol();
169+
if (beanReader.prototype()) {
170+
writer.append(CODE_COMMENT_BUILD_PROVIDER, shortName).eol();
171+
} else {
172+
writer.append(CODE_COMMENT_BUILD, shortName).eol();
173+
}
167174
writer.append(" public static void build(Builder builder");
168175
for (MethodReader.MethodParam param : constructor.getParams()) {
169176
if (param.isGenericParam()) {
@@ -188,25 +195,33 @@ private void writeCreateBean(MethodReader constructor) {
188195
}
189196

190197
private void writeExtraInjection() {
191-
writer.append(" builder.addInjector(b -> {").eol();
192-
writer.append(" // field and method injection").eol();
198+
if (!beanReader.prototype()) {
199+
writer.append(" builder.addInjector(b -> {").eol();
200+
writer.append(" // field and method injection").eol();
201+
}
193202
injectFields();
194203
injectMethods();
195-
writer.append(" });").eol();
204+
if (!beanReader.prototype()) {
205+
writer.append(" });").eol();
206+
}
196207
}
197208

198209
private void injectFields() {
210+
String bean = beanReader.prototype() ? "bean" : "$bean";
211+
String builder = beanReader.prototype() ? "builder" : "b";
199212
for (FieldReader fieldReader : beanReader.getInjectFields()) {
200213
String fieldName = fieldReader.getFieldName();
201-
String getDependency = fieldReader.builderGetDependency();
202-
writer.append(" $bean.%s = %s;", fieldName, getDependency).eol();
214+
String getDependency = fieldReader.builderGetDependency(builder);
215+
writer.append(" %s.%s = %s;", bean, fieldName, getDependency).eol();
203216
}
204217
}
205218

206219
private void injectMethods() {
220+
String bean = beanReader.prototype() ? "bean" : "$bean";
221+
String builder = beanReader.prototype() ? "builder" : "b";
207222
for (MethodReader methodReader : beanReader.getInjectMethods()) {
208-
writer.append(" $bean.%s(", methodReader.getName());
209-
writeMethodParams("b", methodReader);
223+
writer.append(" %s.%s(", bean, methodReader.getName());
224+
writeMethodParams(builder, methodReader);
210225
}
211226
}
212227

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.example.coffee.prototype;
2+
3+
import io.avaje.inject.PostConstruct;
4+
import io.avaje.inject.Prototype;
5+
import jakarta.inject.Inject;
6+
7+
import java.io.Closeable;
8+
import java.io.IOException;
9+
10+
@Prototype
11+
public class ExtraProto implements Closeable {
12+
13+
boolean initRun;
14+
15+
@Inject
16+
MyProto fieldInjected;
17+
18+
OtherProto methodInjected;
19+
20+
@Inject
21+
void methodInjected(OtherProto methodInjected) {
22+
this.methodInjected = methodInjected;
23+
}
24+
25+
@PostConstruct
26+
void init() {
27+
initRun = true;
28+
}
29+
30+
public MyProto fieldInjected() {
31+
return fieldInjected;
32+
}
33+
34+
public OtherProto methodInjected() {
35+
return methodInjected;
36+
}
37+
38+
public boolean initRun() {
39+
return initRun;
40+
}
41+
42+
@Override
43+
public void close() throws IOException {
44+
45+
}
46+
47+
// Compilation error expected with PreDestroy
48+
// @PreDestroy
49+
// void foo() { }
50+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.example.coffee.prototype;
2+
3+
import io.avaje.inject.BeanScope;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
8+
class ExtraProtoTest {
9+
10+
@Test
11+
void fieldMethodInjection() {
12+
try (BeanScope scope = BeanScope.newBuilder()
13+
.build()) {
14+
15+
ExtraProto extra = scope.get(ExtraProto.class);
16+
17+
assertThat(extra.fieldInjected()).isNotNull();
18+
assertThat(extra.methodInjected()).isNotNull();
19+
assertThat(extra.initRun()).isTrue();
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)