Skip to content

Commit b563c3b

Browse files
committed
Merge branch 'feature/94' into jakarta-master
2 parents 8993d37 + d12a937 commit b563c3b

21 files changed

+280
-25
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,9 @@ boolean isExtraInjectionRequired() {
358358

359359
void buildAddFor(Append writer) {
360360
writer.append(" if (builder.isAddBeanFor(");
361+
if (name != null) {
362+
writer.append("\"%s\", ", name);
363+
}
361364
if (addForType != null) {
362365
writer.append(addForType).append(".class, ");
363366
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,18 @@ String getFieldName() {
2323
String builderGetDependency() {
2424
StringBuilder sb = new StringBuilder();
2525
sb.append("b.").append(type.getMethod());
26-
sb.append(type.rawType()).append(".class");
26+
sb.append(getFieldType()).append(".class");
2727
if (name != null) {
2828
sb.append(",\"").append(name).append("\"");
2929
}
3030
sb.append(")");
3131
return sb.toString();
3232
}
3333

34+
private String getFieldType() {
35+
return Util.unwrapProvider(type.rawType());
36+
}
37+
3438
/**
3539
* Check for request scoped dependency.
3640
*/

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,10 @@ void addImports(Set<String> importTypes) {
177177
}
178178

179179
void buildAddFor(Append writer) {
180-
181180
writer.append(" if (builder.isAddBeanFor(");
181+
if (name != null) {
182+
writer.append("\"%s\", ", name);
183+
}
182184
if (addForType != null) {
183185
writer.append(addForType).append(".class, ");
184186
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.example.coffee.provider;
2+
3+
import javax.inject.Inject;
4+
import javax.inject.Provider;
5+
import javax.inject.Singleton;
6+
7+
@Singleton
8+
class FieldInjectProvider {
9+
10+
@Inject
11+
Provider<AProv> aProvProvider;
12+
13+
AProv testGet() {
14+
return aProvProvider.get();
15+
}
16+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.example.coffee.provider;
2+
3+
import io.avaje.inject.SystemContext;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
8+
class FieldInjectProviderTest {
9+
10+
@Test
11+
void test() {
12+
13+
FieldInjectProvider bean = SystemContext.getBean(FieldInjectProvider.class);
14+
AProv aProv = bean.testGet();
15+
16+
assertThat(aProv).isNotNull();
17+
18+
AProv beanDirect = SystemContext.getBean(AProv.class);
19+
assertThat(aProv).isSameAs(beanDirect);
20+
}
21+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.example.coffee.provider;
2+
3+
import javax.inject.Inject;
4+
import javax.inject.Provider;
5+
import javax.inject.Singleton;
6+
7+
@Singleton
8+
class MethodInjectProvider {
9+
10+
private Provider<AProv> aProvProvider;
11+
12+
@Inject
13+
void set(Provider<AProv> aProvProvider) {
14+
this.aProvProvider = aProvProvider;
15+
}
16+
17+
AProv testGet() {
18+
return aProvProvider.get();
19+
}
20+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.example.coffee.provider;
2+
3+
import io.avaje.inject.SystemContext;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
8+
class MethodInjectProviderTest {
9+
10+
@Test
11+
void test() {
12+
13+
MethodInjectProvider bean = SystemContext.getBean(MethodInjectProvider.class);
14+
AProv aProv = bean.testGet();
15+
16+
assertThat(aProv).isNotNull();
17+
18+
AProv beanDirect = SystemContext.getBean(AProv.class);
19+
assertThat(aProv).isSameAs(beanDirect);
20+
}
21+
}

inject-test/src/test/java/org/example/coffee/qualifier/StoreManagerWithSetterQualifierTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,31 @@ void redStore() {
1515
assertThat(manager.greenStore()).isEqualTo("green");
1616
}
1717
}
18+
19+
@Test
20+
void namedTestDouble() {
21+
try (BeanContext context = BeanContext.newBuilder()
22+
.withBean("Blue", SomeStore.class, () -> "TD Blue")
23+
.withBean("Green", SomeStore.class, () -> "TD Green")
24+
.build()) {
25+
26+
StoreManagerWithSetterQualifier manager = context.getBean(StoreManagerWithSetterQualifier.class);
27+
assertThat(manager.blueStore()).isEqualTo("TD Blue");
28+
assertThat(manager.greenStore()).isEqualTo("TD Green");
29+
}
30+
}
31+
32+
@Test
33+
void namedTestDouble_expect_otherNamedStillWired() {
34+
try (BeanContext context = BeanContext.newBuilder()
35+
.withBean("Blue", SomeStore.class, () -> "TD Blue Only")
36+
// with GreenStore still wired
37+
.build()) {
38+
39+
StoreManagerWithSetterQualifier manager = context.getBean(StoreManagerWithSetterQualifier.class);
40+
assertThat(manager.blueStore()).isEqualTo("TD Blue Only");
41+
assertThat(manager.greenStore()).isEqualTo("green");
42+
}
43+
}
44+
1845
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.example.missing;
2+
3+
import javax.inject.Singleton;
4+
5+
/**
6+
* Has only 1 public constructor so that is chosen for injection.
7+
*/
8+
@Singleton
9+
public class MFooUser2 {
10+
11+
private final MFoo mf;
12+
private final boolean usePublicConstructor;
13+
14+
public MFooUser2(MFoo mf) {
15+
this.mf = mf;
16+
this.usePublicConstructor = true;
17+
}
18+
19+
/**
20+
* Extra protected constructor usually for unit testing purposes only.
21+
*/
22+
MFooUser2(MFoo mf, boolean dummy) {
23+
this.mf = mf;
24+
this.usePublicConstructor = true;
25+
}
26+
27+
public boolean isUsePublicConstructor() {
28+
return usePublicConstructor;
29+
}
30+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.example.missing;
2+
3+
import io.avaje.inject.SystemContext;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
8+
class SinglePublicConstructorTest {
9+
10+
@Test
11+
void beanWithSinglePublicConstructor_expect_publicConstructorChosen() {
12+
13+
MFooUser2 bean = SystemContext.getBean(MFooUser2.class);
14+
15+
assertThat(bean.isUsePublicConstructor()).isTrue();
16+
}
17+
}

inject/src/main/java/io/avaje/inject/BeanContextBuilder.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@ public interface BeanContextBuilder {
168168
*/
169169
<D> BeanContextBuilder withBean(Class<D> type, D bean);
170170

171+
/**
172+
* Add a supplied bean instance with the given name and injection type.
173+
*
174+
* @param name The name qualifier
175+
* @param type The dependency injection type this bean is target for
176+
* @param bean The supplied bean instance to use (typically a test mock)
177+
*/
178+
<D> BeanContextBuilder withBean(String name, Class<D> type, D bean);
179+
171180
/**
172181
* Use a mockito mock when injecting this bean type.
173182
*

inject/src/main/java/io/avaje/inject/DBeanContextBuilder.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,19 @@ public BeanContextBuilder withIgnoreMissingModuleDependencies() {
6767
@SuppressWarnings({"unchecked", "rawtypes"})
6868
public BeanContextBuilder withBeans(Object... beans) {
6969
for (Object bean : beans) {
70-
suppliedBeans.add(new SuppliedBean(suppliedType(bean.getClass()), bean));
70+
suppliedBeans.add(new SuppliedBean(null, suppliedType(bean.getClass()), bean));
7171
}
7272
return this;
7373
}
7474

7575
@Override
76-
public <D> DBeanContextBuilder withBean(Class<D> type, D bean) {
77-
suppliedBeans.add(new SuppliedBean<>(type, bean));
76+
public <D> BeanContextBuilder withBean(Class<D> type, D bean) {
77+
return withBean(null, type, bean);
78+
}
79+
80+
@Override
81+
public <D> BeanContextBuilder withBean(String name, Class<D> type, D bean) {
82+
suppliedBeans.add(new SuppliedBean<>(name, type, bean));
7883
return this;
7984
}
8085

@@ -85,7 +90,7 @@ public BeanContextBuilder withMock(Class<?> type) {
8590

8691
@Override
8792
public <D> DBeanContextBuilder withMock(Class<D> type, Consumer<D> consumer) {
88-
suppliedBeans.add(new SuppliedBean<>(type, null, consumer));
93+
suppliedBeans.add(new SuppliedBean<>(null, type, null, consumer));
8994
return this;
9095
}
9196

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ static Builder newBuilder(String name, String[] provides, String[] dependsOn) {
6363
/**
6464
* Return true if the bean should be created and registered with the context.
6565
* <p/>
66-
* Returning false means there has been a (test double) bean already registered and
66+
* Returning false means there has been a supplied bean already registered and
6767
* that we should skip the creation and registration for this bean.
6868
*
6969
* @param addForType The interface that the bean implements and provides
@@ -74,13 +74,36 @@ static Builder newBuilder(String name, String[] provides, String[] dependsOn) {
7474
/**
7575
* Return true if the bean should be created and registered with the context.
7676
* <p/>
77-
* Returning false means there has been a (test double) bean already registered and
77+
* Returning false means there has been a supplied bean already registered and
78+
* that we should skip the creation and registration for this bean.
79+
*
80+
* @param name The qualifier name
81+
* @param addForType The interface that the bean implements and provides
82+
* @param injectTarget The actual bean type we are looking to create and register
83+
*/
84+
boolean isAddBeanFor(String name, Class<?> addForType, Class<?> injectTarget);
85+
86+
/**
87+
* Return true if the bean should be created and registered with the context.
88+
* <p/>
89+
* Returning false means there has been a supplied bean already registered and
7890
* that we should skip the creation and registration for this bean.
7991
*
8092
* @param injectTarget The actual bean type we are looking to create and register
8193
*/
8294
boolean isAddBeanFor(Class<?> injectTarget);
8395

96+
/**
97+
* Return true if the bean should be created and registered with the context.
98+
* <p/>
99+
* Returning false means there has been a supplied bean already registered and
100+
* that we should skip the creation and registration for this bean.
101+
*
102+
* @param name The qualifier name
103+
* @param injectTarget The actual bean type we are looking to create and register
104+
*/
105+
boolean isAddBeanFor(String name, Class<?> injectTarget);
106+
84107
/**
85108
* Register the bean instance into the context.
86109
* <p>

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,7 @@ void add(List<SuppliedBean> suppliedBeans) {
3939
@SuppressWarnings("rawtypes")
4040
private void addSuppliedBean(SuppliedBean supplied) {
4141
Class<?> suppliedType = supplied.getType();
42-
Named annotation = suppliedType.getAnnotation(Named.class);
43-
String name = (annotation == null) ? null : annotation.value();
44-
45-
DContextEntryBean entryBean = DContextEntryBean.of(supplied.getBean(), name, SUPPLIED);
42+
DContextEntryBean entryBean = DContextEntryBean.of(supplied.getBean(), supplied.name(), SUPPLIED);
4643
beans.computeIfAbsent(suppliedType.getCanonicalName(), s -> new DContextEntry()).add(entryBean);
4744
for (Class<?> anInterface : suppliedType.getInterfaces()) {
4845
beans.computeIfAbsent(anInterface.getCanonicalName(), s -> new DContextEntry()).add(entryBean);
@@ -93,8 +90,8 @@ void addAll(Class type, List list) {
9390
/**
9491
* Return true if there is a supplied bean for this type.
9592
*/
96-
boolean isSupplied(String canonicalName) {
93+
boolean isSupplied(String canonicalName, String qualifierName) {
9794
DContextEntry entry = beans.get(canonicalName);
98-
return entry != null && entry.isSupplied();
95+
return entry != null && entry.isSupplied(qualifierName);
9996
}
10097
}

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ class DBuilder implements Builder {
5656
*/
5757
private Class<?> injectTarget;
5858

59+
/**
60+
* Flag set when we are running post construct injection.
61+
*/
62+
private boolean runningPostConstruct;
63+
5964
Builder parent;
6065

6166
/**
@@ -98,18 +103,28 @@ public void setParent(Builder parent) {
98103

99104
@Override
100105
public boolean isAddBeanFor(Class<?> addForType, Class<?> injectTarget) {
106+
return isAddBeanFor(null, addForType, injectTarget);
107+
}
108+
109+
@Override
110+
public boolean isAddBeanFor(String name, Class<?> addForType, Class<?> injectTarget) {
101111
if (parent == null) {
102112
return true;
103113
}
104114
this.injectTarget = injectTarget;
105-
return parent.isAddBeanFor(addForType);
115+
return parent.isAddBeanFor(name, addForType, injectTarget);
106116
}
107117

108118
@Override
109119
public boolean isAddBeanFor(Class<?> injectTarget) {
110120
return isAddBeanFor(injectTarget, injectTarget);
111121
}
112122

123+
@Override
124+
public boolean isAddBeanFor(String name, Class<?> injectTarget) {
125+
return isAddBeanFor(name, injectTarget, injectTarget);
126+
}
127+
113128
@Override
114129
public <T> Set<T> getSet(Class<T> interfaceType) {
115130
return new LinkedHashSet<>(getList(interfaceType));
@@ -224,6 +239,9 @@ public <T> Provider<T> getProvider(Class<T> cls) {
224239

225240
@Override
226241
public <T> Provider<T> getProvider(Class<T> cls, String name) {
242+
if (runningPostConstruct) {
243+
return new ProviderWrapper<>(get(cls, name));
244+
}
227245
ProviderPromise<T> promise = new ProviderPromise<>(cls, name);
228246
injectors.add(promise);
229247
return promise;
@@ -256,6 +274,7 @@ private void runInjectors() {
256274
if (name != null) {
257275
log.debug("perform field injection in context:{}", name);
258276
}
277+
runningPostConstruct = true;
259278
for (Consumer<Builder> injector : injectors) {
260279
injector.accept(this);
261280
}

0 commit comments

Comments
 (0)