com.groupbyinc.common.jackson.jq.internal.misc.JsonNodeUtils Maven / Gradle / Ivy
package net.thisptr.jackson.jq.internal.misc;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import net.thisptr.jackson.jq.exception.IllegalJsonArgumentException;
import net.thisptr.jackson.jq.exception.JsonQueryException;
import net.thisptr.jackson.jq.internal.tree.fieldaccess.resolved.ResolvedAllFieldAccess;
import net.thisptr.jackson.jq.internal.tree.fieldaccess.resolved.ResolvedEmptyFieldAccess;
import net.thisptr.jackson.jq.internal.tree.fieldaccess.resolved.ResolvedFieldAccess;
import net.thisptr.jackson.jq.internal.tree.fieldaccess.resolved.ResolvedIndexFieldAccess;
import net.thisptr.jackson.jq.internal.tree.fieldaccess.resolved.ResolvedRangeFieldAccess;
import net.thisptr.jackson.jq.internal.tree.fieldaccess.resolved.ResolvedStringFieldAccess;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.DoubleNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.MissingNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class JsonNodeUtils {
private JsonNodeUtils() {}
public static boolean asBoolean(final JsonNode n) {
if (n == null || n.isNull() || n.isMissingNode())
return false;
if (n.isBoolean())
return n.asBoolean();
return true;
}
public static boolean isIntegralNumber(final JsonNode n) {
if (!n.isNumber())
return false;
if (n.asDouble() == n.asLong())
return true;
return false;
}
public static JsonNode asNumericNode(final long value) {
if (((int) value) == value)
return new IntNode((int) value);
return new LongNode((long) value);
}
public static JsonNode asNumericNode(final double value) {
if (((int) value) == value)
return new IntNode((int) value);
if (((long) value) == value)
return new LongNode((long) value);
return new DoubleNode(value);
}
public static ArrayNode asArrayNode(final ObjectMapper mapper, final List values) {
final ArrayNode result = mapper.createArrayNode();
result.addAll(values);
return result;
}
public static List asArrayList(final ArrayNode in) {
return Lists.newArrayList(in);
}
public static String typeOf(final JsonNode in) {
if (in == null)
return "null";
switch (in.getNodeType()) {
case ARRAY:
return "array";
case BINARY:
return "string";
case BOOLEAN:
return "boolean";
case MISSING:
return "null";
case NULL:
return "null";
case NUMBER:
return "number";
case OBJECT:
return "object";
case STRING:
return "string";
default:
throw new IllegalArgumentException("Unknown JsonNodeType: " + in.getNodeType());
}
}
public interface Mutation {
JsonNode apply(JsonNode value) throws JsonQueryException;
}
public static void copy(final ArrayNode out, final JsonNode in) throws JsonQueryException {
if (!in.isArray())
throw new IllegalJsonArgumentException("input must be ARRAY");
for (final JsonNode i : in)
out.add(i);
}
public static void copy(final ObjectNode out, final JsonNode in) throws JsonQueryException {
if (!in.isObject())
throw new IllegalJsonArgumentException("input must be OBJECT");
final Iterator> iter = in.fields();
while (iter.hasNext()) {
final Entry entry = iter.next();
out.set(entry.getKey(), entry.getValue());
}
}
public static JsonNode mutate(final ObjectMapper mapper, final JsonNode in, final List path, final Mutation mutation, final boolean creative) throws JsonQueryException {
if (path.isEmpty()) {
return mutation.apply(in);
} else {
final ResolvedFieldAccess accessHead = path.get(0);
final List accessTail = path.subList(1, path.size());
if (accessHead instanceof ResolvedEmptyFieldAccess) {
return in;
} else if (accessHead instanceof ResolvedIndexFieldAccess) {
final ResolvedIndexFieldAccess access = (ResolvedIndexFieldAccess) accessHead;
if (in.isNull()) {
if (!creative)
return NullNode.getInstance();
final ArrayNode result = mapper.createArrayNode();
for (final long index : access.indices()) {
if (index < 0)
throw new JsonQueryException("Out of bounds negative array index");
while (index >= result.size())
result.add(NullNode.getInstance());
result.set((int) index, mutate(mapper, NullNode.getInstance(), accessTail, mutation, creative));
}
return result;
} else if (in.isArray()) {
final ArrayNode result = mapper.createArrayNode();
final ArrayNode tmp = mapper.createArrayNode();
copy(tmp, in);
for (long index : access.indices()) {
index = index >= 0 ? index : index + in.size();
JsonNode value = tmp.get((int) index);
if (value == null && creative)
value = NullNode.getInstance();
final JsonNode newvalue = mutate(mapper, value, accessTail, mutation, creative);
if (newvalue != null) {
while (index >= tmp.size())
tmp.add(NullNode.getInstance());
tmp.set((int) index, newvalue);
} else {
tmp.set((int) index, MissingNode.getInstance());
}
}
for (final JsonNode t : tmp)
if (!t.isMissingNode())
result.add(t);
return result;
} else {
if (!accessHead.permissive)
throw JsonQueryException.format("Cannot index %s with number", in.getNodeType());
return in;
}
} else if (accessHead instanceof ResolvedStringFieldAccess) {
final ResolvedStringFieldAccess access = (ResolvedStringFieldAccess) accessHead;
if (in.isNull()) {
if (!creative)
return NullNode.getInstance();
final ObjectNode result = mapper.createObjectNode();
for (final String key : access.keys())
result.set(key, mutate(mapper, NullNode.getInstance(), accessTail, mutation, creative));
return result;
} else if (in.isObject()) {
final ObjectNode result = mapper.createObjectNode();
copy(result, in);
for (final String key : access.keys()) {
JsonNode value = result.get(key);
if (value == null && creative)
value = NullNode.getInstance();
final JsonNode newvalue = mutate(mapper, value, accessTail, mutation, creative);
if (newvalue == null) {
result.remove(key);
} else if (newvalue != value) {
result.set(key, newvalue);
}
}
return result;
} else {
if (!accessHead.permissive)
throw JsonQueryException.format("Cannot index %s with string \"%s\"", in.getNodeType(), access.keys().get(0));
return in;
}
} else if (accessHead instanceof ResolvedRangeFieldAccess) {
final ResolvedRangeFieldAccess access = (ResolvedRangeFieldAccess) accessHead;
if (in.isNull()) {
final JsonNode newvalue = mutate(mapper, NullNode.getInstance(), accessTail, mutation, creative);
if (!newvalue.isArray())
throw new JsonQueryException("A slice of an array can only be assigned another array");
return newvalue;
} else if (in.isArray()) {
ArrayNode result = mapper.createArrayNode();
copy(result, in);
final ArrayNode tmp = mapper.createArrayNode();
for (Range range : access.ranges()) {
range = range.over(result.size());
for (int i = 0; i < range.begin; ++i)
tmp.add(result.get(i));
final ArrayNode slice = mapper.createArrayNode();
for (int i = (int) range.begin; i < range.end; ++i)
slice.add(result.get(i));
final JsonNode newvalue = mutate(mapper, slice, accessTail, mutation, creative);
if (newvalue != null && newvalue.isArray()) {
for (final JsonNode t : newvalue)
tmp.add(t);
} else {
if (newvalue != null)
throw new JsonQueryException("A slice of an array can only be assigned another array");
}
for (int i = (int) range.end; i < result.size(); ++i)
tmp.add(result.get(i));
result = tmp;
}
return result;
} else if (in.isTextual()) {
throw new JsonQueryException("Cannot update field at object index of string");
} else {
if (!accessHead.permissive)
throw JsonQueryException.format("Cannot index %s with object", in.getNodeType());
return in;
}
} else if (accessHead instanceof ResolvedAllFieldAccess) {
if (in.isNull()) {
throw new JsonQueryException("Cannot iterate over null");
} else if (in.isObject()) {
final ObjectNode result = mapper.createObjectNode();
final Iterator> iter = in.fields();
while (iter.hasNext()) {
final Entry entry = iter.next();
final String key = entry.getKey();
final JsonNode value = entry.getValue();
final JsonNode newvalue = mutate(mapper, value, accessTail, mutation, creative);
if (newvalue != null)
result.set(key, newvalue);
}
return result;
} else if (in.isArray()) {
final ArrayNode result = mapper.createArrayNode();
for (int key = 0; key < in.size(); ++key) {
final JsonNode value = in.get(key);
final JsonNode newvalue = mutate(mapper, value, accessTail, mutation, creative);
if (newvalue != null)
result.add(newvalue);
}
return result;
} else {
throw JsonQueryException.format("Cannot iterate over %s", in.getNodeType());
}
}
throw new IllegalStateException();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy