package sh.calaba.org.codehaus.jackson.map.deser; import java.util.*; import sh.calaba.org.codehaus.jackson.map.*; import sh.calaba.org.codehaus.jackson.map.deser.impl.BeanPropertyMap; import sh.calaba.org.codehaus.jackson.map.deser.impl.ValueInjector; import sh.calaba.org.codehaus.jackson.map.introspect.AnnotatedMember; import sh.calaba.org.codehaus.jackson.map.introspect.BasicBeanDescription; import sh.calaba.org.codehaus.jackson.map.util.Annotations; import sh.calaba.org.codehaus.jackson.type.JavaType; /** * Builder class used for aggregating deserialization information about * a POJO, in order to build a {@link JsonDeserializer} for deserializing * intances. * * @since 1.7 */ public class BeanDeserializerBuilder { /* /********************************************************** /* General information about POJO /********************************************************** */ final protected BasicBeanDescription _beanDesc; /* /********************************************************** /* Accumulated information about properties /********************************************************** */ /** * Properties to deserialize collected so far. *

* Note: since 1.9.1, LinkedHashMap has been used, since preservation * of order is actually important for some use cases. */ final protected HashMap _properties = new LinkedHashMap(); /** * Value injectors for deserialization * * @since 1.9 */ protected List _injectables; /** * Back-reference properties this bean contains (if any) */ protected HashMap _backRefProperties; /** * Set of names of properties that are recognized but are to be ignored for deserialization * purposes (meaning no exception is thrown, value is just skipped). */ protected HashSet _ignorableProps; /** * Object that will handle value instantiation for the bean type. * * @since 1.9 */ protected ValueInstantiator _valueInstantiator; /** * Fallback setter used for handling any properties that are not * mapped to regular setters. If setter is not null, it will be * called once for each such property. */ protected SettableAnyProperty _anySetter; /** * Flag that can be set to ignore and skip unknown properties. * If set, will not throw an exception for unknown properties. */ protected boolean _ignoreAllUnknown; /* /********************************************************** /* Life-cycle: construction /********************************************************** */ public BeanDeserializerBuilder(BasicBeanDescription beanDesc) { _beanDesc = beanDesc; } /** * Copy constructor for sub-classes to use, when constructing * custom builder instances * * @since 1.9 */ protected BeanDeserializerBuilder(BeanDeserializerBuilder src) { _beanDesc = src._beanDesc; _anySetter = src._anySetter; _ignoreAllUnknown = src._ignoreAllUnknown; // let's make copy of properties _properties.putAll(src._properties); _backRefProperties = _copy(src._backRefProperties); // Hmmh. Should we create defensive copies here? For now, not yet _ignorableProps = src._ignorableProps; _valueInstantiator = src._valueInstantiator; } private static HashMap _copy(HashMap src) { if (src == null) { return null; } return new HashMap(src); } /* /********************************************************** /* Life-cycle: state modification (adders, setters) /********************************************************** */ /** * Method for adding a new property or replacing a property. */ public void addOrReplaceProperty(SettableBeanProperty prop, boolean allowOverride) { _properties.put(prop.getName(), prop); } /** * Method to add a property setter. Will ensure that there is no * unexpected override; if one is found will throw a * {@link IllegalArgumentException}. */ public void addProperty(SettableBeanProperty prop) { SettableBeanProperty old = _properties.put(prop.getName(), prop); if (old != null && old != prop) { // should never occur... throw new IllegalArgumentException("Duplicate property '"+prop.getName()+"' for "+_beanDesc.getType()); } } /** * Method called to add a property that represents so-called back reference; * reference that "points back" to object that has forward reference to * currently built bean. */ public void addBackReferenceProperty(String referenceName, SettableBeanProperty prop) { if (_backRefProperties == null) { _backRefProperties = new HashMap(4); } _backRefProperties.put(referenceName, prop); // also: if we had property with same name, actually remove it if (_properties != null) { _properties.remove(prop.getName()); } } /** * @since 1.9 */ public void addInjectable(String propertyName, JavaType propertyType, Annotations contextAnnotations, AnnotatedMember member, Object valueId) { if (_injectables == null) { _injectables = new ArrayList(); } _injectables.add(new ValueInjector(propertyName, propertyType, contextAnnotations, member, valueId)); } /** * Method that will add property name as one of properties that can * be ignored if not recognized. */ public void addIgnorable(String propName) { if (_ignorableProps == null) { _ignorableProps = new HashSet(); } _ignorableProps.add(propName); } /** * Method called by deserializer factory, when a "creator property" * (something that is passed via constructor- or factory method argument; * instead of setter or field). *

* Default implementation does not do anything; we may need to revisit this * decision if these properties need to be available through accessors. * For now, however, we just have to ensure that we don't try to resolve * types that masked setter/field has (see [JACKSON-700] for details). * * @since 1.9.2 */ public void addCreatorProperty(BeanPropertyDefinition propDef) { // do nothing } public void setAnySetter(SettableAnyProperty s) { if (_anySetter != null && s != null) { throw new IllegalStateException("_anySetter already set to non-null"); } _anySetter = s; } public void setIgnoreUnknownProperties(boolean ignore) { _ignoreAllUnknown = ignore; } /** * @since 1.9 */ public void setValueInstantiator(ValueInstantiator inst) { _valueInstantiator = inst; } /* /********************************************************** /* Public accessors /********************************************************** */ /** * Method that allows accessing all properties that this * builder currently contains. *

* Note that properties are returned in order that properties * are ordered (explictly, or by rule), which is the serialization * order. * * @since 1.8.3 */ public Iterator getProperties() { return _properties.values().iterator(); } public boolean hasProperty(String propertyName) { return _properties.containsKey(propertyName); } public SettableBeanProperty removeProperty(String name) { return _properties.remove(name); } /** * @since 1.9 */ public ValueInstantiator getValueInstantiator() { return _valueInstantiator; } /* /********************************************************** /* Build method(s) /********************************************************** */ public JsonDeserializer build(BeanProperty forProperty) { BeanPropertyMap propertyMap = new BeanPropertyMap(_properties.values()); propertyMap.assignIndexes(); return new BeanDeserializer(_beanDesc, forProperty, _valueInstantiator, propertyMap, _backRefProperties, _ignorableProps, _ignoreAllUnknown, _anySetter, _injectables); } }