Skip to content

Commit 57820ee

Browse files
committed
#13 - Support priority of @primary and @secondary across modules
1 parent b506b43 commit 57820ee

File tree

9 files changed

+134
-64
lines changed

9 files changed

+134
-64
lines changed

src/main/java/io/dinject/BeanEntry.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@
55
*/
66
public class BeanEntry<T> {
77

8+
/**
9+
* An explicitly supplied bean. See BootContext.
10+
*/
11+
public static final int SUPPLIED = 2;
12+
13+
/**
14+
* An <code>@Primary</code> bean.
15+
*/
16+
public static final int PRIMARY = 1;
17+
18+
/**
19+
* A normal priority bean.
20+
*/
21+
public static final int NORMAL = 0;
22+
23+
/**
24+
* A <code>@Secondary</code> bean.
25+
*/
26+
public static final int SECONDARY = -1;
27+
828
private final int priority;
929

1030
private final T bean;
@@ -40,4 +60,48 @@ public T getBean() {
4060
public String getName() {
4161
return name;
4262
}
63+
64+
/**
65+
* Return true if this entry has Supplied priority.
66+
*/
67+
public boolean isSupplied() {
68+
return priority == SUPPLIED;
69+
}
70+
71+
/**
72+
* Return true if this entry has Primary priority.
73+
*/
74+
public boolean isPrimary() {
75+
return priority == PRIMARY;
76+
}
77+
78+
/**
79+
* Return true if this entry has Secondary priority.
80+
*/
81+
public boolean isSecondary() {
82+
return priority == SECONDARY;
83+
}
84+
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+
}
43107
}

src/main/java/io/dinject/BootContext.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public BootContext withBeans(Object... beans) {
180180
public BeanContext load() {
181181

182182
// sort factories by dependsOn
183-
FactoryOrder factoryOrder = new FactoryOrder(includeModules);
183+
FactoryOrder factoryOrder = new FactoryOrder(includeModules, !suppliedBeans.isEmpty());
184184
ServiceLoader.load(BeanContextFactory.class).forEach(factoryOrder::add);
185185

186186
Set<String> moduleNames = factoryOrder.orderFactories();
@@ -307,15 +307,17 @@ void shutdown() {
307307
static class FactoryOrder {
308308

309309
private final Set<String> includeModules;
310+
private final boolean suppliedBeans;
310311

311312
private final Set<String> moduleNames = new LinkedHashSet<>();
312313
private final List<BeanContextFactory> factories = new ArrayList<>();
313314
private final List<FactoryState> queue = new ArrayList<>();
314315

315316
private final Map<String,FactoryList> providesMap = new HashMap<>();
316317

317-
FactoryOrder(Set<String> includeModules) {
318+
FactoryOrder(Set<String> includeModules, boolean suppliedBeans) {
318319
this.includeModules = includeModules;
320+
this.suppliedBeans = suppliedBeans;
319321
}
320322

321323
void add(BeanContextFactory factory) {
@@ -382,7 +384,14 @@ private void processQueue() {
382384
count = processQueuedFactories();
383385
} while (count > 0);
384386

385-
if (!queue.isEmpty()) {
387+
if (suppliedBeans) {
388+
// just push everything left assuming supplied beans
389+
// will satisfy the required dependencies
390+
for (FactoryState factoryState : queue) {
391+
push(factoryState);
392+
}
393+
394+
} else if (!queue.isEmpty()) {
386395
StringBuilder sb = new StringBuilder();
387396
for (FactoryState factory : queue) {
388397
sb.append("module ").append(factory.getName()).append(" has unsatisfied dependencies - ");

src/main/java/io/dinject/core/Builder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.dinject.core;
22

33
import io.dinject.BeanContext;
4+
import io.dinject.BeanEntry;
45

56
import java.util.List;
67
import java.util.Optional;
@@ -115,9 +116,9 @@ public interface Builder {
115116
<T> List<T> getList(Class<T> interfaceType);
116117

117118
/**
118-
* Get a named dependency allowing it to be null.
119+
* Get a candidate dependency allowing it to be null.
119120
*/
120-
<T> T getMaybe(Class<T> cls, String name);
121+
<T> BeanEntry<T> candidate(Class<T> cls, String name);
121122

122123
/**
123124
* Build and return the bean context.

src/main/java/io/dinject/core/DBeanContext.java

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,8 @@ public <T> BeanEntry<T> candidate(Class<T> type, String name) {
6969
return entrySort.get();
7070
}
7171

72-
@SuppressWarnings("unchecked")
7372
@Override
7473
public <T> T getBean(Class<T> beanClass, String name) {
75-
7674
BeanEntry<T> candidate = candidate(beanClass, name);
7775
return (candidate == null) ? null : candidate.getBean();
7876
}
@@ -132,46 +130,58 @@ public void close() {
132130
}
133131
}
134132

135-
private static class EntrySort<T> {
133+
static class EntrySort<T> {
136134

135+
private BeanEntry<T> supplied;
137136
private BeanEntry<T> primary;
138137
private int primaryCount;
139138
private BeanEntry<T> secondary;
140139
private int secondaryCount;
141140
private BeanEntry<T> normal;
142141
private int normalCount;
143142

144-
void add(BeanEntry<T> candidate) {
143+
private final List<BeanEntry<T>> all = new ArrayList<>();
145144

146-
if (candidate != null) {
147-
if (candidate.getPriority() == Flag.PRIMARY) {
148-
primary = candidate;
149-
primaryCount++;
150-
} else if (candidate.getPriority() == Flag.SECONDARY) {
151-
secondary = candidate;
152-
secondaryCount++;
153-
} else {
154-
normal = candidate;
155-
normalCount++;
156-
}
145+
void add(BeanEntry<T> candidate) {
146+
if (candidate == null) {
147+
return;
148+
}
149+
if (candidate.isSupplied()) {
150+
// a supplied bean trumps all
151+
supplied = candidate;
152+
return;
153+
}
154+
all.add(candidate);
155+
if (candidate.isPrimary()) {
156+
primary = candidate;
157+
primaryCount++;
158+
} else if (candidate.isSecondary()) {
159+
secondary = candidate;
160+
secondaryCount++;
161+
} else {
162+
normal = candidate;
163+
normalCount++;
157164
}
158165
}
159166

160167
BeanEntry<T> get() {
168+
if (supplied != null) {
169+
return supplied;
170+
}
161171
if (primaryCount > 1) {
162-
throw new IllegalStateException("Multiple @Primary beans when only expecting one? Last was: " + primary);
172+
throw new IllegalStateException("Multiple @Primary beans when only expecting one? Beans: " + all);
163173
}
164174
if (primaryCount == 1) {
165175
return primary;
166176
}
167177
if (normalCount > 1) {
168-
throw new IllegalStateException("Multiple beans when only expecting one? Maybe use @Primary or @Secondary? Last was: " + normal);
178+
throw new IllegalStateException("Multiple beans when only expecting one? Maybe use @Primary or @Secondary? Beans: " + all);
169179
}
170180
if (normalCount == 1) {
171181
return normal;
172182
}
173183
if (secondaryCount > 1) {
174-
throw new IllegalStateException("Multiple @Secondary beans when only expecting one? Last was: " + primary);
184+
throw new IllegalStateException("Multiple @Secondary beans when only expecting one? Beans: " + all);
175185
}
176186
return secondary;
177187
}

src/main/java/io/dinject/core/DBeanMap.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
import java.util.List;
88
import java.util.Map;
99

10-
import static io.dinject.core.Flag.NORMAL;
11-
import static io.dinject.core.Flag.PRIMARY;
12-
import static io.dinject.core.Flag.SECONDARY;
10+
import static io.dinject.BeanEntry.NORMAL;
11+
import static io.dinject.BeanEntry.PRIMARY;
12+
import static io.dinject.BeanEntry.SECONDARY;
13+
import static io.dinject.BeanEntry.SUPPLIED;
1314

1415
/**
1516
* Map of types (class types, interfaces and annotations) to a DContextEntry where the
@@ -51,7 +52,7 @@ private void addSuppliedBean(Object bean) {
5152
Named annotation = suppliedClass.getAnnotation(Named.class);
5253
String name = (annotation == null) ? null : annotation.value();
5354

54-
DContextEntryBean entryBean = DContextEntryBean.of(bean, name, PRIMARY);
55+
DContextEntryBean entryBean = DContextEntryBean.of(bean, name, SUPPLIED);
5556
beans.computeIfAbsent(suppliedType.getCanonicalName(), s -> new DContextEntry()).add(entryBean);
5657
for (Class<?> anInterface : suppliedClass.getInterfaces()) {
5758
beans.computeIfAbsent(anInterface.getCanonicalName(), s -> new DContextEntry()).add(entryBean);

src/main/java/io/dinject/core/DBuilder.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.dinject.core;
22

33
import io.dinject.BeanContext;
4+
import io.dinject.BeanEntry;
45
import org.slf4j.Logger;
56
import org.slf4j.LoggerFactory;
67

@@ -137,36 +138,31 @@ public <T> List<T> getList(Class<T> interfaceType) {
137138
}
138139

139140
@Override
140-
public <T> T getMaybe(Class<T> beanClass, String name) {
141+
public <T> BeanEntry<T> candidate(Class<T> cls, String name) {
141142

142-
T bean;
143143
if (suppliedBeanMap != null) {
144-
bean = suppliedBeanMap.getBean(beanClass, name);
145-
if (bean != null) {
146-
return bean;
144+
BeanEntry<T> entry = suppliedBeanMap.candidate(cls, name);
145+
if (entry != null) {
146+
return entry;
147147
}
148148
}
149149

150-
// look locally first
151-
bean = beanMap.getBean(beanClass, name);
152-
if (bean != null) {
153-
return bean;
154-
}
155-
156-
// look in child context
150+
DBeanContext.EntrySort<T> entrySort = new DBeanContext.EntrySort<>();
151+
entrySort.add(beanMap.candidate(cls, name));
157152
for (BeanContext childContext : children.values()) {
158-
bean = childContext.getBean(beanClass);
159-
if (bean != null) {
160-
return bean;
161-
}
153+
entrySort.add(childContext.candidate(cls, name));
162154
}
163155

164156
if (parent != null) {
165157
// look in parent context (cross-module dependency)
166-
return parent.getMaybe(beanClass, name);
158+
entrySort.add(parent.candidate(cls, name));
167159
}
160+
return entrySort.get();
161+
}
168162

169-
return null;
163+
private <T> T getMaybe(Class<T> beanClass, String name) {
164+
BeanEntry<T> entry = candidate(beanClass, name);
165+
return (entry == null) ? null : entry.getBean();
170166
}
171167

172168
@Override

src/main/java/io/dinject/core/DContextEntryBean.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@ Object getIfMatchWithDefault(String name) {
5959
}
6060

6161
boolean isPrimary() {
62-
return flag == Flag.PRIMARY;
62+
return flag == BeanEntry.PRIMARY;
6363
}
6464

6565
boolean isSecondary() {
66-
return flag == Flag.SECONDARY;
66+
return flag == BeanEntry.SECONDARY;
6767
}
6868

6969
@SuppressWarnings("unchecked")

src/main/java/io/dinject/core/Flag.java

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/test/java/io/dinject/BootContextTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class BootContextTest {
1515
@Test
1616
public void noDepends() {
1717

18-
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet());
18+
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet(), true);
1919
factoryOrder.add(bc("1", null, null));
2020
factoryOrder.add(bc("2", null, null));
2121
factoryOrder.add(bc("3", null, null));
@@ -27,7 +27,7 @@ public void noDepends() {
2727
@Test
2828
public void name_depends() {
2929

30-
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet());
30+
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet(), true);
3131
factoryOrder.add(bc("two", null, "one"));
3232
factoryOrder.add(bc("one", null, null));
3333
factoryOrder.orderFactories();
@@ -38,7 +38,7 @@ public void name_depends() {
3838
@Test
3939
public void name_depends4() {
4040

41-
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet());
41+
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet(), true);
4242
factoryOrder.add(bc("1", null, "3"));
4343
factoryOrder.add(bc("2", null, "4"));
4444
factoryOrder.add(bc("3", null, "4"));
@@ -52,7 +52,7 @@ public void name_depends4() {
5252
@Test
5353
public void nameFeature_depends() {
5454

55-
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet());
55+
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet(), true);
5656
factoryOrder.add(bc("1", "a", "3"));
5757
factoryOrder.add(bc("2", null, "4,a"));
5858
factoryOrder.add(bc("3", null, "4"));
@@ -66,7 +66,7 @@ public void nameFeature_depends() {
6666
@Test
6767
public void feature_depends() {
6868

69-
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet());
69+
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet(), true);
7070
factoryOrder.add(bc("two", null, "myfeature"));
7171
factoryOrder.add(bc("one", "myfeature", null));
7272
factoryOrder.orderFactories();
@@ -77,7 +77,7 @@ public void feature_depends() {
7777
@Test
7878
public void feature_depends2() {
7979

80-
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet());
80+
BootContext.FactoryOrder factoryOrder = new BootContext.FactoryOrder(Collections.emptySet(), true);
8181
factoryOrder.add(bc("two", null, "myfeature"));
8282
factoryOrder.add(bc("one", "myfeature", null));
8383
factoryOrder.add(bc("three", "myfeature", null));

0 commit comments

Comments
 (0)