mirror of
https://github.com/jlengrand/vert.x.git
synced 2026-03-10 08:51:19 +00:00
Json Pointer implementation (#2898)
* Added Json Pointer implementation
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
* Fixed docs typo
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
* Added tracedQuery to JsonPointer
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
* Moved Json Pointer docs and applied some changes from code review
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
* Renamed build in toString() and buildURI in toURI()
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
* Did some doc changes
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
* Reworked the JsonPointer Javadoc
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
* Added JsonPointer#append(JsonPointer)
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
* Removed generics
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
(cherry picked from commit d9cf8c016e)
Signed-off-by: slinkydeveloper <francescoguard@gmail.com>
This commit is contained in:
committed by
Julien Viet
parent
4bea87e149
commit
4da9b2ff2c
@@ -774,6 +774,8 @@ include::eventbus.adoc[]
|
||||
|
||||
include::override/json.adoc[]
|
||||
|
||||
include::json-pointers.adoc[]
|
||||
|
||||
include::buffers.adoc[]
|
||||
|
||||
include::net.adoc[]
|
||||
|
||||
20
src/main/asciidoc/json-pointers.adoc
Normal file
20
src/main/asciidoc/json-pointers.adoc
Normal file
@@ -0,0 +1,20 @@
|
||||
== Json Pointers
|
||||
|
||||
Vert.x provides an implementation of <a href="https://tools.ietf.org/html/rfc6901">Json Pointers from RFC6901</a>.
|
||||
You can use pointers both for querying and for writing. You can build your {@link io.vertx.core.json.pointer.JsonPointer} using
|
||||
a string, a URI or manually appending paths:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
{@link examples.JsonPointerExamples#example1Pointers}
|
||||
----
|
||||
|
||||
After instantiating your pointer, use {@link io.vertx.core.json.pointer.JsonPointer#queryJson(java.lang.Object)} to query
|
||||
a JSON value. You can update a Json Value using {@link io.vertx.core.json.pointer.JsonPointer#writeJson(java.lang.Object, java.lang.Object)}:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
{@link examples.JsonPointerExamples#example2Pointers}
|
||||
----
|
||||
|
||||
You can use Vert.x Json Pointer with any object model by providing a custom implementation of {@link io.vertx.core.json.pointer.JsonPointerIterator}
|
||||
@@ -14,8 +14,10 @@ package docoverride.json;
|
||||
import io.vertx.core.http.HttpServerRequest;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.json.pointer.JsonPointer;
|
||||
import io.vertx.docgen.Source;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -80,7 +82,4 @@ public class Examples {
|
||||
Boolean boolVal = array.getBoolean(2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
31
src/main/java/examples/JsonPointerExamples.java
Normal file
31
src/main/java/examples/JsonPointerExamples.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package examples;
|
||||
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.json.pointer.JsonPointer;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class JsonPointerExamples {
|
||||
|
||||
public void example1Pointers() {
|
||||
// Build a pointer from a string
|
||||
JsonPointer pointer1 = JsonPointer.from("/hello/world");
|
||||
// Build a pointer manually
|
||||
JsonPointer pointer2 = JsonPointer.create()
|
||||
.append("hello")
|
||||
.append("world");
|
||||
}
|
||||
|
||||
public void example2Pointers(JsonPointer objectPointer, JsonObject jsonObject, JsonPointer arrayPointer, JsonArray jsonArray) {
|
||||
// Query a JsonObject
|
||||
Object result1 = objectPointer.queryJson(jsonObject);
|
||||
// Query a JsonArray
|
||||
Object result2 = arrayPointer.queryJson(jsonArray);
|
||||
// Write starting from a JsonObject
|
||||
objectPointer.writeJson(jsonObject, "new element");
|
||||
// Write starting from a JsonObject
|
||||
arrayPointer.writeJson(jsonArray, "new element");
|
||||
}
|
||||
|
||||
}
|
||||
241
src/main/java/io/vertx/core/json/pointer/JsonPointer.java
Normal file
241
src/main/java/io/vertx/core/json/pointer/JsonPointer.java
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2017 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
*/
|
||||
|
||||
package io.vertx.core.json.pointer;
|
||||
|
||||
import io.vertx.codegen.annotations.Fluent;
|
||||
import io.vertx.codegen.annotations.GenIgnore;
|
||||
import io.vertx.codegen.annotations.Nullable;
|
||||
import io.vertx.codegen.annotations.VertxGen;
|
||||
import io.vertx.core.json.pointer.impl.JsonPointerImpl;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Implementation of <a href="https://tools.ietf.org/html/rfc6901">RFC6901 Json Pointers</a>.
|
||||
*
|
||||
* @author Francesco Guardiani <a href="https://slinkydeveloper.github.io/">@slinkydeveloper</a>
|
||||
*/
|
||||
@VertxGen
|
||||
public interface JsonPointer {
|
||||
|
||||
/**
|
||||
* Return {@code true} if the pointer is a root pointer
|
||||
*/
|
||||
boolean isRootPointer();
|
||||
|
||||
/**
|
||||
* Return {@code true} if the pointer is local (URI with only fragment)
|
||||
*/
|
||||
boolean isLocalPointer();
|
||||
|
||||
/**
|
||||
* Return {@code true} if this pointer is a parent pointer of {@code child}.
|
||||
* <br/>
|
||||
* For instance {@code "/properties"} pointer is parent pointer of {@code "/properties/parent"}
|
||||
*
|
||||
* @param child
|
||||
*/
|
||||
boolean isParent(JsonPointer child);
|
||||
|
||||
/**
|
||||
* Build a <a href="https://tools.ietf.org/html/rfc6901#section-5">string representation</a> of the JSON Pointer
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* Build a <a href="https://tools.ietf.org/html/rfc6901#section-6">URI representation</a> of the JSON Pointer
|
||||
*/
|
||||
@GenIgnore(GenIgnore.PERMITTED_TYPE)
|
||||
URI toURI();
|
||||
|
||||
/**
|
||||
* Return the underlying URI without the fragment
|
||||
*/
|
||||
@GenIgnore(GenIgnore.PERMITTED_TYPE)
|
||||
URI getURIWithoutFragment();
|
||||
|
||||
/**
|
||||
* Append an unescaped {@code token} to this pointer <br/>
|
||||
* Note: If you provide escaped path the behaviour is undefined
|
||||
*
|
||||
* @param token the unescaped reference token
|
||||
* @return a reference to this, so the API can be used fluently
|
||||
*/
|
||||
@Fluent
|
||||
JsonPointer append(String token);
|
||||
|
||||
/**
|
||||
* Append the {@code index} as reference token to JsonPointer
|
||||
*
|
||||
* @param index
|
||||
* @return a reference to this, so the API can be used fluently
|
||||
*/
|
||||
@Fluent
|
||||
JsonPointer append(int index);
|
||||
|
||||
/**
|
||||
* Append an unescaped list of {@code tokens} to JsonPointer <br/>
|
||||
* Note: If you provide escaped paths the behaviour is undefined
|
||||
*
|
||||
* @param tokens unescaped reference tokens
|
||||
* @return a reference to this, so the API can be used fluently
|
||||
*/
|
||||
@Fluent
|
||||
JsonPointer append(List<String> tokens);
|
||||
|
||||
/**
|
||||
* Append all tokens of {@code pointer} to this pointer <br/>
|
||||
* Note: The base URI of this pointer will remain untouched
|
||||
*
|
||||
* @param pointer other pointer
|
||||
* @return a reference to this, so the API can be used fluently
|
||||
*/
|
||||
@Fluent
|
||||
JsonPointer append(JsonPointer pointer);
|
||||
|
||||
/**
|
||||
* Remove last reference token of this pointer
|
||||
*
|
||||
* @return a reference to this, so the API can be used fluently
|
||||
*/
|
||||
@Fluent
|
||||
JsonPointer parent();
|
||||
|
||||
/**
|
||||
* Query {@code objectToQuery} using the provided {@link JsonPointerIterator}. <br/>
|
||||
* If you need to query Vert.x json data structures, use {@link JsonPointer#queryJson(Object)}<br/>
|
||||
* Note: if this pointer is a root pointer, this function returns the provided object
|
||||
*
|
||||
* @param objectToQuery the object to query
|
||||
* @param iterator the json pointer iterator that provides the logic to access to the objectToQuery
|
||||
* @return null if pointer points to not existing value, otherwise the requested value
|
||||
*/
|
||||
default @Nullable Object query(Object objectToQuery, JsonPointerIterator iterator) { return queryOrDefault(objectToQuery, iterator, null); }
|
||||
|
||||
/**
|
||||
* Query {@code objectToQuery} using the provided {@link JsonPointerIterator}. If the query result is null, returns the default. <br/>
|
||||
* If you need to query Vert.x json data structures, use {@link JsonPointer#queryJsonOrDefault(Object, Object)}<br/>
|
||||
* Note: if this pointer is a root pointer, this function returns the provided object
|
||||
*
|
||||
* @param objectToQuery the object to query
|
||||
* @param iterator the json pointer iterator that provides the logic to access to the objectToQuery
|
||||
* @param defaultValue default value if query result is null
|
||||
* @return null if pointer points to not existing value, otherwise the requested value
|
||||
*/
|
||||
Object queryOrDefault(Object objectToQuery, JsonPointerIterator iterator, Object defaultValue);
|
||||
|
||||
/**
|
||||
* Query {@code jsonElement}. <br/>
|
||||
* Note: if this pointer is a root pointer, this function returns the provided json element
|
||||
*
|
||||
* @param jsonElement the json element to query
|
||||
* @return null if pointer points to not existing value, otherwise the requested value
|
||||
*/
|
||||
default @Nullable Object queryJson(Object jsonElement) {return query(jsonElement, JsonPointerIterator.JSON_ITERATOR); }
|
||||
|
||||
/**
|
||||
* Query {@code jsonElement}. If the query result is null, returns the default.<br/>
|
||||
* Note: if this pointer is a root pointer, this function returns the provided object
|
||||
*
|
||||
* @param jsonElement the json element to query
|
||||
* @param defaultValue default value if query result is null
|
||||
* @return null if pointer points to not existing value, otherwise the requested value
|
||||
*/
|
||||
default @Nullable Object queryJsonOrDefault(Object jsonElement, Object defaultValue) {return queryOrDefault(jsonElement, JsonPointerIterator.JSON_ITERATOR, defaultValue); }
|
||||
|
||||
/**
|
||||
* Query {@code objectToQuery} tracing each element walked during the query, including the first and the result (if any).<br/>
|
||||
* The first element of the list is objectToQuery and the last is the result, or the element before the first null was encountered
|
||||
*
|
||||
* @param objectToQuery the object to query
|
||||
* @param iterator the json pointer iterator that provides the logic to access to the objectToQuery
|
||||
* @return the stream of walked elements
|
||||
*/
|
||||
List<Object> tracedQuery(Object objectToQuery, JsonPointerIterator iterator);
|
||||
|
||||
/**
|
||||
* Write {@code newElement} in {@code objectToWrite} using this pointer. The path token "-" is handled as append to end of array <br/>
|
||||
* If you need to write in Vert.x json data structures, use {@link JsonPointer#writeJson(Object, Object)} (Object)}<br/>
|
||||
*
|
||||
* @param objectToWrite object to write
|
||||
* @param iterator the json pointer iterator that provides the logic to access to the objectToMutate
|
||||
* @param newElement object to insert
|
||||
* @param createOnMissing create objects when missing a object key or an array index
|
||||
* @return a reference to objectToWrite if the write was completed, a reference to newElement if the pointer is a root pointer, null if the write failed
|
||||
*/
|
||||
Object write(Object objectToWrite, JsonPointerIterator iterator, Object newElement, boolean createOnMissing);
|
||||
|
||||
/**
|
||||
* Write {@code newElement} in {@code jsonElement} using this pointer. The path token "-" is handled as append to end of array.
|
||||
*
|
||||
* @param jsonElement json element to query and write
|
||||
* @param newElement json to insert
|
||||
* @return a reference to json if the write was completed, a reference to newElement if the pointer is a root pointer, null if the write failed
|
||||
*/
|
||||
default Object writeJson(Object jsonElement, Object newElement) { return writeJson(jsonElement, newElement, false); }
|
||||
|
||||
/**
|
||||
* Write {@code newElement} in {@code jsonElement} using this pointer. The path token "-" is handled as append to end of array.
|
||||
*
|
||||
* @param jsonElement json to query and write
|
||||
* @param newElement json to insert
|
||||
* @param createOnMissing create JsonObject when missing a object key or an array index
|
||||
* @return a reference to json if the write was completed, a reference to newElement if the pointer is a root pointer, null if the write failed
|
||||
*/
|
||||
default Object writeJson(Object jsonElement, Object newElement, boolean createOnMissing) {
|
||||
return write(jsonElement, JsonPointerIterator.JSON_ITERATOR, newElement, createOnMissing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a JsonPointer
|
||||
*
|
||||
* @return a copy of this pointer
|
||||
*/
|
||||
JsonPointer copy();
|
||||
|
||||
/**
|
||||
* Build an empty JsonPointer
|
||||
*
|
||||
* @return a new empty JsonPointer
|
||||
*/
|
||||
static JsonPointer create() {
|
||||
return new JsonPointerImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a JsonPointer from a json pointer string
|
||||
*
|
||||
* @param pointer the string representing a pointer
|
||||
* @return new instance of JsonPointer
|
||||
* @throws IllegalArgumentException if the pointer provided is not valid
|
||||
*/
|
||||
static JsonPointer from(String pointer) {
|
||||
return new JsonPointerImpl(pointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a JsonPointer from a URI.
|
||||
*
|
||||
* @param uri uri representing a json pointer
|
||||
* @return new instance of JsonPointer
|
||||
* @throws IllegalArgumentException if the pointer provided is not valid
|
||||
*/
|
||||
@GenIgnore(GenIgnore.PERMITTED_TYPE)
|
||||
static JsonPointer fromURI(URI uri) {
|
||||
return new JsonPointerImpl(uri);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package io.vertx.core.json.pointer;
|
||||
|
||||
import io.vertx.codegen.annotations.Nullable;
|
||||
import io.vertx.codegen.annotations.VertxGen;
|
||||
import io.vertx.core.json.pointer.impl.JsonPointerIteratorImpl;
|
||||
|
||||
/**
|
||||
* The JsonPointerIterator is used by the read/write algorithms of the {@link JsonPointer} to read/write the querying data structure <br/>
|
||||
*
|
||||
* Every method takes the currentValue as parameter, representing the actual value held by the query algorithm.<br/>
|
||||
*
|
||||
* Implementations of this interface should be stateless, so they can be reused<br/>
|
||||
*
|
||||
* You can implement this interface to query the structure you want using json pointers
|
||||
*
|
||||
* @author Francesco Guardiani <a href="https://slinkydeveloper.github.io/">@slinkydeveloper</a>
|
||||
*
|
||||
*/
|
||||
@VertxGen
|
||||
public interface JsonPointerIterator {
|
||||
|
||||
/**
|
||||
* @param currentValue
|
||||
* @return {@code true} if the current value is a queryable object
|
||||
*/
|
||||
boolean isObject(@Nullable Object currentValue);
|
||||
|
||||
/**
|
||||
* @param currentValue
|
||||
* @return {@code true} if the current value is a queryable array
|
||||
*/
|
||||
boolean isArray(@Nullable Object currentValue);
|
||||
|
||||
/**
|
||||
* @param currentValue
|
||||
* @return {@code true} if the current value is null/empty
|
||||
*/
|
||||
boolean isNull(@Nullable Object currentValue);
|
||||
|
||||
/**
|
||||
* @param currentValue
|
||||
* @param key object key
|
||||
* @return {@code true} if current value is a queryable object that contains the specified key
|
||||
*/
|
||||
boolean objectContainsKey(@Nullable Object currentValue, String key);
|
||||
|
||||
/**
|
||||
* Returns the object parameter with specified key.
|
||||
*
|
||||
* @param currentValue
|
||||
* @param key object key
|
||||
* @param createOnMissing If the current value is an object that doesn't contain the key, put an empty object at provided key
|
||||
* @return the requested object parameter, or null if the method was not able to find it
|
||||
*/
|
||||
Object getObjectParameter(@Nullable Object currentValue, String key, boolean createOnMissing);
|
||||
|
||||
/**
|
||||
* Move the iterator the the array element at specified index
|
||||
*
|
||||
* @param currentValue
|
||||
* @param i array index
|
||||
* @return the request array element, or null if the method was not able to find it
|
||||
*/
|
||||
Object getArrayElement(@Nullable Object currentValue, int i);
|
||||
|
||||
/**
|
||||
* Write object parameter at specified key
|
||||
*
|
||||
* @param currentValue
|
||||
* @param key
|
||||
* @param value
|
||||
* @return true if the operation is successful
|
||||
*/
|
||||
boolean writeObjectParameter(@Nullable Object currentValue, String key, @Nullable Object value);
|
||||
|
||||
/**
|
||||
* Write array element at specified index
|
||||
*
|
||||
* @param currentValue
|
||||
* @param i
|
||||
* @param value
|
||||
* @return true if the operation is successful
|
||||
*/
|
||||
boolean writeArrayElement(@Nullable Object currentValue, int i, @Nullable Object value);
|
||||
|
||||
/**
|
||||
* Append array element
|
||||
*
|
||||
* @param currentValue
|
||||
* @param value
|
||||
* @return true if the operation is successful
|
||||
*/
|
||||
boolean appendArrayElement(@Nullable Object currentValue, @Nullable Object value);
|
||||
|
||||
/**
|
||||
* Instance of a JsonPointerIterator to query Vert.x Json structures
|
||||
*/
|
||||
JsonPointerIterator JSON_ITERATOR = new JsonPointerIteratorImpl();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2017 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
*/
|
||||
|
||||
package io.vertx.core.json.pointer.impl;
|
||||
|
||||
import io.vertx.core.json.pointer.JsonPointer;
|
||||
import io.vertx.core.json.pointer.JsonPointerIterator;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Francesco Guardiani @slinkydeveloper
|
||||
*/
|
||||
public class JsonPointerImpl implements JsonPointer {
|
||||
|
||||
final public static Pattern VALID_POINTER_PATTERN = Pattern.compile("^(/(([^/~])|(~[01]))*)*$");
|
||||
|
||||
URI startingUri;
|
||||
|
||||
// Empty means a pointer to root
|
||||
List<String> decodedTokens;
|
||||
|
||||
public JsonPointerImpl(URI uri) {
|
||||
this.startingUri = removeFragment(uri);
|
||||
this.decodedTokens = parse(uri.getFragment());
|
||||
}
|
||||
|
||||
public JsonPointerImpl(String pointer) {
|
||||
this.startingUri = URI.create("#");
|
||||
this.decodedTokens = parse(pointer);
|
||||
}
|
||||
|
||||
public JsonPointerImpl() {
|
||||
this.startingUri = URI.create("#");
|
||||
this.decodedTokens = parse(null);
|
||||
}
|
||||
|
||||
protected JsonPointerImpl(URI startingUri, List<String> decodedTokens) {
|
||||
this.startingUri = startingUri;
|
||||
this.decodedTokens = new ArrayList<>(decodedTokens);
|
||||
}
|
||||
|
||||
private ArrayList<String> parse(String pointer) {
|
||||
if (pointer == null || "".equals(pointer)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
if (VALID_POINTER_PATTERN.matcher(pointer).matches()) {
|
||||
return Arrays
|
||||
.stream(pointer.split("\\/", -1))
|
||||
.skip(1) //Ignore first element
|
||||
.map(this::unescape)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
} else
|
||||
throw new IllegalArgumentException("The provided pointer is not a valid JSON Pointer");
|
||||
}
|
||||
|
||||
private String escape(String path) {
|
||||
return path.replace("~", "~0")
|
||||
.replace("/", "~1");
|
||||
}
|
||||
|
||||
private String unescape(String path) {
|
||||
return path.replace("~1", "/") // https://tools.ietf.org/html/rfc6901#section-4
|
||||
.replace("~0", "~");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRootPointer() {
|
||||
return decodedTokens.size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocalPointer() {
|
||||
return startingUri == null || startingUri.getSchemeSpecificPart() == null || startingUri.getSchemeSpecificPart().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParent(JsonPointer c) {
|
||||
JsonPointerImpl child = (JsonPointerImpl) c;
|
||||
return child != null &&
|
||||
(child.getURIWithoutFragment() == null && this.getURIWithoutFragment() == null || child.getURIWithoutFragment().equals(this.getURIWithoutFragment())) &&
|
||||
decodedTokens.size() < child.decodedTokens.size() &&
|
||||
IntStream.range(0, decodedTokens.size())
|
||||
.mapToObj(i -> this.decodedTokens.get(i).equals(child.decodedTokens.get(i)))
|
||||
.reduce(Boolean::logicalAnd).orElse(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isRootPointer())
|
||||
return "";
|
||||
else
|
||||
return "/" + String.join("/", decodedTokens.stream().map(this::escape).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI toURI() {
|
||||
if (isRootPointer()) {
|
||||
return replaceFragment(this.startingUri, "");
|
||||
} else
|
||||
return replaceFragment(
|
||||
this.startingUri,
|
||||
"/" + String.join("/", decodedTokens.stream().map(this::escape).collect(Collectors.toList()))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURIWithoutFragment() {
|
||||
return startingUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPointer append(String path) {
|
||||
decodedTokens.add(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPointer append(int i) {
|
||||
return this.append(Integer.toString(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPointer append(List<String> paths) {
|
||||
decodedTokens.addAll(paths);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPointer append(JsonPointer pointer) {
|
||||
decodedTokens.addAll(((JsonPointerImpl)pointer).decodedTokens);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPointer parent() {
|
||||
if (!this.isRootPointer()) decodedTokens.remove(decodedTokens.size() - 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPointer copy() {
|
||||
return new JsonPointerImpl(this.startingUri, this.decodedTokens);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
JsonPointerImpl that = (JsonPointerImpl) o;
|
||||
return Objects.equals(startingUri, that.startingUri) &&
|
||||
Objects.equals(decodedTokens, that.decodedTokens);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(startingUri, decodedTokens);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object queryOrDefault(Object value, JsonPointerIterator iterator, Object defaultValue) {
|
||||
// I should threat this as a special condition because the empty string can be a json obj key!
|
||||
if (isRootPointer())
|
||||
return (iterator.isNull(value)) ? defaultValue : value;
|
||||
else {
|
||||
value = walkTillLastElement(value, iterator, false, null);
|
||||
String lastKey = decodedTokens.get(decodedTokens.size() - 1);
|
||||
if (iterator.isObject(value)) {
|
||||
Object finalValue = iterator.getObjectParameter(value, lastKey, false);
|
||||
return (!iterator.isNull(finalValue)) ? finalValue : defaultValue;
|
||||
} else if (iterator.isArray(value) && !"-".equals(lastKey)) {
|
||||
try {
|
||||
Object finalValue = iterator.getArrayElement(value, Integer.parseInt(lastKey));
|
||||
return (!iterator.isNull(finalValue)) ? finalValue : defaultValue;
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
} else
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> tracedQuery(Object objectToQuery, JsonPointerIterator iterator) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
if (isRootPointer() && !iterator.isNull(objectToQuery))
|
||||
list.add(objectToQuery);
|
||||
else {
|
||||
Object lastValue = walkTillLastElement(objectToQuery, iterator, false, list::add);
|
||||
if (!iterator.isNull(lastValue))
|
||||
list.add(lastValue);
|
||||
String lastKey = decodedTokens.get(decodedTokens.size() - 1);
|
||||
if (iterator.isObject(lastValue)) {
|
||||
lastValue = iterator.getObjectParameter(lastValue, lastKey, false);
|
||||
} else if (iterator.isArray(lastValue) && !"-".equals(lastKey)) {
|
||||
try {
|
||||
lastValue = iterator.getArrayElement(lastValue, Integer.parseInt(lastKey));
|
||||
} catch (NumberFormatException e) { }
|
||||
}
|
||||
if (!iterator.isNull(lastValue))
|
||||
list.add(lastValue);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object write(Object valueToWrite, JsonPointerIterator iterator, Object newElement, boolean createOnMissing) {
|
||||
if (isRootPointer()) {
|
||||
return iterator.isNull(valueToWrite) ? null : newElement;
|
||||
} else {
|
||||
Object walkedValue = walkTillLastElement(valueToWrite, iterator, createOnMissing, null);
|
||||
if (writeLastElement(walkedValue, iterator, newElement))
|
||||
return valueToWrite;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Object walkTillLastElement(Object value, JsonPointerIterator iterator, boolean createOnMissing, Consumer<Object> onNewValue) {
|
||||
for (int i = 0; i < decodedTokens.size() - 1; i++) {
|
||||
String k = decodedTokens.get(i);
|
||||
if (i == 0 && "".equals(k)) {
|
||||
continue; // Avoid errors with root empty string
|
||||
} else if (iterator.isObject(value)) {
|
||||
if (onNewValue != null) onNewValue.accept(value);
|
||||
value = iterator.getObjectParameter(value, k, createOnMissing);
|
||||
} else if (iterator.isArray(value)) {
|
||||
if (onNewValue != null) onNewValue.accept(value);
|
||||
try {
|
||||
value = iterator.getArrayElement(value, Integer.parseInt(k));
|
||||
if (iterator.isNull(value) && createOnMissing) {
|
||||
value = iterator.getObjectParameter(value, k, true);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
value = null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean writeLastElement(Object valueToWrite, JsonPointerIterator iterator, Object newElement) {
|
||||
String lastKey = decodedTokens.get(decodedTokens.size() - 1);
|
||||
if (iterator.isObject(valueToWrite)) {
|
||||
return iterator.writeObjectParameter(valueToWrite, lastKey, newElement);
|
||||
} else if (iterator.isArray(valueToWrite)) {
|
||||
if ("-".equals(lastKey)) { // Append to end
|
||||
return iterator.appendArrayElement(valueToWrite, newElement);
|
||||
} else { // We have a index
|
||||
try {
|
||||
return iterator.writeArrayElement(valueToWrite, Integer.parseInt(lastKey), newElement);
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
private URI removeFragment(URI oldURI) {
|
||||
return replaceFragment(oldURI, null);
|
||||
}
|
||||
|
||||
private URI replaceFragment(URI oldURI, String fragment) {
|
||||
try {
|
||||
if (oldURI != null) {
|
||||
return new URI(oldURI.getScheme(), oldURI.getSchemeSpecificPart(), fragment);
|
||||
} else return new URI(null, null, fragment);
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package io.vertx.core.json.pointer.impl;
|
||||
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.json.pointer.JsonPointerIterator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class JsonPointerIteratorImpl implements JsonPointerIterator {
|
||||
|
||||
@Override
|
||||
public boolean isObject(Object value) {
|
||||
return value instanceof JsonObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isArray(Object value) {
|
||||
return value instanceof JsonArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNull(Object value) {
|
||||
return value == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean objectContainsKey(Object value, String key) {
|
||||
return isObject(value) && ((JsonObject)value).containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectParameter(Object value, String key, boolean createOnMissing) {
|
||||
if (isObject(value)) {
|
||||
if (!objectContainsKey(value, key)) {
|
||||
if (createOnMissing) {
|
||||
writeObjectParameter(value, key, new JsonObject());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return jsonifyValue(((JsonObject) value).getValue(key));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getArrayElement(Object value, int i) {
|
||||
if (isArray(value)) {
|
||||
try {
|
||||
return jsonifyValue(((JsonArray)value).getValue(i));
|
||||
} catch (IndexOutOfBoundsException ignored) {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeObjectParameter(Object value, String key, Object el) {
|
||||
if (isObject(value)) {
|
||||
((JsonObject)value).put(key, el);
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean writeArrayElement(Object value, int i, Object el) {
|
||||
if (isArray(value)) {
|
||||
try {
|
||||
((JsonArray)value).getList().add(i, el);
|
||||
return true;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return false;
|
||||
}
|
||||
} else return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appendArrayElement(Object value, Object el) {
|
||||
if (isArray(value)) {
|
||||
((JsonArray)value).add(el);
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object jsonifyValue(Object v) {
|
||||
if (v instanceof Map) return new JsonObject((Map<String, Object>)v);
|
||||
else if (v instanceof List) return new JsonArray((List)v);
|
||||
else return v;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2017 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
*/
|
||||
package io.vertx.core.json.pointer.impl;
|
||||
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.json.pointer.JsonPointer;
|
||||
import io.vertx.core.json.pointer.JsonPointerIterator;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Francesco Guardiani @slinkydeveloper
|
||||
*/
|
||||
public class JsonPointerTest {
|
||||
|
||||
@Test
|
||||
public void testParsing() {
|
||||
JsonPointer pointer = JsonPointer.from("/hello/world");
|
||||
assertEquals("/hello/world", pointer.toString());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParsingErrorWrongFirstElement() {
|
||||
JsonPointer.from("bla/hello/world");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodingParsing() {
|
||||
JsonPointer pointer = JsonPointer.create().append("hell/o").append("worl~d");
|
||||
assertEquals("/hell~1o/worl~0d", pointer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURIParsing() {
|
||||
JsonPointer pointer = JsonPointer.fromURI(URI.create("http://www.example.org#/hello/world"));
|
||||
assertEquals("/hello/world", pointer.toString());
|
||||
assertEquals(URI.create("http://www.example.org#/hello/world"), pointer.toURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURIEncodedParsing() {
|
||||
JsonPointer pointer = JsonPointer.fromURI(URI.create("http://www.example.org#/hello/world/%5Ea"));
|
||||
assertEquals("/hello/world/^a", pointer.toString());
|
||||
assertEquals(URI.create("http://www.example.org#/hello/world/%5Ea"), pointer.toURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURIJsonPointerEncodedParsing() {
|
||||
JsonPointer pointer = JsonPointer.fromURI(URI.create("http://www.example.org#/hell~1o/worl~0d"));
|
||||
assertEquals("/hell~1o/worl~0d", pointer.toString());
|
||||
assertEquals(URI.create("http://www.example.org#/hell~1o/worl~0d"), pointer.toURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuilding() {
|
||||
List<String> keys = new ArrayList<>();
|
||||
keys.add("hello");
|
||||
keys.add("world");
|
||||
JsonPointer pointer = new JsonPointerImpl(URI.create("#"), keys);
|
||||
assertEquals("/hello/world", pointer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURIBuilding() {
|
||||
JsonPointer pointer = JsonPointer.create().append("hello").append("world");
|
||||
assertEquals(URI.create("#/hello/world"), pointer.toURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyBuilding() {
|
||||
JsonPointer pointer = JsonPointer.create();
|
||||
assertEquals("", pointer.toString());
|
||||
assertEquals(URI.create("#"), pointer.toURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppendOtherPointer() {
|
||||
JsonPointer firstPointer = JsonPointer.fromURI(URI.create("http://example.com/stuff.json#/hello")).append("world");
|
||||
JsonPointer otherPointer = JsonPointer.fromURI(URI.create("http://example.com/other.json#/francesco"));
|
||||
firstPointer.append(otherPointer);
|
||||
assertEquals(URI.create("http://example.com/stuff.json#/hello/world/francesco"), firstPointer.toURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullQuerying() {
|
||||
JsonPointer pointer = JsonPointer.from("/hello/world");
|
||||
assertNull(pointer.queryJson(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullQueryingRootPointer() {
|
||||
JsonPointer pointer = JsonPointer.create();
|
||||
assertNull(pointer.queryJson(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullQueryingRootPointerDefault() {
|
||||
JsonPointer pointer = JsonPointer.create();
|
||||
assertEquals(1, pointer.queryJsonOrDefault(null, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonObjectQuerying() {
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
JsonPointer pointer = JsonPointer.from("/hello/world");
|
||||
assertEquals(1, pointer.queryJson(obj));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonObjectQueryingDefaultValue() {
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
JsonPointer pointer = JsonPointer.from("/hello/world/my/friend");
|
||||
assertEquals(1, pointer.queryJsonOrDefault(obj, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonArrayQuerying() {
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 2).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
));
|
||||
array.add(new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
));
|
||||
assertEquals(1, JsonPointer.from("/1/hello/world").queryJson(array));
|
||||
assertEquals(1, JsonPointer.fromURI(URI.create("#/1/hello/world")).queryJson(array));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonArrayQueryingOrDefault() {
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 2).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
));
|
||||
array.add(new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
));
|
||||
assertEquals(1, JsonPointer.from("/5/hello/world").queryJsonOrDefault(array, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRootPointer() {
|
||||
JsonPointer pointer = JsonPointer.create();
|
||||
JsonArray array = new JsonArray();
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 2).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
array.add(obj);
|
||||
array.add(new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
));
|
||||
|
||||
assertEquals(array, pointer.queryJson(array));
|
||||
assertEquals(obj, pointer.queryJson(obj));
|
||||
assertEquals("hello", pointer.queryJson("hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRootPointerWrite() {
|
||||
JsonPointer pointer = JsonPointer.create();
|
||||
JsonObject obj = new JsonObject();
|
||||
JsonArray arr = new JsonArray();
|
||||
assertSame(arr, pointer.writeJson(obj, arr, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongUsageOfDashForQuerying() {
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 2).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
));
|
||||
array.add(new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
));
|
||||
JsonPointer pointer = JsonPointer.from("/-/hello/world");
|
||||
assertNull(pointer.queryJson(array));
|
||||
}
|
||||
|
||||
/*
|
||||
The following JSON strings evaluate to the accompanying values:
|
||||
|
||||
"" // the whole document
|
||||
"/foo" ["bar", "baz"]
|
||||
"/foo/0" "bar"
|
||||
"/" 0
|
||||
"/a~1b" 1
|
||||
"/c%d" 2
|
||||
"/e^f" 3
|
||||
"/g|h" 4
|
||||
"/i\\j" 5
|
||||
"/k\"l" 6
|
||||
"/ " 7
|
||||
"/m~0n" 8
|
||||
|
||||
*/
|
||||
@Test
|
||||
public void testRFCExample() {
|
||||
JsonObject obj = new JsonObject(" {\n" +
|
||||
" \"foo\": [\"bar\", \"baz\"],\n" +
|
||||
" \"\": 0,\n" +
|
||||
" \"a/b\": 1,\n" +
|
||||
" \"c%d\": 2,\n" +
|
||||
" \"e^f\": 3,\n" +
|
||||
" \"g|h\": 4,\n" +
|
||||
" \"i\\\\j\": 5,\n" +
|
||||
" \"k\\\"l\": 6,\n" +
|
||||
" \" \": 7,\n" +
|
||||
" \"m~n\": 8\n" +
|
||||
" }");
|
||||
|
||||
assertEquals(obj, JsonPointer.from("").queryJson(obj));
|
||||
assertEquals(obj.getJsonArray("foo"), JsonPointer.from("/foo").queryJson(obj));
|
||||
assertEquals(obj.getJsonArray("foo").getString(0), JsonPointer.from("/foo/0").queryJson(obj));
|
||||
assertEquals(obj.getInteger(""), JsonPointer.from("/").queryJson(obj));
|
||||
assertEquals(obj.getInteger("a/b"), JsonPointer.from("/a~1b").queryJson(obj));
|
||||
assertEquals(obj.getInteger("c%d"), JsonPointer.from("/c%d").queryJson(obj));
|
||||
assertEquals(obj.getInteger("e^f"), JsonPointer.from("/e^f").queryJson(obj));
|
||||
assertEquals(obj.getInteger("g|h"), JsonPointer.from("/g|h").queryJson(obj));
|
||||
assertEquals(obj.getInteger("i\\\\j"), JsonPointer.from("/i\\\\j").queryJson(obj));
|
||||
assertEquals(obj.getInteger("k\\\"l"), JsonPointer.from("/k\\\"l").queryJson(obj));
|
||||
assertEquals(obj.getInteger(" "), JsonPointer.from("/ ").queryJson(obj));
|
||||
assertEquals(obj.getInteger("m~n"), JsonPointer.from("/m~0n").queryJson(obj));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteJsonObject() {
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
Object toInsert = new JsonObject().put("github", "slinkydeveloper");
|
||||
assertEquals(obj, JsonPointer.from("/hello/francesco").writeJson(obj, toInsert));
|
||||
assertEquals(toInsert, JsonPointer.from("/hello/francesco").queryJson(obj));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteWithCreateOnMissingJsonObject() {
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
Object toInsert = new JsonObject().put("github", "slinkydeveloper");
|
||||
assertEquals(obj, JsonPointer.from("/hello/users/francesco").write(obj, JsonPointerIterator.JSON_ITERATOR, toInsert, true));
|
||||
assertEquals(toInsert, JsonPointer.from("/hello/users/francesco").queryJson(obj));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteJsonObjectOverride() {
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
Object toInsert = new JsonObject().put("github", "slinkydeveloper");
|
||||
assertEquals(obj, JsonPointer.from("/hello/world").writeJson(obj, toInsert));
|
||||
assertEquals(toInsert, JsonPointer.from("/hello/world").queryJson(obj));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteJsonArray() {
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", new JsonObject()).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(obj.copy());
|
||||
array.add(obj.copy());
|
||||
Object toInsert = new JsonObject().put("github", "slinkydeveloper");
|
||||
assertEquals(array, JsonPointer.from("/0/hello/world/francesco").writeJson(array, toInsert));
|
||||
assertEquals(toInsert, JsonPointer.from("/0/hello/world/francesco").queryJson(array));
|
||||
assertNotEquals(array.getValue(0), array.getValue(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteJsonArrayAppend() {
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(obj.copy());
|
||||
array.add(obj.copy());
|
||||
Object toInsert = new JsonObject().put("github", "slinkydeveloper");
|
||||
assertEquals(array, JsonPointer.from("/-").writeJson(array, toInsert));
|
||||
assertEquals(toInsert, JsonPointer.from("/2").queryJson(array));
|
||||
assertEquals(array.getValue(0), array.getValue(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteJsonArraySubstitute() {
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(obj.copy());
|
||||
array.add(obj.copy());
|
||||
Object toInsert = new JsonObject().put("github", "slinkydeveloper");
|
||||
assertEquals(array, JsonPointer.from("/0").writeJson(array, toInsert));
|
||||
assertEquals(toInsert, JsonPointer.from("/0").queryJson(array));
|
||||
assertNotEquals(array.getValue(0), array.getValue(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedWriteJsonArraySubstitute() {
|
||||
JsonObject obj = new JsonObject()
|
||||
.put("hello",
|
||||
new JsonObject().put("world", 1).put("worl", "wrong")
|
||||
).put("helo",
|
||||
new JsonObject().put("world", "wrong").put("worl", "wrong")
|
||||
);
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(obj.copy());
|
||||
array.add(obj.copy());
|
||||
JsonObject root = new JsonObject().put("array", array);
|
||||
|
||||
Object toInsert = new JsonObject().put("github", "slinkydeveloper");
|
||||
assertEquals(root, JsonPointer.from("/array/0").writeJson(root, toInsert));
|
||||
assertEquals(toInsert, JsonPointer.from("/array/0").queryJson(root));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsParent() {
|
||||
JsonPointer parent = JsonPointer.fromURI(URI.create("yaml/valid/refs/Circular.yaml#/properties"));
|
||||
JsonPointer child = JsonPointer.fromURI(URI.create("yaml/valid/refs/Circular.yaml#/properties/parent"));
|
||||
assertTrue(parent.isParent(child));
|
||||
assertFalse(child.isParent(parent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsParentDifferentURI() {
|
||||
JsonPointer parent = JsonPointer.fromURI(URI.create("yaml/valid/refs/Circular.yaml#/properties"));
|
||||
JsonPointer child = JsonPointer.fromURI(URI.create("json/valid/refs/Circular.yaml#/properties/parent"));
|
||||
assertFalse(parent.isParent(child));
|
||||
assertFalse(child.isParent(parent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsParentWithRootPointer() {
|
||||
JsonPointer parent = JsonPointer.fromURI(URI.create("yaml/valid/refs/Circular.yaml#"));
|
||||
JsonPointer child = JsonPointer.fromURI(URI.create("yaml/valid/refs/Circular.yaml#/properties/parent"));
|
||||
assertTrue(parent.isParent(child));
|
||||
assertFalse(child.isParent(parent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTracedQuery() {
|
||||
JsonObject child2 = new JsonObject().put("child3", 1);
|
||||
JsonArray child1 = new JsonArray().add(child2);
|
||||
JsonObject root = new JsonObject().put("child1", child1);
|
||||
|
||||
JsonPointer pointer = JsonPointer
|
||||
.create()
|
||||
.append("child1")
|
||||
.append("0")
|
||||
.append("child3");
|
||||
|
||||
List<Object> traced = pointer.tracedQuery(root, JsonPointerIterator.JSON_ITERATOR);
|
||||
assertEquals(4, traced.size());
|
||||
assertSame(root, traced.get(0));
|
||||
assertSame(child1, traced.get(1));
|
||||
assertSame(child2, traced.get(2));
|
||||
assertEquals(1, traced.get(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyTracedQuery() {
|
||||
JsonPointer pointer = JsonPointer
|
||||
.create()
|
||||
.append("child1")
|
||||
.append("0")
|
||||
.append("child3");
|
||||
|
||||
List<Object> traced = pointer.tracedQuery(null, JsonPointerIterator.JSON_ITERATOR);
|
||||
assertTrue(traced.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotFoundTracedQuery() {
|
||||
JsonObject child2 = new JsonObject().put("child5", 1);
|
||||
JsonArray child1 = new JsonArray().add(child2);
|
||||
JsonObject root = new JsonObject().put("child1", child1);
|
||||
|
||||
JsonPointer pointer = JsonPointer
|
||||
.create()
|
||||
.append("child1")
|
||||
.append("0")
|
||||
.append("child3");
|
||||
|
||||
List<Object> traced = pointer.tracedQuery(root, JsonPointerIterator.JSON_ITERATOR);
|
||||
assertEquals(3, traced.size());
|
||||
assertSame(root, traced.get(0));
|
||||
assertSame(child1, traced.get(1));
|
||||
assertSame(child2, traced.get(2));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user