1 package com.fasterxml.jackson.databind.jsontype.impl;
2
3 import java.lang.reflect.Modifier;
4 import java.util.*;
5
6 import com.fasterxml.jackson.databind.AnnotationIntrospector;
7 import com.fasterxml.jackson.databind.JavaType;
8 import com.fasterxml.jackson.databind.cfg.MapperConfig;
9 import com.fasterxml.jackson.databind.introspect.*;
10 import com.fasterxml.jackson.databind.jsontype.NamedType;
11 import com.fasterxml.jackson.databind.jsontype.SubtypeResolver;
12
13
16 public class StdSubtypeResolver
17 extends SubtypeResolver
18 implements java.io.Serializable
19 {
20 private static final long serialVersionUID = 1L;
21
22 protected LinkedHashSet<NamedType> _registeredSubtypes;
23
24 public StdSubtypeResolver() { }
25
26
27 protected StdSubtypeResolver(StdSubtypeResolver src) {
28 LinkedHashSet<NamedType> reg = src._registeredSubtypes;
29 _registeredSubtypes = (reg == null) ? null
30 : new LinkedHashSet<>(reg);
31 }
32
33
34 @Override
35 public SubtypeResolver copy() {
36 return new StdSubtypeResolver(this);
37 }
38
39
44
45 @Override
46 public void registerSubtypes(NamedType... types) {
47 if (_registeredSubtypes == null) {
48 _registeredSubtypes = new LinkedHashSet<NamedType>();
49 }
50 for (NamedType type : types) {
51 _registeredSubtypes.add(type);
52 }
53 }
54
55 @Override
56 public void registerSubtypes(Class<?>... classes) {
57 NamedType[] types = new NamedType[classes.length];
58 for (int i = 0, len = classes.length; i < len; ++i) {
59 types[i] = new NamedType(classes[i]);
60 }
61 registerSubtypes(types);
62 }
63
64 @Override
65 public void registerSubtypes(Collection<Class<?>> subtypes) {
66 int len = subtypes.size();
67 NamedType[] types = new NamedType[len];
68 int i = 0;
69 for (Class<?> subtype : subtypes) {
70 types[i++] = new NamedType(subtype);
71 }
72 registerSubtypes(types);
73 }
74
75
80
81 @Override
82 public Collection<NamedType> collectAndResolveSubtypesByClass(MapperConfig<?> config,
83 AnnotatedMember property, JavaType baseType)
84 {
85 final AnnotationIntrospector ai = config.getAnnotationIntrospector();
86
87 Class<?> rawBase = (baseType == null) ? property.getRawType() : baseType.getRawClass();
88
89 HashMap<NamedType, NamedType> collected = new HashMap<NamedType, NamedType>();
90
91 if (_registeredSubtypes != null) {
92 for (NamedType subtype : _registeredSubtypes) {
93
94 if (rawBase.isAssignableFrom(subtype.getType())) {
95 AnnotatedClass curr = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
96 subtype.getType());
97 _collectAndResolve(curr, subtype, config, ai, collected);
98 }
99 }
100 }
101
102
103 if (property != null) {
104 Collection<NamedType> st = ai.findSubtypes(property);
105 if (st != null) {
106 for (NamedType nt : st) {
107 AnnotatedClass ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
108 nt.getType());
109 _collectAndResolve(ac, nt, config, ai, collected);
110 }
111 }
112 }
113
114 NamedType rootType = new NamedType(rawBase, null);
115 AnnotatedClass ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config, rawBase);
116
117
118 _collectAndResolve(ac, rootType, config, ai, collected);
119
120 return new ArrayList<NamedType>(collected.values());
121 }
122
123 @Override
124 public Collection<NamedType> collectAndResolveSubtypesByClass(MapperConfig<?> config,
125 AnnotatedClass type)
126 {
127 final AnnotationIntrospector ai = config.getAnnotationIntrospector();
128 HashMap<NamedType, NamedType> subtypes = new HashMap<>();
129
130
131 if (_registeredSubtypes != null) {
132 Class<?> rawBase = type.getRawType();
133 for (NamedType subtype : _registeredSubtypes) {
134
135 if (rawBase.isAssignableFrom(subtype.getType())) {
136 AnnotatedClass curr = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
137 subtype.getType());
138 _collectAndResolve(curr, subtype, config, ai, subtypes);
139 }
140 }
141 }
142
143 NamedType rootType = new NamedType(type.getRawType(), null);
144 _collectAndResolve(type, rootType, config, ai, subtypes);
145 return new ArrayList<NamedType>(subtypes.values());
146 }
147
148
153
154 @Override
155 public Collection<NamedType> collectAndResolveSubtypesByTypeId(MapperConfig<?> config,
156 AnnotatedMember property, JavaType baseType)
157 {
158 final AnnotationIntrospector ai = config.getAnnotationIntrospector();
159 Class<?> rawBase = baseType.getRawClass();
160
161
162 Set<Class<?>> typesHandled = new HashSet<Class<?>>();
163 Map<String,NamedType> byName = new LinkedHashMap<String,NamedType>();
164
165
166 NamedType rootType = new NamedType(rawBase, null);
167 AnnotatedClass ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
168 rawBase);
169 _collectAndResolveByTypeId(ac, rootType, config, typesHandled, byName);
170
171
172 if (property != null) {
173 Collection<NamedType> st = ai.findSubtypes(property);
174 if (st != null) {
175 for (NamedType nt : st) {
176 ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config, nt.getType());
177 _collectAndResolveByTypeId(ac, nt, config, typesHandled, byName);
178 }
179 }
180 }
181
182 if (_registeredSubtypes != null) {
183 for (NamedType subtype : _registeredSubtypes) {
184
185 if (rawBase.isAssignableFrom(subtype.getType())) {
186 AnnotatedClass curr = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
187 subtype.getType());
188 _collectAndResolveByTypeId(curr, subtype, config, typesHandled, byName);
189 }
190 }
191 }
192 return _combineNamedAndUnnamed(rawBase, typesHandled, byName);
193 }
194
195 @Override
196 public Collection<NamedType> collectAndResolveSubtypesByTypeId(MapperConfig<?> config,
197 AnnotatedClass baseType)
198 {
199 final Class<?> rawBase = baseType.getRawType();
200 Set<Class<?>> typesHandled = new HashSet<Class<?>>();
201 Map<String,NamedType> byName = new LinkedHashMap<String,NamedType>();
202
203 NamedType rootType = new NamedType(rawBase, null);
204 _collectAndResolveByTypeId(baseType, rootType, config, typesHandled, byName);
205
206 if (_registeredSubtypes != null) {
207 for (NamedType subtype : _registeredSubtypes) {
208
209 if (rawBase.isAssignableFrom(subtype.getType())) {
210 AnnotatedClass curr = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
211 subtype.getType());
212 _collectAndResolveByTypeId(curr, subtype, config, typesHandled, byName);
213 }
214 }
215 }
216 return _combineNamedAndUnnamed(rawBase, typesHandled, byName);
217 }
218
219
224
225
229 protected void _collectAndResolve(AnnotatedClass annotatedType, NamedType namedType,
230 MapperConfig<?> config, AnnotationIntrospector ai,
231 HashMap<NamedType, NamedType> collectedSubtypes)
232 {
233 if (!namedType.hasName()) {
234 String name = ai.findTypeName(annotatedType);
235 if (name != null) {
236 namedType = new NamedType(namedType.getType(), name);
237 }
238 }
239
240
241
242 NamedType typeOnlyNamedType = new NamedType(namedType.getType());
243
244
245 if (collectedSubtypes.containsKey(typeOnlyNamedType)) {
246
247 if (namedType.hasName()) {
248 NamedType prev = collectedSubtypes.get(typeOnlyNamedType);
249 if (!prev.hasName()) {
250 collectedSubtypes.put(typeOnlyNamedType, namedType);
251 }
252 }
253 return;
254 }
255
256 collectedSubtypes.put(typeOnlyNamedType, namedType);
257 Collection<NamedType> st = ai.findSubtypes(annotatedType);
258 if (st != null && !st.isEmpty()) {
259 for (NamedType subtype : st) {
260 AnnotatedClass subtypeClass = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
261 subtype.getType());
262 _collectAndResolve(subtypeClass, subtype, config, ai, collectedSubtypes);
263 }
264 }
265 }
266
267
271 protected void _collectAndResolveByTypeId(AnnotatedClass annotatedType, NamedType namedType,
272 MapperConfig<?> config,
273 Set<Class<?>> typesHandled, Map<String,NamedType> byName)
274 {
275 final AnnotationIntrospector ai = config.getAnnotationIntrospector();
276 if (!namedType.hasName()) {
277 String name = ai.findTypeName(annotatedType);
278 if (name != null) {
279 namedType = new NamedType(namedType.getType(), name);
280 }
281 }
282 if (namedType.hasName()) {
283 byName.put(namedType.getName(), namedType);
284 }
285
286
287 if (typesHandled.add(namedType.getType())) {
288 Collection<NamedType> st = ai.findSubtypes(annotatedType);
289 if (st != null && !st.isEmpty()) {
290 for (NamedType subtype : st) {
291 AnnotatedClass subtypeClass = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
292 subtype.getType());
293 _collectAndResolveByTypeId(subtypeClass, subtype, config, typesHandled, byName);
294 }
295 }
296 }
297 }
298
299
303 protected Collection<NamedType> _combineNamedAndUnnamed(Class<?> rawBase,
304 Set<Class<?>> typesHandled, Map<String,NamedType> byName)
305 {
306 ArrayList<NamedType> result = new ArrayList<NamedType>(byName.values());
307
308
309
310
311 for (NamedType t : byName.values()) {
312 typesHandled.remove(t.getType());
313 }
314 for (Class<?> cls : typesHandled) {
315
316
317 if ((cls == rawBase) && Modifier.isAbstract(cls.getModifiers())) {
318 continue;
319 }
320 result.add(new NamedType(cls));
321 }
322 return result;
323 }
324 }
325