package com.fasterxml.jackson.databind.deser.std;
import java.io.IOException;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.node.*;
import com.fasterxml.jackson.databind.type.LogicalType;
import com.fasterxml.jackson.databind.util.RawValue;
@SuppressWarnings("serial")
public class JsonNodeDeserializer
extends BaseNodeDeserializer<JsonNode>
{
private final static JsonNodeDeserializer instance = new JsonNodeDeserializer();
protected JsonNodeDeserializer() {
super(JsonNode.class, null);
}
public static JsonDeserializer<? extends JsonNode> getDeserializer(Class<?> nodeClass)
{
if (nodeClass == ObjectNode.class) {
return ObjectDeserializer.getInstance();
}
if (nodeClass == ArrayNode.class) {
return ArrayDeserializer.getInstance();
}
return instance;
}
@Override
public JsonNode getNullValue(DeserializationContext ctxt) {
return ctxt.getNodeFactory().nullNode();
}
@Override
public JsonNode deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
switch (p.currentTokenId()) {
case JsonTokenId.ID_START_OBJECT:
return deserializeObject(p, ctxt, ctxt.getNodeFactory());
case JsonTokenId.ID_START_ARRAY:
return deserializeArray(p, ctxt, ctxt.getNodeFactory());
default:
}
return deserializeAny(p, ctxt, ctxt.getNodeFactory());
}
final static class ObjectDeserializer
extends BaseNodeDeserializer<ObjectNode>
{
private static final long serialVersionUID = 1L;
protected final static ObjectDeserializer _instance = new ObjectDeserializer();
protected ObjectDeserializer() { super(ObjectNode.class, true); }
public static ObjectDeserializer getInstance() { return _instance; }
@Override
public ObjectNode deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
if (p.isExpectedStartObjectToken()) {
return deserializeObject(p, ctxt, ctxt.getNodeFactory());
}
if (p.hasToken(JsonToken.FIELD_NAME)) {
return deserializeObjectAtName(p, ctxt, ctxt.getNodeFactory());
}
if (p.hasToken(JsonToken.END_OBJECT)) {
return ctxt.getNodeFactory().objectNode();
}
return (ObjectNode) ctxt.handleUnexpectedToken(ObjectNode.class, p);
}
@Override
public ObjectNode deserialize(JsonParser p, DeserializationContext ctxt,
ObjectNode node) throws IOException
{
if (p.isExpectedStartObjectToken() || p.hasToken(JsonToken.FIELD_NAME)) {
return (ObjectNode) updateObject(p, ctxt, (ObjectNode) node);
}
return (ObjectNode) ctxt.handleUnexpectedToken(ObjectNode.class, p);
}
}
final static class ArrayDeserializer
extends BaseNodeDeserializer<ArrayNode>
{
private static final long serialVersionUID = 1L;
protected final static ArrayDeserializer _instance = new ArrayDeserializer();
protected ArrayDeserializer() { super(ArrayNode.class, true); }
public static ArrayDeserializer getInstance() { return _instance; }
@Override
public ArrayNode deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
if (p.isExpectedStartArrayToken()) {
return deserializeArray(p, ctxt, ctxt.getNodeFactory());
}
return (ArrayNode) ctxt.handleUnexpectedToken(ArrayNode.class, p);
}
@Override
public ArrayNode deserialize(JsonParser p, DeserializationContext ctxt,
ArrayNode node) throws IOException
{
if (p.isExpectedStartArrayToken()) {
return (ArrayNode) updateArray(p, ctxt, (ArrayNode) node);
}
return (ArrayNode) ctxt.handleUnexpectedToken(ArrayNode.class, p);
}
}
}
@SuppressWarnings("serial")
abstract class BaseNodeDeserializer<T extends JsonNode>
extends StdDeserializer<T>
{
protected final Boolean _supportsUpdates;
public BaseNodeDeserializer(Class<T> vc, Boolean supportsUpdates) {
super(vc);
_supportsUpdates = supportsUpdates;
}
@Override
public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
TypeDeserializer typeDeserializer)
throws IOException
{
return typeDeserializer.deserializeTypedFromAny(p, ctxt);
}
@Override
public LogicalType logicalType() {
return LogicalType.Untyped;
}
@Override
public boolean isCachable() { return true; }
@Override
public Boolean supportsUpdate(DeserializationConfig config) {
return _supportsUpdates;
}
protected void _handleDuplicateField(JsonParser p, DeserializationContext ctxt,
JsonNodeFactory nodeFactory,
String fieldName, ObjectNode objectNode,
JsonNode oldValue, JsonNode newValue)
throws JsonProcessingException
{
if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY)) {
ctxt.reportInputMismatch(JsonNode.class,
"Duplicate field '%s' for `ObjectNode`: not allowed when `DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY` enabled",
fieldName);
}
if (ctxt.isEnabled(StreamReadCapability.DUPLICATE_PROPERTIES)) {
if (oldValue.isArray()) {
((ArrayNode) oldValue).add(newValue);
objectNode.replace(fieldName, oldValue);
} else {
ArrayNode arr = nodeFactory.arrayNode();
arr.add(oldValue);
arr.add(newValue);
objectNode.replace(fieldName, arr);
}
}
}
protected final ObjectNode deserializeObject(JsonParser p, DeserializationContext ctxt,
final JsonNodeFactory nodeFactory) throws IOException
{
final ObjectNode node = nodeFactory.objectNode();
String key = p.nextFieldName();
for (; key != null; key = p.nextFieldName()) {
JsonNode value;
JsonToken t = p.nextToken();
if (t == null) {
t = JsonToken.NOT_AVAILABLE;
}
switch (t.id()) {
case JsonTokenId.ID_START_OBJECT:
value = deserializeObject(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_START_ARRAY:
value = deserializeArray(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_EMBEDDED_OBJECT:
value = _fromEmbedded(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_STRING:
value = nodeFactory.textNode(p.getText());
break;
case JsonTokenId.ID_NUMBER_INT:
value = _fromInt(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_TRUE:
value = nodeFactory.booleanNode(true);
break;
case JsonTokenId.ID_FALSE:
value = nodeFactory.booleanNode(false);
break;
case JsonTokenId.ID_NULL:
value = nodeFactory.nullNode();
break;
default:
value = deserializeAny(p, ctxt, nodeFactory);
}
JsonNode old = node.replace(key, value);
if (old != null) {
_handleDuplicateField(p, ctxt, nodeFactory,
key, node, old, value);
}
}
return node;
}
protected final ObjectNode deserializeObjectAtName(JsonParser p, DeserializationContext ctxt,
final JsonNodeFactory nodeFactory) throws IOException
{
final ObjectNode node = nodeFactory.objectNode();
String key = p.currentName();
for (; key != null; key = p.nextFieldName()) {
JsonNode value;
JsonToken t = p.nextToken();
if (t == null) {
t = JsonToken.NOT_AVAILABLE;
}
switch (t.id()) {
case JsonTokenId.ID_START_OBJECT:
value = deserializeObject(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_START_ARRAY:
value = deserializeArray(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_EMBEDDED_OBJECT:
value = _fromEmbedded(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_STRING:
value = nodeFactory.textNode(p.getText());
break;
case JsonTokenId.ID_NUMBER_INT:
value = _fromInt(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_TRUE:
value = nodeFactory.booleanNode(true);
break;
case JsonTokenId.ID_FALSE:
value = nodeFactory.booleanNode(false);
break;
case JsonTokenId.ID_NULL:
value = nodeFactory.nullNode();
break;
default:
value = deserializeAny(p, ctxt, nodeFactory);
}
JsonNode old = node.replace(key, value);
if (old != null) {
_handleDuplicateField(p, ctxt, nodeFactory,
key, node, old, value);
}
}
return node;
}
protected final JsonNode updateObject(JsonParser p, DeserializationContext ctxt,
final ObjectNode node) throws IOException
{
String key;
if (p.isExpectedStartObjectToken()) {
key = p.nextFieldName();
} else {
if (!p.hasToken(JsonToken.FIELD_NAME)) {
return deserialize(p, ctxt);
}
key = p.currentName();
}
for (; key != null; key = p.nextFieldName()) {
JsonToken t = p.nextToken();
JsonNode old = node.get(key);
if (old != null) {
if (old instanceof ObjectNode) {
if (t == JsonToken.START_OBJECT) {
JsonNode newValue = updateObject(p, ctxt, (ObjectNode) old);
if (newValue != old) {
node.set(key, newValue);
}
continue;
}
} else if (old instanceof ArrayNode) {
if (t == JsonToken.START_ARRAY) {
JsonNode newValue = updateArray(p, ctxt, (ArrayNode) old);
if (newValue != old) {
node.set(key, newValue);
}
continue;
}
}
}
if (t == null) {
t = JsonToken.NOT_AVAILABLE;
}
JsonNode value;
JsonNodeFactory nodeFactory = ctxt.getNodeFactory();
switch (t.id()) {
case JsonTokenId.ID_START_OBJECT:
value = deserializeObject(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_START_ARRAY:
value = deserializeArray(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_EMBEDDED_OBJECT:
value = _fromEmbedded(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_STRING:
value = nodeFactory.textNode(p.getText());
break;
case JsonTokenId.ID_NUMBER_INT:
value = _fromInt(p, ctxt, nodeFactory);
break;
case JsonTokenId.ID_TRUE:
value = nodeFactory.booleanNode(true);
break;
case JsonTokenId.ID_FALSE:
value = nodeFactory.booleanNode(false);
break;
case JsonTokenId.ID_NULL:
value = nodeFactory.nullNode();
break;
default:
value = deserializeAny(p, ctxt, nodeFactory);
}
node.set(key, value);
}
return node;
}
protected final ArrayNode deserializeArray(JsonParser p, DeserializationContext ctxt,
final JsonNodeFactory nodeFactory) throws IOException
{
ArrayNode node = nodeFactory.arrayNode();
JsonToken t;
while ((t = p.nextToken()) != null) {
switch (t.id()) {
case JsonTokenId.ID_START_OBJECT:
node.add(deserializeObject(p, ctxt, nodeFactory));
break;
case JsonTokenId.ID_START_ARRAY:
node.add(deserializeArray(p, ctxt, nodeFactory));
break;
case JsonTokenId.ID_END_ARRAY:
return node;
case JsonTokenId.ID_EMBEDDED_OBJECT:
node.add(_fromEmbedded(p, ctxt, nodeFactory));
break;
case JsonTokenId.ID_STRING:
node.add(nodeFactory.textNode(p.getText()));
break;
case JsonTokenId.ID_NUMBER_INT:
node.add(_fromInt(p, ctxt, nodeFactory));
break;
case JsonTokenId.ID_TRUE:
node.add(nodeFactory.booleanNode(true));
break;
case JsonTokenId.ID_FALSE:
node.add(nodeFactory.booleanNode(false));
break;
case JsonTokenId.ID_NULL:
node.add(nodeFactory.nullNode());
break;
default:
node.add(deserializeAny(p, ctxt, nodeFactory));
break;
}
}
return node;
}
protected final JsonNode updateArray(JsonParser p, DeserializationContext ctxt,
final ArrayNode node) throws IOException
{
final JsonNodeFactory nodeFactory = ctxt.getNodeFactory();
while (true) {
JsonToken t = p.nextToken();
switch (t.id()) {
case JsonTokenId.ID_START_OBJECT:
node.add(deserializeObject(p, ctxt, nodeFactory));
break;
case JsonTokenId.ID_START_ARRAY:
node.add(deserializeArray(p, ctxt, nodeFactory));
break;
case JsonTokenId.ID_END_ARRAY:
return node;
case JsonTokenId.ID_EMBEDDED_OBJECT:
node.add(_fromEmbedded(p, ctxt, nodeFactory));
break;
case JsonTokenId.ID_STRING:
node.add(nodeFactory.textNode(p.getText()));
break;
case JsonTokenId.ID_NUMBER_INT:
node.add(_fromInt(p, ctxt, nodeFactory));
break;
case JsonTokenId.ID_TRUE:
node.add(nodeFactory.booleanNode(true));
break;
case JsonTokenId.ID_FALSE:
node.add(nodeFactory.booleanNode(false));
break;
case JsonTokenId.ID_NULL:
node.add(nodeFactory.nullNode());
break;
default:
node.add(deserializeAny(p, ctxt, nodeFactory));
break;
}
}
}
protected final JsonNode deserializeAny(JsonParser p, DeserializationContext ctxt,
final JsonNodeFactory nodeFactory) throws IOException
{
switch (p.currentTokenId()) {
case JsonTokenId.ID_END_OBJECT:
return nodeFactory.objectNode();
case JsonTokenId.ID_FIELD_NAME:
return deserializeObjectAtName(p, ctxt, nodeFactory);
case JsonTokenId.ID_EMBEDDED_OBJECT:
return _fromEmbedded(p, ctxt, nodeFactory);
case JsonTokenId.ID_STRING:
return nodeFactory.textNode(p.getText());
case JsonTokenId.ID_NUMBER_INT:
return _fromInt(p, ctxt, nodeFactory);
case JsonTokenId.ID_NUMBER_FLOAT:
return _fromFloat(p, ctxt, nodeFactory);
case JsonTokenId.ID_TRUE:
return nodeFactory.booleanNode(true);
case JsonTokenId.ID_FALSE:
return nodeFactory.booleanNode(false);
case JsonTokenId.ID_NULL:
return nodeFactory.nullNode();
default:
}
return (JsonNode) ctxt.handleUnexpectedToken(handledType(), p);
}
protected final JsonNode _fromInt(JsonParser p, DeserializationContext ctxt,
JsonNodeFactory nodeFactory) throws IOException
{
JsonParser.NumberType nt;
int feats = ctxt.getDeserializationFeatures();
if ((feats & F_MASK_INT_COERCIONS) != 0) {
if (DeserializationFeature.USE_BIG_INTEGER_FOR_INTS.enabledIn(feats)) {
nt = JsonParser.NumberType.BIG_INTEGER;
} else if (DeserializationFeature.USE_LONG_FOR_INTS.enabledIn(feats)) {
nt = JsonParser.NumberType.LONG;
} else {
nt = p.getNumberType();
}
} else {
nt = p.getNumberType();
}
if (nt == JsonParser.NumberType.INT) {
return nodeFactory.numberNode(p.getIntValue());
}
if (nt == JsonParser.NumberType.LONG) {
return nodeFactory.numberNode(p.getLongValue());
}
return nodeFactory.numberNode(p.getBigIntegerValue());
}
protected final JsonNode _fromFloat(JsonParser p, DeserializationContext ctxt,
final JsonNodeFactory nodeFactory) throws IOException
{
JsonParser.NumberType nt = p.getNumberType();
if (nt == JsonParser.NumberType.BIG_DECIMAL) {
return nodeFactory.numberNode(p.getDecimalValue());
}
if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) {
if (p.isNaN()) {
return nodeFactory.numberNode(p.getDoubleValue());
}
return nodeFactory.numberNode(p.getDecimalValue());
}
if (nt == JsonParser.NumberType.FLOAT) {
return nodeFactory.numberNode(p.getFloatValue());
}
return nodeFactory.numberNode(p.getDoubleValue());
}
protected final JsonNode _fromEmbedded(JsonParser p, DeserializationContext ctxt,
JsonNodeFactory nodeFactory) throws IOException
{
Object ob = p.getEmbeddedObject();
if (ob == null) {
return nodeFactory.nullNode();
}
Class<?> type = ob.getClass();
if (type == byte[].class) {
return nodeFactory.binaryNode((byte[]) ob);
}
if (ob instanceof RawValue) {
return nodeFactory.rawValueNode((RawValue) ob);
}
if (ob instanceof JsonNode) {
return (JsonNode) ob;
}
return nodeFactory.pojoNode(ob);
}
}