19
19
import jakarta .enterprise .inject .Typed ;
20
20
21
21
import java .lang .annotation .Annotation ;
22
+ import java .util .ArrayList ;
22
23
import java .util .Arrays ;
23
24
import java .util .Collection ;
24
25
import java .util .Collections ;
25
26
import java .util .HashMap ;
26
27
import java .util .HashSet ;
27
- import java .util .IdentityHashMap ;
28
28
import java .util .Map ;
29
+ import java .util .Optional ;
29
30
import java .util .Set ;
31
+ import java .util .function .Function ;
32
+ import java .util .function .Predicate ;
33
+ import java .util .stream .Stream ;
34
+
35
+ import static io .crysknife .client .internal .QualifierUtil .ANY_ANNOTATION ;
36
+ import static io .crysknife .client .internal .QualifierUtil .DEFAULT_ANNOTATION ;
37
+ import static io .crysknife .client .internal .QualifierUtil .DEFAULT_QUALIFIERS ;
38
+ import static io .crysknife .client .internal .QualifierUtil .SPECIALIZES_ANNOTATION ;
39
+ import static io .crysknife .client .internal .QualifierUtil .matches ;
30
40
31
41
/**
32
42
* @author Dmitrii Tikhomirov Created by treblereel 3/28/19
33
43
*/
44
+ @ SuppressWarnings ("unchecked" )
34
45
public abstract class AbstractBeanManager implements BeanManager {
35
46
36
47
private final Map <Class , BeanDefinitionHolder > beans = new HashMap <>();
37
48
38
- private final Map <Object , BeanFactory > pool = new IdentityHashMap <>();
49
+ private final Map <Object , BeanFactory > pool = new HashMap <>();
39
50
private final Map <String , Class > beansByBeanName = new HashMap <>();
40
51
41
- protected AbstractBeanManager () {
52
+ private final Predicate <SyncBeanDefImpl > isTyped =
53
+ syncBeanDef -> syncBeanDef .getTyped ().isPresent ();
54
+ private final Predicate <SyncBeanDefImpl > isNotTyped =
55
+ syncBeanDef -> syncBeanDef .getTyped ().isEmpty ();
42
56
43
- }
57
+ private final Predicate <SyncBeanDefImpl > hasFactory =
58
+ syncBeanDef -> syncBeanDef .getFactory ().isPresent ();
44
59
45
- public void register (SyncBeanDefImpl beanDefinition ) {
46
- BeanDefinitionHolder holder = get (beanDefinition .getType ());
47
- holder .beanDefinition = beanDefinition ;
48
- beanDefinition .getAssignableTypes ().forEach (superType -> {
49
- get ((Class <?>) superType ).subTypes .add (holder );
50
- beansByBeanName .put (((Class <?>) superType ).getCanonicalName (), (Class <?>) superType );
60
+ private final Predicate <SyncBeanDefImpl > hasDefaultQualifiers =
61
+ bean -> bean .matches (setOf (DEFAULT_ANNOTATION ));
62
+
63
+ protected AbstractBeanManager () {
51
64
52
- });
53
- beansByBeanName .put (beanDefinition .getName (), beanDefinition .getType ());
54
65
}
55
66
56
- private BeanDefinitionHolder get (Class <?> type ) {
57
- if (!beans .containsKey (type )) {
58
- BeanDefinitionHolder holder = new BeanDefinitionHolder ();
59
- beans .put (type , holder );
67
+ public void register (final SyncBeanDefImpl beanDefinition ) {
68
+ BeanDefinitionHolder holder =
69
+ beans .computeIfAbsent (beanDefinition .getType (), k -> new BeanDefinitionHolder ());
70
+ for (Class <?> superType : (Collection <Class <?>>) beanDefinition .getAssignableTypes ()) {
71
+ beans .computeIfAbsent (superType , k -> new BeanDefinitionHolder ()).subTypes .add (holder );
72
+ beansByBeanName .put (superType .getCanonicalName (), superType );
60
73
}
61
- return beans .get (type );
74
+ Set <Annotation > temp = new HashSet <Annotation >(beanDefinition .getActualQualifiers ());
75
+ holder .qualifiers .put (temp , beanDefinition );
76
+ beansByBeanName .put (beanDefinition .getName (), beanDefinition .getType ());
62
77
}
63
78
64
79
@ Override
65
80
public Collection <SyncBeanDef > lookupBeans (String name ) {
66
81
if (beansByBeanName .containsKey (name )) {
67
82
return lookupBeans (beansByBeanName .get (name ));
68
83
}
84
+ return Collections .EMPTY_SET ;
85
+ }
69
86
87
+ public <T > Collection <SyncBeanDef <T >> lookupBeans (final Class <T > type ) {
88
+ Set <SyncBeanDef <T >> result = new HashSet <>();
89
+ if (!beans .containsKey (type )) {
90
+ return result ;
91
+ }
92
+ of (beans .get (type )).map (f -> (SyncBeanDef <T >) f ).forEach (result ::add );
93
+ return result ;
94
+ }
70
95
71
- return Collections .EMPTY_SET ;
96
+ private Stream <SyncBeanDefImpl > of (BeanDefinitionHolder holder ,
97
+ Predicate <SyncBeanDefImpl >... filters ) {
98
+ Stream <SyncBeanDefImpl > stream =
99
+ Stream .of (holder .subTypes .stream ().flatMap (f -> f .qualifiers .values ().stream ()),
100
+ holder .qualifiers .values ().stream ()).flatMap (Function .identity ());
101
+ for (Predicate <SyncBeanDefImpl > filter : filters ) {
102
+ stream = stream .filter (filter );
103
+ }
104
+
105
+ return stream ;
72
106
}
73
107
74
108
public <T > Collection <SyncBeanDef <T >> lookupBeans (final Class <T > type , Annotation ... qualifiers ) {
@@ -78,33 +112,25 @@ public <T> Collection<SyncBeanDef<T>> lookupBeans(final Class<T> type, Annotatio
78
112
}
79
113
80
114
if (qualifiers .length == 0 ) {
81
- if (beans .get (type ).beanDefinition != null ) {
82
- result .add (beans .get (type ).beanDefinition );
83
- }
84
- beans .get (type ).subTypes .stream ().filter (f -> f .beanDefinition != null )
85
- .forEach (bean -> result .add (bean .beanDefinition ));
86
- return result ;
115
+ return lookupBeans (type );
87
116
}
88
117
89
- if (beans .get (type ).beanDefinition != null ) {
90
- if (compareAnnotations (beans .get (type ).beanDefinition .getActualQualifiers (), qualifiers )) {
91
- result .add (beans .get (type ).beanDefinition );
92
- }
93
- }
94
- beans .get (type ).subTypes .stream ().filter (f -> f .beanDefinition != null )
95
- .filter (f -> compareAnnotations (f .beanDefinition .getActualQualifiers (), qualifiers ))
96
- .forEach (bean -> result .add (bean .beanDefinition ));
118
+ of (beans .get (type )).filter (bean -> bean .matches (setOf (qualifiers ))).map (f -> (SyncBeanDef <T >) f )
119
+ .forEach (result ::add );
97
120
98
121
return result ;
99
122
}
100
123
101
- private boolean compareAnnotations (Collection <Annotation > all , Annotation ... in ) {
102
- Annotation [] _all = all .toArray (new Annotation [all .size ()]);
103
- return QualifierUtil .matches (in , _all );
104
- }
105
-
106
124
public <T > SyncBeanDef <T > lookupBean (final Class <T > type ) {
107
- return lookupBean (type , QualifierUtil .DEFAULT_ANNOTATION );
125
+ Collection <IOCBeanDef <T >> candidates = doLookupBean (type , QualifierUtil .DEFAULT_ANNOTATION );
126
+
127
+ if (candidates .size () > 1 ) {
128
+ throw BeanManagerUtil .ambiguousResolutionException (type , candidates , DEFAULT_ANNOTATION );
129
+ } else if (candidates .isEmpty ()) {
130
+ throw BeanManagerUtil .unsatisfiedResolutionException (type , DEFAULT_ANNOTATION );
131
+ } else {
132
+ return (SyncBeanDef <T >) candidates .iterator ().next ();
133
+ }
108
134
}
109
135
110
136
public <T > SyncBeanDef <T > lookupBean (final Class <T > type , Annotation ... qualifiers ) {
@@ -126,110 +152,113 @@ public void destroyBean(Object ref) {
126
152
}
127
153
}
128
154
129
- <T > T addBeanInstanceToPool (Object instance , BeanFactory factory ) {
130
- pool .put (instance , factory );
131
- return (T ) instance ;
132
- }
155
+ private <T > Collection <IOCBeanDef <T >> doLookupBean (final Class <T > type ,
156
+ final Annotation ... qualifiers ) {
157
+ if (!beans .containsKey (type )) {
158
+ return Collections .EMPTY_SET ;
159
+ }
133
160
134
- <T > Collection <IOCBeanDef <T >> doLookupBean (final Class <T > type , Annotation ... qualifiers ) {
135
161
Collection <IOCBeanDef <T >> candidates = new HashSet <>();
136
- if ( beans .containsKey (type )) {
162
+ BeanDefinitionHolder holder = beans .get (type );
137
163
138
- if ( qualifiers == null || qualifiers . length == 0 ) {
139
- qualifiers = new Annotation [] { QualifierUtil . DEFAULT_ANNOTATION };
140
- }
164
+ Optional < IOCBeanDef < T >> maybeTyped = of ( holder , isTyped )
165
+ . filter ( bean -> Arrays . asList ((( Typed ) bean . getTyped (). get ()). value ()). contains ( type ))
166
+ . map ( bean -> ( IOCBeanDef < T >) bean ). findFirst ();
141
167
142
- if (beans .get (type ).beanDefinition != null ) {
143
- if (beans .get (type ).beanDefinition .getTyped ().isPresent ()) {
144
- if (Arrays .stream (((Typed ) beans .get (type ).beanDefinition .getTyped ().get ()).value ())
145
- .anyMatch (any -> any .equals (type ))) {
146
- Set <IOCBeanDef <T >> result = new HashSet <>();
147
- result .add (beans .get (type ).beanDefinition );
148
- return result ;
149
- }
150
- }
168
+ if (maybeTyped .isPresent ()) {
169
+ return setOf (maybeTyped .get ());
170
+ }
151
171
152
- if (compareAnnotations (beans .get (type ).beanDefinition .getQualifiers (), qualifiers )) {
153
- if (beans .get (type ).beanDefinition .getFactory ().isPresent ()) {
154
- candidates .add (beans .get (type ).beanDefinition );
155
- }
156
- }
172
+ of (holder , hasFactory , isNotTyped ).filter (bean -> {
173
+ Set <Annotation > temp = new HashSet <>(bean .getActualQualifiers ());
174
+ Collections .addAll (temp , DEFAULT_QUALIFIERS );
175
+ return compareAnnotations (temp , qualifiers );
176
+ }).forEach (bean -> candidates .add ((IOCBeanDef <T >) bean ));
177
+
178
+ if (qualifiers .length == 1 && isDefault (qualifiers )) {
179
+ Optional <IOCBeanDef <T >> maybeSpecialized =
180
+ of (holder , isNotTyped ).filter (bean -> bean .matches (setOf (SPECIALIZES_ANNOTATION )))
181
+ .map (bean -> (IOCBeanDef <T >) bean ).findFirst ();
182
+
183
+ // TODO this is not correct, specialized bean totally overrides the parent bean, including
184
+ // qualifiers
185
+ if (maybeSpecialized .isPresent ()) {
186
+ return setOf (maybeSpecialized .get ());
157
187
}
158
188
159
- if (qualifiers .length == 1 && !beans .get (type ).subTypes .isEmpty () && isDefault (qualifiers )) {
160
- for (BeanDefinitionHolder subType : beans .get (type ).subTypes ) {
161
- if (subType .beanDefinition != null ) {
162
- if (!subType .beanDefinition .getActualQualifiers ().isEmpty ()
163
- && compareAnnotations (subType .beanDefinition .getActualQualifiers (),
164
- QualifierUtil .SPECIALIZES_ANNOTATION )) {
165
- Collection <IOCBeanDef <T >> result = new HashSet <>();
166
- result .add (subType .beanDefinition );
167
- return result ;
168
- }
169
- }
170
- }
171
- for (BeanDefinitionHolder subType : beans .get (type ).subTypes ) {
172
- if (subType .beanDefinition != null ) {
173
- if (!subType .beanDefinition .getActualQualifiers ().isEmpty () && compareAnnotations (
174
- subType .beanDefinition .getActualQualifiers (), QualifierUtil .DEFAULT_ANNOTATION )) {
175
- Collection <IOCBeanDef <T >> result = new HashSet <>();
176
- result .add (subType .beanDefinition );
177
- return result ;
178
- }
179
- }
180
- }
181
- for (BeanDefinitionHolder subType : beans .get (type ).subTypes ) {
182
- Set <Annotation > annotations = new HashSet <>();
183
- annotations .add (QualifierUtil .DEFAULT_ANNOTATION );
184
- if (compareAnnotations (subType .beanDefinition .getActualQualifiers (), qualifiers )) {
185
- if (subType .beanDefinition .getTyped ().isPresent ()) {
186
- continue ;
187
- } else if (subType .beanDefinition .getFactory ().isPresent ())
188
- candidates .add (subType .beanDefinition );
189
- }
190
- }
191
- } else {
192
- Set <Annotation > _qual = new HashSet <>();
193
- Collections .addAll (_qual , qualifiers );
194
- Collections .addAll (_qual , QualifierUtil .DEFAULT_QUALIFIERS );
195
- _qual .toArray (new Annotation [_qual .size ()]);
196
-
197
- for (BeanDefinitionHolder subType : beans .get (type ).subTypes ) {
198
- if (compareAnnotations (subType .beanDefinition .getQualifiers (),
199
- _qual .toArray (new Annotation [_qual .size ()]))) {
200
- if (subType .beanDefinition .getTyped ().isPresent ()
201
- && !isDefault (subType .beanDefinition .getActualQualifiers ())) {
202
- continue ;
203
- } else if (subType .beanDefinition .getFactory ().isPresent ())
204
- candidates .add (subType .beanDefinition );
205
- }
206
- }
189
+ Optional <IOCBeanDef <T >> maybeDefault = of (holder , isNotTyped , hasDefaultQualifiers )
190
+ .map (bean -> (IOCBeanDef <T >) bean ).findFirst ();
191
+
192
+ if (maybeDefault .isPresent ()) {
193
+ return setOf (maybeDefault .get ());
207
194
}
195
+
196
+ of (holder , isNotTyped , hasFactory , hasDefaultQualifiers ).map (bean -> (IOCBeanDef <T >) bean )
197
+ .forEach (candidates ::add );
198
+ } else if (qualifiers .length == 1 && isAny (qualifiers )) {
199
+
200
+ of (holder , hasFactory )
201
+ // .filter(bean -> bean.getTyped().isEmpty()) //TODO not sure about this, may I have to
202
+ // filter out @typed beans
203
+ .map (bean -> (IOCBeanDef <T >) bean ).forEach (candidates ::add );
204
+ } else {
205
+ of (holder , isNotTyped , hasFactory ).filter (bean -> bean .matches (setOf (qualifiers )))
206
+ .map (bean -> (IOCBeanDef <T >) bean ).forEach (candidates ::add );
208
207
}
209
208
return candidates ;
210
209
}
211
210
212
- private boolean isDefault (Collection <Annotation > qualifiers ) {
213
- if (qualifiers .isEmpty ()) {
214
- return false ;
215
- }
216
- return isDefault (qualifiers .toArray (new Annotation [qualifiers .size ()]));
211
+ private boolean compareAnnotations (Collection <Annotation > all , Annotation ... in ) {
212
+ Annotation [] _all = all .toArray (new Annotation [all .size ()]);
213
+ return matches (in , _all );
217
214
}
218
215
219
216
private boolean isDefault (Annotation [] qualifiers ) {
220
217
Annotation [] a1 = new Annotation [] {qualifiers [0 ]};
221
- Annotation [] a2 = new Annotation [] {QualifierUtil .DEFAULT_ANNOTATION };
222
- return QualifierUtil .matches (a1 , a2 );
218
+ Annotation [] a2 = new Annotation [] {DEFAULT_ANNOTATION };
219
+ return matches (a1 , a2 );
220
+ }
221
+
222
+ private boolean isAny (Annotation [] qualifiers ) {
223
+ Annotation [] a1 = new Annotation [] {qualifiers [0 ]};
224
+ Annotation [] a2 = new Annotation [] {ANY_ANNOTATION };
225
+ return matches (a1 , a2 );
226
+ }
227
+
228
+ private <T > Collection <IOCBeanDef <T >> doLookupBean (final Class <T > type ) {
229
+ Collection <IOCBeanDef <T >> candidates = new ArrayList <>();
230
+ if (beans .containsKey (type )) {
231
+ if (!beans .get (type ).qualifiers .isEmpty ()) {
232
+ beans .get (type ).qualifiers .values ().forEach (candidates ::add );
233
+ } else {
234
+ of (beans .get (type ), isNotTyped , hasFactory ).filter (syncBeanDef -> {
235
+ if (syncBeanDef .getActualQualifiers ().isEmpty ()) {
236
+ return true ;
237
+ } else {
238
+ return syncBeanDef .matches (setOf (DEFAULT_ANNOTATION ));
239
+ }
240
+ }).map (bean -> (IOCBeanDef <T >) bean ).forEach (candidates ::add );
241
+ }
242
+ }
243
+ return candidates ;
223
244
}
224
245
225
- private boolean compareAnnotations (Annotation [] all , Annotation [] in ) {
226
- return QualifierUtil .matches (in , all );
246
+ // replace it with setOf right after we move to Java 11 emulated by J2CL
247
+ public static <T > Set <T > setOf (T ... values ) {
248
+ Set <T > set = new HashSet <>();
249
+ Collections .addAll (set , values );
250
+ return Collections .unmodifiableSet (set );
251
+ }
252
+
253
+ <T > T addBeanInstanceToPool (Object instance , BeanFactory <T > factory ) {
254
+ pool .put (instance , factory );
255
+ return (T ) instance ;
227
256
}
228
257
229
258
private static class BeanDefinitionHolder {
230
259
231
- SyncBeanDefImpl beanDefinition ;
232
- Set <BeanDefinitionHolder > subTypes = new HashSet <>();
260
+ private final Set <BeanDefinitionHolder > subTypes = new HashSet <>();
261
+ private final Map <Set <Annotation >, SyncBeanDefImpl > qualifiers = new HashMap <>();
262
+
233
263
}
234
264
}
235
-
0 commit comments