JsonNodeDeserializer.java
package tools.jackson.databind.deser.jackson;
import tools.jackson.core.*;
import tools.jackson.databind.*;
import tools.jackson.databind.node.*;
/**
* Deserializer that can build instances of {@link JsonNode} from any
* JSON content, using appropriate {@link JsonNode} type.
*/
public class JsonNodeDeserializer
extends BaseNodeDeserializer<JsonNode>
{
/**
* Singleton instance of generic deserializer for {@link JsonNode}.
* Only used for types other than JSON Object and Array.
*/
private final static JsonNodeDeserializer instance = new JsonNodeDeserializer();
protected JsonNodeDeserializer() {
// `null` means that explicit "merge" is honored and may or may not work, but
// that per-type and global defaults do not enable merging. This because
// some node types (Object, Array) do support, others don't.
super(JsonNode.class, null);
}
protected JsonNodeDeserializer(JsonNodeDeserializer base,
boolean mergeArrays, boolean mergeObjects) {
super(base, mergeArrays, mergeObjects);
}
@Override
protected BaseNodeDeserializer<?> _createWithMerge(boolean mergeArrays,
boolean mergeObjects) {
return new JsonNodeDeserializer(this, mergeArrays, mergeObjects);
}
/**
* Factory method for accessing deserializer for specific node type
*/
public static BaseNodeDeserializer<?> getDeserializer(Class<?> nodeClass)
{
if (nodeClass == ObjectNode.class) {
return ObjectDeserializer.getInstance();
}
if (nodeClass == ArrayNode.class) {
return ArrayDeserializer.getInstance();
}
// For others, generic one works fine
return instance;
}
/*
/**********************************************************************
/* Actual deserialization method implementations
/**********************************************************************
*/
@Override
public JsonNode getNullValue(DeserializationContext ctxt) {
return ctxt.getNodeFactory().nullNode();
}
/**
* Overridden variant to ensure that absent values are NOT coerced into
* {@code NullNode}s, unlike incoming {@code null} values.
*/
@Override // since 2.13
public Object getAbsentValue(DeserializationContext ctxt) {
return null;
}
/**
* Implementation that will produce types of any JSON nodes; not just one
* deserializer is registered to handle (in case of more specialized handler).
* Overridden by typed sub-classes for more thorough checking
*/
@Override
public JsonNode deserialize(JsonParser p, DeserializationContext ctxt)
throws JacksonException
{
final ContainerStack stack = new ContainerStack();
final JsonNodeFactory nodeF = ctxt.getNodeFactory();
JsonToken t = p.currentToken();
if (t == JsonToken.START_OBJECT) {
return _deserializeContainerNoRecursion(p, ctxt, nodeF, stack, nodeF.objectNode());
}
if (t == JsonToken.START_ARRAY) {
return _deserializeContainerNoRecursion(p, ctxt, nodeF, stack, nodeF.arrayNode());
}
switch (p.currentTokenId()) {
case JsonTokenId.ID_END_OBJECT:
return nodeF.objectNode();
case JsonTokenId.ID_PROPERTY_NAME:
return _deserializeObjectAtName(p, ctxt, nodeF, stack);
default:
}
return _deserializeAnyScalar(p, ctxt);
}
@Override
public Boolean supportsUpdate(DeserializationConfig config) {
return _supportsUpdates;
}
/*
/**********************************************************************
/* Specific instances for more accurate types
/**********************************************************************
*/
/**
* Implementation used when declared type is specifically {@link ObjectNode}.
*/
final static class ObjectDeserializer
extends BaseNodeDeserializer<ObjectNode>
{
protected final static ObjectDeserializer _instance = new ObjectDeserializer();
protected ObjectDeserializer() { super(ObjectNode.class, true); }
public static ObjectDeserializer getInstance() { return _instance; }
protected ObjectDeserializer(ObjectDeserializer base,
boolean mergeArrays, boolean mergeObjects) {
super(base, mergeArrays, mergeObjects);
}
@Override
protected BaseNodeDeserializer<?> _createWithMerge(boolean mergeArrays,
boolean mergeObjects) {
return new ObjectDeserializer(this, mergeArrays, mergeObjects);
}
@Override
public ObjectNode deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException
{
final JsonNodeFactory nodeF = ctxt.getNodeFactory();
if (p.isExpectedStartObjectToken()) {
final ObjectNode root = nodeF.objectNode();
_deserializeContainerNoRecursion(p, ctxt, nodeF, new ContainerStack(), root);
return root;
}
if (p.hasToken(JsonToken.PROPERTY_NAME)) {
return _deserializeObjectAtName(p, ctxt, nodeF, new ContainerStack());
}
// 23-Sep-2015, tatu: Ugh. We may also be given END_OBJECT (similar to PROPERTY_NAME),
// if caller has advanced to the first token of Object, but for empty Object
if (p.hasToken(JsonToken.END_OBJECT)) {
return nodeF.objectNode();
}
return (ObjectNode) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
}
/**
* Variant needed to support both root-level `updateValue()` and merging.
*/
@Override
public ObjectNode deserialize(JsonParser p, DeserializationContext ctxt,
ObjectNode node) throws JacksonException
{
if (p.isExpectedStartObjectToken() || p.hasToken(JsonToken.PROPERTY_NAME)) {
return (ObjectNode) updateObject(p, ctxt, (ObjectNode) node,
new ContainerStack());
}
return (ObjectNode) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
}
}
/**
* Implementation used when declared type is specifically {@link ArrayNode}.
*/
final static class ArrayDeserializer
extends BaseNodeDeserializer<ArrayNode>
{
protected final static ArrayDeserializer _instance = new ArrayDeserializer();
protected ArrayDeserializer() { super(ArrayNode.class, true); }
public static ArrayDeserializer getInstance() { return _instance; }
protected ArrayDeserializer(ArrayDeserializer base,
boolean mergeArrays, boolean mergeObjects) {
super(base, mergeArrays, mergeObjects);
}
@Override
protected BaseNodeDeserializer<?> _createWithMerge(boolean mergeArrays,
boolean mergeObjects) {
return new ArrayDeserializer(this, mergeArrays, mergeObjects);
}
@Override
public ArrayNode deserialize(JsonParser p, DeserializationContext ctxt)
throws JacksonException
{
if (p.isExpectedStartArrayToken()) {
final JsonNodeFactory nodeF = ctxt.getNodeFactory();
final ArrayNode arrayNode = nodeF.arrayNode();
_deserializeContainerNoRecursion(p, ctxt, nodeF,
new ContainerStack(), arrayNode);
return arrayNode;
}
return (ArrayNode) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
}
/**
* Variant needed to support both root-level {@code updateValue()} and merging.
*/
@Override
public ArrayNode deserialize(JsonParser p, DeserializationContext ctxt,
ArrayNode arrayNode) throws JacksonException
{
if (p.isExpectedStartArrayToken()) {
_deserializeContainerNoRecursion(p, ctxt, ctxt.getNodeFactory(),
new ContainerStack(), arrayNode);
return arrayNode;
}
return (ArrayNode) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
}
}
}