package com.fasterxml.jackson.databind.introspect; import java.util.*; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.cfg.ConfigOverride; import com.fasterxml.jackson.databind.cfg.MapperConfig; import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.databind.util.ClassUtil; /** * Helper class used for aggregating information about a single * potential POJO property. */ public class POJOPropertyBuilder extends BeanPropertyDefinition implements Comparable<POJOPropertyBuilder> { /** * Marker value used to denote that no reference-property information found for * this property * * @since 2.9 */ private final static AnnotationIntrospector.ReferenceProperty NOT_REFEFERENCE_PROP = AnnotationIntrospector.ReferenceProperty.managed(""); /** * Whether property is being composed for serialization * (true) or deserialization (false) */ protected final boolean _forSerialization; protected final MapperConfig<?> _config; protected final AnnotationIntrospector _annotationIntrospector; /** * External name of logical property; may change with * renaming (by new instance being constructed using * a new name) */ protected final PropertyName _name; /** * Original internal name, derived from accessor, of this * property. Will not be changed by renaming. */ protected final PropertyName _internalName; protected Linked<AnnotatedField> _fields; protected Linked<AnnotatedParameter> _ctorParameters; protected Linked<AnnotatedMethod> _getters; protected Linked<AnnotatedMethod> _setters; protected transient PropertyMetadata _metadata; /** * Lazily accessed information about this property iff it is a forward or * back reference. * * @since 2.9 */ protected transient AnnotationIntrospector.ReferenceProperty _referenceInfo; public POJOPropertyBuilder(MapperConfig<?> config, AnnotationIntrospector ai, boolean forSerialization, PropertyName internalName) { this(config, ai, forSerialization, internalName, internalName); } protected POJOPropertyBuilder(MapperConfig<?> config, AnnotationIntrospector ai, boolean forSerialization, PropertyName internalName, PropertyName name) { _config = config; _annotationIntrospector = ai; _internalName = internalName; _name = name; _forSerialization = forSerialization; } // protected since 2.9 (was public before) protected POJOPropertyBuilder(POJOPropertyBuilder src, PropertyName newName) { _config = src._config; _annotationIntrospector = src._annotationIntrospector; _internalName = src._internalName; _name = newName; _fields = src._fields; _ctorParameters = src._ctorParameters; _getters = src._getters; _setters = src._setters; _forSerialization = src._forSerialization; } /* /********************************************************** /* Mutant factory methods /********************************************************** */ @Override public POJOPropertyBuilder withName(PropertyName newName) { return new POJOPropertyBuilder(this, newName); } @Override public POJOPropertyBuilder withSimpleName(String newSimpleName) { PropertyName newName = _name.withSimpleName(newSimpleName); return (newName == _name) ? this : new POJOPropertyBuilder(this, newName); } /* /********************************************************** /* Comparable implementation: sort alphabetically, except /* that properties with constructor parameters sorted /* before other properties /********************************************************** */ @Override public int compareTo(POJOPropertyBuilder other) { // first, if one has ctor params, that should come first: if (_ctorParameters != null) { if (other._ctorParameters == null) { return -1; } } else if (other._ctorParameters != null) { return 1; } /* otherwise sort by external name (including sorting of * ctor parameters) */ return getName().compareTo(other.getName()); } /* /********************************************************** /* BeanPropertyDefinition implementation, name/type /********************************************************** */ @Override public String getName() { return (_name == null) ? null : _name.getSimpleName(); } @Override public PropertyName getFullName() { return _name; } @Override public boolean hasName(PropertyName name) { return _name.equals(name); } @Override public String getInternalName() { return _internalName.getSimpleName(); } @Override public PropertyName getWrapperName() { /* 13-Mar-2013, tatu: Accessing via primary member SHOULD work, * due to annotation merging. However, I have seen some problems * with this access (for other annotations)... so if this should * occur, try commenting out full traversal code */ AnnotatedMember member = getPrimaryMember(); return (member == null || _annotationIntrospector == null) ? null : _annotationIntrospector.findWrapperName(member); /* return fromMemberAnnotations(new WithMember<PropertyName>() { @Override public PropertyName withMember(AnnotatedMember member) { return _annotationIntrospector.findWrapperName(member); } }); */ } @Override public boolean isExplicitlyIncluded() { return _anyExplicits(_fields) || _anyExplicits(_getters) || _anyExplicits(_setters) // 16-Jan-2016, tatu: Creator names are special, in that name should exist too; // reason for this is [databind#1317]. Let's hope this works well, may need // to tweak further if this lowers visibility // || _anyExplicits(_ctorParameters) || _anyExplicitNames(_ctorParameters) ; } @Override public boolean isExplicitlyNamed() { return _anyExplicitNames(_fields) || _anyExplicitNames(_getters) || _anyExplicitNames(_setters) || _anyExplicitNames(_ctorParameters) ; } /* /********************************************************** /* Simple metadata /********************************************************** */ @Override public PropertyMetadata getMetadata() { if (_metadata == null) { final Boolean b = _findRequired(); final String desc = _findDescription(); final Integer idx = _findIndex(); final String def = _findDefaultValue(); if (b == null && idx == null && def == null) { _metadata = (desc == null) ? PropertyMetadata.STD_REQUIRED_OR_OPTIONAL : PropertyMetadata.STD_REQUIRED_OR_OPTIONAL.withDescription(desc); } else { _metadata = PropertyMetadata.construct(b, desc, idx, def); } if (!_forSerialization) { _metadata = _getSetterInfo(_metadata); } } return _metadata; } /** * Helper method that contains logic for accessing and merging all setter * information that we needed, regarding things like possible merging * of property value, and handling of incoming nulls. */ protected PropertyMetadata _getSetterInfo(PropertyMetadata metadata) { boolean needMerge = true; Nulls valueNulls = null; Nulls contentNulls = null; // Slightly confusing: first, annotations should be accessed via primary member // (mutator); but accessor is needed for actual merge operation. So: AnnotatedMember prim = getPrimaryMember(); AnnotatedMember acc = getAccessor(); if (prim != null) { // Ok, first: does property itself have something to say? if (_annotationIntrospector != null) { if (acc != null) { Boolean b = _annotationIntrospector.findMergeInfo(prim); if (b != null) { needMerge = false; if (b.booleanValue()) { metadata = metadata.withMergeInfo(PropertyMetadata.MergeInfo.createForPropertyOverride(acc)); } } } JsonSetter.Value setterInfo = _annotationIntrospector.findSetterInfo(prim); if (setterInfo != null) { valueNulls = setterInfo.nonDefaultValueNulls(); contentNulls = setterInfo.nonDefaultContentNulls(); } } // If not, config override? // 25-Oct-2016, tatu: Either this, or type of accessor... if (needMerge || (valueNulls == null) || (contentNulls == null)) { Class<?> rawType = getRawPrimaryType(); ConfigOverride co = _config.getConfigOverride(rawType); JsonSetter.Value setterInfo = co.getSetterInfo(); if (setterInfo != null) { if (valueNulls == null) { valueNulls = setterInfo.nonDefaultValueNulls(); } if (contentNulls == null) { contentNulls = setterInfo.nonDefaultContentNulls(); } } if (needMerge && (acc != null)) { Boolean b = co.getMergeable(); if (b != null) { needMerge = false; if (b.booleanValue()) { metadata = metadata.withMergeInfo(PropertyMetadata.MergeInfo.createForTypeOverride(acc)); } } } } } if (needMerge || (valueNulls == null) || (contentNulls == null)) { JsonSetter.Value setterInfo = _config.getDefaultSetterInfo(); if (valueNulls == null) { valueNulls = setterInfo.nonDefaultValueNulls(); } if (contentNulls == null) { contentNulls = setterInfo.nonDefaultContentNulls(); } if (needMerge) { Boolean b = _config.getDefaultMergeable(); if ((acc != null) && (b != null)) { if (b.booleanValue()) { metadata = metadata.withMergeInfo(PropertyMetadata.MergeInfo.createForDefaults(acc)); } } } } if ((valueNulls != null) || (contentNulls != null)) { metadata = metadata.withNulls(valueNulls, contentNulls); } return metadata; } /** * Type determined from the primary member for the property being built, * considering precedence according to whether we are processing serialization * or deserialization. */ @Override public JavaType getPrimaryType() { if (_forSerialization) { AnnotatedMember m = getGetter(); if (m == null) { m = getField(); if (m == null) { // 09-Feb-2017, tatu: Not sure if this or `null` but... return TypeFactory.unknownType(); } return m.getType(); } return m.getType(); } AnnotatedMember m = getConstructorParameter(); if (m == null) { m = getSetter(); // Important: can't try direct type access for setter; what we need is // type of the first parameter if (m != null) { return ((AnnotatedMethod) m).getParameterType(0); } m = getField(); } // for setterless properties, however, can further try getter if (m == null) { m = getGetter(); if (m == null) { return TypeFactory.unknownType(); } } return m.getType(); } @Override public Class<?> getRawPrimaryType() { return getPrimaryType().getRawClass(); } /* /********************************************************** /* BeanPropertyDefinition implementation, accessor access /********************************************************** */ @Override public boolean hasGetter() { return _getters != null; } @Override public boolean hasSetter() { return _setters != null; } @Override public boolean hasField() { return _fields != null; } @Override public boolean hasConstructorParameter() { return _ctorParameters != null; } @Override public boolean couldDeserialize() { return (_ctorParameters != null) || (_setters != null) || (_fields != null); } @Override public boolean couldSerialize() { return (_getters != null) || (_fields != null); } @Override public AnnotatedMethod getGetter() { // Easy with zero or one getters... Linked<AnnotatedMethod> curr = _getters; if (curr == null) { return null; } Linked<AnnotatedMethod> next = curr.next; if (next == null) { return curr.value; } // But if multiple, verify that they do not conflict... for (; next != null; next = next.next) { /* [JACKSON-255] Allow masking, i.e. do not report exception if one * is in super-class from the other */ Class<?> currClass = curr.value.getDeclaringClass(); Class<?> nextClass = next.value.getDeclaringClass(); if (currClass != nextClass) { if (currClass.isAssignableFrom(nextClass)) { // next is more specific curr = next; continue; } if (nextClass.isAssignableFrom(currClass)) { // current more specific continue; } } /* 30-May-2014, tatu: Three levels of precedence: * * 1. Regular getters ("getX") * 2. Is-getters ("isX") * 3. Implicit, possible getters ("x") */ int priNext = _getterPriority(next.value); int priCurr = _getterPriority(curr.value); if (priNext != priCurr) { if (priNext < priCurr) { curr = next; } continue; } throw new IllegalArgumentException("Conflicting getter definitions for property \""+getName()+"\": " +curr.value.getFullName()+" vs "+next.value.getFullName()); } // One more thing; to avoid having to do it again... _getters = curr.withoutNext(); return curr.value; } @Override public AnnotatedMethod getSetter() { // Easy with zero or one getters... Linked<AnnotatedMethod> curr = _setters; if (curr == null) { return null; } Linked<AnnotatedMethod> next = curr.next; if (next == null) { return curr.value; } // But if multiple, verify that they do not conflict... for (; next != null; next = next.next) { // Allow masking, i.e. do not fail if one is in super-class from the other Class<?> currClass = curr.value.getDeclaringClass(); Class<?> nextClass = next.value.getDeclaringClass(); if (currClass != nextClass) { if (currClass.isAssignableFrom(nextClass)) { // next is more specific curr = next; continue; } if (nextClass.isAssignableFrom(currClass)) { // current more specific continue; } } AnnotatedMethod nextM = next.value; AnnotatedMethod currM = curr.value; /* 30-May-2014, tatu: Two levels of precedence: * * 1. Regular setters ("setX(...)") * 2. Implicit, possible setters ("x(...)") */ int priNext = _setterPriority(nextM); int priCurr = _setterPriority(currM); if (priNext != priCurr) { if (priNext < priCurr) { curr = next; } continue; } // 11-Dec-2015, tatu: As per [databind#1033] allow pluggable conflict resolution if (_annotationIntrospector != null) { AnnotatedMethod pref = _annotationIntrospector.resolveSetterConflict(_config, currM, nextM); // note: should be one of nextM/currM; but no need to check if (pref == currM) { continue; } if (pref == nextM) { curr = next; continue; } } throw new IllegalArgumentException(String.format( "Conflicting setter definitions for property \"%s\": %s vs %s", getName(), curr.value.getFullName(), next.value.getFullName())); } // One more thing; to avoid having to do it again... _setters = curr.withoutNext(); return curr.value; } @Override public AnnotatedField getField() { if (_fields == null) { return null; } // If multiple, verify that they do not conflict... AnnotatedField field = _fields.value; Linked<AnnotatedField> next = _fields.next; for (; next != null; next = next.next) { AnnotatedField nextField = next.value; Class<?> fieldClass = field.getDeclaringClass(); Class<?> nextClass = nextField.getDeclaringClass(); if (fieldClass != nextClass) { if (fieldClass.isAssignableFrom(nextClass)) { // next is more specific field = nextField; continue; } if (nextClass.isAssignableFrom(fieldClass)) { // getter more specific continue; } } throw new IllegalArgumentException("Multiple fields representing property \""+getName()+"\": " +field.getFullName()+" vs "+nextField.getFullName()); } return field; } @Override public AnnotatedParameter getConstructorParameter() { if (_ctorParameters == null) { return null; } /* Hmmh. Checking for constructor parameters is trickier; for one, * we must allow creator and factory method annotations. * If this is the case, constructor parameter has the precedence. * * So, for now, just try finding the first constructor parameter; * if none, first factory method. And don't check for dups, if we must, * can start checking for them later on. */ Linked<AnnotatedParameter> curr = _ctorParameters; do { if (curr.value.getOwner() instanceof AnnotatedConstructor) { return curr.value; } curr = curr.next; } while (curr != null); return _ctorParameters.value; } @Override public Iterator<AnnotatedParameter> getConstructorParameters() { if (_ctorParameters == null) { return ClassUtil.emptyIterator(); } return new MemberIterator<AnnotatedParameter>(_ctorParameters); } @Override public AnnotatedMember getPrimaryMember() { if (_forSerialization) { return getAccessor(); } AnnotatedMember m = getMutator(); // for setterless properties, however... if (m == null) { m = getAccessor(); } return m; } protected int _getterPriority(AnnotatedMethod m) { final String name = m.getName(); // [databind#238]: Also, regular getters have precedence over "is-getters" if (name.startsWith("get") && name.length() > 3) { // should we check capitalization? return 1; } if (name.startsWith("is") && name.length() > 2) { return 2; } return 3; } protected int _setterPriority(AnnotatedMethod m) { final String name = m.getName(); if (name.startsWith("set") && name.length() > 3) { // should we check capitalization? return 1; } return 2; } /* /********************************************************** /* Implementations of refinement accessors /********************************************************** */ @Override public Class<?>[] findViews() { return fromMemberAnnotations(new WithMember<Class<?>[]>() { @Override public Class<?>[] withMember(AnnotatedMember member) { return _annotationIntrospector.findViews(member); } }); } @Override public AnnotationIntrospector.ReferenceProperty findReferenceType() { // 30-Mar-2017, tatu: Access lazily but retain information since it needs // to be accessed multiple times during processing. AnnotationIntrospector.ReferenceProperty result = _referenceInfo; if (result != null) { if (result == NOT_REFEFERENCE_PROP) { return null; } return result; } result = fromMemberAnnotations(new WithMember<AnnotationIntrospector.ReferenceProperty>() { @Override public AnnotationIntrospector.ReferenceProperty withMember(AnnotatedMember member) { return _annotationIntrospector.findReferenceType(member); } }); _referenceInfo = (result == null) ? NOT_REFEFERENCE_PROP : result; return result; } @Override public boolean isTypeId() { Boolean b = fromMemberAnnotations(new WithMember<Boolean>() { @Override public Boolean withMember(AnnotatedMember member) { return _annotationIntrospector.isTypeId(member); } }); return (b != null) && b.booleanValue(); } protected Boolean _findRequired() { return fromMemberAnnotations(new WithMember<Boolean>() { @Override public Boolean withMember(AnnotatedMember member) { return _annotationIntrospector.hasRequiredMarker(member); } }); } protected String _findDescription() { return fromMemberAnnotations(new WithMember<String>() { @Override public String withMember(AnnotatedMember member) { return _annotationIntrospector.findPropertyDescription(member); } }); } protected Integer _findIndex() { return fromMemberAnnotations(new WithMember<Integer>() { @Override public Integer withMember(AnnotatedMember member) { return _annotationIntrospector.findPropertyIndex(member); } }); } protected String _findDefaultValue() { return fromMemberAnnotations(new WithMember<String>() { @Override public String withMember(AnnotatedMember member) { return _annotationIntrospector.findPropertyDefaultValue(member); } }); } @Override public ObjectIdInfo findObjectIdInfo() { return fromMemberAnnotations(new WithMember<ObjectIdInfo>() { @Override public ObjectIdInfo withMember(AnnotatedMember member) { ObjectIdInfo info = _annotationIntrospector.findObjectIdInfo(member); if (info != null) { info = _annotationIntrospector.findObjectReferenceInfo(member, info); } return info; } }); } @Override public JsonInclude.Value findInclusion() { AnnotatedMember a = getAccessor(); // 16-Apr-2106, tatu: Let's include per-type default inclusion too // 17-Aug-2016, tatu: Do NOT include global, or per-type defaults, because // not all of this information (specifically, enclosing type's settings) // is available here JsonInclude.Value v = (_annotationIntrospector == null) ? null : _annotationIntrospector.findPropertyInclusion(a); return (v == null) ? JsonInclude.Value.empty() : v; } public JsonProperty.Access findAccess() { return fromMemberAnnotationsExcept(new WithMember<JsonProperty.Access>() { @Override public JsonProperty.Access withMember(AnnotatedMember member) { return _annotationIntrospector.findPropertyAccess(member); } }, JsonProperty.Access.AUTO); } /* /********************************************************** /* Data aggregation /********************************************************** */ public void addField(AnnotatedField a, PropertyName name, boolean explName, boolean visible, boolean ignored) { _fields = new Linked<AnnotatedField>(a, _fields, name, explName, visible, ignored); } public void addCtor(AnnotatedParameter a, PropertyName name, boolean explName, boolean visible, boolean ignored) { _ctorParameters = new Linked<AnnotatedParameter>(a, _ctorParameters, name, explName, visible, ignored); } public void addGetter(AnnotatedMethod a, PropertyName name, boolean explName, boolean visible, boolean ignored) { _getters = new Linked<AnnotatedMethod>(a, _getters, name, explName, visible, ignored); } public void addSetter(AnnotatedMethod a, PropertyName name, boolean explName, boolean visible, boolean ignored) { _setters = new Linked<AnnotatedMethod>(a, _setters, name, explName, visible, ignored); } /** * Method for adding all property members from specified collector into * this collector. */ public void addAll(POJOPropertyBuilder src) { _fields = merge(_fields, src._fields); _ctorParameters = merge(_ctorParameters, src._ctorParameters); _getters= merge(_getters, src._getters); _setters = merge(_setters, src._setters); } private static <T> Linked<T> merge(Linked<T> chain1, Linked<T> chain2) { if (chain1 == null) { return chain2; } if (chain2 == null) { return chain1; } return chain1.append(chain2); } /* /********************************************************** /* Modifications /********************************************************** */ /** * Method called to remove all entries that are marked as * ignored. */ public void removeIgnored() { _fields = _removeIgnored(_fields); _getters = _removeIgnored(_getters); _setters = _removeIgnored(_setters); _ctorParameters = _removeIgnored(_ctorParameters); } /** * @param inferMutators Whether mutators can be "pulled in" by visible * accessors or not. */ public JsonProperty.Access removeNonVisible(boolean inferMutators) { /* 07-Jun-2015, tatu: With 2.6, we will allow optional definition * of explicit access type for property; if not "AUTO", it will * dictate how visibility checks are applied. */ JsonProperty.Access acc = findAccess(); if (acc == null) { acc = JsonProperty.Access.AUTO; } switch (acc) { case READ_ONLY: // Remove setters, creators for sure, but fields too if deserializing _setters = null; _ctorParameters = null; if (!_forSerialization) { _fields = null; } break; case READ_WRITE: // no trimming whatsoever? break; case WRITE_ONLY: // remove getters, definitely, but also fields if serializing _getters = null; if (_forSerialization) { _fields = null; } break; default: case AUTO: // the default case: base it on visibility _getters = _removeNonVisible(_getters); _ctorParameters = _removeNonVisible(_ctorParameters); if (!inferMutators || (_getters == null)) { _fields = _removeNonVisible(_fields); _setters = _removeNonVisible(_setters); } } return acc; } /** * Mutator that will simply drop any constructor parameters property may have. * * @since 2.5 */ public void removeConstructors() { _ctorParameters = null; } /** * Method called to trim unnecessary entries, such as implicit * getter if there is an explict one available. This is important * for later stages, to avoid unnecessary conflicts. */ public void trimByVisibility() { _fields = _trimByVisibility(_fields); _getters = _trimByVisibility(_getters); _setters = _trimByVisibility(_setters); _ctorParameters = _trimByVisibility(_ctorParameters); } @SuppressWarnings("unchecked") public void mergeAnnotations(boolean forSerialization) { if (forSerialization) { if (_getters != null) { AnnotationMap ann = _mergeAnnotations(0, _getters, _fields, _ctorParameters, _setters); _getters = _applyAnnotations(_getters, ann); } else if (_fields != null) { AnnotationMap ann = _mergeAnnotations(0, _fields, _ctorParameters, _setters); _fields = _applyAnnotations(_fields, ann); } } else { // for deserialization if (_ctorParameters != null) { AnnotationMap ann = _mergeAnnotations(0, _ctorParameters, _setters, _fields, _getters); _ctorParameters = _applyAnnotations(_ctorParameters, ann); } else if (_setters != null) { AnnotationMap ann = _mergeAnnotations(0, _setters, _fields, _getters); _setters = _applyAnnotations(_setters, ann); } else if (_fields != null) { AnnotationMap ann = _mergeAnnotations(0, _fields, _getters); _fields = _applyAnnotations(_fields, ann); } } } private AnnotationMap _mergeAnnotations(int index, Linked<? extends AnnotatedMember>... nodes) { AnnotationMap ann = _getAllAnnotations(nodes[index]); while (++index < nodes.length) { if (nodes[index] != null) { return AnnotationMap.merge(ann, _mergeAnnotations(index, nodes)); } } return ann; } /** * Replacement, as per [databind#868], of simple access to annotations, which * does "deep merge" if an as necessary. *<pre> * nodes[index].value.getAllAnnotations() *</pre> * * @since 2.6 */ private <T extends AnnotatedMember> AnnotationMap _getAllAnnotations(Linked<T> node) { AnnotationMap ann = node.value.getAllAnnotations(); if (node.next != null) { ann = AnnotationMap.merge(ann, _getAllAnnotations(node.next)); } return ann; } /** * Helper method to handle recursive merging of annotations within accessor class, * to ensure no annotations are accidentally dropped within chain when non-visible * and secondary accessors are pruned later on. *<p> * See [databind#868] for more information. * * @since 2.6 */ private <T extends AnnotatedMember> Linked<T> _applyAnnotations(Linked<T> node, AnnotationMap ann) { @SuppressWarnings("unchecked") T value = (T) node.value.withAnnotations(ann); if (node.next != null) { node = node.withNext(_applyAnnotations(node.next, ann)); } return node.withValue(value); } private <T> Linked<T> _removeIgnored(Linked<T> node) { if (node == null) { return node; } return node.withoutIgnored(); } private <T> Linked<T> _removeNonVisible(Linked<T> node) { if (node == null) { return node; } return node.withoutNonVisible(); } private <T> Linked<T> _trimByVisibility(Linked<T> node) { if (node == null) { return node; } return node.trimByVisibility(); } /* /********************************************************** /* Accessors for aggregate information /********************************************************** */ private <T> boolean _anyExplicits(Linked<T> n) { for (; n != null; n = n.next) { if (n.name != null && n.name.hasSimpleName()) { return true; } } return false; } private <T> boolean _anyExplicitNames(Linked<T> n) { for (; n != null; n = n.next) { if (n.name != null && n.isNameExplicit) { return true; } } return false; } public boolean anyVisible() { return _anyVisible(_fields) || _anyVisible(_getters) || _anyVisible(_setters) || _anyVisible(_ctorParameters) ; } private <T> boolean _anyVisible(Linked<T> n) { for (; n != null; n = n.next) { if (n.isVisible) { return true; } } return false; } public boolean anyIgnorals() { return _anyIgnorals(_fields) || _anyIgnorals(_getters) || _anyIgnorals(_setters) || _anyIgnorals(_ctorParameters) ; } private <T> boolean _anyIgnorals(Linked<T> n) { for (; n != null; n = n.next) { if (n.isMarkedIgnored) { return true; } } return false; } /** * Method called to find out set of explicit names for accessors * bound together due to implicit name. * * @since 2.4 */ public Set<PropertyName> findExplicitNames() { Set<PropertyName> renamed = null; renamed = _findExplicitNames(_fields, renamed); renamed = _findExplicitNames(_getters, renamed); renamed = _findExplicitNames(_setters, renamed); renamed = _findExplicitNames(_ctorParameters, renamed); if (renamed == null) { return Collections.emptySet(); } return renamed; } /** * Method called when a previous call to {@link #findExplicitNames} found * multiple distinct explicit names, and the property this builder represents * basically needs to be broken apart and replaced by a set of more than * one properties. * * @since 2.4 */ public Collection<POJOPropertyBuilder> explode(Collection<PropertyName> newNames) { HashMap<PropertyName,POJOPropertyBuilder> props = new HashMap<PropertyName,POJOPropertyBuilder>(); _explode(newNames, props, _fields); _explode(newNames, props, _getters); _explode(newNames, props, _setters); _explode(newNames, props, _ctorParameters); return props.values(); } @SuppressWarnings("unchecked") private void _explode(Collection<PropertyName> newNames, Map<PropertyName,POJOPropertyBuilder> props, Linked<?> accessors) { final Linked<?> firstAcc = accessors; // clumsy, part 1 for (Linked<?> node = accessors; node != null; node = node.next) { PropertyName name = node.name; if (!node.isNameExplicit || name == null) { // no explicit name -- problem! // [databind#541] ... but only as long as it's visible if (!node.isVisible) { continue; } throw new IllegalStateException("Conflicting/ambiguous property name definitions (implicit name '" +_name+"'): found multiple explicit names: " +newNames+", but also implicit accessor: "+node); } POJOPropertyBuilder prop = props.get(name); if (prop == null) { prop = new POJOPropertyBuilder(_config, _annotationIntrospector, _forSerialization, _internalName, name); props.put(name, prop); } // ultra-clumsy, part 2 -- lambdas would be nice here if (firstAcc == _fields) { Linked<AnnotatedField> n2 = (Linked<AnnotatedField>) node; prop._fields = n2.withNext(prop._fields); } else if (firstAcc == _getters) { Linked<AnnotatedMethod> n2 = (Linked<AnnotatedMethod>) node; prop._getters = n2.withNext(prop._getters); } else if (firstAcc == _setters) { Linked<AnnotatedMethod> n2 = (Linked<AnnotatedMethod>) node; prop._setters = n2.withNext(prop._setters); } else if (firstAcc == _ctorParameters) { Linked<AnnotatedParameter> n2 = (Linked<AnnotatedParameter>) node; prop._ctorParameters = n2.withNext(prop._ctorParameters); } else { throw new IllegalStateException("Internal error: mismatched accessors, property: "+this); } } } private Set<PropertyName> _findExplicitNames(Linked<? extends AnnotatedMember> node, Set<PropertyName> renamed) { for (; node != null; node = node.next) { /* 30-Mar-2014, tatu: Second check should not be needed, but seems like * removing it can cause nasty exceptions with certain version * combinations (2.4 databind, an older module). * So leaving it in for now until this is resolved * (or version beyond 2.4) */ if (!node.isNameExplicit || node.name == null) { continue; } if (renamed == null) { renamed = new HashSet<PropertyName>(); } renamed.add(node.name); } return renamed; } // For trouble-shooting @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[Property '").append(_name) .append("'; ctors: ").append(_ctorParameters) .append(", field(s): ").append(_fields) .append(", getter(s): ").append(_getters) .append(", setter(s): ").append(_setters) ; sb.append("]"); return sb.toString(); } /* /********************************************************** /* Helper methods /********************************************************** */ /** * Helper method used for finding annotation values, from accessors * relevant to current usage (deserialization, serialization) */ protected <T> T fromMemberAnnotations(WithMember<T> func) { T result = null; if (_annotationIntrospector != null) { if (_forSerialization) { if (_getters != null) { result = func.withMember(_getters.value); } } else { if (_ctorParameters != null) { result = func.withMember(_ctorParameters.value); } if (result == null && _setters != null) { result = func.withMember(_setters.value); } } if (result == null && _fields != null) { result = func.withMember(_fields.value); } } return result; } protected <T> T fromMemberAnnotationsExcept(WithMember<T> func, T defaultValue) { if (_annotationIntrospector == null) { return null; } // NOTE: here we must ask ALL accessors, but the order varies between // serialization, deserialization if (_forSerialization) { if (_getters != null) { T result = func.withMember(_getters.value); if ((result != null) && (result != defaultValue)) { return result; } } if (_fields != null) { T result = func.withMember(_fields.value); if ((result != null) && (result != defaultValue)) { return result; } } if (_ctorParameters != null) { T result = func.withMember(_ctorParameters.value); if ((result != null) && (result != defaultValue)) { return result; } } if (_setters != null) { T result = func.withMember(_setters.value); if ((result != null) && (result != defaultValue)) { return result; } } return null; } if (_ctorParameters != null) { T result = func.withMember(_ctorParameters.value); if ((result != null) && (result != defaultValue)) { return result; } } if (_setters != null) { T result = func.withMember(_setters.value); if ((result != null) && (result != defaultValue)) { return result; } } if (_fields != null) { T result = func.withMember(_fields.value); if ((result != null) && (result != defaultValue)) { return result; } } if (_getters != null) { T result = func.withMember(_getters.value); if ((result != null) && (result != defaultValue)) { return result; } } return null; } /* /********************************************************** /* Helper classes /********************************************************** */ private interface WithMember<T> { public T withMember(AnnotatedMember member); } /** * @since 2.5 */ protected static class MemberIterator<T extends AnnotatedMember> implements Iterator<T> { private Linked<T> next; public MemberIterator(Linked<T> first) { next = first; } @Override public boolean hasNext() { return (next != null); } @Override public T next() { if (next == null) throw new NoSuchElementException(); T result = next.value; next = next.next; return result; } @Override public void remove() { throw new UnsupportedOperationException(); } } /** * Node used for creating simple linked lists to efficiently store small sets * of things. */ protected final static class Linked<T> { public final T value; public final Linked<T> next; public final PropertyName name; public final boolean isNameExplicit; public final boolean isVisible; public final boolean isMarkedIgnored; public Linked(T v, Linked<T> n, PropertyName name, boolean explName, boolean visible, boolean ignored) { value = v; next = n; // ensure that we'll never have missing names this.name = (name == null || name.isEmpty()) ? null : name; if (explName) { if (this.name == null) { // sanity check to catch internal problems throw new IllegalArgumentException("Can not pass true for 'explName' if name is null/empty"); } // 03-Apr-2014, tatu: But how about name-space only override? // Probably should not be explicit? Or, need to merge somehow? if (!name.hasSimpleName()) { explName = false; } } isNameExplicit = explName; isVisible = visible; isMarkedIgnored = ignored; } public Linked<T> withoutNext() { if (next == null) { return this; } return new Linked<T>(value, null, name, isNameExplicit, isVisible, isMarkedIgnored); } public Linked<T> withValue(T newValue) { if (newValue == value) { return this; } return new Linked<T>(newValue, next, name, isNameExplicit, isVisible, isMarkedIgnored); } public Linked<T> withNext(Linked<T> newNext) { if (newNext == next) { return this; } return new Linked<T>(value, newNext, name, isNameExplicit, isVisible, isMarkedIgnored); } public Linked<T> withoutIgnored() { if (isMarkedIgnored) { return (next == null) ? null : next.withoutIgnored(); } if (next != null) { Linked<T> newNext = next.withoutIgnored(); if (newNext != next) { return withNext(newNext); } } return this; } public Linked<T> withoutNonVisible() { Linked<T> newNext = (next == null) ? null : next.withoutNonVisible(); return isVisible ? withNext(newNext) : newNext; } /** * Method called to append given node(s) at the end of this * node chain. */ protected Linked<T> append(Linked<T> appendable) { if (next == null) { return withNext(appendable); } return withNext(next.append(appendable)); } public Linked<T> trimByVisibility() { if (next == null) { return this; } Linked<T> newNext = next.trimByVisibility(); if (name != null) { // this already has highest; how about next one? if (newNext.name == null) { // next one not, drop it return withNext(null); } // both have it, keep return withNext(newNext); } if (newNext.name != null) { // next one has higher, return it... return newNext; } // neither has explicit name; how about visibility? if (isVisible == newNext.isVisible) { // same; keep both in current order return withNext(newNext); } return isVisible ? withNext(null) : newNext; } @Override public String toString() { String msg = String.format("%s[visible=%b,ignore=%b,explicitName=%b]", value.toString(), isVisible, isMarkedIgnored, isNameExplicit); if (next != null) { msg = msg + ", "+next.toString(); } return msg; } } }