1 package com.fasterxml.jackson.databind.introspect;
2
3 import java.lang.reflect.Modifier;
4 import java.util.*;
5
6 import com.fasterxml.jackson.annotation.JacksonInject;
7 import com.fasterxml.jackson.annotation.JsonCreator;
8 import com.fasterxml.jackson.annotation.JsonProperty;
9
10 import com.fasterxml.jackson.databind.*;
11
12 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
13 import com.fasterxml.jackson.databind.cfg.MapperConfig;
14 import com.fasterxml.jackson.databind.util.BeanUtil;
15 import com.fasterxml.jackson.databind.util.ClassUtil;
16
17 /**
18  * Helper class used for aggregating information about all possible
19  * properties of a POJO.
20  */

21 public class POJOPropertiesCollector
22 {
23     /*
24     /**********************************************************
25     /* Configuration
26     /**********************************************************
27      */

28
29     /**
30      * Configuration settings
31      */

32     protected final MapperConfig<?> _config;
33
34     /**
35      * True if introspection is done for serialization (giving
36      * precedence for serialization annotations), or not (false, deserialization)
37      */

38     protected final boolean _forSerialization;
39
40     /**
41      * @since 2.5
42      */

43     protected final boolean _stdBeanNaming;
44
45     /**
46      * Type of POJO for which properties are being collected.
47      */

48     protected final JavaType _type;
49
50     /**
51      * Low-level introspected class information (methods, fields etc)
52      */

53     protected final AnnotatedClass _classDef;
54
55     protected final VisibilityChecker<?> _visibilityChecker;
56
57     protected final AnnotationIntrospector _annotationIntrospector;
58
59     /**
60      * @since 2.9
61      */

62     protected final boolean _useAnnotations;
63
64     /**
65      * Prefix used by auto-detected mutators ("setters"): usually "set",
66      * but differs for builder objects ("with" by default).
67      */

68     protected final String _mutatorPrefix;
69     
70     /*
71     /**********************************************************
72     /* Collected property information
73     /**********************************************************
74      */

75
76     /**
77      * State flag we keep to indicate whether actual property information
78      * has been collected or not.
79      */

80     protected boolean _collected;
81     
82     /**
83      * Set of logical property information collected so far.
84      *<p>
85      * Since 2.6, this has been constructed (more) lazily, to defer
86      * throwing of exceptions for potential conflicts in cases where
87      * this may not be an actual problem.
88      */

89     protected LinkedHashMap<String, POJOPropertyBuilder> _properties;
90
91     protected LinkedList<POJOPropertyBuilder> _creatorProperties;
92
93     /**
94      * A set of "field renamings" that have been discovered, indicating
95      * intended renaming of other accesors: key is the implicit original
96      * name and value intended name to use instead.
97      *<p>
98      * Note that these renamings are applied earlier than "regular" (explicit)
99      * renamings and affect implicit name: their effect may be changed by
100      * further renaming based on explicit indicators.
101      * The main use case is to effectively relink accessors based on fields
102      * discovered, and used to sort of correct otherwise missing linkage between
103      * fields and other accessors.
104      *
105      * @since 2.11
106      */

107     protected Map<PropertyName, PropertyName> _fieldRenameMappings;
108     
109     protected LinkedList<AnnotatedMember> _anyGetters;
110
111     protected LinkedList<AnnotatedMethod> _anySetters;
112     
113     protected LinkedList<AnnotatedMember> _anySetterField;
114
115     /**
116      * Method(s) marked with 'JsonValue' annotation
117      *<p>
118      * NOTE: before 2.9, was `AnnotatedMethod`; with 2.9 allows fields too
119      */

120     protected LinkedList<AnnotatedMember> _jsonValueAccessors;
121
122     /**
123      * Lazily collected list of properties that can be implicitly
124      * ignored during serialization; only updated when collecting
125      * information for deserialization purposes
126      */

127     protected HashSet<String> _ignoredPropertyNames;
128
129     /**
130      * Lazily collected list of members that were annotated to
131      * indicate that they represent mutators for deserializer
132      * value injection.
133      */

134     protected LinkedHashMap<Object, AnnotatedMember> _injectables;
135     
136     /*
137     /**********************************************************
138     /* Life-cycle
139     /**********************************************************
140      */

141
142     protected POJOPropertiesCollector(MapperConfig<?> config, boolean forSerialization,
143             JavaType type, AnnotatedClass classDef, String mutatorPrefix)
144     {
145         _config = config;
146         _stdBeanNaming = config.isEnabled(MapperFeature.USE_STD_BEAN_NAMING);
147         _forSerialization = forSerialization;
148         _type = type;
149         _classDef = classDef;
150         _mutatorPrefix = (mutatorPrefix == null) ? "set" : mutatorPrefix;
151         if (config.isAnnotationProcessingEnabled()) {
152             _useAnnotations = true;
153             _annotationIntrospector = _config.getAnnotationIntrospector();
154         } else {
155             _useAnnotations = false;
156             _annotationIntrospector = AnnotationIntrospector.nopInstance();
157         }
158         _visibilityChecker = _config.getDefaultVisibilityChecker(type.getRawClass(),
159                 classDef);
160     }
161
162     /*
163     /**********************************************************
164     /* Public API
165     /**********************************************************
166      */

167
168     public MapperConfig<?> getConfig() {
169         return _config;
170     }
171
172     public JavaType getType() {
173         return _type;
174     }
175     
176     public AnnotatedClass getClassDef() {
177         return _classDef;
178     }
179
180     public AnnotationIntrospector getAnnotationIntrospector() {
181         return _annotationIntrospector;
182     }
183     
184     public List<BeanPropertyDefinition> getProperties() {
185         // make sure we return a copy, so caller can remove entries if need be:
186         Map<String, POJOPropertyBuilder> props = getPropertyMap();
187         return new ArrayList<BeanPropertyDefinition>(props.values());
188     }
189
190     public Map<Object, AnnotatedMember> getInjectables() {
191         if (!_collected) {
192             collectAll();
193         }
194         return _injectables;
195     }
196
197     /**
198      * @since 2.9
199      */

200     public AnnotatedMember getJsonValueAccessor()
201     {
202         if (!_collected) {
203             collectAll();
204         }
205         // If @JsonValue defined, must have a single one
206         if (_jsonValueAccessors != null) {
207             if (_jsonValueAccessors.size() > 1) {
208                 reportProblem("Multiple 'as-value' properties defined (%s vs %s)",
209                         _jsonValueAccessors.get(0),
210                         _jsonValueAccessors.get(1));
211             }
212             // otherwise we won't greatly care
213             return _jsonValueAccessors.get(0);
214         }
215         return null;
216     }
217
218     public AnnotatedMember getAnyGetter()
219     {
220         if (!_collected) {
221             collectAll();
222         }
223         if (_anyGetters != null) {
224             if (_anyGetters.size() > 1) {
225                 reportProblem("Multiple 'any-getters' defined (%s vs %s)",
226                         _anyGetters.get(0), _anyGetters.get(1));
227             }
228             return _anyGetters.getFirst();
229         }        
230         return null;
231     }
232
233     public AnnotatedMember getAnySetterField()
234     {
235         if (!_collected) {
236             collectAll();
237         }
238         if (_anySetterField != null) {
239             if (_anySetterField.size() > 1) {
240                 reportProblem("Multiple 'any-setter' fields defined (%s vs %s)",
241                         _anySetterField.get(0), _anySetterField.get(1));
242             }
243             return _anySetterField.getFirst();
244         }
245         return null;
246     }
247
248     public AnnotatedMethod getAnySetterMethod()
249     {
250         if (!_collected) {
251             collectAll();
252         }
253         if (_anySetters != null) {
254             if (_anySetters.size() > 1) {
255                 reportProblem("Multiple 'any-setter' methods defined (%s vs %s)",
256                         _anySetters.get(0), _anySetters.get(1));
257             }
258             return _anySetters.getFirst();
259         }
260         return null;
261     }
262
263     /**
264      * Accessor for set of properties that are explicitly marked to be ignored
265      * via per-property markers (but NOT class annotations).
266      */

267     public Set<String> getIgnoredPropertyNames() {
268         return _ignoredPropertyNames;
269     }
270
271     /**
272      * Accessor to find out whether type specified requires inclusion
273      * of Object Identifier.
274      */

275     public ObjectIdInfo getObjectIdInfo()
276     {
277         ObjectIdInfo info = _annotationIntrospector.findObjectIdInfo(_classDef);
278         if (info != null) { // 2.1: may also have different defaults for refs:
279             info = _annotationIntrospector.findObjectReferenceInfo(_classDef, info);
280         }
281         return info;
282     }
283
284     // for unit tests:
285     protected Map<String, POJOPropertyBuilder> getPropertyMap() {
286         if (!_collected) {
287             collectAll();
288         }
289         return _properties;
290     }
291
292     @Deprecated // since 2.9
293     public AnnotatedMethod getJsonValueMethod() {
294         AnnotatedMember m = getJsonValueAccessor();
295         if (m instanceof AnnotatedMethod) {
296             return (AnnotatedMethod) m;
297         }
298         return null;
299     }
300
301     @Deprecated // since 2.11 (not used by anything at this point)
302     public Class<?> findPOJOBuilderClass() {
303         return _annotationIntrospector.findPOJOBuilder(_classDef);
304     }
305
306     /*
307     /**********************************************************
308     /* Public API: main-level collection
309     /**********************************************************
310      */

311
312     /**
313      * Internal method that will collect actual property information.
314      *
315      * @since 2.6
316      */

317     protected void collectAll()
318     {
319         LinkedHashMap<String, POJOPropertyBuilder> props = new LinkedHashMap<String, POJOPropertyBuilder>();
320
321         // First: gather basic data
322         _addFields(props); // note: populates _fieldRenameMappings
323         _addMethods(props);
324         // 25-Jan-2016, tatu: Avoid introspecting (constructor-)creators for non-static
325         //    inner classes, see [databind#1502]
326         if (!_classDef.isNonStaticInnerClass()) {
327             _addCreators(props);
328         }
329
330         // Remove ignored properties, first; this MUST precede annotation merging
331         // since logic relies on knowing exactly which accessor has which annotation
332         _removeUnwantedProperties(props);
333         // and then remove unneeded accessors (wrt read-only, read-write)
334         _removeUnwantedAccessor(props);
335
336         // Rename remaining properties
337         _renameProperties(props);
338
339         // and now add injectables, but taking care to avoid overlapping ones
340         // via creator and regular properties
341         _addInjectables(props);
342
343         // then merge annotations, to simplify further processing
344         // 26-Sep-2017, tatu: Before 2.9.2 was done earlier but that prevented some of
345         //   annotations from getting properly merged
346         for (POJOPropertyBuilder property : props.values()) {
347             property.mergeAnnotations(_forSerialization);
348         }
349
350         // And use custom naming strategy, if applicable...
351         PropertyNamingStrategy naming = _findNamingStrategy();
352         if (naming != null) {
353             _renameUsing(props, naming);
354         }
355
356         // Sort by visibility (explicit over implicit); drop all but first of member
357         // type (getter, setter etc) if there is visibility difference
358         for (POJOPropertyBuilder property : props.values()) {
359             property.trimByVisibility();
360         }
361
362         // and, if required, apply wrapper name: note, MUST be done after
363         // annotations are merged.
364         if (_config.isEnabled(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME)) {
365             _renameWithWrappers(props);
366         }
367
368         // well, almost last: there's still ordering...
369         _sortProperties(props);
370         _properties = props;
371         _collected = true;
372     }
373
374     /*
375     /**********************************************************
376     /* Overridable internal methods, adding members
377     /**********************************************************
378      */

379     
380     /**
381      * Method for collecting basic information on all fields found
382      */

383     protected void _addFields(Map<String, POJOPropertyBuilder> props)
384     {
385         final AnnotationIntrospector ai = _annotationIntrospector;
386         /* 28-Mar-2013, tatu: For deserialization we may also want to remove
387          *   final fields, as often they won't make very good mutators...
388          *   (although, maybe surprisingly, JVM _can_ force setting of such fields!)
389          */

390         final boolean pruneFinalFields = !_forSerialization && !_config.isEnabled(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS);
391         final boolean transientAsIgnoral = _config.isEnabled(MapperFeature.PROPAGATE_TRANSIENT_MARKER);
392
393         for (AnnotatedField f : _classDef.fields()) {
394             // @JsonValue?
395             if (Boolean.TRUE.equals(ai.hasAsValue(f))) {
396                 if (_jsonValueAccessors == null) {
397                     _jsonValueAccessors = new LinkedList<>();
398                 }
399                 _jsonValueAccessors.add(f);
400                 continue;
401             }
402             // @JsonAnySetter?
403             if (Boolean.TRUE.equals(ai.hasAnySetter(f))) {
404                 if (_anySetterField == null) {
405                     _anySetterField = new LinkedList<AnnotatedMember>();
406                 }
407                 _anySetterField.add(f);
408                 continue;
409             }
410             String implName = ai.findImplicitPropertyName(f);
411             if (implName == null) {
412                 implName = f.getName();
413             }
414             final PropertyName implNameP = _propNameFromSimple(implName);
415
416             // [databind#2527: Field-based renaming can be applied early (here),
417             // or at a later point, but probably must be done before pruning
418             // final fields. So let's do it early here
419             final PropertyName rename = ai.findRenameByField(_config, f, implNameP);
420             if ((rename != null) && !rename.equals(implNameP)) {
421                 if (_fieldRenameMappings == null) {
422                     _fieldRenameMappings = new HashMap<>();
423                 }
424                 _fieldRenameMappings.put(rename, implNameP);
425                 // todo
426             }
427
428             PropertyName pn;
429
430             if (_forSerialization) {
431                 // 18-Aug-2011, tatu: As per existing unit tests, we should only
432                 //   use serialization annotation (@JsonSerialize) when serializing
433                 //   fields, and similarly for deserialize-only annotations... so
434                 //   no fallbacks in this particular case.
435                 pn = ai.findNameForSerialization(f);
436             } else {
437                 pn = ai.findNameForDeserialization(f);
438             }
439             boolean hasName = (pn != null);
440             boolean nameExplicit = hasName;
441
442             if (nameExplicit && pn.isEmpty()) { // empty String meaning "use default name", here just means "same as field name"
443                 pn = _propNameFromSimple(implName);
444                 nameExplicit = false;
445             }
446             // having explicit name means that field is visible; otherwise need to check the rules
447             boolean visible = (pn != null);
448             if (!visible) {
449                 visible = _visibilityChecker.isFieldVisible(f);
450             }
451             // and finally, may also have explicit ignoral
452             boolean ignored = ai.hasIgnoreMarker(f);
453
454             // 13-May-2015, tatu: Moved from earlier place (AnnotatedClass) in 2.6
455             if (f.isTransient()) {
456                 // 20-May-2016, tatu: as per [databind#1184] explicit annotation should override
457                 //    "default" `transient`
458                 if (!hasName) {
459                     visible = false;
460                     if (transientAsIgnoral) {
461                         ignored = true;
462                     }
463                 }
464             }
465             /* [databind#190]: this is the place to prune final fields, if they are not
466              *  to be used as mutators. Must verify they are not explicitly included.
467              *  Also: if 'ignored' is set, need to include until a later point, to
468              *  avoid losing ignoral information.
469              */

470             if (pruneFinalFields && (pn == null) && !ignored
471                     && Modifier.isFinal(f.getModifiers())) {
472                 continue;
473             }
474             _property(props, implName).addField(f, pn, nameExplicit, visible, ignored);
475         }
476     }
477
478     /**
479      * Method for collecting basic information on constructor(s) found
480      */

481     protected void _addCreators(Map<String, POJOPropertyBuilder> props)
482     {
483         // can be null if annotation processing is disabled...
484         if (!_useAnnotations) {
485             return;
486         }
487         for (AnnotatedConstructor ctor : _classDef.getConstructors()) {
488             if (_creatorProperties == null) {
489                 _creatorProperties = new LinkedList<POJOPropertyBuilder>();
490             }
491             for (int i = 0, len = ctor.getParameterCount(); i < len; ++i) {
492                 _addCreatorParam(props, ctor.getParameter(i));
493             }
494         }
495         for (AnnotatedMethod factory : _classDef.getFactoryMethods()) {
496             if (_creatorProperties == null) {
497                 _creatorProperties = new LinkedList<POJOPropertyBuilder>();
498             }
499             for (int i = 0, len = factory.getParameterCount(); i < len; ++i) {
500                 _addCreatorParam(props, factory.getParameter(i));
501             }
502         }
503     }
504
505     /**
506      * @since 2.4
507      */

508     protected void _addCreatorParam(Map<String, POJOPropertyBuilder> props,
509             AnnotatedParameter param)
510     {
511         // JDK 8, paranamer, Scala can give implicit name
512         String impl = _annotationIntrospector.findImplicitPropertyName(param);
513         if (impl == null) {
514             impl = "";
515         }
516         PropertyName pn = _annotationIntrospector.findNameForDeserialization(param);
517         boolean expl = (pn != null && !pn.isEmpty());
518         if (!expl) {
519             if (impl.isEmpty()) {
520                 // Important: if neither implicit nor explicit name, cannot make use of
521                 // this creator parameter -- may or may not be a problem, verified at a later point.
522                 return;
523             }
524             // Also: if this occurs, there MUST be explicit annotation on creator itself
525             JsonCreator.Mode creatorMode = _annotationIntrospector.findCreatorAnnotation(_config,
526                     param.getOwner());
527             if ((creatorMode == null) || (creatorMode == JsonCreator.Mode.DISABLED)) {
528                 return;
529             }
530             pn = PropertyName.construct(impl);
531         }
532
533         // 27-Dec-2019, tatu: [databind#2527] may need to rename according to field
534         impl = _checkRenameByField(impl);
535
536         // shouldn't need to worry about @JsonIgnore, since creators only added
537         // if so annotated
538         
539         /* 13-May-2015, tatu: We should try to start with implicit name, similar to how
540          *   fields and methods work; but unlike those, we don't necessarily have
541          *   implicit name to use (pre-Java8 at least). So:
542          */

543         POJOPropertyBuilder prop = (expl && impl.isEmpty())
544                 ? _property(props, pn) : _property(props, impl);
545         prop.addCtor(param, pn, expl, truefalse);
546         _creatorProperties.add(prop);
547     }
548
549     /**
550      * Method for collecting basic information on all fields found
551      */

552     protected void _addMethods(Map<String, POJOPropertyBuilder> props)
553     {
554         final AnnotationIntrospector ai = _annotationIntrospector;
555         for (AnnotatedMethod m : _classDef.memberMethods()) {
556             // For methods, handling differs between getters and setters; and
557             // we will also only consider entries that either follow the bean
558             // naming convention or are explicitly marked: just being visible
559             // is not enough (unlike with fields)
560
561             int argCount = m.getParameterCount();
562             if (argCount == 0) { // getters (including 'any getter')
563                 _addGetterMethod(props, m, ai);
564             } else if (argCount == 1) { // setters
565                 _addSetterMethod(props, m, ai);
566             } else if (argCount == 2) { // any getter?
567                 if (ai != null) {
568                     if (Boolean.TRUE.equals(ai.hasAnySetter(m))) {
569                         if (_anySetters == null) {
570                             _anySetters = new LinkedList<AnnotatedMethod>();
571                         }
572                         _anySetters.add(m);
573                     }
574                 }
575             }
576         }
577     }
578
579     protected void _addGetterMethod(Map<String, POJOPropertyBuilder> props,
580             AnnotatedMethod m, AnnotationIntrospector ai)
581     {
582         // Very first thing: skip if not returning any value
583         if (!m.hasReturnType()) {
584             return;
585         }
586         
587         // any getter?
588         // @JsonAnyGetter?
589         if (Boolean.TRUE.equals(ai.hasAnyGetter(m))) {
590             if (_anyGetters == null) {
591                 _anyGetters = new LinkedList<AnnotatedMember>();
592             }
593             _anyGetters.add(m);
594             return;
595         }
596         // @JsonValue?
597         if (Boolean.TRUE.equals(ai.hasAsValue(m))) {
598             if (_jsonValueAccessors == null) {
599                 _jsonValueAccessors = new LinkedList<>();
600             }
601             _jsonValueAccessors.add(m);
602             return;
603         }
604         String implName; // from naming convention
605         boolean visible;
606
607         PropertyName pn = ai.findNameForSerialization(m);
608         boolean nameExplicit = (pn != null);
609
610         if (!nameExplicit) { // no explicit name; must consider implicit
611             implName = ai.findImplicitPropertyName(m);
612             if (implName == null) {
613                 implName = BeanUtil.okNameForRegularGetter(m, m.getName(), _stdBeanNaming);
614             }
615             if (implName == null) { // if not, must skip
616                 implName = BeanUtil.okNameForIsGetter(m, m.getName(), _stdBeanNaming);
617                 if (implName == null) {
618                     return;
619                 }
620                 visible = _visibilityChecker.isIsGetterVisible(m);
621             } else {
622                 visible = _visibilityChecker.isGetterVisible(m);
623             }
624         } else { // explicit indication of inclusion, but may be empty
625             // we still need implicit name to link with other pieces
626             implName = ai.findImplicitPropertyName(m);
627             if (implName == null) {
628                 implName = BeanUtil.okNameForGetter(m, _stdBeanNaming);
629             }
630             // if not regular getter name, use method name as is
631             if (implName == null) {
632                 implName = m.getName();
633             }
634             if (pn.isEmpty()) {
635                 // !!! TODO: use PropertyName for implicit names too
636                 pn = _propNameFromSimple(implName);
637                 nameExplicit = false;
638             }
639             visible = true;
640         }
641         // 27-Dec-2019, tatu: [databind#2527] may need to rename according to field
642         implName = _checkRenameByField(implName);
643         boolean ignore = ai.hasIgnoreMarker(m);
644         _property(props, implName).addGetter(m, pn, nameExplicit, visible, ignore);
645     }
646
647     protected void _addSetterMethod(Map<String, POJOPropertyBuilder> props,
648             AnnotatedMethod m, AnnotationIntrospector ai)
649     {
650         String implName; // from naming convention
651         boolean visible;
652         PropertyName pn = (ai == null) ? null : ai.findNameForDeserialization(m);
653         boolean nameExplicit = (pn != null);
654         if (!nameExplicit) { // no explicit name; must follow naming convention
655             implName = (ai == null) ? null : ai.findImplicitPropertyName(m);
656             if (implName == null) {
657                 implName = BeanUtil.okNameForMutator(m, _mutatorPrefix, _stdBeanNaming);
658             }
659             if (implName == null) { // if not, must skip
660                 return;
661             }
662             visible = _visibilityChecker.isSetterVisible(m);
663         } else { // explicit indication of inclusion, but may be empty
664             // we still need implicit name to link with other pieces
665             implName = (ai == null) ? null : ai.findImplicitPropertyName(m);
666             if (implName == null) {
667                 implName = BeanUtil.okNameForMutator(m, _mutatorPrefix, _stdBeanNaming);
668             }
669             // if not regular getter name, use method name as is
670             if (implName == null) {
671                 implName = m.getName();
672             }
673             if (pn.isEmpty()) {
674                 // !!! TODO: use PropertyName for implicit names too
675                 pn = _propNameFromSimple(implName);
676                 nameExplicit = false;
677             }
678             visible = true;
679         }
680         // 27-Dec-2019, tatu: [databind#2527] may need to rename according to field
681         implName = _checkRenameByField(implName);
682         boolean ignore = (ai == null) ? false : ai.hasIgnoreMarker(m);
683         _property(props, implName).addSetter(m, pn, nameExplicit, visible, ignore);
684     }
685
686     protected void _addInjectables(Map<String, POJOPropertyBuilder> props)
687     {
688         final AnnotationIntrospector ai = _annotationIntrospector;
689         // first fields, then methods, to allow overriding
690         for (AnnotatedField f : _classDef.fields()) {
691             _doAddInjectable(ai.findInjectableValue(f), f);
692         }
693         
694         for (AnnotatedMethod m : _classDef.memberMethods()) {
695             // for now, only allow injection of a single arg (to be changed in future?)
696             if (m.getParameterCount() != 1) {
697                 continue;
698             }
699             _doAddInjectable(ai.findInjectableValue(m), m);
700         }
701     }
702
703     protected void _doAddInjectable(JacksonInject.Value injectable, AnnotatedMember m)
704     {
705         if (injectable == null) {
706             return;
707         }
708         Object id = injectable.getId();
709         if (_injectables == null) {
710             _injectables = new LinkedHashMap<Object, AnnotatedMember>();
711         }
712         AnnotatedMember prev = _injectables.put(id, m);
713         if (prev != null) {
714             // 12-Apr-2017, tatu: Let's allow masking of Field by Method
715             if (prev.getClass() == m.getClass()) {
716                 String type = id.getClass().getName();
717                 throw new IllegalArgumentException("Duplicate injectable value with id '"
718                         +String.valueOf(id)+"' (of type "+type+")");
719             }
720         }
721     }
722
723     private PropertyName _propNameFromSimple(String simpleName) {
724         return PropertyName.construct(simpleName, null);
725     }
726
727     // @since 2.11
728     private String _checkRenameByField(String implName) {
729         if (_fieldRenameMappings != null) {
730             PropertyName p = _fieldRenameMappings.get(_propNameFromSimple(implName));
731             if (p != null) {
732                 implName = p.getSimpleName();
733                 return implName;
734
735             }
736         }
737         return implName;
738     }
739
740     /*
741     /**********************************************************
742     /* Internal methods; removing ignored properties
743     /**********************************************************
744      */

745
746     /**
747      * Method called to get rid of candidate properties that are marked
748      * as ignored.
749      */

750     protected void _removeUnwantedProperties(Map<String, POJOPropertyBuilder> props)
751     {
752         Iterator<POJOPropertyBuilder> it = props.values().iterator();
753         while (it.hasNext()) {
754             POJOPropertyBuilder prop = it.next();
755
756             // First: if nothing visible, just remove altogether
757             if (!prop.anyVisible()) {
758                 it.remove();
759                 continue;
760             }
761             // Otherwise, check ignorals
762             if (prop.anyIgnorals()) {
763                 // first: if one or more ignorals, and no explicit markers, remove the whole thing
764                 if (!prop.isExplicitlyIncluded()) {
765                     it.remove();
766                     _collectIgnorals(prop.getName());
767                     continue;
768                 }
769                 // otherwise just remove ones marked to be ignored
770                 prop.removeIgnored();
771                 if (!prop.couldDeserialize()) {
772                     _collectIgnorals(prop.getName());
773                 }
774             }
775         }
776     }
777
778     /**
779      * Method called to further get rid of unwanted individual accessors,
780      * based on read/write settings and rules for "pulling in" accessors
781      * (or not).
782      */

783     protected void _removeUnwantedAccessor(Map<String, POJOPropertyBuilder> props)
784     {
785         final boolean inferMutators = _config.isEnabled(MapperFeature.INFER_PROPERTY_MUTATORS);
786         Iterator<POJOPropertyBuilder> it = props.values().iterator();
787
788         while (it.hasNext()) {
789             POJOPropertyBuilder prop = it.next();
790             // 26-Jan-2017, tatu: [databind#935]: need to denote removal of
791             JsonProperty.Access acc = prop.removeNonVisible(inferMutators);
792             if (acc == JsonProperty.Access.READ_ONLY) {
793                 _collectIgnorals(prop.getName());
794             }
795         }
796     }
797
798     /**
799      * Helper method called to add explicitly ignored properties to a list
800      * of known ignored properties; this helps in proper reporting of
801      * errors.
802      */

803     private void _collectIgnorals(String name)
804     {
805         if (!_forSerialization) {
806             if (_ignoredPropertyNames == null) {
807                 _ignoredPropertyNames = new HashSet<String>();
808             }
809             _ignoredPropertyNames.add(name);
810         }
811     }
812
813     /*
814     /**********************************************************
815     /* Internal methods; renaming properties
816     /**********************************************************
817      */

818
819     protected void _renameProperties(Map<String, POJOPropertyBuilder> props)
820     {
821         // With renaming need to do in phases: first, find properties to rename
822         Iterator<Map.Entry<String,POJOPropertyBuilder>> it = props.entrySet().iterator();
823         LinkedList<POJOPropertyBuilder> renamed = null;
824         while (it.hasNext()) {
825             Map.Entry<String, POJOPropertyBuilder> entry = it.next();
826             POJOPropertyBuilder prop = entry.getValue();
827
828             Collection<PropertyName> l = prop.findExplicitNames();
829
830             // no explicit names? Implicit one is fine as is
831             if (l.isEmpty()) {
832                 continue;
833             }
834             it.remove(); // need to replace with one or more renamed
835             if (renamed == null) {
836                 renamed = new LinkedList<POJOPropertyBuilder>();
837             }
838             // simple renaming? Just do it
839             if (l.size() == 1) {
840                 PropertyName n = l.iterator().next();
841                 renamed.add(prop.withName(n));
842                 continue;
843             }
844             // but this may be problematic...
845             renamed.addAll(prop.explode(l));
846
847             /*
848             String newName = prop.findNewName();
849             if (newName != null) {
850                 if (renamed == null) {
851                     renamed = new LinkedList<POJOPropertyBuilder>();
852                 }
853                 prop = prop.withSimpleName(newName);
854                 renamed.add(prop);
855                 it.remove();
856             }
857             */

858         }
859         
860         // and if any were renamed, merge back in...
861         if (renamed != null) {
862             for (POJOPropertyBuilder prop : renamed) {
863                 String name = prop.getName();
864                 POJOPropertyBuilder old = props.get(name);
865                 if (old == null) {
866                     props.put(name, prop);
867                 } else {
868                     old.addAll(prop);
869                 }
870                 // replace the creatorProperty too, if there is one
871                 _updateCreatorProperty(prop, _creatorProperties);
872                 // [databind#2001]: New name of property was ignored previously? Remove from ignored
873                 // 01-May-2018, tatu: I have a feeling this will need to be revisited at some point,
874                 //   to avoid removing some types of removals, possibly. But will do for now.
875                 if (_ignoredPropertyNames != null) {
876                     _ignoredPropertyNames.remove(name);
877                 }
878             }
879         }
880     }
881
882     protected void _renameUsing(Map<String, POJOPropertyBuilder> propMap,
883             PropertyNamingStrategy naming)
884     {
885         POJOPropertyBuilder[] props = propMap.values().toArray(new POJOPropertyBuilder[propMap.size()]);
886         propMap.clear();
887         for (POJOPropertyBuilder prop : props) {
888             PropertyName fullName = prop.getFullName();
889             String rename = null;
890             // As per [databind#428] need to skip renaming if property has
891             // explicitly defined name, unless feature  is enabled
892             if (!prop.isExplicitlyNamed() || _config.isEnabled(MapperFeature.ALLOW_EXPLICIT_PROPERTY_RENAMING)) {
893                 if (_forSerialization) {
894                     if (prop.hasGetter()) {
895                         rename = naming.nameForGetterMethod(_config, prop.getGetter(), fullName.getSimpleName());
896                     } else if (prop.hasField()) {
897                         rename = naming.nameForField(_config, prop.getField(), fullName.getSimpleName());
898                     }
899                 } else {
900                     if (prop.hasSetter()) {
901                         rename = naming.nameForSetterMethod(_config, prop.getSetter(), fullName.getSimpleName());
902                     } else if (prop.hasConstructorParameter()) {
903                         rename = naming.nameForConstructorParameter(_config, prop.getConstructorParameter(), fullName.getSimpleName());
904                     } else if (prop.hasField()) {
905                         rename = naming.nameForField(_config, prop.getField(), fullName.getSimpleName());
906                     } else if (prop.hasGetter()) {
907                         /* Plus, when getter-as-setter is used, need to convert that too..
908                          * (should we verify that's enabled? For now, assume it's ok always)
909                          */

910                         rename = naming.nameForGetterMethod(_config, prop.getGetter(), fullName.getSimpleName());
911                     }
912                 }
913             }
914             final String simpleName;
915             if ((rename != null) && !fullName.hasSimpleName(rename)) {
916                 prop = prop.withSimpleName(rename);
917                 simpleName = rename;
918             } else {
919                 simpleName = fullName.getSimpleName();
920             }
921             // Need to consider case where there may already be something in there...
922             POJOPropertyBuilder old = propMap.get(simpleName);
923             if (old == null) {
924                 propMap.put(simpleName, prop);
925             } else {
926                 old.addAll(prop);
927             }
928
929             // replace the creatorProperty too, if there is one
930             _updateCreatorProperty(prop, _creatorProperties);
931         }
932     }
933
934     protected void _renameWithWrappers(Map<String, POJOPropertyBuilder> props)
935     {
936         // 11-Sep-2012, tatu: To support 'MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME',
937         //   need another round of renaming...
938         Iterator<Map.Entry<String,POJOPropertyBuilder>> it = props.entrySet().iterator();
939         LinkedList<POJOPropertyBuilder> renamed = null;
940         while (it.hasNext()) {
941             Map.Entry<String, POJOPropertyBuilder> entry = it.next();
942             POJOPropertyBuilder prop = entry.getValue();
943             AnnotatedMember member = prop.getPrimaryMember();
944             if (member == null) {
945                 continue;
946             }
947             PropertyName wrapperName = _annotationIntrospector.findWrapperName(member);
948             // One trickier part (wrt [#24] of JAXB annotations: wrapper that
949             // indicates use of actual property... But hopefully has been taken care
950             // of previously
951             if (wrapperName == null || !wrapperName.hasSimpleName()) {
952                 continue;
953             }
954             if (!wrapperName.equals(prop.getFullName())) {
955                 if (renamed == null) {
956                     renamed = new LinkedList<POJOPropertyBuilder>();
957                 }
958                 prop = prop.withName(wrapperName);
959                 renamed.add(prop);
960                 it.remove();
961             }
962         }
963         // and if any were renamed, merge back in...
964         if (renamed != null) {
965             for (POJOPropertyBuilder prop : renamed) {
966                 String name = prop.getName();
967                 POJOPropertyBuilder old = props.get(name);
968                 if (old == null) {
969                     props.put(name, prop);
970                 } else {
971                     old.addAll(prop);
972                 }
973             }
974         }
975     }
976
977     /*
978     /**********************************************************
979     /* Overridable internal methods, sorting, other stuff
980     /**********************************************************
981      */

982     
983     // First, order by(explicit ordering and/or alphabetic),
984     // then by (optional) index (if any)
985     // and then implicitly order creator properties before others)
986
987     protected void _sortProperties(Map<String, POJOPropertyBuilder> props)
988     {
989         // Then how about explicit ordering?
990         final AnnotationIntrospector intr = _annotationIntrospector;
991         Boolean alpha = intr.findSerializationSortAlphabetically((Annotated) _classDef);
992         final boolean sort = (alpha == null)
993                 ? _config.shouldSortPropertiesAlphabetically()
994                 : alpha.booleanValue();
995         final boolean indexed = _anyIndexed(props.values());
996
997         String[] propertyOrder = intr.findSerializationPropertyOrder(_classDef);
998         
999         // no sorting? no need to shuffle, then
1000         if (!sort && !indexed && (_creatorProperties == null) && (propertyOrder == null)) {
1001             return;
1002         }
1003         int size = props.size();
1004         Map<String, POJOPropertyBuilder> all;
1005         // Need to (re)sort alphabetically?
1006         if (sort) {
1007             all = new TreeMap<String,POJOPropertyBuilder>();
1008         } else {
1009             all = new LinkedHashMap<String,POJOPropertyBuilder>(size+size);
1010         }
1011
1012         for (POJOPropertyBuilder prop : props.values()) {
1013             all.put(prop.getName(), prop);
1014         }
1015         Map<String,POJOPropertyBuilder> ordered = new LinkedHashMap<>(size+size);
1016         // Ok: primarily by explicit order
1017         if (propertyOrder != null) {
1018             for (String name : propertyOrder) {
1019                 POJOPropertyBuilder w = all.remove(name);
1020                 if (w == null) { // will also allow use of "implicit" names for sorting
1021                     for (POJOPropertyBuilder prop : props.values()) {
1022                         if (name.equals(prop.getInternalName())) {
1023                             w = prop;
1024                             // plus re-map to external name, to avoid dups:
1025                             name = prop.getName();
1026                             break;
1027                         }
1028                     }
1029                 }
1030                 if (w != null) {
1031                     ordered.put(name, w);
1032                 }
1033             }
1034         }
1035
1036         // Second (starting with 2.11): index, if any:
1037         if (indexed) {
1038             Map<Integer,POJOPropertyBuilder> byIndex = new TreeMap<>();
1039             Iterator<Map.Entry<String,POJOPropertyBuilder>> it = all.entrySet().iterator();
1040             while (it.hasNext()) {
1041                 Map.Entry<String,POJOPropertyBuilder> entry = it.next();
1042                 POJOPropertyBuilder prop = entry.getValue();
1043                 Integer index = prop.getMetadata().getIndex();
1044                 if (index != null) {
1045                     byIndex.put(index, prop);
1046                     it.remove();
1047                 }
1048             }
1049             for (POJOPropertyBuilder prop : byIndex.values()) {
1050                 ordered.put(prop.getName(), prop);
1051             }
1052         }
1053
1054         // Third by sorting Creator properties before other unordered properties
1055         if (_creatorProperties != null) {
1056             /* As per [databind#311], this is bit delicate; but if alphabetic ordering
1057              * is mandated, at least ensure creator properties are in alphabetic
1058              * order. Related question of creator vs non-creator is punted for now,
1059              * so creator properties still fully predate non-creator ones.
1060              */

1061             Collection<POJOPropertyBuilder> cr;
1062             if (sort) {
1063                 TreeMap<String, POJOPropertyBuilder> sorted =
1064                         new TreeMap<String,POJOPropertyBuilder>();
1065                 for (POJOPropertyBuilder prop : _creatorProperties) {
1066                     sorted.put(prop.getName(), prop);
1067                 }
1068                 cr = sorted.values();
1069             } else {
1070                 cr = _creatorProperties;
1071             }
1072             for (POJOPropertyBuilder prop : cr) {
1073                 // 16-Jan-2016, tatu: Related to [databind#1317], make sure not to accidentally
1074                 //    add back pruned creator properties!
1075                 String name = prop.getName();
1076                 // 27-Nov-2019, tatu: Not sure why, but we should NOT remove it from `all` tho:
1077 //                if (all.remove(name) != null) {
1078                 if (all.containsKey(name)) {
1079                     ordered.put(name, prop);
1080                 }
1081             }
1082         }
1083         // And finally whatever is left (trying to put again will not change ordering)
1084         ordered.putAll(all);
1085         props.clear();
1086         props.putAll(ordered);
1087     }
1088
1089     private boolean _anyIndexed(Collection<POJOPropertyBuilder> props) {
1090         for (POJOPropertyBuilder prop : props) {
1091             if (prop.getMetadata().hasIndex()) {
1092                 return true;
1093             }
1094         }
1095         return false;
1096     }
1097
1098     /*
1099     /**********************************************************
1100     /* Internal methods; helpers
1101     /**********************************************************
1102      */

1103
1104     protected void reportProblem(String msg, Object... args) {
1105         if (args.length > 0) {
1106             msg = String.format(msg, args);
1107         }
1108         throw new IllegalArgumentException("Problem with definition of "+_classDef+": "+msg);
1109     }
1110
1111     protected POJOPropertyBuilder _property(Map<String, POJOPropertyBuilder> props,
1112             PropertyName name) {
1113         String simpleName = name.getSimpleName();
1114         POJOPropertyBuilder prop = props.get(simpleName);
1115         if (prop == null) {
1116             prop = new POJOPropertyBuilder(_config, _annotationIntrospector,
1117                     _forSerialization, name);
1118             props.put(simpleName, prop);
1119         }
1120         return prop;
1121     }
1122     
1123     // !!! TODO: deprecate, require use of PropertyName
1124     protected POJOPropertyBuilder _property(Map<String, POJOPropertyBuilder> props,
1125             String implName)
1126     {
1127         POJOPropertyBuilder prop = props.get(implName);
1128         if (prop == null) {
1129             prop = new POJOPropertyBuilder(_config, _annotationIntrospector, _forSerialization,
1130                     PropertyName.construct(implName));
1131             props.put(implName, prop);
1132         }
1133         return prop;
1134     }
1135
1136     private PropertyNamingStrategy _findNamingStrategy()
1137     {
1138         Object namingDef = _annotationIntrospector.findNamingStrategy(_classDef);
1139         if (namingDef == null) {
1140             return _config.getPropertyNamingStrategy();
1141         }
1142         if (namingDef instanceof PropertyNamingStrategy) {
1143             return (PropertyNamingStrategy) namingDef;
1144         }
1145         /* Alas, there's no way to force return type of "either class
1146          * X or Y" -- need to throw an exception after the fact
1147          */

1148         if (!(namingDef instanceof Class)) {
1149             throw new IllegalStateException("AnnotationIntrospector returned PropertyNamingStrategy definition of type "
1150                     +namingDef.getClass().getName()+"; expected type PropertyNamingStrategy or Class<PropertyNamingStrategy> instead");
1151         }
1152         Class<?> namingClass = (Class<?>)namingDef;
1153         // 09-Nov-2015, tatu: Need to consider pseudo-value of STD, which means "use default"
1154         if (namingClass == PropertyNamingStrategy.class) {
1155             return null;
1156         }
1157         
1158         if (!PropertyNamingStrategy.class.isAssignableFrom(namingClass)) {
1159             throw new IllegalStateException("AnnotationIntrospector returned Class "
1160                     +namingClass.getName()+"; expected Class<PropertyNamingStrategy>");
1161         }
1162         HandlerInstantiator hi = _config.getHandlerInstantiator();
1163         if (hi != null) {
1164             PropertyNamingStrategy pns = hi.namingStrategyInstance(_config, _classDef, namingClass);
1165             if (pns != null) {
1166                 return pns;
1167             }
1168         }
1169         return (PropertyNamingStrategy) ClassUtil.createInstance(namingClass,
1170                     _config.canOverrideAccessModifiers());
1171     }
1172
1173     protected void _updateCreatorProperty(POJOPropertyBuilder prop, List<POJOPropertyBuilder> creatorProperties) {
1174
1175         if (creatorProperties != null) {
1176             final String intName = prop.getInternalName();
1177             for (int i = 0, len = creatorProperties.size(); i < len; ++i) {
1178                 if (creatorProperties.get(i).getInternalName().equals(intName)) {
1179                     creatorProperties.set(i, prop);
1180                     break;
1181                 }
1182             }
1183         }
1184     }
1185 }
1186