1 package com.fasterxml.jackson.databind.introspect;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Method;
5 import java.util.*;
6
7 import com.fasterxml.jackson.annotation.JsonCreator;
8 import com.fasterxml.jackson.annotation.JsonFormat;
9 import com.fasterxml.jackson.annotation.JsonInclude;
10
11 import com.fasterxml.jackson.databind.*;
12 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
13 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
14 import com.fasterxml.jackson.databind.cfg.MapperConfig;
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 import com.fasterxml.jackson.databind.util.Converter;
19
20
28 public class BasicBeanDescription extends BeanDescription
29 {
30
31 private final static Class<?>[] NO_VIEWS = new Class<?>[0];
32
33
38
39
44 final protected POJOPropertiesCollector _propCollector;
45
46 final protected MapperConfig<?> _config;
47
48 final protected AnnotationIntrospector _annotationIntrospector;
49
50
55
56
59 final protected AnnotatedClass _classInfo;
60
61
64 protected Class<?>[] _defaultViews;
65
66
69 protected boolean _defaultViewsResolved;
70
71
76
77
80 protected List<BeanPropertyDefinition> _properties;
81
82
85 protected ObjectIdInfo _objectIdInfo;
86
87
92
93 protected BasicBeanDescription(POJOPropertiesCollector coll,
94 JavaType type, AnnotatedClass classDef)
95 {
96 super(type);
97 _propCollector = coll;
98 _config = coll.getConfig();
99
100 if (_config == null) {
101 _annotationIntrospector = null;
102 } else {
103 _annotationIntrospector = _config.getAnnotationIntrospector();
104 }
105 _classInfo = classDef;
106 }
107
108
112 protected BasicBeanDescription(MapperConfig<?> config,
113 JavaType type, AnnotatedClass classDef, List<BeanPropertyDefinition> props)
114 {
115 super(type);
116 _propCollector = null;
117 _config = config;
118
119 if (_config == null) {
120 _annotationIntrospector = null;
121 } else {
122 _annotationIntrospector = _config.getAnnotationIntrospector();
123 }
124 _classInfo = classDef;
125 _properties = props;
126 }
127
128 protected BasicBeanDescription(POJOPropertiesCollector coll)
129 {
130 this(coll, coll.getType(), coll.getClassDef());
131 _objectIdInfo = coll.getObjectIdInfo();
132 }
133
134
138 public static BasicBeanDescription forDeserialization(POJOPropertiesCollector coll) {
139 return new BasicBeanDescription(coll);
140 }
141
142
146 public static BasicBeanDescription forSerialization(POJOPropertiesCollector coll) {
147 return new BasicBeanDescription(coll);
148 }
149
150
155 public static BasicBeanDescription forOtherUse(MapperConfig<?> config,
156 JavaType type, AnnotatedClass ac)
157 {
158 return new BasicBeanDescription(config, type,
159 ac, Collections.<BeanPropertyDefinition>emptyList());
160 }
161
162 protected List<BeanPropertyDefinition> _properties() {
163 if (_properties == null) {
164 _properties = _propCollector.getProperties();
165 }
166 return _properties;
167 }
168
169
174
175
182 public boolean removeProperty(String propName)
183 {
184 Iterator<BeanPropertyDefinition> it = _properties().iterator();
185 while (it.hasNext()) {
186 BeanPropertyDefinition prop = it.next();
187 if (prop.getName().equals(propName)) {
188 it.remove();
189 return true;
190 }
191 }
192 return false;
193 }
194
195 public boolean addProperty(BeanPropertyDefinition def)
196 {
197
198 if (hasProperty(def.getFullName())) {
199 return false;
200 }
201 _properties().add(def);
202 return true;
203 }
204
205
208 public boolean hasProperty(PropertyName name) {
209 return findProperty(name) != null;
210 }
211
212
215 public BeanPropertyDefinition findProperty(PropertyName name)
216 {
217 for (BeanPropertyDefinition prop : _properties()) {
218 if (prop.hasName(name)) {
219 return prop;
220 }
221 }
222 return null;
223 }
224
225
230
231 @Override
232 public AnnotatedClass getClassInfo() { return _classInfo; }
233
234 @Override
235 public ObjectIdInfo getObjectIdInfo() { return _objectIdInfo; }
236
237 @Override
238 public List<BeanPropertyDefinition> findProperties() {
239 return _properties();
240 }
241
242 @Override
243 @Deprecated
244 public AnnotatedMethod findJsonValueMethod() {
245 return (_propCollector == null) ? null
246 : _propCollector.getJsonValueMethod();
247 }
248
249 @Override
250 public AnnotatedMember findJsonValueAccessor() {
251 return (_propCollector == null) ? null
252 : _propCollector.getJsonValueAccessor();
253 }
254
255 @Override
256 public Set<String> getIgnoredPropertyNames() {
257 Set<String> ign = (_propCollector == null) ? null
258 : _propCollector.getIgnoredPropertyNames();
259 if (ign == null) {
260 return Collections.emptySet();
261 }
262 return ign;
263 }
264
265 @Override
266 public boolean hasKnownClassAnnotations() {
267 return _classInfo.hasAnnotations();
268 }
269
270 @Override
271 public Annotations getClassAnnotations() {
272 return _classInfo.getAnnotations();
273 }
274
275 @Override
276 @Deprecated
277 public TypeBindings bindingsForBeanType() {
278 return _type.getBindings();
279 }
280
281 @Override
282 @Deprecated
283 public JavaType resolveType(java.lang.reflect.Type jdkType) {
284 if (jdkType == null) {
285 return null;
286 }
287 return _config.getTypeFactory().constructType(jdkType, _type.getBindings());
288 }
289
290 @Override
291 public AnnotatedConstructor findDefaultConstructor() {
292 return _classInfo.getDefaultConstructor();
293 }
294
295 @Override
296 public AnnotatedMember findAnySetterAccessor() throws IllegalArgumentException
297 {
298 if (_propCollector != null) {
299 AnnotatedMethod anyMethod = _propCollector.getAnySetterMethod();
300 if (anyMethod != null) {
301
302
303
304
307 Class<?> type = anyMethod.getRawParameterType(0);
308 if ((type != String.class) && (type != Object.class)) {
309 throw new IllegalArgumentException(String.format(
310 "Invalid 'any-setter' annotation on method '%s()': first argument not of type String or Object, but %s",
311 anyMethod.getName(), type.getName()));
312 }
313 return anyMethod;
314 }
315 AnnotatedMember anyField = _propCollector.getAnySetterField();
316 if (anyField != null) {
317
318
319 Class<?> type = anyField.getRawType();
320 if (!Map.class.isAssignableFrom(type)) {
321 throw new IllegalArgumentException(String.format(
322 "Invalid 'any-setter' annotation on field '%s': type is not instance of java.util.Map",
323 anyField.getName()));
324 }
325 return anyField;
326 }
327 }
328 return null;
329 }
330
331 @Override
332 public Map<Object, AnnotatedMember> findInjectables() {
333 if (_propCollector != null) {
334 return _propCollector.getInjectables();
335 }
336 return Collections.emptyMap();
337 }
338
339 @Override
340 public List<AnnotatedConstructor> getConstructors() {
341 return _classInfo.getConstructors();
342 }
343
344 @Override
345 public Object instantiateBean(boolean fixAccess) {
346 AnnotatedConstructor ac = _classInfo.getDefaultConstructor();
347 if (ac == null) {
348 return null;
349 }
350 if (fixAccess) {
351 ac.fixAccess(_config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
352 }
353 try {
354 return ac.getAnnotated().newInstance();
355 } catch (Exception e) {
356 Throwable t = e;
357 while (t.getCause() != null) {
358 t = t.getCause();
359 }
360 ClassUtil.throwIfError(t);
361 ClassUtil.throwIfRTE(t);
362 throw new IllegalArgumentException("Failed to instantiate bean of type "
363 +_classInfo.getAnnotated().getName()+": ("+t.getClass().getName()+") "
364 +ClassUtil.exceptionMessage(t), t);
365 }
366 }
367
368
373
374 @Override
375 public AnnotatedMethod findMethod(String name, Class<?>[] paramTypes) {
376 return _classInfo.findMethod(name, paramTypes);
377 }
378
379
384
385 @Override
386 public JsonFormat.Value findExpectedFormat(JsonFormat.Value defValue)
387 {
388
389
390 if (_annotationIntrospector != null) {
391 JsonFormat.Value v = _annotationIntrospector.findFormat(_classInfo);
392 if (v != null) {
393 if (defValue == null) {
394 defValue = v;
395 } else {
396 defValue = defValue.withOverrides(v);
397 }
398 }
399 }
400 JsonFormat.Value v = _config.getDefaultPropertyFormat(_classInfo.getRawType());
401 if (v != null) {
402 if (defValue == null) {
403 defValue = v;
404 } else {
405 defValue = defValue.withOverrides(v);
406 }
407 }
408 return defValue;
409 }
410
411 @Override
412 public Class<?>[] findDefaultViews()
413 {
414 if (!_defaultViewsResolved) {
415 _defaultViewsResolved = true;
416 Class<?>[] def = (_annotationIntrospector == null) ? null
417 : _annotationIntrospector.findViews(_classInfo);
418
419 if (def == null) {
420 if (!_config.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
421 def = NO_VIEWS;
422 }
423 }
424 _defaultViews = def;
425 }
426 return _defaultViews;
427 }
428
429
434
435 @Override
436 public Converter<Object,Object> findSerializationConverter()
437 {
438 if (_annotationIntrospector == null) {
439 return null;
440 }
441 return _createConverter(_annotationIntrospector.findSerializationConverter(_classInfo));
442 }
443
444
450 @Override
451 public JsonInclude.Value findPropertyInclusion(JsonInclude.Value defValue) {
452 if (_annotationIntrospector != null) {
453 JsonInclude.Value incl = _annotationIntrospector.findPropertyInclusion(_classInfo);
454 if (incl != null) {
455 return (defValue == null) ? incl : defValue.withOverrides(incl);
456 }
457 }
458 return defValue;
459 }
460
461
467 @Override
468 public AnnotatedMember findAnyGetter() throws IllegalArgumentException
469 {
470 AnnotatedMember anyGetter = (_propCollector == null) ? null
471 : _propCollector.getAnyGetter();
472 if (anyGetter != null) {
473
476 Class<?> type = anyGetter.getRawType();
477 if (!Map.class.isAssignableFrom(type)) {
478 throw new IllegalArgumentException("Invalid 'any-getter' annotation on method "+anyGetter.getName()+"(): return type is not instance of java.util.Map");
479 }
480 }
481 return anyGetter;
482 }
483
484 @Override
485 public List<BeanPropertyDefinition> findBackReferences()
486 {
487 List<BeanPropertyDefinition> result = null;
488 HashSet<String> names = null;
489 for (BeanPropertyDefinition property : _properties()) {
490 AnnotationIntrospector.ReferenceProperty refDef = property.findReferenceType();
491 if ((refDef == null) || !refDef.isBackReference()) {
492 continue;
493 }
494 final String refName = refDef.getName();
495 if (result == null) {
496 result = new ArrayList<BeanPropertyDefinition>();
497 names = new HashSet<>();
498 names.add(refName);
499 } else {
500 if (!names.add(refName)) {
501 throw new IllegalArgumentException("Multiple back-reference properties with name '"+refName+"'");
502 }
503 }
504 result.add(property);
505 }
506 return result;
507 }
508
509 @Deprecated
510 @Override
511 public Map<String,AnnotatedMember> findBackReferenceProperties()
512 {
513 List<BeanPropertyDefinition> props = findBackReferences();
514 if (props == null) {
515 return null;
516 }
517 Map<String,AnnotatedMember> result = new HashMap<>();
518 for (BeanPropertyDefinition prop : props) {
519 result.put(prop.getName(), prop.getMutator());
520 }
521 return result;
522 }
523
524
529
530 @Override
531 public List<AnnotatedMethod> getFactoryMethods()
532 {
533
534 List<AnnotatedMethod> candidates = _classInfo.getFactoryMethods();
535 if (candidates.isEmpty()) {
536 return candidates;
537 }
538 List<AnnotatedMethod> result = null;
539 for (AnnotatedMethod am : candidates) {
540 if (isFactoryMethod(am)) {
541 if (result == null) {
542 result = new ArrayList<AnnotatedMethod>();
543 }
544 result.add(am);
545 }
546 }
547 if (result == null) {
548 return Collections.emptyList();
549 }
550 return result;
551 }
552
553 @Override
554 public Constructor<?> findSingleArgConstructor(Class<?>... argTypes)
555 {
556 for (AnnotatedConstructor ac : _classInfo.getConstructors()) {
557
558
561 if (ac.getParameterCount() == 1) {
562 Class<?> actArg = ac.getRawParameterType(0);
563 for (Class<?> expArg : argTypes) {
564 if (expArg == actArg) {
565 return ac.getAnnotated();
566 }
567 }
568 }
569 }
570 return null;
571 }
572
573 @Override
574 public Method findFactoryMethod(Class<?>... expArgTypes)
575 {
576
577 for (AnnotatedMethod am : _classInfo.getFactoryMethods()) {
578
579 if (isFactoryMethod(am) && am.getParameterCount() == 1) {
580
581 Class<?> actualArgType = am.getRawParameterType(0);
582 for (Class<?> expArgType : expArgTypes) {
583
584 if (actualArgType.isAssignableFrom(expArgType)) {
585 return am.getAnnotated();
586 }
587 }
588 }
589 }
590 return null;
591 }
592
593 protected boolean isFactoryMethod(AnnotatedMethod am)
594 {
595
596
597 Class<?> rt = am.getRawReturnType();
598 if (!getBeanClass().isAssignableFrom(rt)) {
599 return false;
600 }
601
605 JsonCreator.Mode mode = _annotationIntrospector.findCreatorAnnotation(_config, am);
606 if ((mode != null) && (mode != JsonCreator.Mode.DISABLED)) {
607 return true;
608 }
609 final String name = am.getName();
610
611 if ("valueOf".equals(name)) {
612 if (am.getParameterCount() == 1) {
613 return true;
614 }
615 }
616
617 if ("fromString".equals(name)) {
618 if (am.getParameterCount() == 1) {
619 Class<?> cls = am.getRawParameterType(0);
620 if (cls == String.class || CharSequence.class.isAssignableFrom(cls)) {
621 return true;
622 }
623 }
624 }
625 return false;
626 }
627
628
631 @Deprecated
632 protected PropertyName _findCreatorPropertyName(AnnotatedParameter param)
633 {
634 PropertyName name = _annotationIntrospector.findNameForDeserialization(param);
635 if (name == null || name.isEmpty()) {
636 String str = _annotationIntrospector.findImplicitPropertyName(param);
637 if (str != null && !str.isEmpty()) {
638 name = PropertyName.construct(str);
639 }
640 }
641 return name;
642 }
643
644
649
650 @Override
651 public Class<?> findPOJOBuilder() {
652 return (_annotationIntrospector == null) ?
653 null : _annotationIntrospector.findPOJOBuilder(_classInfo);
654 }
655
656 @Override
657 public JsonPOJOBuilder.Value findPOJOBuilderConfig()
658 {
659 return (_annotationIntrospector == null) ?
660 null : _annotationIntrospector.findPOJOBuilderConfig(_classInfo);
661 }
662
663 @Override
664 public Converter<Object,Object> findDeserializationConverter()
665 {
666 if (_annotationIntrospector == null) {
667 return null;
668 }
669 return _createConverter(_annotationIntrospector.findDeserializationConverter(_classInfo));
670 }
671
672 @Override
673 public String findClassDescription() {
674 return (_annotationIntrospector == null) ?
675 null : _annotationIntrospector.findClassDescription(_classInfo);
676 }
677
678
683
684
696 @Deprecated
697 public LinkedHashMap<String,AnnotatedField> _findPropertyFields(
698 Collection<String> ignoredProperties, boolean forSerialization)
699 {
700 LinkedHashMap<String,AnnotatedField> results = new LinkedHashMap<String,AnnotatedField>();
701 for (BeanPropertyDefinition property : _properties()) {
702 AnnotatedField f = property.getField();
703 if (f != null) {
704 String name = property.getName();
705 if (ignoredProperties != null) {
706 if (ignoredProperties.contains(name)) {
707 continue;
708 }
709 }
710 results.put(name, f);
711 }
712 }
713 return results;
714 }
715
716
721
722 @SuppressWarnings("unchecked")
723 protected Converter<Object,Object> _createConverter(Object converterDef)
724 {
725 if (converterDef == null) {
726 return null;
727 }
728 if (converterDef instanceof Converter<?,?>) {
729 return (Converter<Object,Object>) converterDef;
730 }
731 if (!(converterDef instanceof Class)) {
732 throw new IllegalStateException("AnnotationIntrospector returned Converter definition of type "
733 +converterDef.getClass().getName()+"; expected type Converter or Class<Converter> instead");
734 }
735 Class<?> converterClass = (Class<?>)converterDef;
736
737 if (converterClass == Converter.None.class || ClassUtil.isBogusClass(converterClass)) {
738 return null;
739 }
740 if (!Converter.class.isAssignableFrom(converterClass)) {
741 throw new IllegalStateException("AnnotationIntrospector returned Class "
742 +converterClass.getName()+"; expected Class<Converter>");
743 }
744 HandlerInstantiator hi = _config.getHandlerInstantiator();
745 Converter<?,?> conv = (hi == null) ? null : hi.converterInstance(_config, _classInfo, converterClass);
746 if (conv == null) {
747 conv = (Converter<?,?>) ClassUtil.createInstance(converterClass,
748 _config.canOverrideAccessModifiers());
749 }
750 return (Converter<Object,Object>) conv;
751 }
752 }
753