1 package com.fasterxml.jackson.databind.introspect;
2
3 import java.lang.annotation.Annotation;
4 import java.lang.annotation.Retention;
5 import java.lang.annotation.Target;
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.List;
9 import java.util.Map;
10
11 import com.fasterxml.jackson.databind.AnnotationIntrospector;
12 import com.fasterxml.jackson.databind.JavaType;
13 import com.fasterxml.jackson.databind.cfg.MapperConfig;
14 import com.fasterxml.jackson.databind.introspect.ClassIntrospector.MixInResolver;
15 import com.fasterxml.jackson.databind.type.TypeBindings;
16 import com.fasterxml.jackson.databind.util.Annotations;
17 import com.fasterxml.jackson.databind.util.ClassUtil;
18
19
25 public class AnnotatedClassResolver
26 {
27 private final static Annotations NO_ANNOTATIONS = AnnotationCollector.emptyAnnotations();
28
29 private final static Class<?> CLS_OBJECT = Object.class;
30 private final static Class<?> CLS_ENUM = Enum.class;
31
32 private final static Class<?> CLS_LIST = List.class;
33 private final static Class<?> CLS_MAP = Map.class;
34
35 private final MapperConfig<?> _config;
36 private final AnnotationIntrospector _intr;
37 private final MixInResolver _mixInResolver;
38 private final TypeBindings _bindings;
39
40 private final JavaType _type;
41 private final Class<?> _class;
42 private final Class<?> _primaryMixin;
43
44
47 private final boolean _collectAnnotations;
48
49 AnnotatedClassResolver(MapperConfig<?> config, JavaType type, MixInResolver r) {
50 _config = config;
51 _type = type;
52 _class = type.getRawClass();
53 _mixInResolver = r;
54 _bindings = type.getBindings();
55 _intr = config.isAnnotationProcessingEnabled()
56 ? config.getAnnotationIntrospector() : null;
57 _primaryMixin = (r == null) ? null : r.findMixInClassFor(_class);
58
59
60
61 _collectAnnotations = (_intr != null) &&
62 (!ClassUtil.isJDKClass(_class) || !_type.isContainerType());
63 }
64
65 AnnotatedClassResolver(MapperConfig<?> config, Class<?> cls, MixInResolver r) {
66 _config = config;
67 _type = null;
68 _class = cls;
69 _mixInResolver = r;
70 _bindings = TypeBindings.emptyBindings();
71 if (config == null) {
72 _intr = null;
73 _primaryMixin = null;
74 } else {
75 _intr = config.isAnnotationProcessingEnabled()
76 ? config.getAnnotationIntrospector() : null;
77 _primaryMixin = (r == null) ? null : r.findMixInClassFor(_class);
78 }
79
80 _collectAnnotations = (_intr != null);
81 }
82
83 public static AnnotatedClass resolve(MapperConfig<?> config, JavaType forType,
84 MixInResolver r)
85 {
86 if (forType.isArrayType() && skippableArray(config, forType.getRawClass())) {
87 return createArrayType(config, forType.getRawClass());
88 }
89 return new AnnotatedClassResolver(config, forType, r).resolveFully();
90 }
91
92 public static AnnotatedClass resolveWithoutSuperTypes(MapperConfig<?> config, Class<?> forType) {
93 return resolveWithoutSuperTypes(config, forType, config);
94 }
95
96 public static AnnotatedClass resolveWithoutSuperTypes(MapperConfig<?> config, JavaType forType,
97 MixInResolver r)
98 {
99 if (forType.isArrayType() && skippableArray(config, forType.getRawClass())) {
100 return createArrayType(config, forType.getRawClass());
101 }
102 return new AnnotatedClassResolver(config, forType, r).resolveWithoutSuperTypes();
103 }
104
105 public static AnnotatedClass resolveWithoutSuperTypes(MapperConfig<?> config, Class<?> forType,
106 MixInResolver r)
107 {
108 if (forType.isArray() && skippableArray(config, forType)) {
109 return createArrayType(config, forType);
110 }
111 return new AnnotatedClassResolver(config, forType, r).resolveWithoutSuperTypes();
112 }
113
114 private static boolean skippableArray(MapperConfig<?> config, Class<?> type) {
115 return (config == null) || (config.findMixInClassFor(type) == null);
116 }
117
118
122 static AnnotatedClass createPrimordial(Class<?> raw) {
123 return new AnnotatedClass(raw);
124 }
125
126
130 static AnnotatedClass createArrayType(MapperConfig<?> config, Class<?> raw) {
131 return new AnnotatedClass(raw);
132 }
133
134 AnnotatedClass resolveFully() {
135 List<JavaType> superTypes = new ArrayList<JavaType>(8);
136 if (!_type.hasRawClass(Object.class)) {
137 if (_type.isInterface()) {
138 _addSuperInterfaces(_type, superTypes, false);
139 } else {
140 _addSuperTypes(_type, superTypes, false);
141 }
142 }
143
144 return new AnnotatedClass(_type, _class, superTypes, _primaryMixin,
145 resolveClassAnnotations(superTypes),
146 _bindings, _intr, _mixInResolver, _config.getTypeFactory(),
147 _collectAnnotations);
148
149 }
150
151 AnnotatedClass resolveWithoutSuperTypes() {
152 List<JavaType> superTypes = Collections.<JavaType>emptyList();
153 return new AnnotatedClass(null, _class, superTypes, _primaryMixin,
154 resolveClassAnnotations(superTypes),
155 _bindings, _intr, _mixInResolver, _config.getTypeFactory(),
156 _collectAnnotations);
157 }
158
159 private static void _addSuperTypes(JavaType type, List<JavaType> result,
160 boolean addClassItself)
161 {
162 final Class<?> cls = type.getRawClass();
163
164
165 if ((cls == CLS_OBJECT) || (cls == CLS_ENUM)) {
166 return;
167 }
168 if (addClassItself) {
169 if (_contains(result, cls)) {
170 return;
171 }
172 result.add(type);
173 }
174 for (JavaType intCls : type.getInterfaces()) {
175 _addSuperInterfaces(intCls, result, true);
176 }
177 final JavaType superType = type.getSuperClass();
178 if (superType != null) {
179 _addSuperTypes(superType, result, true);
180 }
181 }
182
183 private static void _addSuperInterfaces(JavaType type, List<JavaType> result,
184 boolean addClassItself)
185 {
186 final Class<?> cls = type.getRawClass();
187 if (addClassItself) {
188 if (_contains(result, cls)) {
189 return;
190 }
191 result.add(type);
192
193 if ((cls == CLS_LIST) || (cls == CLS_MAP)) {
194 return;
195 }
196 }
197 for (JavaType intCls : type.getInterfaces()) {
198 _addSuperInterfaces(intCls, result, true);
199 }
200 }
201
202 private static boolean _contains(List<JavaType> found, Class<?> raw) {
203 for (int i = 0, end = found.size(); i < end; ++i) {
204 if (found.get(i).getRawClass() == raw) {
205 return true;
206 }
207 }
208 return false;
209 }
210
211
216
217
222 private Annotations resolveClassAnnotations(List<JavaType> superTypes)
223 {
224
225 if (_intr == null) {
226 return NO_ANNOTATIONS;
227 }
228
229 final boolean checkMixIns = (_mixInResolver != null)
230 && (!(_mixInResolver instanceof SimpleMixInResolver)
231 || ((SimpleMixInResolver) _mixInResolver).hasMixIns());
232
233
234 if (!checkMixIns && !_collectAnnotations) {
235 return NO_ANNOTATIONS;
236 }
237
238 AnnotationCollector resolvedCA = AnnotationCollector.emptyCollector();
239
240 if (_primaryMixin != null) {
241 resolvedCA = _addClassMixIns(resolvedCA, _class, _primaryMixin);
242 }
243
244
245 if (_collectAnnotations) {
246 resolvedCA = _addAnnotationsIfNotPresent(resolvedCA,
247 ClassUtil.findClassAnnotations(_class));
248 }
249
250
251 for (JavaType type : superTypes) {
252
253 if (checkMixIns) {
254 Class<?> cls = type.getRawClass();
255 resolvedCA = _addClassMixIns(resolvedCA, cls,
256 _mixInResolver.findMixInClassFor(cls));
257 }
258 if (_collectAnnotations) {
259 resolvedCA = _addAnnotationsIfNotPresent(resolvedCA,
260 ClassUtil.findClassAnnotations(type.getRawClass()));
261 }
262 }
263
264
265
266
267
268
269 if (checkMixIns) {
270 resolvedCA = _addClassMixIns(resolvedCA, Object.class,
271 _mixInResolver.findMixInClassFor(Object.class));
272 }
273 return resolvedCA.asAnnotations();
274 }
275
276 private AnnotationCollector _addClassMixIns(AnnotationCollector annotations,
277 Class<?> target, Class<?> mixin)
278 {
279 if (mixin != null) {
280
281 annotations = _addAnnotationsIfNotPresent(annotations, ClassUtil.findClassAnnotations(mixin));
282
283
284
285
286
287
288 for (Class<?> parent : ClassUtil.findSuperClasses(mixin, target, false)) {
289 annotations = _addAnnotationsIfNotPresent(annotations, ClassUtil.findClassAnnotations(parent));
290 }
291 }
292 return annotations;
293 }
294
295 private AnnotationCollector _addAnnotationsIfNotPresent(AnnotationCollector c,
296 Annotation[] anns)
297 {
298 if (anns != null) {
299 for (Annotation ann : anns) {
300
301 if (!c.isPresent(ann)) {
302 c = c.addOrOverride(ann);
303 if (_intr.isAnnotationBundle(ann)) {
304 c = _addFromBundleIfNotPresent(c, ann);
305 }
306 }
307 }
308 }
309 return c;
310 }
311
312 private AnnotationCollector _addFromBundleIfNotPresent(AnnotationCollector c,
313 Annotation bundle)
314 {
315 for (Annotation ann : ClassUtil.findClassAnnotations(bundle.annotationType())) {
316
317 if ((ann instanceof Target) || (ann instanceof Retention)) {
318 continue;
319 }
320 if (!c.isPresent(ann)) {
321 c = c.addOrOverride(ann);
322 if (_intr.isAnnotationBundle(ann)) {
323 c = _addFromBundleIfNotPresent(c, ann);
324 }
325 }
326 }
327 return c;
328 }
329 }
330