Skip to content

Commit b506b43

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

File tree

7 files changed

+177
-12
lines changed

7 files changed

+177
-12
lines changed

src/main/java/io/dinject/BeanContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ public interface BeanContext extends Closeable {
9393
*/
9494
<T> T getBean(Class<T> type, String name);
9595

96+
/**
97+
* Return the wiring candidate bean with name and priority.
98+
*/
99+
<T> BeanEntry<T> candidate(Class<T> type, String name);
100+
96101
/**
97102
* Return the list of beans that have an annotation.
98103
*
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.dinject;
2+
3+
/**
4+
* A bean entry in the context with priority and optional name.
5+
*/
6+
public class BeanEntry<T> {
7+
8+
private final int priority;
9+
10+
private final T bean;
11+
12+
private final String name;
13+
14+
/**
15+
* Construct with priorty, name and the bean.
16+
*/
17+
public BeanEntry(int priority, T bean, String name) {
18+
this.priority = priority;
19+
this.bean = bean;
20+
this.name = name;
21+
}
22+
23+
/**
24+
* Return the priority (Primary, Normal and Secondary).
25+
*/
26+
public int getPriority() {
27+
return priority;
28+
}
29+
30+
/**
31+
* Return the bean.
32+
*/
33+
public T getBean() {
34+
return bean;
35+
}
36+
37+
/**
38+
* Return the bean name.
39+
*/
40+
public String getName() {
41+
return name;
42+
}
43+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,11 @@ public <T> T getBean(Class<T> beanClass, String name) {
260260
return context.getBean(beanClass, name);
261261
}
262262

263+
@Override
264+
public <T> BeanEntry<T> candidate(Class<T> type, String name) {
265+
return context.candidate(type, name);
266+
}
267+
263268
@Override
264269
public List<Object> getBeansWithAnnotation(Class<?> annotation) {
265270
return context.getBeansWithAnnotation(annotation);

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

Lines changed: 62 additions & 11 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

@@ -55,20 +56,25 @@ public <T> T getBean(Class<T> beanClass) {
5556
return getBean(beanClass, null);
5657
}
5758

58-
@SuppressWarnings("unchecked")
5959
@Override
60-
public <T> T getBean(Class<T> beanClass, String name) {
61-
T bean = beans.getBean(beanClass, name);
62-
if (bean != null) {
63-
return bean;
64-
}
60+
public <T> BeanEntry<T> candidate(Class<T> type, String name) {
61+
62+
// sort candiates by priority - Primary, Normal, Secondary
63+
EntrySort<T> entrySort = new EntrySort<>();
64+
65+
entrySort.add(beans.candidate(type, name));
6566
for (BeanContext childContext : children.values()) {
66-
bean = childContext.getBean(beanClass, name);
67-
if (bean != null) {
68-
return bean;
69-
}
67+
entrySort.add(childContext.candidate(type, name));
7068
}
71-
return null;
69+
return entrySort.get();
70+
}
71+
72+
@SuppressWarnings("unchecked")
73+
@Override
74+
public <T> T getBean(Class<T> beanClass, String name) {
75+
76+
BeanEntry<T> candidate = candidate(beanClass, name);
77+
return (candidate == null) ? null : candidate.getBean();
7278
}
7379

7480
@Override
@@ -125,4 +131,49 @@ public void close() {
125131
}
126132
}
127133
}
134+
135+
private static class EntrySort<T> {
136+
137+
private BeanEntry<T> primary;
138+
private int primaryCount;
139+
private BeanEntry<T> secondary;
140+
private int secondaryCount;
141+
private BeanEntry<T> normal;
142+
private int normalCount;
143+
144+
void add(BeanEntry<T> candidate) {
145+
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+
}
157+
}
158+
}
159+
160+
BeanEntry<T> get() {
161+
if (primaryCount > 1) {
162+
throw new IllegalStateException("Multiple @Primary beans when only expecting one? Last was: " + primary);
163+
}
164+
if (primaryCount == 1) {
165+
return primary;
166+
}
167+
if (normalCount > 1) {
168+
throw new IllegalStateException("Multiple beans when only expecting one? Maybe use @Primary or @Secondary? Last was: " + normal);
169+
}
170+
if (normalCount == 1) {
171+
return normal;
172+
}
173+
if (secondaryCount > 1) {
174+
throw new IllegalStateException("Multiple @Secondary beans when only expecting one? Last was: " + primary);
175+
}
176+
return secondary;
177+
}
178+
}
128179
}

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

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

3+
import io.dinject.BeanEntry;
4+
35
import javax.inject.Named;
46
import java.util.LinkedHashMap;
57
import java.util.List;
@@ -113,6 +115,19 @@ <T> T getBean(Class<T> type, String name) {
113115
return null;
114116
}
115117

118+
<T> BeanEntry<T> candidate(Class<T> type, String name) {
119+
120+
if (beans == null) {
121+
// no beans in the root suppliedBeanMap
122+
return null;
123+
}
124+
DContextEntry entry = beans.get(type.getCanonicalName());
125+
if (entry != null) {
126+
return entry.candidate(name);
127+
}
128+
return null;
129+
}
130+
116131
/**
117132
* Add all bean instances matching the given type to the list.
118133
*/

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.dinject.core;
22

3+
import io.dinject.BeanEntry;
4+
35
import java.util.ArrayList;
46
import java.util.List;
57

@@ -12,6 +14,21 @@ class DContextEntry {
1214

1315
private final List<DContextEntryBean> entries = new ArrayList<>();
1416

17+
@SuppressWarnings("unchecked")
18+
<T> BeanEntry<T> candidate(String name) {
19+
if (entries.isEmpty()) {
20+
return null;
21+
}
22+
if (entries.size() == 1) {
23+
DContextEntryBean entry = entries.get(0);
24+
return entry.candidate(name);
25+
}
26+
27+
EntryMatcher matcher = new EntryMatcher(name);
28+
matcher.match(entries);
29+
return matcher.candidate();
30+
}
31+
1532
/**
1633
* Get a single bean given the name.
1734
*/
@@ -96,10 +113,23 @@ Object getBean() {
96113
if (match == null) {
97114
return null;
98115
}
116+
checkSecondary();
117+
return match.getBean();
118+
}
119+
120+
BeanEntry candidate() {
121+
if (match == null) {
122+
return null;
123+
}
124+
checkSecondary();
125+
return match.getBeanEntry();
126+
}
127+
128+
private void checkSecondary() {
99129
if (match.isSecondary() && ignoredSecondaryMatch != null) {
100130
throw new IllegalStateException("Expecting only 1 bean match but have multiple secondary beans " + match.getBean() + " and " + ignoredSecondaryMatch.getBean());
101131
}
102-
return match.getBean();
103132
}
133+
104134
}
105135
}

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

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

3+
import io.dinject.BeanEntry;
4+
35
import javax.inject.Provider;
46
import java.util.Objects;
57

@@ -64,6 +66,20 @@ boolean isSecondary() {
6466
return flag == Flag.SECONDARY;
6567
}
6668

69+
@SuppressWarnings("unchecked")
70+
BeanEntry getBeanEntry() {
71+
return new BeanEntry(flag, getBean(), name);
72+
}
73+
74+
@SuppressWarnings("unchecked")
75+
BeanEntry candidate(String name) {
76+
if (name == null || Objects.equals(this.name, name)) {
77+
return new BeanEntry(flag, obtainInstance(), name);
78+
} else {
79+
return null;
80+
}
81+
}
82+
6783
/**
6884
* Provider based entry - get it once.
6985
*/

0 commit comments

Comments
 (0)