Skip to content

Commit d69781f

Browse files
committed
Add BeanScope.all() method to return all BeanEntry
This changes the existing BeanEntry to be an interface and makes it more consistent API wise.
1 parent 1515748 commit d69781f

File tree

10 files changed

+226
-84
lines changed

10 files changed

+226
-84
lines changed

inject-test/src/test/java/org/example/coffee/CoffeeMakerTest.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package org.example.coffee;
22

3-
import io.avaje.inject.ApplicationScope;
3+
import io.avaje.inject.BeanEntry;
44
import io.avaje.inject.BeanScope;
55
import org.example.coffee.core.DuperPump;
6+
import org.example.coffee.list.BSomei;
7+
import org.example.coffee.list.Somei;
68
import org.junit.jupiter.api.Test;
79

10+
import java.util.List;
11+
import java.util.Optional;
12+
13+
import static java.util.stream.Collectors.toList;
814
import static org.assertj.core.api.Assertions.assertThat;
915

1016
public class CoffeeMakerTest {
@@ -22,7 +28,6 @@ public void makeIt_via_SystemContext() {
2228

2329
@Test
2430
public void makeIt_via_BootContext_withNoShutdownHook() {
25-
2631
try (BeanScope context = BeanScope.newBuilder()
2732
.withShutdownHook(false)
2833
.build()) {
@@ -34,10 +39,29 @@ public void makeIt_via_BootContext_withNoShutdownHook() {
3439

3540
@Test
3641
public void makeIt_via_BootContext() {
37-
3842
try (BeanScope context = BeanScope.newBuilder().build()) {
3943
String makeIt = context.get(CoffeeMaker.class).makeIt();
4044
assertThat(makeIt).isEqualTo("done");
45+
46+
final List<BeanEntry> beanEntries = context.all();
47+
assertThat(beanEntries).hasSizeGreaterThan(10);
48+
49+
// all entries for an interface
50+
final List<BeanEntry> someiEntries = beanEntries.stream()
51+
.filter(beanEntry -> beanEntry.hasKey(Somei.class))
52+
.collect(toList());
53+
assertThat(someiEntries).hasSize(3);
54+
55+
final Optional<BeanEntry> bsomeEntry = someiEntries.stream().filter(entry -> entry.type().equals(BSomei.class)).findFirst();
56+
assertThat(bsomeEntry).isPresent();
57+
58+
final BeanEntry entry = bsomeEntry.get();
59+
assertThat(entry.qualifierName()).isEqualTo("b");
60+
assertThat(entry.keys()).containsExactly(BSomei.class.getCanonicalName(), Somei.class.getCanonicalName());
61+
assertThat(entry.type()).isEqualTo(BSomei.class);
62+
assertThat(entry.priority()).isEqualTo(0);
63+
assertThat(entry.bean()).isEqualTo(context.get(Somei.class, "b"));
64+
assertThat(entry.bean()).isEqualTo(context.get(BSomei.class));
4165
}
4266
}
4367

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package org.example.custom;
22

3+
import jakarta.inject.Named;
34
import org.example.MyCustomScope;
45

6+
@Named("Hello")
57
@MyCustomScope
68
public class CustomBean {
79

8-
int id;
910
}

inject-test/src/test/java/org/example/custom/CustomScopeTest.java

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package org.example.custom;
22

3+
import io.avaje.inject.BeanEntry;
34
import io.avaje.inject.BeanScope;
5+
import org.example.MyCustomScope;
46
import org.example.coffee.CoffeeMaker;
57
import org.junit.jupiter.api.Test;
68
import org.mockito.Mockito;
79

10+
import java.util.List;
11+
import java.util.Optional;
12+
13+
import static java.util.stream.Collectors.toList;
814
import static org.assertj.core.api.Assertions.assertThat;
915

1016
class CustomScopeTest {
@@ -45,7 +51,7 @@ void buildSimpleCustomScope() {
4551

4652
try (BeanScope beanScope = BeanScope.newBuilder()
4753
.withModules(new MyCustomModule())
48-
.withBeans(LocalExternal.class, ext)
54+
.withBean(LocalExternal.class, ext)
4955
.withBean(CoffeeMaker.class, suppliedCoffeeMaker)
5056
.build()) {
5157

@@ -62,6 +68,60 @@ void buildSimpleCustomScope() {
6268
}
6369
}
6470

71+
@Test
72+
void customScopeAll() {
73+
74+
LocalExt ext = new LocalExt();
75+
CoffeeMaker suppliedCoffeeMaker = Mockito.mock(CoffeeMaker.class);
76+
77+
try (BeanScope beanScope = BeanScope.newBuilder()
78+
.withModules(new MyCustomModule())
79+
.withBean(LocalExternal.class, ext)
80+
.withBean(CoffeeMaker.class, suppliedCoffeeMaker)
81+
.build()) {
82+
83+
// includes the 2 supplied beans
84+
final List<BeanEntry> all = beanScope.all();
85+
assertThat(all).hasSize(5);
86+
87+
final CustomBean customBean = beanScope.get(CustomBean.class);
88+
89+
final Optional<BeanEntry> customBeanEntry = all.stream()
90+
.filter(beanEntry -> beanEntry.hasKey(CustomBean.class))
91+
.findFirst();
92+
93+
assertThat(customBeanEntry).isPresent();
94+
assertThat(customBeanEntry.get().bean()).isSameAs(customBean);
95+
assertThat(customBeanEntry.get().qualifierName()).isEqualTo("hello");
96+
assertThat(customBeanEntry.get().priority()).isEqualTo(0);
97+
assertThat(customBeanEntry.get().keys()).containsExactly(CustomBean.class.getCanonicalName(), MyCustomScope.class.getCanonicalName());
98+
99+
100+
final Optional<BeanEntry> fooCustomEntry = all.stream()
101+
.filter(beanEntry -> beanEntry.hasKey(FooCustom.class))
102+
.findFirst();
103+
104+
assertThat(fooCustomEntry).isPresent();
105+
assertThat(fooCustomEntry.get().qualifierName()).isNull();
106+
107+
// only the beans with MyCustomScope annotation
108+
final List<BeanEntry> myCustomScopeBeans = all.stream()
109+
.filter(beanEntry -> beanEntry.hasKey(MyCustomScope.class))
110+
.collect(toList());
111+
assertThat(myCustomScopeBeans).hasSize(3);
112+
113+
final OtherCBean cBean = beanScope.get(OtherCBean.class);
114+
assertThat(customBean).isNotNull();
115+
assertThat(cBean.dependency()).isSameAs(customBean);
116+
117+
final LocalExternal externallyProvided = beanScope.get(LocalExternal.class);
118+
assertThat(externallyProvided).isSameAs(ext);
119+
120+
final CoffeeMaker coffeeMaker = beanScope.get(CoffeeMaker.class);
121+
assertThat(coffeeMaker).isSameAs(suppliedCoffeeMaker);
122+
}
123+
}
124+
65125
static class LocalExt implements LocalExternal {
66126

67127
}
Lines changed: 29 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,66 @@
11
package io.avaje.inject;
22

3+
import java.util.Set;
4+
35
/**
46
* A bean entry with priority and optional name.
57
*/
6-
public class BeanEntry<T> {
8+
public interface BeanEntry {
79

810
/**
9-
* An explicitly supplied bean. See BeanScopeBuilder.
11+
* Priority of externally supplied bean.
1012
*/
11-
public static final int SUPPLIED = 2;
13+
int SUPPLIED = 2;
1214

1315
/**
14-
* An <code>@Primary</code> bean.
16+
* Priority of <code>@Primary</code> bean.
1517
*/
16-
public static final int PRIMARY = 1;
18+
int PRIMARY = 1;
1719

1820
/**
19-
* A normal priority bean.
21+
* Priority of normal bean.
2022
*/
21-
public static final int NORMAL = 0;
23+
int NORMAL = 0;
2224

2325
/**
24-
* A <code>@Secondary</code> bean.
26+
* Priority of <code>@Secondary</code> bean.
2527
*/
26-
public static final int SECONDARY = -1;
27-
28-
private final int priority;
29-
30-
private final T bean;
31-
32-
private final String name;
28+
int SECONDARY = -1;
3329

3430
/**
35-
* Construct with priority, name and the bean.
36-
*/
37-
public BeanEntry(int priority, T bean, String name) {
38-
this.priority = priority;
39-
this.bean = bean;
40-
this.name = name;
41-
}
42-
43-
/**
44-
* Return the priority (Primary, Normal and Secondary).
31+
* Return the bean name.
4532
*/
46-
public int getPriority() {
47-
return priority;
48-
}
33+
String qualifierName();
4934

5035
/**
51-
* Return the bean.
36+
* Return the bean instance.
5237
*/
53-
public T getBean() {
54-
return bean;
55-
}
38+
Object bean();
5639

5740
/**
58-
* Return the bean name.
41+
* The bean instance type.
5942
*/
60-
public String getName() {
61-
return name;
62-
}
43+
Class<?> type();
6344

6445
/**
65-
* Return true if this entry has Supplied priority.
46+
* Return the priority indicating if the bean is Supplied Primary, Normal or Secondary.
6647
*/
67-
public boolean isSupplied() {
68-
return priority == SUPPLIED;
69-
}
48+
int priority();
7049

7150
/**
72-
* Return true if this entry has Primary priority.
51+
* Return the type keys for this bean.
52+
* <p>
53+
* This is the set of type, interface types and annotation types that the entry is registered for.
7354
*/
74-
public boolean isPrimary() {
75-
return priority == PRIMARY;
76-
}
55+
Set<String> keys();
7756

7857
/**
79-
* Return true if this entry has Secondary priority.
58+
* Return true if the entry has a key for this type.
59+
* <p>
60+
* This is true if the keys contains the canonical name of the given type.
61+
*
62+
* @param type The type to match. Can be any type including concrete, interface or annotation type.
8063
*/
81-
public boolean isSecondary() {
82-
return priority == SECONDARY;
83-
}
64+
boolean hasKey(Class<?> type);
8465

85-
@Override
86-
public String toString() {
87-
StringBuilder sb = new StringBuilder();
88-
sb.append("{bean:").append(bean);
89-
if (name != null) {
90-
sb.append(", name:").append(name);
91-
}
92-
switch (priority) {
93-
case SUPPLIED:
94-
sb.append(", Supplied");
95-
break;
96-
case PRIMARY:
97-
sb.append(", @Primary");
98-
break;
99-
case SECONDARY:
100-
sb.append(", @Secondary");
101-
break;
102-
default:
103-
sb.append(", Normal");
104-
}
105-
return sb.append("}").toString();
106-
}
10766
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ static BeanScopeBuilder newBuilder() {
141141
*/
142142
<T> List<T> listByPriority(Class<T> interfaceType, Class<? extends Annotation> priority);
143143

144+
/**
145+
* Return all the bean entries from the scope.
146+
* <p>
147+
* The bean entries include
148+
* This includes entries from the parent scope if it has one.
149+
*
150+
* @return All bean entries from the scope.
151+
*/
152+
List<BeanEntry> all();
153+
144154
/**
145155
* Close the scope firing any <code>@PreDestroy</code> methods.
146156
*/

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package io.avaje.inject.spi;
22

3-
import io.avaje.inject.BeanEntry;
3+
import java.util.Collections;
4+
import java.util.LinkedHashMap;
5+
import java.util.List;
6+
import java.util.Map;
47

5-
import java.util.*;
6-
7-
import static io.avaje.inject.BeanEntry.*;
8+
import static io.avaje.inject.BeanEntry.SUPPLIED;
89

910
/**
1011
* Map of types (class types, interfaces and annotations) to a DContextEntry where the
@@ -19,6 +20,17 @@ class DBeanMap {
1920
DBeanMap() {
2021
}
2122

23+
/**
24+
* Add to the map of entries.
25+
*/
26+
void addAll(Map<DContextEntryBean,DEntry> map) {
27+
for (Map.Entry<String, DContextEntry> entry : beans.entrySet()) {
28+
for (DContextEntryBean contentEntry : entry.getValue().entries()) {
29+
map.computeIfAbsent(contentEntry, dContextEntryBean -> contentEntry.entry()).addKey(entry.getKey());
30+
}
31+
}
32+
}
33+
2234
/**
2335
* Add test double supplied beans.
2436
*/

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package io.avaje.inject.spi;
22

3+
import io.avaje.inject.BeanEntry;
34
import io.avaje.inject.BeanScope;
45
import io.avaje.inject.Priority;
56
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
78

89
import java.lang.annotation.Annotation;
9-
import java.util.ArrayList;
10-
import java.util.Collections;
11-
import java.util.List;
10+
import java.util.*;
1211
import java.util.concurrent.locks.ReentrantLock;
1312

1413
class DBeanScope implements BeanScope {
@@ -37,6 +36,20 @@ class DBeanScope implements BeanScope {
3736
}
3837
}
3938

39+
@Override
40+
public List<BeanEntry> all() {
41+
IdentityHashMap<DContextEntryBean, DEntry> map = new IdentityHashMap<>();
42+
if (parent != null) {
43+
((DBeanScope) parent).addAll(map);
44+
}
45+
addAll(map);
46+
return new ArrayList<>(map.values());
47+
}
48+
49+
void addAll(Map<DContextEntryBean, DEntry> map) {
50+
beans.addAll(map);
51+
}
52+
4053
@Override
4154
public <T> T get(Class<T> beanClass) {
4255
return get(beanClass, null);

0 commit comments

Comments
 (0)