Skip to content

Commit c2bdaf9

Browse files
authored
Support Builder using name qualifier with List and Set (#944)
This supports injecting a List or Set of beans that have a common name qualifier. This seems like a rare use case, for example: ``` // A List of String that all have the same qualifier name of "args" @nAmed("args") List<String> ```
1 parent 4484601 commit c2bdaf9

File tree

11 files changed

+100
-23
lines changed

11 files changed

+100
-23
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
@Factory
1212
public class ListFactory {
1313

14+
@Bean
15+
@Named("args")
16+
List<String> someNamedStrings() {
17+
return List.of("arg0", "arg1");
18+
}
19+
1420
@Bean
1521
List<String> test(List<Cloneable> emptyList) {
1622
return List.of("test1", "test2");

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,39 @@
11
package org.example.myapp;
22

33
import java.util.List;
4+
import java.util.Set;
45

6+
import jakarta.inject.Named;
57
import jakarta.inject.Singleton;
68

79
@Singleton
810
public class ListService {
911

1012
private final List<String> strings;
13+
private final List<String> argStrings;
14+
private final Set<String> argsAsSet;
1115
private final List<ListFactory.Some> somes;
1216

13-
public ListService(List<String> strings, List<ListFactory.Some> somes) {
14-
this.strings = strings;
17+
public ListService(
18+
List<String> allStrings,
19+
@Named("args") List<String> argStrings,
20+
@Named("args") Set<String> argsAsSet,
21+
List<ListFactory.Some> somes) {
22+
23+
this.strings = allStrings;
24+
this.argStrings = argStrings;
25+
this.argsAsSet = argsAsSet;
1526
this.somes = somes;
1627
}
1728

29+
public List<String> args() {
30+
return argStrings;
31+
}
32+
33+
public Set<String> argsAsSet() {
34+
return argsAsSet;
35+
}
36+
1837
public List<String> strings() {
1938
return strings;
2039
}

blackbox-test-inject/src/test/java/org/example/myapp/ListFactoryTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ class ListFactoryTest {
1818
@Test
1919
void test() {
2020

21-
assertThat(list.strings()).contains("test1", "test1", "test3");
21+
assertThat(list.strings()).contains("test1", "test1", "test3", "arg0", "arg1");
22+
assertThat(list.args()).containsOnly("arg0", "arg1");
23+
assertThat(list.argsAsSet()).containsOnly("arg0", "arg1");
2224

2325
List<ListFactory.Some> somes = list.somes();
2426
assertThat(somes).hasSize(4);

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,14 @@ default <T> T get(Type type) {
199199
*/
200200
<T> List<T> list(Type type);
201201

202-
/** Return the list of beans that implement the class sorting by priority. */
202+
/**
203+
* Return the list of beans for the given type and name.
204+
*/
205+
<T> List<T> list(Type type, @Nullable String name);
206+
207+
/**
208+
* Return the list of beans that implement the class sorting by priority.
209+
*/
203210
default <T> List<T> listByPriority(Class<T> type) {
204211
return listByPriority((Type) type);
205212
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ default <T> void registerLazy(Provider<T> provider, Function<Provider<T>, T> pro
237237
*/
238238
<T> List<T> list(Type type);
239239

240+
/**
241+
* Get a list of dependencies for the type and name.
242+
*/
243+
<T> List<T> list(Type type, String name);
244+
240245
/**
241246
* Get a set of dependencies for the type.
242247
*/
@@ -247,6 +252,11 @@ default <T> void registerLazy(Provider<T> provider, Function<Provider<T>, T> pro
247252
*/
248253
<T> Set<T> set(Type type);
249254

255+
/**
256+
* Get a set of dependencies for the type and name.
257+
*/
258+
<T> Set<T> set(Type type, String name);
259+
250260
/**
251261
* Return a map of dependencies for the type keyed by qualifier name.
252262
*/

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,11 @@ <T> Provider<T> provider(Type type, String name) {
157157
}
158158

159159
/**
160-
* Return all bean instances matching the given type.
160+
* Return all bean instances matching the given type and name.
161161
*/
162-
List<Object> all(Type type) {
162+
List<Object> all(Type type, @Nullable String name) {
163163
DContextEntry entry = beans.get(type.getTypeName());
164-
return entry != null ? entry.all() : List.of();
164+
return entry != null ? entry.all(name) : List.of();
165165
}
166166

167167
/**

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,21 +158,26 @@ public <T> Map<String, T> map(Type type) {
158158

159159
@Override
160160
public <T> List<T> list(Class<T> type) {
161-
return listOf(type);
161+
return listOf(type, null);
162162
}
163163

164164
@Override
165165
public <T> List<T> list(Type type) {
166-
return listOf(type);
166+
return listOf(type, null);
167+
}
168+
169+
@Override
170+
public <T> List<T> list(Type type, @Nullable String name) {
171+
return listOf(type, name);
167172
}
168173

169174
@SuppressWarnings("unchecked")
170-
private <T> List<T> listOf(Type type) {
171-
List<T> values = (List<T>) beans.all(type);
175+
private <T> List<T> listOf(Type type, @Nullable String name) {
176+
List<T> values = (List<T>) beans.all(type, name);
172177
if (parent == null) {
173178
return values;
174179
}
175-
return combine(values, parent.list(type));
180+
return combine(values, parent.list(type, name));
176181
}
177182

178183
static <T> List<T> combine(List<T> values, List<T> parentValues) {

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import io.avaje.inject.BeanEntry;
1010
import io.avaje.inject.BeanScope;
11+
import org.jspecify.annotations.Nullable;
1112

1213
/** Proxy used when injecting the BeanScope. */
1314
final class DBeanScopeProxy implements BeanScope {
@@ -88,7 +89,6 @@ public List<Object> listByAnnotation(Class<? extends Annotation> annotation) {
8889

8990
@Override
9091
public <T> List<T> list(Class<T> type) {
91-
9292
if (delegate != null) {
9393
return delegate.list(type);
9494
} else {
@@ -105,6 +105,15 @@ public <T> List<T> list(Type type) {
105105
}
106106
}
107107

108+
@Override
109+
public <T> List<T> list(Type type, @Nullable String name) {
110+
if (delegate != null) {
111+
return delegate.list(type, name);
112+
} else {
113+
return builder.list(type, name);
114+
}
115+
}
116+
108117
@Override
109118
public <T> List<T> listByPriority(Type type) {
110119
if (delegate != null) {

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,31 +120,41 @@ private Type firstOf(Type[] types) {
120120

121121
@Override
122122
public final <T> Set<T> set(Class<T> type) {
123-
return new LinkedHashSet<>(listOf(type));
123+
return new LinkedHashSet<>(listOf(type, null));
124124
}
125125

126126
@Override
127127
public final <T> List<T> list(Class<T> type) {
128-
return listOf(type);
128+
return listOf(type, null);
129129
}
130130

131131
@Override
132132
public final <T> Set<T> set(Type type) {
133-
return new LinkedHashSet<>(listOf(type));
133+
return set(type, null);
134+
}
135+
136+
@Override
137+
public final <T> Set<T> set(Type type, String name) {
138+
return new LinkedHashSet<>(listOf(type, name));
134139
}
135140

136141
@Override
137142
public final <T> List<T> list(Type type) {
138-
return listOf(type);
143+
return listOf(type, null);
144+
}
145+
146+
@Override
147+
public <T> List<T> list(Type type, String name) {
148+
return listOf(type, name);
139149
}
140150

141151
@SuppressWarnings({"unchecked"})
142-
private <T> List<T> listOf(Type type) {
143-
final List<T> values = (List<T>) beanMap.all(type);
152+
private <T> List<T> listOf(Type type, @Nullable String name) {
153+
final List<T> values = (List<T>) beanMap.all(type, name);
144154
if (parent == null) {
145155
return values;
146156
}
147-
return combine(values, parent.list(type));
157+
return combine(values, parent.list(type, name));
148158
}
149159

150160
@Override

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import io.avaje.inject.BeanEntry;
99
import jakarta.inject.Provider;
10+
import org.jspecify.annotations.Nullable;
1011

1112
/**
1213
* Entry for a given key (bean class, interface class or annotation class).
@@ -55,12 +56,14 @@ Object get(String name, Class<? extends AvajeModule> currentModule) {
5556
}
5657

5758
/**
58-
* Return all the beans.
59+
* Return all the beans matching the name qualifier (if passed).
5960
*/
60-
List<Object> all() {
61+
List<Object> all(@Nullable String name) {
6162
List<Object> list = new ArrayList<>(entries.size());
6263
for (DContextEntryBean entry : entries) {
63-
list.add(entry.bean());
64+
if (entry.isNameMatch(name)) {
65+
list.add(entry.bean());
66+
}
6467
}
6568
return list;
6669
}

0 commit comments

Comments
 (0)