Skip to content

Commit d632f95

Browse files
authored
Merge pull request #440 from avaje/feature/439
#439 Handle case where Factory method throws exception
2 parents 3755485 + dda793f commit d632f95

File tree

7 files changed

+123
-45
lines changed

7 files changed

+123
-45
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import io.avaje.inject.Bean;
44
import io.avaje.inject.Factory;
55

6+
import java.io.IOException;
7+
68
@Factory
79
class AFactory {
810

@@ -27,10 +29,19 @@ void ad(A0.Builder b1, A1.Builder b2) {
2729
b2.hashCode();
2830
}
2931

32+
@Bean
33+
AFoo buildAfoo() throws IOException {
34+
return new AFoo();
35+
}
36+
3037
static class I0 implements A0.Builder {
3138

3239
}
3340
static class I1 implements A1.Builder {
3441

3542
}
43+
44+
static class AFoo {
45+
46+
}
3647
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,29 @@ final class Append {
1212
private final Writer writer;
1313
private int nameIndex;
1414
private boolean comma;
15+
private String extraIndent;
1516

1617
Append(Writer writer) {
1718
this.writer = writer;
1819
}
1920

21+
Append setExtraIndent(String extraIndent) {
22+
this.extraIndent = extraIndent;
23+
return this;
24+
}
25+
26+
Append indent(String content) {
27+
try {
28+
if (extraIndent != null) {
29+
writer.append(extraIndent);
30+
}
31+
writer.append(content);
32+
return this;
33+
} catch (IOException e) {
34+
throw new UncheckedIOException(e);
35+
}
36+
}
37+
2038
Append append(String content) {
2139
try {
2240
writer.append(content);

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ void buildRegister(Append writer) {
240240
if (prototype) {
241241
return;
242242
}
243-
writer.append(" ");
243+
writer.indent(" ");
244244
if (isExtraInjectionRequired() || hasLifecycleMethods()) {
245245
writer.append("var $bean = ");
246246
}
@@ -255,14 +255,14 @@ void buildRegister(Append writer) {
255255

256256
void addLifecycleCallbacks(Append writer, String indent) {
257257
if (postConstructMethod != null && !prototype) {
258-
writer.append("%s builder.addPostConstruct($bean::%s);", indent, postConstructMethod.getSimpleName()).eol();
258+
writer.indent(indent).append(" builder.addPostConstruct($bean::%s);", postConstructMethod.getSimpleName()).eol();
259259
}
260260
if (preDestroyMethod != null) {
261261
prototypeNotSupported("@PreDestroy");
262262
var priority = preDestroyPriority == null || preDestroyPriority == 1000 ? "" : ", " + preDestroyPriority;
263-
writer.append("%s builder.addPreDestroy($bean::%s%s);", indent, preDestroyMethod.getSimpleName(), priority).eol();
263+
writer.indent(indent).append(" builder.addPreDestroy($bean::%s%s);", preDestroyMethod.getSimpleName(), priority).eol();
264264
} else if (typeReader.isClosable() && !prototype) {
265-
writer.append("%s builder.addPreDestroy($bean);", indent).eol();
265+
writer.indent(indent).append(" builder.addPreDestroy($bean);").eol();
266266
}
267267
}
268268

@@ -448,4 +448,13 @@ private String beanPackageName() {
448448
private String beanQualifiedName() {
449449
return beanType.getQualifiedName().toString();
450450
}
451+
452+
boolean needsTryForMethodInjection() {
453+
for (MethodReader injectMethod : injectMethods) {
454+
if (injectMethod.methodThrows()) {
455+
return true;
456+
}
457+
}
458+
return false;
459+
}
451460
}

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

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ final class MethodReader {
2626
private final boolean isVoid;
2727
private final List<MethodParam> params = new ArrayList<>();
2828
private final String factoryShortName;
29-
private final boolean isFactory;
3029
private final String initMethod;
3130
private final String destroyMethod;
3231
private final Integer destroyPriority;
@@ -41,15 +40,12 @@ final class MethodReader {
4140
}
4241

4342
MethodReader(ExecutableElement element, TypeElement beanType, BeanPrism bean, String qualifierName, ImportTypeMap importTypes) {
44-
this.isFactory = bean != null;
4543
this.element = element;
46-
if (isFactory) {
44+
if (bean != null) {
4745
prototype = PrototypePrism.isPresent(element);
4846
primary = PrimaryPrism.isPresent(element);
4947
secondary = SecondaryPrism.isPresent(element);
50-
5148
conditions.readAll(element);
52-
5349
} else {
5450
prototype = false;
5551
primary = false;
@@ -164,7 +160,7 @@ void builderGetFactory(Append writer, boolean factoryHasConditions) {
164160
}
165161

166162
void builderBuildBean(Append writer) {
167-
writer.append(" ");
163+
writer.indent(" ");
168164
if (isVoid) {
169165
writer.append("factory.%s(", methodName);
170166
} else {
@@ -175,7 +171,7 @@ void builderBuildBean(Append writer) {
175171
if (i > 0) {
176172
writer.append(", ");
177173
}
178-
params.get(i).builderGetDependency(writer, "builder", true);
174+
params.get(i).builderGetDependency(writer, "builder");
179175
}
180176
writer.append(");").eol();
181177
}
@@ -191,31 +187,31 @@ void builderAddBeanProvider(Append writer) {
191187
}
192188
String indent = " ";
193189
if (prototype) {
194-
writer.append(indent).append(" builder.asPrototype().registerProvider(() -> {").eol();
190+
writer.indent(indent).append(" builder.asPrototype().registerProvider(() -> {").eol();
195191
} else {
196-
writer.append(indent).append(" builder.asSecondary().registerProvider(() -> {").eol();
192+
writer.indent(indent).append(" builder.asSecondary().registerProvider(() -> {").eol();
197193
}
198-
writer.append("%s return ", indent);
199-
writer.append(String.format("factory.%s(", methodName));
194+
writer.indent(indent).append(" return ");
195+
writer.append("factory.%s(", methodName);
200196
for (int i = 0; i < params.size(); i++) {
201197
if (i > 0) {
202198
writer.append(", ");
203199
}
204-
params.get(i).builderGetDependency(writer, "builder", true);
200+
params.get(i).builderGetDependency(writer, "builder");
205201
}
206202
writer.append(");").eol();
207-
writer.append(indent).append(" });").eol();
208-
writer.append(indent).append("}").eol();
203+
writer.indent(indent).append(" });").eol();
204+
writer.indent(indent).append("}").eol();
209205
}
210206

211207
void builderBuildAddBean(Append writer) {
212208
if (!isVoid) {
213-
String indent = optionalType ? " " : " ";
214209
if (optionalType) {
215210
writer.append(" if (optionalBean.isPresent()) {").eol();
216211
writer.append(" var bean = optionalBean.get();").eol();
217212
}
218-
writer.append(indent);
213+
String indent = optionalType ? " " : " ";
214+
writer.indent(indent);
219215
if (hasLifecycleMethods()) {
220216
writer.append("var $bean = ");
221217
}
@@ -227,15 +223,15 @@ void builderBuildAddBean(Append writer) {
227223
}
228224
writer.append(".register(bean);").eol();
229225
if (notEmpty(initMethod)) {
230-
writer.append(indent).append("builder.addPostConstruct($bean::%s);", initMethod).eol();
226+
writer.indent(indent).append("builder.addPostConstruct($bean::%s);", initMethod).eol();
231227
}
232228
var priority = destroyPriority == null || destroyPriority == 1000 ? "" : ", " + destroyPriority;
233229
if (notEmpty(destroyMethod)) {
234-
writer.append(indent).append("builder.addPreDestroy($bean::%s%s);", destroyMethod, priority).eol();
230+
writer.indent(indent).append("builder.addPreDestroy($bean::%s%s);", destroyMethod, priority).eol();
235231
} else if (typeReader != null && typeReader.isClosable()) {
236-
writer.append(indent).append("builder.addPreDestroy($bean::close%s);", priority).eol();
232+
writer.indent(indent).append("builder.addPreDestroy($bean::close%s);", priority).eol();
237233
} else if (beanCloseable) {
238-
writer.append(indent).append("builder.addAutoClosable($bean);").eol();
234+
writer.indent(indent).append("builder.addAutoClosable($bean);").eol();
239235
}
240236
if (optionalType) {
241237
writer.append(" }").eol();
@@ -285,6 +281,26 @@ void buildAddFor(Append writer) {
285281
writer.append(")) {").eol();
286282
}
287283

284+
boolean methodThrows() {
285+
return !element.getThrownTypes().isEmpty();
286+
}
287+
288+
void startTry(Append writer) {
289+
if (methodThrows()) {
290+
writer.append(" try {").eol();
291+
writer.setExtraIndent(" ");
292+
}
293+
}
294+
295+
void endTry(Append writer) {
296+
if (methodThrows()) {
297+
writer.setExtraIndent(null);
298+
writer.append(" } catch (Throwable e) {").eol();
299+
writer.append(" throw new RuntimeException(\"Error during wiring\", e);").eol();
300+
writer.append(" }").eol();
301+
}
302+
}
303+
288304
/**
289305
* Check for request scoped dependency.
290306
*/
@@ -356,7 +372,7 @@ void removeFromProvides(List<String> provides) {
356372

357373
static class MethodParam {
358374

359-
private VariableElement element;
375+
private final VariableElement element;
360376
private final String named;
361377
private final UtilType utilType;
362378
private final String paramType;
@@ -382,7 +398,6 @@ static class MethodParam {
382398
if (nullable || param.asType().toString().startsWith("java.util.Optional<")) {
383399
ProcessingContext.addOptionalType(paramType);
384400
}
385-
386401
}
387402

388403
@Override
@@ -396,7 +411,7 @@ void addDependsOnGeneric(Set<GenericType> set) {
396411
}
397412
}
398413

399-
void builderGetDependency(Append writer, String builderName, boolean forFactory) {
414+
void builderGetDependency(Append writer, String builderName) {
400415
writer.append(builderName).append(".").append(utilType.getMethod(nullable, isBeanMap));
401416
if (!genericType.isGenericType()) {
402417
writer.append(Util.shortName(genericType.topType())).append(".class");
@@ -472,11 +487,9 @@ void writeRequestConstructor(Append writer) {
472487
}
473488

474489
void writeMethodParam(Append writer) {
475-
476490
if (nullable) {
477491
writer.append("@Nullable ");
478492
}
479-
480493
if (genericType.isGenericType()) {
481494
genericType.writeShort(writer);
482495
} else {

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

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,14 @@ private void writeFactoryBeanMethod(MethodReader method) {
135135
method.buildConditional(writer);
136136
method.buildAddFor(writer);
137137
method.builderGetFactory(writer, beanReader.hasConditions());
138-
if (method.isProtoType()) {
139-
method.builderAddBeanProvider(writer);
140-
} else if (method.isUseProviderForSecondary()) {
138+
method.startTry(writer);
139+
if (method.isProtoType() || method.isUseProviderForSecondary()) {
141140
method.builderAddBeanProvider(writer);
141+
method.endTry(writer);
142142
} else {
143143
method.builderBuildBean(writer);
144144
method.builderBuildAddBean(writer);
145+
method.endTry(writer);
145146
writer.append(" }").eol();
146147
}
147148
writer.append(" }").eol().eol();
@@ -169,6 +170,7 @@ private void writeAddFor(MethodReader constructor) {
169170
indent += " ";
170171
writer.append(" builder.asPrototype().registerProvider(() -> {", shortName, shortName).eol();
171172
}
173+
constructor.startTry(writer);
172174
writeCreateBean(constructor);
173175
beanReader.buildRegister(writer);
174176
beanReader.addLifecycleCallbacks(writer, indent);
@@ -177,9 +179,10 @@ private void writeAddFor(MethodReader constructor) {
177179
}
178180
if (beanReader.prototype()) {
179181
beanReader.prototypePostConstruct(writer, indent);
180-
writer.append(" return bean;").eol();
181-
writer.append(" });", shortName, shortName).eol();
182+
writer.indent(" return bean;").eol();
183+
writer.indent(" });").eol();
182184
}
185+
constructor.endTry(writer);
183186
writer.append(" }").eol();
184187
}
185188

@@ -195,20 +198,20 @@ private void writeBuildMethodStart() {
195198
private String indent = " ";
196199

197200
private void writeCreateBean(MethodReader constructor) {
198-
writer.append(indent).append(" var bean = new %s(", shortName);
201+
writer.indent(indent).append(" var bean = new %s(", shortName);
199202
// add constructor dependencies
200203
writeMethodParams("builder", constructor);
201204
}
202205

203206
private void writeExtraInjection() {
204207
if (!beanReader.prototype()) {
205-
writer.append(" builder.addInjector(b -> {").eol();
206-
writer.append(" // field and method injection").eol();
208+
writer.indent(" ").append("builder.addInjector(b -> {").eol();
209+
writer.indent(" ").append(" // field and method injection").eol();
207210
}
208211
injectFields();
209212
injectMethods();
210213
if (!beanReader.prototype()) {
211-
writer.append(" });").eol();
214+
writer.indent(" });").eol();
212215
}
213216
}
214217

@@ -218,17 +221,27 @@ private void injectFields() {
218221
for (FieldReader fieldReader : beanReader.injectFields()) {
219222
String fieldName = fieldReader.fieldName();
220223
String getDependency = fieldReader.builderGetDependency(builder);
221-
writer.append(" %s.%s = %s;", bean, fieldName, getDependency).eol();
224+
writer.indent(" ").append("%s.%s = %s;", bean, fieldName, getDependency).eol();
222225
}
223226
}
224227

225228
private void injectMethods() {
226-
String bean = beanReader.prototype() ? "bean" : "$bean";
227-
String builder = beanReader.prototype() ? "builder" : "b";
229+
final var needsTry = beanReader.needsTryForMethodInjection();
230+
final var bean = beanReader.prototype() ? "bean" : "$bean";
231+
final var builder = beanReader.prototype() ? "builder" : "b";
232+
if (needsTry) {
233+
writer.indent(" try {").eol();
234+
}
235+
final var indent = needsTry ? " " : " ";
228236
for (MethodReader methodReader : beanReader.injectMethods()) {
229-
writer.append(" %s.%s(", bean, methodReader.name());
237+
writer.indent(indent).append("%s.%s(", bean, methodReader.name());
230238
writeMethodParams(builder, methodReader);
231239
}
240+
if (needsTry) {
241+
writer.indent(" } catch (Throwable e) {").eol();
242+
writer.indent(" throw new RuntimeException(\"Error wiring method\", e);").eol();
243+
writer.indent(" }").eol();
244+
}
232245
}
233246

234247
private void writeMethodParams(String builderRef, MethodReader methodReader) {
@@ -237,7 +250,7 @@ private void writeMethodParams(String builderRef, MethodReader methodReader) {
237250
if (i > 0) {
238251
writer.append(", ");
239252
}
240-
methodParams.get(i).builderGetDependency(writer, builderRef, false);
253+
methodParams.get(i).builderGetDependency(writer, builderRef);
241254
}
242255
writer.append(");").eol();
243256
}

inject-test/src/test/java/org/example/autonamed/MyAutoB2OneImplied.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,24 @@
22

33
import jakarta.inject.Singleton;
44

5+
import javax.annotation.PostConstruct;
6+
57
@Singleton
68
public class MyAutoB2OneImplied {
79

810
final AutoB2 one;
911

10-
public MyAutoB2OneImplied(AutoB2 one) {
12+
public MyAutoB2OneImplied(AutoB2 one) throws Exception {
1113
this.one = one;
1214
}
1315

1416
public String one() {
1517
return one.who();
1618
}
1719

20+
@PostConstruct
21+
public void postInit() {
22+
23+
}
24+
1825
}

0 commit comments

Comments
 (0)