All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.thisptr.jackson.jq.path.ArrayIndexPath Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
package net.thisptr.jackson.jq.path;

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.IntNode;
import com.fasterxml.jackson.databind.node.NullNode;

import net.thisptr.jackson.jq.PathOutput;
import net.thisptr.jackson.jq.exception.JsonQueryException;
import net.thisptr.jackson.jq.exception.JsonQueryTypeException;

public class ArrayIndexPath implements Path {
	public final JsonNode index;
	private final Path parent;

	public static ArrayIndexPath chainIfNotNull(final Path parent, final int index) {
		return chainIfNotNull(parent, IntNode.valueOf(index));
	}

	public static ArrayIndexPath chainIfNotNull(final Path parent, final JsonNode index) {
		if (parent == null)
			return null;
		return new ArrayIndexPath(parent, index);
	}

	public ArrayIndexPath(final Path parent, final JsonNode index) {
		if (parent == null)
			throw new NullPointerException("parent must not be null");
		this.parent = parent;
		if (index == null)
			throw new NullPointerException("index must not be null");
		if (!index.isNumber())
			throw new IllegalArgumentException("index must be a number");
		this.index = index;
	}

	@Override
	public void toJsonNode(final ArrayNode out) throws JsonQueryException {
		parent.toJsonNode(out);
		out.add(index);
	}

	@Override
	public void get(final JsonNode in, final Path ipath, final PathOutput output, boolean permissive) throws JsonQueryException {
		parent.get(in, ipath, (parent, ppath) -> {
			resolve(parent, ppath, output, index, permissive);
		}, permissive);
	}

	private static final ObjectMapper MAPPER = new ObjectMapper();

	@Override
	public JsonNode mutate(final JsonNode in, final Mutation mutation, final boolean makeParent) throws JsonQueryException {
		return parent.mutate(in, (oldval) -> {
			return mutate(oldval, index, mutation, makeParent, !makeParent);
		}, makeParent);
	}

	private static JsonNode mutate(JsonNode in, final JsonNode index, final Mutation mutation, final boolean makeParent, final boolean deleteMode) throws JsonQueryException {
		assert index.isNumber();
		if (in == null || in.isNull()) {
			if (!makeParent)
				return in;
			in = MAPPER.createArrayNode();
		}
		if (in.isArray()) {
			final int indexAsInt = index.asInt();
			final int _index = indexAsInt < 0 ? indexAsInt + in.size() : indexAsInt;
			if (deleteMode && (_index < 0 || in.size() <= _index))
				return in;
			if (_index < 0)
				throw new JsonQueryException("Out of bounds negative array index");

			final JsonNode newval = mutation.apply(_index < in.size() ? in.get(_index) : null);
			if (newval == null)
				return in;

			final ArrayNode out = MAPPER.createArrayNode();
			for (int i = 0; i < in.size(); ++i)
				out.add(in.get(i));
			for (int i = in.size(); i <= _index; ++i)
				out.add(NullNode.getInstance());
			out.set(_index, newval);
			return out;
		} else {
			throw new JsonQueryTypeException("Cannot index %s with number", in.getNodeType());
		}
	}

	public static void resolve(final JsonNode pobj, final Path ppath, final PathOutput output, final JsonNode index, final boolean permissive) throws JsonQueryException {
		assert index.isNumber();
		if (pobj.isArray()) {
			final int indexAsInt = index.asInt();
			if (index.asDouble() != indexAsInt) { // if index is not an integer, emit null
				output.emit(NullNode.getInstance(), ArrayIndexPath.chainIfNotNull(ppath, index));
				return;
			}
			final int indexResolved = indexAsInt < 0 ? indexAsInt + pobj.size() : indexAsInt;
			if (indexResolved < 0 || pobj.size() <= indexResolved) { // out of range index
				output.emit(NullNode.getInstance(), ArrayIndexPath.chainIfNotNull(ppath, index));
				return;
			}
			output.emit(pobj.get(indexResolved), ArrayIndexPath.chainIfNotNull(ppath, index));
		} else if (pobj.isNull()) {
			output.emit(NullNode.getInstance(), ArrayIndexPath.chainIfNotNull(ppath, index));
		} else {
			if (!permissive)
				throw new JsonQueryTypeException("Cannot index %s with number", pobj.getNodeType());
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy