com.fasterxml.jackson.databind.PropertyName Maven / Gradle / Ivy
package com.fasterxml.jackson.databind;
import com.fasterxml.jackson.core.SerializableString;
import com.fasterxml.jackson.core.io.SerializedString;
import com.fasterxml.jackson.core.util.InternCache;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.util.ClassUtil;
import java.util.Objects;
/**
* Simple value class used for containing names of properties as defined
* by annotations (and possibly other configuration sources).
*
* @since 2.1
*/
public class PropertyName
implements java.io.Serializable
{
private static final long serialVersionUID = 1L; // 2.5
private final static String _USE_DEFAULT = "";
private final static String _NO_NAME = "";
/**
* Special placeholder value that indicates that name to use should be
* based on the standard heuristics. This can be different from returning
* null, as null means "no information available, whereas this value
* indicates explicit defaulting.
*/
public final static PropertyName USE_DEFAULT = new PropertyName(_USE_DEFAULT, null);
/**
* Special placeholder value that indicates that there is no name associated.
* Exact semantics to use (if any) depend on actual annotation in use, but
* commonly this value disables behavior for which name would be needed.
*/
public final static PropertyName NO_NAME = new PropertyName(new String(_NO_NAME), null);
/**
* Basic name of the property.
*/
protected final String _simpleName;
/**
* Additional namespace, for formats that have such concept (JSON
* does not, XML does, for example).
*/
protected final String _namespace;
/**
* Lazily-constructed efficient representation of the simple name.
*
* NOTE: not defined as volatile to avoid performance problem with
* concurrent access in multi-core environments; due to statelessness
* of {@link SerializedString} at most leads to multiple instantiations.
*
* @since 2.4
*/
protected SerializableString _encodedSimple;
public PropertyName(String simpleName) {
this(simpleName, null);
}
public PropertyName(String simpleName, String namespace)
{
_simpleName = ClassUtil.nonNullString(simpleName);
_namespace = namespace;
}
// To support JDK serialization, recovery of Singleton instance
protected Object readResolve() {
if (_namespace == null) {
if (_simpleName == null || _USE_DEFAULT.equals(_simpleName)) {
return USE_DEFAULT;
}
// 30-Oct-2016, tatu: I don't see how this could ever occur...
// or how to distinguish USE_DEFAULT/NO_NAME from serialized
/*
if (_simpleName.equals(_NO_NAME)) {
return NO_NAME;
}
*/
}
return this;
}
/**
* @since 2.6
*/
public static PropertyName construct(String simpleName)
{
if (simpleName == null || simpleName.isEmpty()) {
return USE_DEFAULT;
}
return new PropertyName(InternCache.instance.intern(simpleName), null);
}
public static PropertyName construct(String simpleName, String ns)
{
if (simpleName == null) {
simpleName = "";
}
if (ns == null && simpleName.isEmpty()) {
return USE_DEFAULT;
}
return new PropertyName(InternCache.instance.intern(simpleName), ns);
}
/**
* Method that will combine information from two {@link PropertyName}
* instances
*
* @param name1 Name with higher precedence; may be {@code null}
* @param name2 Name with lower precedence; may be {@code null}
*
* @return Merged information; only {@code null} if both arguments
* are {@code null}s.
*
* @since 2.17
*/
public static PropertyName merge(PropertyName name1, PropertyName name2) {
if (name1 == null) {
return name2;
}
if (name2 == null) {
return name1;
}
String ns = _nonEmpty(name1._namespace, name2._namespace);
String simple = _nonEmpty(name1._simpleName, name2._simpleName);
// But see if we can just return one of arguments as-is:
if (ns == name1._namespace && simple == name1._simpleName) {
return name1;
}
if (ns == name2._namespace && simple == name2._simpleName) {
return name2;
}
return construct(simple, ns);
}
private static String _nonEmpty(String str1, String str2) {
if (str1 == null) {
return str2;
}
if (str2 == null) {
return str1;
}
if (str1.isEmpty()) {
return str2;
}
return str1;
}
public PropertyName internSimpleName()
{
if (_simpleName.isEmpty()) { // empty String is canonical already
return this;
}
String interned = InternCache.instance.intern(_simpleName);
if (interned == _simpleName) { // was already interned
return this;
}
return new PropertyName(interned, _namespace);
}
/**
* Fluent factory method for constructing an instance with different
* simple name.
*/
public PropertyName withSimpleName(String simpleName)
{
if (simpleName == null) {
simpleName = "";
}
if (simpleName.equals(_simpleName)) {
return this;
}
return new PropertyName(simpleName, _namespace);
}
/**
* Fluent factory method for constructing an instance with different
* namespace.
*/
public PropertyName withNamespace(String ns) {
if (ns == null) {
if (_namespace == null) {
return this;
}
} else if (ns.equals(_namespace)) {
return this;
}
return new PropertyName(_simpleName, ns);
}
/*
/**********************************************************
/* Accessors
/**********************************************************
*/
public String getSimpleName() {
return _simpleName;
}
/**
* Accessor that may be used to get lazily-constructed efficient
* representation of the simple name.
*
* @since 2.4
*/
public SerializableString simpleAsEncoded(MapperConfig> config) {
SerializableString sstr = _encodedSimple;
if (sstr == null) {
if (config == null) {
sstr = new SerializedString(_simpleName);
} else {
sstr = config.compileString(_simpleName);
}
_encodedSimple = sstr;
}
return sstr;
}
public String getNamespace() {
return _namespace;
}
public boolean hasSimpleName() {
return !_simpleName.isEmpty();
}
/**
* @since 2.3
*/
public boolean hasSimpleName(String str) {
// _simpleName never null so...
return _simpleName.equals(str);
}
public boolean hasNamespace() {
return _namespace != null;
}
/**
* Method that is basically equivalent of:
*
* !hasSimpleName() << !hasNamespace();
*
*
* @since 2.4
*/
public boolean isEmpty() {
return (_namespace == null) && (_simpleName.isEmpty());
}
/*
/**********************************************************
/* Std method overrides
/**********************************************************
*/
@Override
public boolean equals(Object o)
{
if (o == this) return true;
if (o == null) return false;
// 13-Nov-2012, tatu: by default, require strict type equality.
// Re-evaluate if this becomes an issue.
if (o.getClass() != getClass()) return false;
// 13-Nov-2012, tatu: Should we have specific rules on matching USE_DEFAULT?
// (like, it only ever matching exact instance)
// If we did, would need to check symmetrically; that is, if either 'this'
// or 'o' was USE_DEFAULT, both would have to be.
PropertyName other = (PropertyName) o;
if (_simpleName == null) {
if (other._simpleName != null) return false;
} else if (!_simpleName.equals(other._simpleName)) {
return false;
}
if (_namespace == null) {
return (null == other._namespace);
}
return _namespace.equals(other._namespace);
}
@Override
public int hashCode() {
return Objects.hashCode(_simpleName) * 31
+ Objects.hashCode(_namespace);
}
@Override
public String toString() {
if (_namespace == null) {
return _simpleName;
}
return "{"+_namespace + "}" + _simpleName;
}
}