blob: db518288d12fa8535ff6a97bb3ebd623da1b0ccc [file] [log] [blame]
package org.codehaus.jackson;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
/**
* Base class for all JSON nodes, which form the basis of JSON
* Tree Model that Jackson implements.
* One way to think of these nodes is to consider them
* similar to DOM nodes in XML DOM trees.
*<p>
* As a general design rule, most accessors ("getters") are included
* in this base class, to allow for traversing structure without
* type casts. Most mutators, however, need to be accessed through
* specific sub-classes (such as <code>org.codehaus.jackson.node.ObjectNode</code>
* and <code>org.codehaus.jackson.node.ArrayNode</code>).
* This seems sensible because proper type
* information is generally available when building or modifying
* trees, but less often when reading a tree (newly built from
* parsed JSON content).
*<p>
* Actual concrete sub-classes can be found from package
* {@link org.codehaus.jackson.node}, which is in 'mapper' jar
* (whereas this class is in 'core' jar, since it is declared as
* nominal type for operations in {@link ObjectCodec})
*/
public abstract class JsonNode
implements Iterable<JsonNode>
{
protected final static List<JsonNode> NO_NODES = Collections.emptyList();
protected final static List<String> NO_STRINGS = Collections.emptyList();
protected JsonNode() { }
/*
/**********************************************************
/* Public API, type introspection
/**********************************************************
*/
// // First high-level division between values, containers and "missing"
/**
* Method that returns true for all value nodes: ones that
* are not containers, and that do not represent "missing" nodes
* in the path. Such value nodes represent String, Number, Boolean
* and null values from JSON.
*<p>
* Note: one and only one of methods {@link #isValueNode},
* {@link #isContainerNode} and {@link #isMissingNode} ever
* returns true for any given node.
*/
public boolean isValueNode() { return false; }
/**
* Method that returns true for container nodes: Arrays and Objects.
*<p>
* Note: one and only one of methods {@link #isValueNode},
* {@link #isContainerNode} and {@link #isMissingNode} ever
* returns true for any given node.
*/
public boolean isContainerNode() { return false; }
/**
* Method that returns true for "virtual" nodes which represent
* missing entries constructed by path accessor methods when
* there is no actual node matching given criteria.
*<p>
* Note: one and only one of methods {@link #isValueNode},
* {@link #isContainerNode} and {@link #isMissingNode} ever
* returns true for any given node.
*/
public boolean isMissingNode() { return false; }
// // Then more specific type introspection
// // (along with defaults to be overridden)
/**
* @return True if this node represents Json Array
*/
public boolean isArray() { return false; }
/**
* @return True if this node represents Json Object
*/
public boolean isObject() { return false; }
/**
* Method that can be used to check if the node is a wrapper
* for a POJO ("Plain Old Java Object" aka "bean".
* Returns true only for
* instances of {@link org.codehaus.jackson.node.POJONode}.
*
* @return True if this node wraps a POJO
*/
public boolean isPojo() { return false; }
/**
* @return True if this node represents a numeric Json
* value
*/
public boolean isNumber() { return false; }
/**
* @return True if this node represents an integral (integer)
* numeric Json value
*/
public boolean isIntegralNumber() { return false; }
/**
* @return True if this node represents a non-integral
* numeric Json value
*/
public boolean isFloatingPointNumber() { return false; }
/**
* @return True if this node represents an integral
* numeric Json value that withs in Java int value space
*/
public boolean isInt() { return false; }
/**
* @return True if this node represents an integral
* numeric Json value that fits in Java long value space
* (but not int value space, i.e. {@link #isInt} returns false)
*/
public boolean isLong() { return false; }
public boolean isDouble() { return false; }
public boolean isBigDecimal() { return false; }
public boolean isBigInteger() { return false; }
public boolean isTextual() { return false; }
/**
* Method that can be used to check if this node was created from
* Json boolean value (literals "true" and "false").
*/
public boolean isBoolean() { return false; }
/**
* Method that can be used to check if this node was created from
* Json liternal null value.
*/
public boolean isNull() { return false; }
/**
* Method that can be used to check if this node represents
* binary data (Base64 encoded). Although this will be externally
* written as Json String value, {@link #isTextual} will
* return false if this method returns true.
*
* @return True if this node represents base64 encoded binary data
*/
public boolean isBinary() { return false; }
/**
* Method that can be used for efficient type detection
* when using stream abstraction for traversing nodes.
* Will return the first {@link JsonToken} that equivalent
* stream event would produce (for most nodes there is just
* one token but for structured/container types multiple)
*
* @since 1.3
*/
public abstract JsonToken asToken();
/**
* If this node is a numeric type (as per {@link #isNumber}),
* returns native type that node uses to store the numeric
* value.
*/
public abstract JsonParser.NumberType getNumberType();
/*
/**********************************************************
/* Public API, straight value access
/**********************************************************
*/
/**
* Method to use for accessing String values.
* Does <b>NOT</b> do any conversions for non-String value nodes;
* for non-String values (ones for which {@link #isTextual} returns
* false) null will be returned.
* For String values, null is never returned (but empty Strings may be)
*
* @return Textual value this node contains, iff it is a textual
* json node (comes from Json String value entry)
*/
public String getTextValue() { return null; }
/**
* Method to use for accessing binary content of binary nodes (nodes
* for which {@link #isBinary} returns true); or for Text Nodes
* (ones for which {@link #getTextValue} returns non-null value),
* to read decoded base64 data.
* For other types of nodes, returns null.
*
* @return Binary data this node contains, iff it is a binary
* node; null otherwise
*/
public byte[] getBinaryValue() throws IOException
{
return null;
}
/**
* Method to use for accessing JSON boolean values (value
* literals 'true' and 'false').
* For other types, always returns false.
*
* @return Textual value this node contains, iff it is a textual
* json node (comes from Json String value entry)
*/
public boolean getBooleanValue() { return false; }
/**
* Returns numeric value for this node, <b>if and only if</b>
* this node is numeric ({@link #isNumber} returns true); otherwise
* returns null
*
* @return Number value this node contains, if any (null for non-number
* nodes).
*/
public Number getNumberValue() { return null; }
/**
* Returns integer value for this node, <b>if and only if</b>
* this node is numeric ({@link #isNumber} returns true). For other
* types returns 0.
* For floating-point numbers, value is truncated using default
* Java coercion, similar to how cast from double to int operates.
*
* @return Integer value this node contains, if any; 0 for non-number
* nodes.
*/
public int getIntValue() { return 0; }
public long getLongValue() { return 0L; }
public double getDoubleValue() { return 0.0; }
public BigDecimal getDecimalValue() { return BigDecimal.ZERO; }
public BigInteger getBigIntegerValue() { return BigInteger.ZERO; }
/**
* Method for accessing value of the specified element of
* an array node. For other nodes, null is always returned.
*<p>
* For array nodes, index specifies
* exact location within array and allows for efficient iteration
* over child elements (underlying storage is guaranteed to
* be efficiently indexable, i.e. has random-access to elements).
* If index is less than 0, or equal-or-greater than
* <code>node.size()</code>, null is returned; no exception is
* thrown for any index.
*
* @return Node that represent value of the specified element,
* if this node is an array and has specified element.
* Null otherwise.
*/
public JsonNode get(int index) { return null; }
/**
* Method for accessing value of the specified field of
* an object node. If this node is not an object (or it
* does not have a value for specified field name), or
* if there is no field with such name, null is returned.
*
* @return Node that represent value of the specified field,
* if this node is an object and has value for the specified
* field. Null otherwise.
*/
public JsonNode get(String fieldName) { return null; }
/*
/**********************************************************
/* Public API, value access with conversion(s)/coercion(s)
/**********************************************************
*/
/**
* Method that will return valid String representation of
* the container value, if the node is a value node
* (method {@link #isValueNode} returns true), otherwise
* empty String.
*
* @since 1.9 (replaces <code>getValueAsText</code>)
*/
public abstract String asText();
/**
* Method that will try to convert value of this node to a Java <b>int</b>.
* Numbers are coerced using default Java rules; booleans convert to 0 (false)
* and 1 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an int (including structured types
* like Objects and Arrays),
* default value of <b>0</b> will be returned; no exceptions are thrown.
*
* @since 1.9 (replaces <code>getValueAsInt</code>)
*/
public int asInt() {
return asInt(0);
}
/**
* Method that will try to convert value of this node to a Java <b>int</b>.
* Numbers are coerced using default Java rules; booleans convert to 0 (false)
* and 1 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an int (including structured types
* like Objects and Arrays),
* specified <b>defaultValue</b> will be returned; no exceptions are thrown.
*
* @since 1.9 (replaces <code>getValueAsInt</code>)
*/
public int asInt(int defaultValue) {
return defaultValue;
}
/**
* Method that will try to convert value of this node to a Java <b>long</b>.
* Numbers are coerced using default Java rules; booleans convert to 0 (false)
* and 1 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an long (including structured types
* like Objects and Arrays),
* default value of <b>0</b> will be returned; no exceptions are thrown.
*
* @since 1.9 (replaces <code>getValueAsLong</code>)
*/
public long asLong() {
return asLong(0L);
}
/**
* Method that will try to convert value of this node to a Java <b>long</b>.
* Numbers are coerced using default Java rules; booleans convert to 0 (false)
* and 1 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an long (including structured types
* like Objects and Arrays),
* specified <b>defaultValue</b> will be returned; no exceptions are thrown.
*
* @since 1.9 (replaces <code>getValueAsLong</code>)
*/
public long asLong(long defaultValue) {
return defaultValue;
}
/**
* Method that will try to convert value of this node to a Java <b>double</b>.
* Numbers are coerced using default Java rules; booleans convert to 0.0 (false)
* and 1.0 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an int (including structured types
* like Objects and Arrays),
* default value of <b>0.0</b> will be returned; no exceptions are thrown.
*
* @since 1.9 (replaces <code>getValueAsDouble</code>)
*/
public double asDouble() {
return asDouble(0.0);
}
/**
* Method that will try to convert value of this node to a Java <b>double</b>.
* Numbers are coerced using default Java rules; booleans convert to 0.0 (false)
* and 1.0 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an int (including structured types
* like Objects and Arrays),
* specified <b>defaultValue</b> will be returned; no exceptions are thrown.
*
* @since 1.9 (replaces <code>getValueAsLong</code>)
*/
public double asDouble(double defaultValue) {
return defaultValue;
}
/**
* Method that will try to convert value of this node to a Java <b>boolean</b>.
* JSON booleans map naturally; integer numbers other than 0 map to true, and
* 0 maps to false
* and Strings 'true' and 'false' map to corresponding values.
*<p>
* If representation can not be converted to a boolean value (including structured types
* like Objects and Arrays),
* default value of <b>false</b> will be returned; no exceptions are thrown.
*
* @since 1.9 (replaces <code>getValueAsBoolean</code>)
*/
public boolean asBoolean() {
return asBoolean(false);
}
/**
* Method that will try to convert value of this node to a Java <b>boolean</b>.
* JSON booleans map naturally; integer numbers other than 0 map to true, and
* 0 maps to false
* and Strings 'true' and 'false' map to corresponding values.
*<p>
* If representation can not be converted to a boolean value (including structured types
* like Objects and Arrays),
* specified <b>defaultValue</b> will be returned; no exceptions are thrown.
*
* @since 1.9 (replaces <code>getValueAsBoolean</code>)
*/
public boolean asBoolean(boolean defaultValue) {
return defaultValue;
}
/*
/**********************************************************
/* Public API, value access with conversion(s)/coercion(s)
/**********************************************************
*/
/**
* Method that will return valid String representation of
* the container value, if the node is a value node
* (method {@link #isValueNode} returns true), otherwise null.
*<p>
* Note: to serialize nodes of any type, you should call
* {@link #toString} instead.
*
* @deprecated Since 1.9, use {@link #asText} instead
*/
@Deprecated
public String getValueAsText() { return asText(); }
/**
* Method that will try to convert value of this node to a Java <b>int</b>.
* Numbers are coerced using default Java rules; booleans convert to 0 (false)
* and 1 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an int (including structured types
* like Objects and Arrays),
* default value of <b>0</b> will be returned; no exceptions are thrown.
*
* @since 1.6
*
* @deprecated Since 1.9, use {@link #asInt} instead
*/
@Deprecated
public int getValueAsInt() { return asInt(0); }
/**
* Method that will try to convert value of this node to a Java <b>int</b>.
* Numbers are coerced using default Java rules; booleans convert to 0 (false)
* and 1 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an int (including structured types
* like Objects and Arrays),
* specified <b>defaultValue</b> will be returned; no exceptions are thrown.
*
* @since 1.6
*
* @deprecated Since 1.9, use {@link #asInt} instead
*/
@Deprecated
public int getValueAsInt(int defaultValue) { return asInt(defaultValue); }
/**
* Method that will try to convert value of this node to a Java <b>long</b>.
* Numbers are coerced using default Java rules; booleans convert to 0 (false)
* and 1 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an long (including structured types
* like Objects and Arrays),
* default value of <b>0</b> will be returned; no exceptions are thrown.
*
* @since 1.6
*
* @deprecated Since 1.9, use {@link #asLong} instead
*/
@Deprecated
public long getValueAsLong() { return asLong(0L); }
/**
* Method that will try to convert value of this node to a Java <b>long</b>.
* Numbers are coerced using default Java rules; booleans convert to 0 (false)
* and 1 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an long (including structured types
* like Objects and Arrays),
* specified <b>defaultValue</b> will be returned; no exceptions are thrown.
*
* @since 1.6
*
* @deprecated Since 1.9, use {@link #asLong} instead
*/
@Deprecated
public long getValueAsLong(long defaultValue) { return asLong(defaultValue); }
/**
* Method that will try to convert value of this node to a Java <b>double</b>.
* Numbers are coerced using default Java rules; booleans convert to 0.0 (false)
* and 1.0 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an int (including structured types
* like Objects and Arrays),
* default value of <b>0.0</b> will be returned; no exceptions are thrown.
*
* @since 1.6
*
* @deprecated Since 1.9, use {@link #asDouble} instead
*/
@Deprecated
public double getValueAsDouble() { return asDouble(0.0); }
/**
* Method that will try to convert value of this node to a Java <b>double</b>.
* Numbers are coerced using default Java rules; booleans convert to 0.0 (false)
* and 1.0 (true), and Strings are parsed using default Java language integer
* parsing rules.
*<p>
* If representation can not be converted to an int (including structured types
* like Objects and Arrays),
* specified <b>defaultValue</b> will be returned; no exceptions are thrown.
*
* @since 1.6
*
* @deprecated Since 1.9, use {@link #asDouble} instead
*/
@Deprecated
public double getValueAsDouble(double defaultValue) { return asDouble(defaultValue); }
/**
* Method that will try to convert value of this node to a Java <b>boolean</b>.
* JSON booleans map naturally; integer numbers other than 0 map to true, and
* 0 maps to false
* and Strings 'true' and 'false' map to corresponding values.
*<p>
* If representation can not be converted to a boolean value (including structured types
* like Objects and Arrays),
* default value of <b>false</b> will be returned; no exceptions are thrown.
*
* @since 1.7
*
* @deprecated Since 1.9, use {@link #asBoolean} instead
*/
@Deprecated
public boolean getValueAsBoolean() { return asBoolean(false); }
/**
* Method that will try to convert value of this node to a Java <b>boolean</b>.
* JSON booleans map naturally; integer numbers other than 0 map to true, and
* 0 maps to false
* and Strings 'true' and 'false' map to corresponding values.
*<p>
* If representation can not be converted to a boolean value (including structured types
* like Objects and Arrays),
* specified <b>defaultValue</b> will be returned; no exceptions are thrown.
*
* @since 1.7
*
* @deprecated Since 1.9, use {@link #asBoolean} instead
*/
@Deprecated
public boolean getValueAsBoolean(boolean defaultValue) { return asBoolean(defaultValue); }
/*
/**********************************************************
/* Public API, value find / existence check methods
/**********************************************************
*/
/**
* Method that allows checking whether this node is JSON Object node
* and contains value for specified property. If this is the case
* (including properties with explicit null values), returns true;
* otherwise returns false.
*<p>
* This method is equivalent to:
*<pre>
* node.get(fieldName) != null
*</pre>
* (since return value of get() is node, not value node contains)
*
* @param fieldName Name of element to check
*
* @return True if this node is a JSON Object node, and has a property
* entry with specified name (with any value, including null value)
*
* @since 1.6
*/
public boolean has(String fieldName) {
return get(fieldName) != null;
}
/**
* Method that allows checking whether this node is JSON Array node
* and contains a value for specified index
* If this is the case
* (including case of specified indexing having null as value), returns true;
* otherwise returns false.
*<p>
* Note: array element indexes are 0-based.
*<p>
* This method is equivalent to:
*<pre>
* node.get(index) != null
*</pre>
*
* @param index Index to check
*
* @return True if this node is a JSON Object node, and has a property
* entry with specified name (with any value, including null value)
*
* @since 1.6
*/
public boolean has(int index) {
return get(index) != null;
}
/**
* Method for finding a JSON Object field with specified name in this
* node or its child nodes, and returning value it has.
* If no matching field is found in this node or its descendants, returns null.
*
* @param fieldName Name of field to look for
*
* @return Value of first matching node found, if any; null if none
*
* @since 1.6
*/
public abstract JsonNode findValue(String fieldName);
/**
* Method for finding JSON Object fields with specified name, and returning
* found ones as a List. Note that sub-tree search ends if a field is found,
* so possible children of result nodes are <b>not</b> included.
* If no matching fields are found in this node or its descendants, returns
* an empty List.
*
* @param fieldName Name of field to look for
*
* @since 1.6
*/
public final List<JsonNode> findValues(String fieldName)
{
List<JsonNode> result = findValues(fieldName, null);
if (result == null) {
return Collections.emptyList();
}
return result;
}
/**
* Similar to {@link #findValues}, but will additionally convert
* values into Strings, calling {@link #getValueAsText}.
*
* @since 1.6
*/
public final List<String> findValuesAsText(String fieldName)
{
List<String> result = findValuesAsText(fieldName, null);
if (result == null) {
return Collections.emptyList();
}
return result;
}
/**
* Method similar to {@link #findValue}, but that will return a
* "missing node" instead of null if no field is found. Missing node
* is a specific kind of node for which {@link #isMissingNode}
* returns true; and all value access methods return empty or
* missing value.
*
* @param fieldName Name of field to look for
*
* @return Value of first matching node found; or if not found, a
* "missing node" (non-null instance that has no value)
*
* @since 1.6
*/
public abstract JsonNode findPath(String fieldName);
/**
* Method for finding a JSON Object that contains specified field,
* within this node or its descendants.
* If no matching field is found in this node or its descendants, returns null.
*
* @param fieldName Name of field to look for
*
* @return Value of first matching node found, if any; null if none
*
* @since 1.6
*/
public abstract JsonNode findParent(String fieldName);
/**
* Method for finding a JSON Object that contains specified field,
* within this node or its descendants.
* If no matching field is found in this node or its descendants, returns null.
*
* @param fieldName Name of field to look for
*
* @return Value of first matching node found, if any; null if none
*
* @since 1.6
*/
public final List<JsonNode> findParents(String fieldName)
{
List<JsonNode> result = findParents(fieldName, null);
if (result == null) {
return Collections.emptyList();
}
return result;
}
public abstract List<JsonNode> findValues(String fieldName, List<JsonNode> foundSoFar);
public abstract List<String> findValuesAsText(String fieldName, List<String> foundSoFar);
public abstract List<JsonNode> findParents(String fieldName, List<JsonNode> foundSoFar);
/*
/**********************************************************
/* Public API, container access
/**********************************************************
*/
/**
* Method that returns number of child nodes this node contains:
* for Array nodes, number of child elements, for Object nodes,
* number of fields, and for all other nodes 0.
*
* @return For non-container nodes returns 0; for arrays number of
* contained elements, and for objects number of fields.
*/
public int size() { return 0; }
/**
* Same as calling {@link #getElements}; implemented so that
* convenience "for-each" loop can be used for looping over elements
* of JSON Array constructs.
*/
@Override
public final Iterator<JsonNode> iterator() { return getElements(); }
/**
* Method for accessing all value nodes of this Node, iff
* this node is a JSON Array or Object node. In case of Object node,
* field names (keys) are not included, only values.
* For other types of nodes, returns empty iterator.
*/
public Iterator<JsonNode> getElements() { return NO_NODES.iterator(); }
/**
* Method for accessing names of all fields for this Node, iff
* this node is a JSON Object node.
*/
public Iterator<String> getFieldNames() { return NO_STRINGS.iterator(); }
/**
* @return Iterator that can be used to traverse all key/value pairs for
* object nodes; empty iterator (no contents) for other types
*
* @since 1.8 (although existed in ObjectNode since 1.0 or so)
*/
public Iterator<Map.Entry<String, JsonNode>> getFields() {
Collection<Map.Entry<String, JsonNode>> coll = Collections.emptyList();
return coll.iterator();
}
/*
/**********************************************************
/* Public API, path handling
/**********************************************************
*/
/**
* This method is similar to {@link #get(String)}, except
* that instead of returning null if no such value exists (due
* to this node not being an object, or object not having value
* for the specified field),
* a "missing node" (node that returns true for
* {@link #isMissingNode}) will be returned. This allows for
* convenient and safe chained access via path calls.
*/
public abstract JsonNode path(String fieldName);
/**
* Alias of {@link #path(String)}.
*
* @deprecated Use {@link #path(String)} instead
*/
@Deprecated
public final JsonNode getPath(String fieldName) { return path(fieldName); }
/**
* This method is similar to {@link #get(int)}, except
* that instead of returning null if no such element exists (due
* to index being out of range, or this node not being an array),
* a "missing node" (node that returns true for
* {@link #isMissingNode}) will be returned. This allows for
* convenient and safe chained access via path calls.
*/
public abstract JsonNode path(int index);
/**
* Alias of {@link #path(int)}.
*
* @deprecated Use {@link #path(int)} instead
*/
@Deprecated
public final JsonNode getPath(int index) { return path(index); }
/**
* Method that can be called on object nodes, to access a property
* that has object value; or if no such property exists, to create and
* return such object node.
* If node method is called on is not Object node,
* or if property exists and has value that is not object node,
* {@link UnsupportedOperationException} is thrown
*
* @since 1.8
*/
public JsonNode with(String propertyName) {
throw new UnsupportedOperationException("JsonNode not of type ObjectNode (but "
+getClass().getName()+"), can not call with() on it");
}
/*
/**********************************************************
/* Public API: converting to/from Streaming API
/**********************************************************
*/
/**
* Method for constructing a {@link JsonParser} instance for
* iterating over contents of the tree that this
* node is root of.
* Functionally equivalent to first serializing tree using
* {@link ObjectCodec} and then re-parsing but
* more efficient.
*/
public abstract JsonParser traverse();
/*
/**********************************************************
/* Overridden standard methods
/**********************************************************
*/
/**
*<p>
* Note: marked as abstract to ensure all implementation
* classes define it properly.
*/
@Override
public abstract String toString();
/**
* Equality for node objects is defined as full (deep) value
* equality. This means that it is possible to compare complete
* JSON trees for equality by comparing equality of root nodes.
*<p>
* Note: marked as abstract to ensure all implementation
* classes define it properly and not rely on definition
* from {@link java.lang.Object}.
*/
@Override
public abstract boolean equals(Object o);
}