1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau;
18
19 import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
20 import static org.apache.juneau.commons.utils.AssertionUtils.*;
21 import static org.apache.juneau.commons.utils.CollectionUtils.*;
22 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
23 import static org.apache.juneau.commons.utils.Utils.*;
24
25 import java.lang.reflect.*;
26 import java.util.*;
27 import java.util.concurrent.*;
28
29 import org.apache.juneau.annotation.*;
30 import org.apache.juneau.commons.collections.*;
31 import org.apache.juneau.commons.reflect.*;
32 import org.apache.juneau.commons.utils.*;
33 import org.apache.juneau.cp.*;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class BeanRegistry {
55
56 private final Map<String,ClassMeta<?>> map;
57 private final Map<Class<?>,String> reverseMap;
58 private final BeanContext bc;
59 private final AnnotationProvider ap;
60 private final boolean isEmpty;
61
62 BeanRegistry(BeanContext bc, BeanRegistry parent, List<ClassInfo> classes) {
63 assertArgNotNull("bc", bc);
64 assertArgNotNull("classes", classes);
65 this.bc = bc;
66 this.ap = bc.getAnnotationProvider();
67 this.map = new ConcurrentHashMap<>();
68 this.reverseMap = new ConcurrentHashMap<>();
69 bc.getBeanDictionary().forEach(this::addClass);
70 if (nn(parent))
71 parent.map.forEach(this::addToMap);
72 classes.forEach(this::addClass);
73 isEmpty = map.isEmpty();
74 }
75
76
77
78
79
80
81
82
83
84 public ClassMeta<?> getClassMeta(String typeName) {
85 if (isEmpty || typeName == null)
86 return null;
87 var cm = map.get(typeName);
88 if (nn(cm))
89 return cm;
90 if (typeName.charAt(typeName.length() - 1) == '^') {
91 cm = getClassMeta(typeName.substring(0, typeName.length() - 1));
92 if (nn(cm)) {
93 cm = bc.getClassMeta(Array.newInstance(cm.inner(), 1).getClass());
94 map.put(typeName, cm);
95 }
96 return cm;
97 }
98 return null;
99 }
100
101
102
103
104
105
106
107 public String getTypeName(ClassMeta<?> c) {
108 return isEmpty ? null : reverseMap.get(c.inner());
109 }
110
111
112
113
114
115
116
117 public boolean hasName(String typeName) {
118 return nn(getClassMeta(typeName));
119 }
120
121 protected FluentMap<String,Object> properties() {
122 var m = filteredBeanPropertyMap();
123 map.forEach((k, v) -> m.a(k, v.toString(true)));
124 return m;
125 }
126
127 @Override
128 public String toString() {
129 return r(properties());
130 }
131
132 private void addClass(ClassInfo ci) {
133 try {
134 if (nn(ci) && nn(ci.inner())) {
135 if (ci.isChildOf(Collection.class)) {
136 Collection<?> cc = BeanCreator.of(Collection.class).type(ci).run();
137 cc.forEach(x -> {
138 if (x instanceof Class<?> x2)
139 addClass(info(x2));
140 else
141 throw bex("Collection class ''{0}'' passed to BeanRegistry does not contain Class objects.", ci.getName());
142 });
143 } else if (ci.isChildOf(Map.class)) {
144 Map<?,?> m = BeanCreator.of(Map.class).type(ci).run();
145 m.forEach((k, v) -> {
146 var typeName = s(k);
147 var val = (ClassMeta<?>)null;
148 if (v instanceof Type v2)
149 val = bc.getClassMeta(v2);
150 else if (isArray(v))
151 val = getTypedClassMeta(v);
152 else
153 throw bex("Class ''{0}'' was passed to BeanRegistry but value of type ''{1}'' found in map is not a Type object.", ci.getName(), cn(v));
154 addToMap(typeName, val);
155 });
156 } else {
157
158 var typeName = ap.find(Bean.class, ci)
159 .stream()
160 .map(x -> x.inner().typeName())
161 .filter(Utils::ne)
162 .findFirst()
163 .orElseThrow(() -> bex("Class ''{0}'' was passed to BeanRegistry but it doesn't have a @Bean(typeName) annotation defined.", ci.getName()));
164
165 addToMap(typeName, bc.getClassMeta(ci.inner()));
166 }
167 }
168 } catch (BeanRuntimeException e) {
169 throw e;
170 } catch (Exception e) {
171 throw bex(e);
172 }
173 }
174
175 private void addToMap(String typeName, ClassMeta<?> cm) {
176 map.put(typeName, cm);
177 reverseMap.put(cm.inner(), typeName);
178 }
179
180 private ClassMeta<?> getTypedClassMeta(Object array) {
181 var len = Array.getLength(array);
182 if (len == 0)
183 throw bex("Map entry had an empty array value.");
184 var type = (Type)Array.get(array, 0);
185 var args = new Type[len - 1];
186 for (var i = 1; i < len; i++)
187 args[i - 1] = (Type)Array.get(array, i);
188 return bc.getClassMeta(type, args);
189 }
190 }