| 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; |
| |
| /** |
| * 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. |
| *<p> |
| * 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 = (simpleName == null) ? "" : simpleName; |
| _namespace = namespace; |
| } |
| |
| // To support JDK serialization, recovery of Singleton instance |
| protected Object readResolve() { |
| if (_simpleName == null || _USE_DEFAULT.equals(_simpleName)) { |
| return USE_DEFAULT; |
| } |
| if (_simpleName.equals(_NO_NAME) && _namespace == null) { |
| return NO_NAME; |
| } |
| return this; |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| public static PropertyName construct(String simpleName) |
| { |
| if (simpleName == null || simpleName.length() == 0) { |
| 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.length() == 0) { |
| return USE_DEFAULT; |
| } |
| return new PropertyName(InternCache.instance.intern(simpleName), ns); |
| } |
| |
| public PropertyName internSimpleName() |
| { |
| if (_simpleName.length() == 0) { // 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.length() > 0; |
| } |
| |
| /** |
| * @since 2.3 |
| */ |
| public boolean hasSimpleName(String str) { |
| if (str == null) { |
| return _simpleName == null; |
| } |
| return str.equals(_simpleName); |
| } |
| |
| public boolean hasNamespace() { |
| return _namespace != null; |
| } |
| |
| /** |
| * Method that is basically equivalent of: |
| *<pre> |
| * !hasSimpleName() << !hasNamespace(); |
| *</pre> |
| * |
| * @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() { |
| if (_namespace == null) { |
| return _simpleName.hashCode(); |
| } |
| return _namespace.hashCode() ^ _simpleName.hashCode(); |
| } |
| |
| @Override |
| public String toString() { |
| if (_namespace == null) { |
| return _simpleName; |
| } |
| return "{"+_namespace + "}" + _simpleName; |
| } |
| } |