blob: 9b57186c2f123ef0873f2a5b7cc54992cea8a3b6 [file] [log] [blame]
package com.fasterxml.jackson.databind;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
/**
* Simple container class used for storing "additional" metadata about
* properties. Carved out to reduce number of distinct properties that
* actual property implementations and place holders need to store;
* since instances are immutable, they can be freely shared.
*
* @since 2.3
*/
public class PropertyMetadata
implements java.io.Serializable
{
private static final long serialVersionUID = -1;
public final static PropertyMetadata STD_REQUIRED = new PropertyMetadata(Boolean.TRUE,
null, null, null, null, null, null);
public final static PropertyMetadata STD_OPTIONAL = new PropertyMetadata(Boolean.FALSE,
null, null, null, null, null, null);
public final static PropertyMetadata STD_REQUIRED_OR_OPTIONAL = new PropertyMetadata(null,
null, null, null, null, null, null);
/**
* Helper class used for containing information about expected merge
* information for this property, if merging is expected.
*
* @since 2.9
*/
public final static class MergeInfo
// NOTE: need not be Serializable, not persisted
{
public final AnnotatedMember getter;
/**
* Flag that is set if the information came from global defaults,
* and not from explicit per-property annotations or per-type
* config overrides.
*/
public final boolean fromDefaults;
protected MergeInfo(AnnotatedMember getter, boolean fromDefaults) {
this.getter = getter;
this.fromDefaults = fromDefaults;
}
public static MergeInfo createForDefaults(AnnotatedMember getter) {
return new MergeInfo(getter, true);
}
public static MergeInfo createForTypeOverride(AnnotatedMember getter) {
return new MergeInfo(getter, false);
}
public static MergeInfo createForPropertyOverride(AnnotatedMember getter) {
return new MergeInfo(getter, false);
}
}
/**
* Three states: required, not required and unknown; unknown represented
* as null.
*/
protected final Boolean _required;
/**
* Optional human-readable description associated with the property.
*/
protected final String _description;
/**
* Optional index of the property within containing Object.
*
* @since 2.4
*/
protected final Integer _index;
/**
* Optional default value, as String, for property; not used for
* any functionality by core databind, offered as metadata for
* extensions.
*/
protected final String _defaultValue;
/**
* Settings regarding merging, if property is determined to possibly
* be mergeable (possibly since global settings may be omitted for
* non-mergeable types).
*<p>
* NOTE: transient since it is assumed that this information is only
* relevant during initial setup and not needed after full initialization.
* May be changed if this proves necessary.
*
* @since 2.9
*/
protected final transient MergeInfo _mergeInfo;
/**
* Settings regarding handling of incoming `null`s, both for value itself
* and, for structured types, content values (array/Collection elements,
* Map values).
*
* @since 2.9
*/
protected Nulls _valueNulls, _contentNulls;
/*
/**********************************************************
/* Construction, configuration
/**********************************************************
*/
/**
* @since 2.9
*/
protected PropertyMetadata(Boolean req, String desc, Integer index, String def,
MergeInfo mergeInfo, Nulls valueNulls, Nulls contentNulls)
{
_required = req;
_description = desc;
_index = index;
_defaultValue = (def == null || def.isEmpty()) ? null : def;
_mergeInfo = mergeInfo;
_valueNulls = valueNulls;
_contentNulls = contentNulls;
}
/**
* @since 2.8.8
*/
public static PropertyMetadata construct(Boolean req, String desc, Integer index,
String defaultValue) {
if ((desc != null) || (index != null) || (defaultValue != null)) {
return new PropertyMetadata(req, desc, index, defaultValue,
null, null, null);
}
if (req == null) {
return STD_REQUIRED_OR_OPTIONAL;
}
return req ? STD_REQUIRED : STD_OPTIONAL;
}
@Deprecated // since 2.8.8
public static PropertyMetadata construct(boolean req, String desc, Integer index,
String defaultValue) {
if (desc != null || index != null || defaultValue != null) {
return new PropertyMetadata(req, desc, index, defaultValue,
null, null, null);
}
return req ? STD_REQUIRED : STD_OPTIONAL;
}
/**
* Minor optimization: let's canonicalize back to placeholders in cases
* where there is no real data to consider
*/
protected Object readResolve()
{
if ((_description == null) && (_index == null) && (_defaultValue == null)
&& (_mergeInfo == null)
&& (_valueNulls == null) && (_contentNulls == null)) {
if (_required == null) {
return STD_REQUIRED_OR_OPTIONAL;
}
return _required.booleanValue() ? STD_REQUIRED : STD_OPTIONAL;
}
return this;
}
public PropertyMetadata withDescription(String desc) {
return new PropertyMetadata(_required, desc, _index, _defaultValue,
_mergeInfo, _valueNulls, _contentNulls);
}
/**
* @since 2.9
*/
public PropertyMetadata withMergeInfo(MergeInfo mergeInfo) {
return new PropertyMetadata(_required, _description, _index, _defaultValue,
mergeInfo, _valueNulls, _contentNulls);
}
/**
* @since 2.9
*/
public PropertyMetadata withNulls(Nulls valueNulls,
Nulls contentNulls) {
return new PropertyMetadata(_required, _description, _index, _defaultValue,
_mergeInfo, valueNulls, contentNulls);
}
public PropertyMetadata withDefaultValue(String def) {
if ((def == null) || def.isEmpty()) {
if (_defaultValue == null) {
return this;
}
def = null;
} else if (def.equals(_defaultValue)) {
return this;
}
return new PropertyMetadata(_required, _description, _index, def,
_mergeInfo, _valueNulls, _contentNulls);
}
public PropertyMetadata withIndex(Integer index) {
return new PropertyMetadata(_required, _description, index, _defaultValue,
_mergeInfo, _valueNulls, _contentNulls);
}
public PropertyMetadata withRequired(Boolean b) {
if (b == null) {
if (_required == null) {
return this;
}
} else if (b.equals(_required)) {
return this;
}
return new PropertyMetadata(b, _description, _index, _defaultValue,
_mergeInfo, _valueNulls, _contentNulls);
}
/*
/**********************************************************
/* Accessors
/**********************************************************
*/
public String getDescription() { return _description; }
/**
* @since 2.5
*/
public String getDefaultValue() { return _defaultValue; }
/**
* Accessor for determining whether property has declared "default value",
* which may be used by extension modules.
*
* @since 2.6
*/
public boolean hasDefaultValue() { return (_defaultValue != null); }
public boolean isRequired() { return (_required != null) && _required.booleanValue(); }
public Boolean getRequired() { return _required; }
/**
* @since 2.4
*/
public Integer getIndex() { return _index; }
/**
* @since 2.4
*/
public boolean hasIndex() { return _index != null; }
/**
* @since 2.9
*/
public MergeInfo getMergeInfo() { return _mergeInfo; }
/**
* @since 2.9
*/
public Nulls getValueNulls() { return _valueNulls; }
/**
* @since 2.9
*/
public Nulls getContentNulls() { return _contentNulls; }
}