Skip to content

Commit afab32d

Browse files
authored
Bug fix for @bean returning Optional not registering extended type (#782)
Example: ``` @bean Optional<CFace> optional() { ... } ``` The generated isBeanAbsent() method should include all the types that CFace extends such as interfaces. If CFace extends C2Face then both should be there like: .isBeanAbsent(CFace.class, C2Face.class)) The bug was that only the top type of CFace was included like: ``` .isBeanAbsent(CFace.class)) ``` This was due to a bug in MethodReader determining the incorrect returnElement for the optionalType = true case. The returnElement was the Optional type rather than the parameter type CFace.
1 parent b4f4dba commit afab32d

File tree

6 files changed

+83
-1
lines changed

6 files changed

+83
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.example.myapp.config;
2+
3+
public interface C2Face {
4+
5+
String msg();
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.example.myapp.config;
2+
3+
public interface CFace extends C2Face {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.example.myapp.config;
2+
3+
import io.avaje.inject.Bean;
4+
import io.avaje.inject.Factory;
5+
import jakarta.inject.Named;
6+
7+
import java.util.Optional;
8+
9+
@Factory
10+
class CFactory {
11+
12+
@Bean @Named("base")
13+
CFace base() {
14+
return new TheCFace("base");
15+
}
16+
17+
@Bean @Named("optional")
18+
Optional<CFace> optional() {
19+
return Optional.of(new TheCFace("optional"));
20+
}
21+
22+
static final class TheCFace implements CFace {
23+
24+
private final String msg;
25+
26+
TheCFace(String msg) {
27+
this.msg = msg;
28+
}
29+
30+
@Override
31+
public String msg() {
32+
return msg;
33+
}
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.example.myapp.config;
2+
3+
import io.avaje.inject.BeanScope;
4+
import io.avaje.inject.test.TestBeanScope;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.util.List;
8+
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
11+
class CFactoryTest {
12+
13+
@Test
14+
void optionalWithCascadingInterfaces() {
15+
try (BeanScope scope = TestBeanScope.builder().build()) {
16+
C2Face base = scope.get(C2Face.class, "base");
17+
CFace cface = scope.get(CFace.class, "optional");
18+
C2Face c2face = scope.get(C2Face.class, "optional");
19+
assertThat(base.msg()).isEqualTo("base");
20+
assertThat(cface.msg()).isEqualTo("optional");
21+
assertThat(c2face.msg()).isEqualTo("optional");
22+
23+
List<C2Face> list = scope.list(C2Face.class);
24+
assertThat(list).hasSize(2);
25+
}
26+
}
27+
}

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ final class MethodReader {
9191
// for multiRegister we desire a qualifier name such that builder.isBeanAbsent() uses it and allows
9292
// other beans of the same type to also register, otherwise it defaults to slightly confusing behaviour
9393
this.name = multiRegister && qualifierName == null ? "multi" : qualifierName;
94-
TypeElement returnElement = multiRegister ? APContext.typeElement(uType.mainType()) : asElement(returnMirror);
94+
TypeElement returnElement =
95+
multiRegister
96+
? APContext.typeElement(returnTypeRaw)
97+
: optionalType ? APContext.typeElement(returnTypeRaw) : asElement(returnMirror);
9598
if (returnElement == null) {
9699
this.typeReader = null;
97100
this.initMethod = initMethod;

inject-generator/src/test/java/io/avaje/inject/generator/models/valid/ConfigFactory.java

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.avaje.inject.generator.models.valid;
22

33
import java.util.Map;
4+
import java.util.Optional;
45

56
import io.avaje.inject.Bean;
67
import io.avaje.inject.Factory;
@@ -19,4 +20,10 @@ Map<String, Long> map1() {
1920
Map<String, String> map2(@Named("map1") Map<String, Long> map1) {
2021
return Map.of();
2122
}
23+
24+
@Bean
25+
@Named("optionalA0")
26+
Optional<A0> build() {
27+
return Optional.empty();
28+
}
2229
}

0 commit comments

Comments
 (0)