1 package com.fasterxml.jackson.databind.introspect;
2
3 import java.lang.annotation.Annotation;
4 import java.lang.reflect.AnnotatedElement;
5 import java.lang.reflect.Constructor;
6 import java.lang.reflect.Method;
7 import java.lang.reflect.Modifier;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.List;
11
12 import com.fasterxml.jackson.databind.AnnotationIntrospector;
13 import com.fasterxml.jackson.databind.JavaType;
14 import com.fasterxml.jackson.databind.introspect.AnnotatedClass.Creators;
15 import com.fasterxml.jackson.databind.type.TypeFactory;
16 import com.fasterxml.jackson.databind.util.ClassUtil;
17
18
24 final class AnnotatedCreatorCollector
25 extends CollectorBase
26 {
27
28
29 private final TypeResolutionContext _typeContext;
30
31
32 private final TypeFactory _typeFactory;
33
34
37 private final boolean _collectAnnotations;
38
39
40
41 private AnnotatedConstructor _defaultConstructor;
42
43 AnnotatedCreatorCollector(AnnotationIntrospector intr, TypeFactory tf,
44 TypeResolutionContext tc, boolean collectAnnotations)
45 {
46 super(intr);
47 _typeFactory = tf;
48 _typeContext = tc;
49 _collectAnnotations = collectAnnotations;
50 }
51
52 @Deprecated
53 public static Creators collectCreators(AnnotationIntrospector intr,
54 TypeResolutionContext tc,
55 JavaType type, Class<?> primaryMixIn, boolean collectAnnotations)
56 {
57 return collectCreators(intr, TypeFactory.defaultInstance(),
58 tc, type, primaryMixIn, collectAnnotations);
59 }
60
61
64 public static Creators collectCreators(AnnotationIntrospector intr,
65 TypeFactory typeFactory, TypeResolutionContext tc,
66 JavaType type, Class<?> primaryMixIn, boolean collectAnnotations)
67 {
68
69
70 collectAnnotations |= (primaryMixIn != null);
71
72
73 return new AnnotatedCreatorCollector(intr, typeFactory, tc, collectAnnotations)
74 .collect(type, primaryMixIn);
75 }
76
77 Creators collect(JavaType type, Class<?> primaryMixIn)
78 {
79
80
81
82
83 List<AnnotatedConstructor> constructors = _findPotentialConstructors(type, primaryMixIn);
84 List<AnnotatedMethod> factories = _findPotentialFactories(type, primaryMixIn);
85
86
89
90 if (_collectAnnotations) {
91 if (_defaultConstructor != null) {
92 if (_intr.hasIgnoreMarker(_defaultConstructor)) {
93 _defaultConstructor = null;
94 }
95 }
96
97 for (int i = constructors.size(); --i >= 0; ) {
98 if (_intr.hasIgnoreMarker(constructors.get(i))) {
99 constructors.remove(i);
100 }
101 }
102 for (int i = factories.size(); --i >= 0; ) {
103 if (_intr.hasIgnoreMarker(factories.get(i))) {
104 factories.remove(i);
105 }
106 }
107 }
108 return new AnnotatedClass.Creators(_defaultConstructor, constructors, factories);
109 }
110
111
116 private List<AnnotatedConstructor> _findPotentialConstructors(JavaType type,
117 Class<?> primaryMixIn)
118 {
119 ClassUtil.Ctor defaultCtor = null;
120 List<ClassUtil.Ctor> ctors = null;
121
122
123
124
125
126
127 if (!type.isEnumType()) {
128 ClassUtil.Ctor[] declaredCtors = ClassUtil.getConstructors(type.getRawClass());
129 for (ClassUtil.Ctor ctor : declaredCtors) {
130 if (!isIncludableConstructor(ctor.getConstructor())) {
131 continue;
132 }
133 if (ctor.getParamCount() == 0) {
134 defaultCtor = ctor;
135 } else {
136 if (ctors == null) {
137 ctors = new ArrayList<>();
138 }
139 ctors.add(ctor);
140 }
141 }
142 }
143 List<AnnotatedConstructor> result;
144 int ctorCount;
145 if (ctors == null) {
146 result = Collections.emptyList();
147
148 if (defaultCtor == null) {
149 return result;
150 }
151 ctorCount = 0;
152 } else {
153 ctorCount = ctors.size();
154 result = new ArrayList<>(ctorCount);
155 for (int i = 0; i < ctorCount; ++i) {
156 result.add(null);
157 }
158 }
159
160
161 if (primaryMixIn != null) {
162 MemberKey[] ctorKeys = null;
163 for (ClassUtil.Ctor mixinCtor : ClassUtil.getConstructors(primaryMixIn)) {
164 if (mixinCtor.getParamCount() == 0) {
165 if (defaultCtor != null) {
166 _defaultConstructor = constructDefaultConstructor(defaultCtor, mixinCtor);
167 defaultCtor = null;
168 }
169 continue;
170 }
171 if (ctors != null) {
172 if (ctorKeys == null) {
173 ctorKeys = new MemberKey[ctorCount];
174 for (int i = 0; i < ctorCount; ++i) {
175 ctorKeys[i] = new MemberKey(ctors.get(i).getConstructor());
176 }
177 }
178 MemberKey key = new MemberKey(mixinCtor.getConstructor());
179
180 for (int i = 0; i < ctorCount; ++i) {
181 if (key.equals(ctorKeys[i])) {
182 result.set(i,
183 constructNonDefaultConstructor(ctors.get(i), mixinCtor));
184 break;
185 }
186 }
187 }
188 }
189 }
190
191 if (defaultCtor != null) {
192 _defaultConstructor = constructDefaultConstructor(defaultCtor, null);
193 }
194 for (int i = 0; i < ctorCount; ++i) {
195 AnnotatedConstructor ctor = result.get(i);
196 if (ctor == null) {
197 result.set(i,
198 constructNonDefaultConstructor(ctors.get(i), null));
199 }
200 }
201 return result;
202 }
203
204 private List<AnnotatedMethod> _findPotentialFactories(JavaType type, Class<?> primaryMixIn)
205 {
206 List<Method> candidates = null;
207
208
209 for (Method m : ClassUtil.getClassMethods(type.getRawClass())) {
210 if (!Modifier.isStatic(m.getModifiers())) {
211 continue;
212 }
213
214
215 if (candidates == null) {
216 candidates = new ArrayList<>();
217 }
218 candidates.add(m);
219 }
220
221 if (candidates == null) {
222 return Collections.emptyList();
223 }
224
225
226
227
228
229 TypeResolutionContext typeResCtxt = new TypeResolutionContext.Empty(_typeFactory);
230
231 int factoryCount = candidates.size();
232 List<AnnotatedMethod> result = new ArrayList<>(factoryCount);
233 for (int i = 0; i < factoryCount; ++i) {
234 result.add(null);
235 }
236
237 if (primaryMixIn != null) {
238 MemberKey[] methodKeys = null;
239 for (Method mixinFactory : primaryMixIn.getDeclaredMethods()) {
240 if (!Modifier.isStatic(mixinFactory.getModifiers())) {
241 continue;
242 }
243 if (methodKeys == null) {
244 methodKeys = new MemberKey[factoryCount];
245 for (int i = 0; i < factoryCount; ++i) {
246 methodKeys[i] = new MemberKey(candidates.get(i));
247 }
248 }
249 MemberKey key = new MemberKey(mixinFactory);
250 for (int i = 0; i < factoryCount; ++i) {
251 if (key.equals(methodKeys[i])) {
252 result.set(i,
253 constructFactoryCreator(candidates.get(i),
254 typeResCtxt, mixinFactory));
255 break;
256 }
257 }
258 }
259 }
260
261 for (int i = 0; i < factoryCount; ++i) {
262 AnnotatedMethod factory = result.get(i);
263 if (factory == null) {
264 result.set(i,
265 constructFactoryCreator(candidates.get(i),
266 typeResCtxt, null));
267 }
268 }
269 return result;
270 }
271
272 protected AnnotatedConstructor constructDefaultConstructor(ClassUtil.Ctor ctor,
273 ClassUtil.Ctor mixin)
274 {
275 return new AnnotatedConstructor(_typeContext, ctor.getConstructor(),
276 collectAnnotations(ctor, mixin),
277
278 NO_ANNOTATION_MAPS);
279 }
280
281 protected AnnotatedConstructor constructNonDefaultConstructor(ClassUtil.Ctor ctor,
282 ClassUtil.Ctor mixin)
283 {
284 final int paramCount = ctor.getParamCount();
285 if (_intr == null) {
286 return new AnnotatedConstructor(_typeContext, ctor.getConstructor(),
287 _emptyAnnotationMap(), _emptyAnnotationMaps(paramCount));
288 }
289
290
294 if (paramCount == 0) {
295 return new AnnotatedConstructor(_typeContext, ctor.getConstructor(),
296 collectAnnotations(ctor, mixin),
297 NO_ANNOTATION_MAPS);
298 }
299
300 AnnotationMap[] resolvedAnnotations;
301 Annotation[][] paramAnns = ctor.getParameterAnnotations();
302 if (paramCount != paramAnns.length) {
303
304
305
306 resolvedAnnotations = null;
307 Class<?> dc = ctor.getDeclaringClass();
308
309 if (ClassUtil.isEnumType(dc) && (paramCount == paramAnns.length + 2)) {
310 Annotation[][] old = paramAnns;
311 paramAnns = new Annotation[old.length+2][];
312 System.arraycopy(old, 0, paramAnns, 2, old.length);
313 resolvedAnnotations = collectAnnotations(paramAnns, null);
314 } else if (dc.isMemberClass()) {
315
316 if (paramCount == (paramAnns.length + 1)) {
317
318 Annotation[][] old = paramAnns;
319 paramAnns = new Annotation[old.length+1][];
320 System.arraycopy(old, 0, paramAnns, 1, old.length);
321 paramAnns[0] = NO_ANNOTATIONS;
322 resolvedAnnotations = collectAnnotations(paramAnns, null);
323 }
324 }
325 if (resolvedAnnotations == null) {
326 throw new IllegalStateException(String.format(
327 "Internal error: constructor for %s has mismatch: %d parameters; %d sets of annotations",
328 ctor.getDeclaringClass().getName(), paramCount, paramAnns.length));
329 }
330 } else {
331 resolvedAnnotations = collectAnnotations(paramAnns,
332 (mixin == null) ? null : mixin.getParameterAnnotations());
333 }
334 return new AnnotatedConstructor(_typeContext, ctor.getConstructor(),
335 collectAnnotations(ctor, mixin), resolvedAnnotations);
336 }
337
338 protected AnnotatedMethod constructFactoryCreator(Method m,
339 TypeResolutionContext typeResCtxt, Method mixin)
340 {
341 final int paramCount = m.getParameterTypes().length;
342 if (_intr == null) {
343 return new AnnotatedMethod(typeResCtxt, m, _emptyAnnotationMap(),
344 _emptyAnnotationMaps(paramCount));
345 }
346 if (paramCount == 0) {
347 return new AnnotatedMethod(typeResCtxt, m, collectAnnotations(m, mixin),
348 NO_ANNOTATION_MAPS);
349 }
350 return new AnnotatedMethod(typeResCtxt, m, collectAnnotations(m, mixin),
351 collectAnnotations(m.getParameterAnnotations(),
352 (mixin == null) ? null : mixin.getParameterAnnotations()));
353 }
354
355 private AnnotationMap[] collectAnnotations(Annotation[][] mainAnns, Annotation[][] mixinAnns) {
356 if (_collectAnnotations) {
357 final int count = mainAnns.length;
358 AnnotationMap[] result = new AnnotationMap[count];
359 for (int i = 0; i < count; ++i) {
360 AnnotationCollector c = collectAnnotations(AnnotationCollector.emptyCollector(),
361 mainAnns[i]);
362 if (mixinAnns != null) {
363 c = collectAnnotations(c, mixinAnns[i]);
364 }
365 result[i] = c.asAnnotationMap();
366 }
367 return result;
368 }
369 return NO_ANNOTATION_MAPS;
370 }
371
372
373
374 private AnnotationMap collectAnnotations(ClassUtil.Ctor main, ClassUtil.Ctor mixin) {
375 if (_collectAnnotations) {
376 AnnotationCollector c = collectAnnotations(main.getDeclaredAnnotations());
377 if (mixin != null) {
378 c = collectAnnotations(c, mixin.getDeclaredAnnotations());
379 }
380 return c.asAnnotationMap();
381 }
382 return _emptyAnnotationMap();
383 }
384
385 private final AnnotationMap collectAnnotations(AnnotatedElement main, AnnotatedElement mixin) {
386 AnnotationCollector c = collectAnnotations(main.getDeclaredAnnotations());
387 if (mixin != null) {
388 c = collectAnnotations(c, mixin.getDeclaredAnnotations());
389 }
390 return c.asAnnotationMap();
391 }
392
393
394 private static boolean isIncludableConstructor(Constructor<?> c) {
395 return !c.isSynthetic();
396 }
397 }
398