Browse Source

Support write operations.

pull/59/head
Kalle Stenflo 10 years ago
parent
commit
4c886174ff
  1. 7
      changelog.md
  2. 18
      json-path/src/main/java/com/jayway/jsonpath/DocumentContext.java
  3. 14
      json-path/src/main/java/com/jayway/jsonpath/EvaluationListener.java
  4. 21
      json-path/src/main/java/com/jayway/jsonpath/InvalidModificationException.java
  5. 107
      json-path/src/main/java/com/jayway/jsonpath/JsonPath.java
  6. 13
      json-path/src/main/java/com/jayway/jsonpath/ParseContext.java
  7. 4
      json-path/src/main/java/com/jayway/jsonpath/ReadContext.java
  8. 73
      json-path/src/main/java/com/jayway/jsonpath/WriteContext.java
  9. 14
      json-path/src/main/java/com/jayway/jsonpath/internal/CompiledPath.java
  10. 3
      json-path/src/main/java/com/jayway/jsonpath/internal/EvaluationContext.java
  11. 38
      json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java
  12. 12
      json-path/src/main/java/com/jayway/jsonpath/internal/Path.java
  13. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java
  14. 239
      json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java
  15. 28
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/AbstractJsonProvider.java
  16. 21
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/GsonJsonProvider.java
  17. 1
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/JsonSmartJsonProvider.java
  18. 3
      json-path/src/main/java/com/jayway/jsonpath/internal/token/ArrayPathToken.java
  19. 32
      json-path/src/main/java/com/jayway/jsonpath/internal/token/EvaluationContextImpl.java
  20. 22
      json-path/src/main/java/com/jayway/jsonpath/internal/token/PathToken.java
  21. 8
      json-path/src/main/java/com/jayway/jsonpath/internal/token/PredicatePathToken.java
  22. 3
      json-path/src/main/java/com/jayway/jsonpath/internal/token/PropertyPathToken.java
  23. 8
      json-path/src/main/java/com/jayway/jsonpath/internal/token/RootPathToken.java
  24. 34
      json-path/src/main/java/com/jayway/jsonpath/internal/token/ScanPathToken.java
  25. 3
      json-path/src/main/java/com/jayway/jsonpath/internal/token/WildcardPathToken.java
  26. 17
      json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java
  27. 219
      json-path/src/test/java/com/jayway/jsonpath/WriteTest.java
  28. 6
      json-path/src/test/java/com/jayway/jsonpath/old/ArraySlicingTest.java

7
changelog.md

@ -3,8 +3,13 @@ In The Pipe
* Added EvaluationListener interface that allows abortion of evaluation if criteria is fulfilled.
this makes it possible to limit the number of results to fetch when a document is scanned. Also
added utility method to limit results `JsonPath.parse(json).limit(1).read("$..title", List.class);`
* Added support for OR in inline filters [?(@.foo == 'bar' || @.foo == 'baz')]
* Added support for OR in inline filters `[?(@.foo == 'bar' || @.foo == 'baz')]`
* Upgrade json-smart to 2.1.0
* Support for Update and Delete by path. **breaks JsonProvider SPI**
`parse(JSON_DOCUMENT).set("$.store.book[*].display-price", 1)`
`parse(JSON_DOCUMENT).put("$.store.book[1]", "new-key", "new-val")`
`parse(JSON_DOCUMENT).add("$.store.book", newBook)`
`parse(JSON_DOCUMENT).delete("$.store.book[1].display-price")`
1.1.0 (2014-10-01)

18
json-path/src/main/java/com/jayway/jsonpath/DocumentContext.java

@ -0,0 +1,18 @@
/*
* Copyright 2011 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jayway.jsonpath;
public interface DocumentContext extends ReadContext, WriteContext {
}

14
json-path/src/main/java/com/jayway/jsonpath/EvaluationListener.java

@ -1,3 +1,17 @@
/*
* Copyright 2011 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jayway.jsonpath;
/**

21
json-path/src/main/java/com/jayway/jsonpath/InvalidModificationException.java

@ -0,0 +1,21 @@
/*
* Copyright 2011 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jayway.jsonpath;
public class InvalidModificationException extends JsonPathException {
public InvalidModificationException(String message) {
super(message);
}
}

107
json-path/src/main/java/com/jayway/jsonpath/JsonPath.java

@ -15,9 +15,11 @@
package com.jayway.jsonpath;
import com.jayway.jsonpath.internal.EvaluationContext;
import com.jayway.jsonpath.internal.JsonReader;
import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.internal.PathCompiler;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.internal.Utils;
import com.jayway.jsonpath.spi.http.HttpProviderFactory;
import com.jayway.jsonpath.spi.json.JsonProvider;
@ -197,9 +199,74 @@ public class JsonPath {
return (T)(path.isDefinite() ? null : configuration.jsonProvider().createArray());
}
}
}
/**
* Set the value this path points to in the provided jsonObject
*
* @param jsonObject a json object
* @param configuration configuration to use
* @param <T> expected return type
* @return the updated jsonObject
*/
public <T> T set(Object jsonObject, Object newVal, Configuration configuration) {
EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true);
for (PathRef updateOperation : evaluationContext.updateOperations()) {
updateOperation.set(newVal, configuration);
}
return (T)jsonObject;
}
/**
* Deletes the object this path points to in the provided jsonObject
*
* @param jsonObject a json object
* @param configuration configuration to use
* @param <T> expected return type
* @return the updated jsonObject
*/
public <T> T delete(Object jsonObject, Configuration configuration) {
EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true);
for (PathRef updateOperation : evaluationContext.updateOperations()) {
updateOperation.delete(configuration);
}
return (T)jsonObject;
}
/**
* Adds a new value to the Array this path points to in the provided jsonObject
*
* @param jsonObject a json object
* @param value the value to add
* @param configuration configuration to use
* @param <T> expected return type
* @return the updated jsonObject
*/
public <T> T add(Object jsonObject, Object value, Configuration configuration) {
EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true);
for (PathRef updateOperation : evaluationContext.updateOperations()) {
updateOperation.add(value, configuration);
}
return (T)jsonObject;
}
/**
* Adds or updates the Object this path points to in the provided jsonObject with a key with a value
*
* @param jsonObject a json object
* @param value the key to add or update
* @param value the new value
* @param configuration configuration to use
* @param <T> expected return type
* @return the updated jsonObject
*/
public <T> T put(Object jsonObject, String key, Object value, Configuration configuration) {
EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true);
for (PathRef updateOperation : evaluationContext.updateOperations()) {
updateOperation.put(key, value, configuration);
}
return (T)jsonObject;
}
/**
* Applies this JsonPath to the provided json string
@ -482,111 +549,111 @@ public class JsonPath {
/**
* Parses the given JSON input using the default {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json input
* @return a read context
*/
public static ReadContext parse(Object json) {
public static DocumentContext parse(Object json) {
return new JsonReader().parse(json);
}
/**
* Parses the given JSON input using the default {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json string
* @return a read context
*/
public static ReadContext parse(String json) {
public static DocumentContext parse(String json) {
return new JsonReader().parse(json);
}
/**
* Parses the given JSON input using the default {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json stream
* @return a read context
*/
public static ReadContext parse(InputStream json) {
public static DocumentContext parse(InputStream json) {
return new JsonReader().parse(json);
}
/**
* Parses the given JSON input using the default {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json file
* @return a read context
*/
public static ReadContext parse(File json) throws IOException {
public static DocumentContext parse(File json) throws IOException {
return new JsonReader().parse(json);
}
/**
* Parses the given JSON input using the default {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json url
* @return a read context
*/
public static ReadContext parse(URL json) throws IOException {
public static DocumentContext parse(URL json) throws IOException {
return new JsonReader().parse(json);
}
/**
* Parses the given JSON input using the provided {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json input
* @return a read context
*/
public static ReadContext parse(Object json, Configuration configuration) {
public static DocumentContext parse(Object json, Configuration configuration) {
return new JsonReader(configuration).parse(json);
}
/**
* Parses the given JSON input using the provided {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json input
* @return a read context
*/
public static ReadContext parse(String json, Configuration configuration) {
public static DocumentContext parse(String json, Configuration configuration) {
return new JsonReader(configuration).parse(json);
}
/**
* Parses the given JSON input using the provided {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json input
* @return a read context
*/
public static ReadContext parse(InputStream json, Configuration configuration) {
public static DocumentContext parse(InputStream json, Configuration configuration) {
return new JsonReader(configuration).parse(json);
}
/**
* Parses the given JSON input using the provided {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json input
* @return a read context
*/
public static ReadContext parse(File json, Configuration configuration) throws IOException {
public static DocumentContext parse(File json, Configuration configuration) throws IOException {
return new JsonReader(configuration).parse(json);
}
/**
* Parses the given JSON input using the provided {@link Configuration} and
* returns a {@link ReadContext} for path evaluation
* returns a {@link DocumentContext} for path evaluation
*
* @param json input
* @return a read context
*/
public static ReadContext parse(URL json, Configuration configuration) throws IOException {
public static DocumentContext parse(URL json, Configuration configuration) throws IOException {
return new JsonReader(configuration).parse(json);
}
}

13
json-path/src/main/java/com/jayway/jsonpath/ParseContext.java

@ -21,15 +21,16 @@ import java.net.URL;
public interface ParseContext {
ReadContext parse(String json);
DocumentContext parse(String json);
ReadContext parse(Object json);
DocumentContext parse(Object json);
ReadContext parse(InputStream json);
DocumentContext parse(InputStream json);
ReadContext parse(InputStream json, String charset);
DocumentContext parse(InputStream json, String charset);
ReadContext parse(File json) throws IOException;
DocumentContext parse(File json) throws IOException;
ReadContext parse(URL json) throws IOException;
@Deprecated
DocumentContext parse(URL json) throws IOException;
}

4
json-path/src/main/java/com/jayway/jsonpath/ReadContext.java

@ -24,11 +24,11 @@ public interface ReadContext {
Configuration configuration();
/**
* Returns the JSON model that this context is reading
* Returns the JSON model that this context is operating on
*
* @return json model
*/
Object json();
<T> T json();
/**
* Reads the given path from this context

73
json-path/src/main/java/com/jayway/jsonpath/WriteContext.java

@ -0,0 +1,73 @@
/*
* Copyright 2011 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jayway.jsonpath;
public interface WriteContext {
/**
* Returns the configuration used for reading
*
* @return an immutable configuration
*/
Configuration configuration();
/**
* Returns the JSON model that this context is operating on
*
* @return json model
*/
<T> T json();
/**
* Set the value a the given path
*
* @param path path to set
* @param newValue new value
* @param filters filters
* @return a document context
*/
DocumentContext set(String path, Object newValue, Predicate... filters);
/**
* Deletes the given path
*
* @param path path to delete
* @param filters filters
* @return a document context
*/
DocumentContext delete(String path, Predicate... filters);
/**
* Add value to array at the given path
*
* @param path path to array
* @param value value to add
* @param filters filters
* @return a document context
*/
DocumentContext add(String path, Object value, Predicate... filters);
/**
* Add or update the key with a the given value at the given path
*
* @param path path to array
* @param key key to add
* @param value value of key
* @param filters filters
* @return a document context
*/
DocumentContext put(String path, String key, Object value, Predicate... filters);
}

14
json-path/src/main/java/com/jayway/jsonpath/internal/CompiledPath.java

@ -29,6 +29,8 @@ public class CompiledPath implements Path {
private final boolean isRootPath;
public CompiledPath(PathToken root, boolean isRootPath) {
this.root = root;
this.isRootPath = isRootPath;
@ -40,19 +42,25 @@ public class CompiledPath implements Path {
}
@Override
public EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration) {
public EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration, boolean forUpdate) {
if (logger.isDebugEnabled()) {
logger.debug("Evaluating path: {}", toString());
}
EvaluationContextImpl ctx = new EvaluationContextImpl(this, rootDocument, configuration);
EvaluationContextImpl ctx = new EvaluationContextImpl(this, rootDocument, configuration, forUpdate);
try {
root.evaluate("", document, ctx);
PathRef op = ctx.forUpdate() ? PathRef.createRoot(rootDocument) : PathRef.NO_OP;
root.evaluate("", op, document, ctx);
} catch (EvaluationAbortException abort){};
return ctx;
}
@Override
public EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration){
return evaluate(document, rootDocument, configuration, false);
}
@Override
public boolean isDefinite() {
return root.isPathDefinite();

3
json-path/src/main/java/com/jayway/jsonpath/internal/EvaluationContext.java

@ -16,6 +16,7 @@ package com.jayway.jsonpath.internal;
import com.jayway.jsonpath.Configuration;
import java.util.Collection;
import java.util.List;
public interface EvaluationContext {
@ -53,4 +54,6 @@ public interface EvaluationContext {
*/
List<String> getPathList();
Collection<PathRef> updateOperations();
}

38
json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java

@ -15,6 +15,7 @@
package com.jayway.jsonpath.internal;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.EvaluationListener;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ParseContext;
@ -31,7 +32,7 @@ import java.net.URL;
import static com.jayway.jsonpath.internal.Utils.notEmpty;
import static com.jayway.jsonpath.internal.Utils.notNull;
public class JsonReader implements ParseContext, ReadContext {
public class JsonReader implements ParseContext, DocumentContext {
private final Configuration configuration;
private Object json;
@ -58,26 +59,26 @@ public class JsonReader implements ParseContext, ReadContext {
//
//------------------------------------------------
@Override
public ReadContext parse(Object json) {
public DocumentContext parse(Object json) {
notNull(json, "json object can not be null");
this.json = json;
return this;
}
@Override
public ReadContext parse(String json) {
public DocumentContext parse(String json) {
notEmpty(json, "json string can not be null or empty");
this.json = configuration.jsonProvider().parse(json);
return this;
}
@Override
public ReadContext parse(InputStream json) {
public DocumentContext parse(InputStream json) {
return parse(json, "UTF-8");
}
@Override
public ReadContext parse(InputStream json, String charset) {
public DocumentContext parse(InputStream json, String charset) {
notNull(json, "json input stream can not be null");
notNull(json, "charset can not be null");
try {
@ -89,7 +90,7 @@ public class JsonReader implements ParseContext, ReadContext {
}
@Override
public ReadContext parse(File json) throws IOException {
public DocumentContext parse(File json) throws IOException {
notNull(json, "json file can not be null");
FileInputStream fis = null;
try {
@ -102,7 +103,7 @@ public class JsonReader implements ParseContext, ReadContext {
}
@Override
public ReadContext parse(URL json) throws IOException {
public DocumentContext parse(URL json) throws IOException {
notNull(json, "json url can not be null");
InputStream is = HttpProviderFactory.getProvider().get(json);
return parse(is);
@ -158,6 +159,29 @@ public class JsonReader implements ParseContext, ReadContext {
return configuration.mappingProvider().map(obj, targetType, configuration);
}
@Override
public DocumentContext set(String path, Object newValue, Predicate... filters) {
Object modifiedJson = JsonPath.compile(path, filters).set(json, newValue, configuration);
return new JsonReader(modifiedJson, configuration);
}
@Override
public DocumentContext delete(String path, Predicate... filters) {
Object modifiedJson = JsonPath.compile(path, filters).delete(json, configuration);
return new JsonReader(modifiedJson, configuration);
}
@Override
public DocumentContext add(String path, Object value, Predicate... filters){
Object modifiedJson = JsonPath.compile(path, filters).add(json, value, configuration);
return new JsonReader(modifiedJson, configuration);
}
@Override
public DocumentContext put(String path, String key, Object value, Predicate... filters){
Object modifiedJson = JsonPath.compile(path, filters).put(json, key, value, configuration);
return new JsonReader(modifiedJson, configuration);
}
private final class LimitingEvaluationListener implements EvaluationListener {

12
json-path/src/main/java/com/jayway/jsonpath/internal/Path.java

@ -21,6 +21,7 @@ import com.jayway.jsonpath.Configuration;
*/
public interface Path {
/**
* Evaluates this path
*
@ -31,6 +32,17 @@ public interface Path {
*/
EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration);
/**
* Evaluates this path
*
* @param document the json document to apply the path on
* @param rootDocument the root json document that started this evaluation
* @param configuration configuration to use
* @param forUpdate is this a read or a write operation
* @return EvaluationContext containing results of evaluation
*/
EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration, boolean forUpdate);
/**
*
* @return true id this path is definite

4
json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java

@ -54,6 +54,10 @@ public class PathCompiler {
notEmpty(path, "Path may not be null empty");
path = path.trim();
if(path.endsWith("..")){
throw new InvalidPathException("A path can not end with a scan.");
}
LinkedList<Predicate> filterList = new LinkedList<Predicate>(asList(filters));
if (path.charAt(0) != '$' && path.charAt(0) != '@') {

239
json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java

@ -0,0 +1,239 @@
package com.jayway.jsonpath.internal;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.InvalidModificationException;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.Collection;
public abstract class PathRef implements Comparable<PathRef> {
public static final PathRef NO_OP = new PathRef(null){
@Override
public Object getAccessor() {
return null;
}
@Override
public void set(Object newVal, Configuration configuration) {}
@Override
public void delete(Configuration configuration) {}
@Override
public void add(Object newVal, Configuration configuration) {}
@Override
public void put(String key, Object newVal, Configuration configuration) {}
};
protected Object parent;
private PathRef(Object parent) {
this.parent = parent;
}
abstract Object getAccessor();
public abstract void set(Object newVal, Configuration configuration);
public abstract void delete(Configuration configuration);
public abstract void add(Object newVal, Configuration configuration);
public abstract void put(String key, Object newVal, Configuration configuration);
@Override
public int compareTo(PathRef o) {
return this.getAccessor().toString().compareTo(o.getAccessor().toString()) * -1;
}
public static PathRef create(Object obj, String property){
return new ObjectPropertyPathRef(obj, property);
}
public static PathRef create(Object obj, Collection<String> properties){
return new ObjectMultiPropertyPathRef(obj, properties);
}
public static PathRef create(Object array, int index){
return new ArrayIndexPathRef(array, index);
}
public static PathRef createRoot(Object root){
return new RootPathRef(root);
}
private static class RootPathRef extends PathRef {
private RootPathRef(Object parent) {
super(parent);
}
@Override
Object getAccessor() {
return "$";
}
@Override
public void set(Object newVal, Configuration configuration) {
throw new InvalidModificationException("Invalid delete operation");
}
@Override
public void delete(Configuration configuration) {
throw new InvalidModificationException("Invalid delete operation");
}
@Override
public void add(Object newVal, Configuration configuration) {
if(configuration.jsonProvider().isArray(parent)){
configuration.jsonProvider().setProperty(parent, null, newVal);
} else {
throw new InvalidModificationException("Invalid add operation. $ is not an array");
}
}
@Override
public void put(String key, Object newVal, Configuration configuration) {
if(configuration.jsonProvider().isMap(parent)){
configuration.jsonProvider().setProperty(parent, key, newVal);
} else {
throw new InvalidModificationException("Invalid add operation. $ is not an array");
}
}
}
private static class ArrayIndexPathRef extends PathRef {
private int index;
private ArrayIndexPathRef(Object parent, int index) {
super(parent);
this.index = index;
}
public void set(Object newVal, Configuration configuration){
configuration.jsonProvider().setArrayIndex(parent, index, newVal);
}
public void delete(Configuration configuration){
configuration.jsonProvider().removeProperty(parent, index);
}
public void add(Object value, Configuration configuration){
Object target = configuration.jsonProvider().getArrayIndex(parent, index);
if(target == JsonProvider.UNDEFINED || target == null){
return;
}
if(configuration.jsonProvider().isArray(target)){
configuration.jsonProvider().setProperty(target, null, value);
} else {
throw new InvalidModificationException("Can only add to an array");
}
}
public void put(String key, Object value, Configuration configuration){
Object target = configuration.jsonProvider().getArrayIndex(parent, index);
if(target == JsonProvider.UNDEFINED || target == null){
return;
}
if(configuration.jsonProvider().isMap(target)){
configuration.jsonProvider().setProperty(target, key, value);
} else {
throw new InvalidModificationException("Can only add properties to a map");
}
}
@Override
public Object getAccessor() {
return index;
}
}
private static class ObjectPropertyPathRef extends PathRef {
private String property;
private ObjectPropertyPathRef(Object parent, String property) {
super(parent);
this.property = property;
}
public void set(Object newVal, Configuration configuration){
configuration.jsonProvider().setProperty(parent, property, newVal);
}
public void delete(Configuration configuration){
configuration.jsonProvider().removeProperty(parent, property);
}
public void add(Object value, Configuration configuration){
Object target = configuration.jsonProvider().getMapValue(parent, property);
if(target == JsonProvider.UNDEFINED || target == null){
return;
}
if(configuration.jsonProvider().isArray(target)){
configuration.jsonProvider().setProperty(target, null, value);
} else {
throw new InvalidModificationException("Can only add to an array");
}
}
public void put(String key, Object value, Configuration configuration){
Object target = configuration.jsonProvider().getMapValue(parent, property);
if(target == JsonProvider.UNDEFINED || target == null){
return;
}
if(configuration.jsonProvider().isMap(target)){
configuration.jsonProvider().setProperty(target, key, value);
} else {
throw new InvalidModificationException("Can only add properties to a map");
}
}
@Override
public Object getAccessor() {
return property;
}
}
private static class ObjectMultiPropertyPathRef extends PathRef {
private Collection<String> properties;
private ObjectMultiPropertyPathRef(Object parent, Collection<String> properties) {
super(parent);
this.properties = properties;
}
public void set(Object newVal, Configuration configuration){
for (String property : properties) {
configuration.jsonProvider().setProperty(parent, property, newVal);
}
}
public void delete(Configuration configuration){
for (String property : properties) {
configuration.jsonProvider().removeProperty(parent, property);
}
}
@Override
public void add(Object newVal, Configuration configuration) {
throw new InvalidModificationException("Add can not be performed to multiple properties");
}
@Override
public void put(String key, Object newVal, Configuration configuration) {
throw new InvalidModificationException("Add can not be performed to multiple properties");
}
@Override
public Object getAccessor() {
return Utils.join("&&", properties);
}
}
}

28
json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/AbstractJsonProvider.java

@ -49,6 +49,15 @@ public abstract class AbstractJsonProvider implements JsonProvider {
return ((List) obj).get(idx);
}
public void setArrayIndex(Object array, int index, Object newValue) {
if (!isArray(array)) {
throw new UnsupportedOperationException();
} else {
((List) array).set(index, newValue);
}
}
/**
* Extracts a value from an map
*
@ -89,6 +98,25 @@ public abstract class AbstractJsonProvider implements JsonProvider {
}
/**
* Removes a value in an object or array
*
* @param obj an array or an object
* @param key a String key or a numerical index to remove
*/
@SuppressWarnings("unchecked")
public void removeProperty(Object obj, Object key) {
if (isMap(obj))
((Map) obj).remove(key.toString());
else {
List list = (List) obj;
int index = key instanceof Integer ? (Integer) key : Integer.parseInt(key.toString());
list.remove(index);
}
}
/**
* checks if object is a map (i.e. no array)
*

21
json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/GsonJsonProvider.java

@ -132,6 +132,14 @@ public class GsonJsonProvider extends AbstractJsonProvider {
return unwrap(toJsonArray(obj).get(idx));
}
@Override
public void setArrayIndex(Object array, int index, Object newValue) {
if (!isArray(array)) {
throw new UnsupportedOperationException();
} else {
toJsonArray(array).set (index, createJsonElement(newValue));
}
}
@Override
public Object getMapValue(Object obj, String key) {
@ -164,6 +172,19 @@ public class GsonJsonProvider extends AbstractJsonProvider {
}
}
@SuppressWarnings("unchecked")
public void removeProperty(Object obj, Object key) {
if (isMap(obj))
toJsonObject(obj).remove(key.toString());
else {
JsonArray array = toJsonArray(obj);
int index = key instanceof Integer ? (Integer) key : Integer.parseInt(key.toString());
array.remove(index);
}
}
@Override
public boolean isMap(Object obj) {
//return (obj instanceof JsonObject || obj instanceof Map);

1
json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/JsonSmartJsonProvider.java

@ -17,7 +17,6 @@ package com.jayway.jsonpath.internal.spi.json;
import com.jayway.jsonpath.InvalidJsonException;
import com.jayway.jsonpath.JsonPathException;
import com.jayway.jsonpath.spi.json.Mode;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import net.minidev.json.JSONStyle;

3
json-path/src/main/java/com/jayway/jsonpath/internal/token/ArrayPathToken.java

@ -16,6 +16,7 @@ package com.jayway.jsonpath.internal.token;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.internal.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -51,7 +52,7 @@ public class ArrayPathToken extends PathToken {
}
@Override
public void evaluate(String currentPath, Object model, EvaluationContextImpl ctx) {
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if(model == null){
throw new PathNotFoundException("The path " + currentPath + " is null");
}

32
json-path/src/main/java/com/jayway/jsonpath/internal/token/EvaluationContextImpl.java

@ -21,9 +21,14 @@ import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.internal.EvaluationAbortException;
import com.jayway.jsonpath.internal.EvaluationContext;
import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.spi.json.JsonProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
@ -35,31 +40,46 @@ import static com.jayway.jsonpath.internal.Utils.notNull;
*/
public class EvaluationContextImpl implements EvaluationContext {
private static final Logger logger = LoggerFactory.getLogger(EvaluationContextImpl.class);
private final Configuration configuration;
private final Object valueResult;
private final Object pathResult;
private final Path path;
private final Object rootDocument;
private final List<PathRef> updateOperations;
private final HashMap<Path, Object> documentEvalCache = new HashMap<Path, Object>();
private final boolean forUpdate;
private int resultIndex = 0;
public EvaluationContextImpl(Path path, Object rootDocument, Configuration configuration) {
public EvaluationContextImpl(Path path, Object rootDocument, Configuration configuration, boolean forUpdate) {
notNull(path, "path can not be null");
notNull(rootDocument, "root can not be null");
notNull(configuration, "configuration can not be null");
this.forUpdate = forUpdate;
this.path = path;
this.rootDocument = rootDocument;
this.configuration = configuration;
this.valueResult = configuration.jsonProvider().createArray();
this.pathResult = configuration.jsonProvider().createArray();
this.updateOperations = new ArrayList<PathRef>();
}
public HashMap<Path, Object> documentEvalCache() {
return documentEvalCache;
}
public void addResult(String path, Object model) {
public boolean forUpdate(){
return forUpdate;
}
public void addResult(String path, PathRef operation, Object model) {
if(forUpdate) {
updateOperations.add(operation);
}
configuration.jsonProvider().setProperty(valueResult, resultIndex, model);
configuration.jsonProvider().setProperty(pathResult, resultIndex, path);
resultIndex++;
@ -74,6 +94,7 @@ public class EvaluationContextImpl implements EvaluationContext {
}
}
public JsonProvider jsonProvider() {
return configuration.jsonProvider();
}
@ -92,6 +113,13 @@ public class EvaluationContextImpl implements EvaluationContext {
return rootDocument;
}
public Collection<PathRef> updateOperations(){
Collections.sort(updateOperations);
return Collections.unmodifiableCollection(updateOperations);
}
@SuppressWarnings("unchecked")
@Override

22
json-path/src/main/java/com/jayway/jsonpath/internal/token/PathToken.java

@ -17,6 +17,7 @@ package com.jayway.jsonpath.internal.token;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.internal.Utils;
import com.jayway.jsonpath.spi.json.JsonProvider;
@ -63,10 +64,11 @@ public abstract class PathToken {
}
}
}
PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, property) : PathRef.NO_OP;
if (isLeaf()) {
ctx.addResult(evalPath, propertyVal);
ctx.addResult(evalPath, pathRef, propertyVal);
} else {
next().evaluate(evalPath, propertyVal, ctx);
next().evaluate(evalPath, pathRef, propertyVal, ctx);
}
} else {
String evalPath = currentPath + "[" + Utils.join(", ", "'", properties) + "]";
@ -77,7 +79,7 @@ public abstract class PathToken {
Object merged = ctx.jsonProvider().createMap();
for (String property : properties) {
Object propertyVal = null;
Object propertyVal;
if(hasProperty(property, model, ctx)) {
propertyVal = readObjectProperty(property, model, ctx);
if(propertyVal == JsonProvider.UNDEFINED){
@ -98,7 +100,8 @@ public abstract class PathToken {
}
ctx.jsonProvider().setProperty(merged, property, propertyVal);
}
ctx.addResult(evalPath, merged);
PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, properties) : PathRef.NO_OP;
ctx.addResult(evalPath, pathRef, merged);
}
}
@ -111,14 +114,15 @@ public abstract class PathToken {
}
void handleArrayIndex(int index, String currentPath, Object json, EvaluationContextImpl ctx) {
void handleArrayIndex(int index, String currentPath, Object model, EvaluationContextImpl ctx) {
String evalPath = currentPath + "[" + index + "]";
PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, index) : PathRef.NO_OP;
try {
Object evalHit = ctx.jsonProvider().getArrayIndex(json, index);
Object evalHit = ctx.jsonProvider().getArrayIndex(model, index);
if (isLeaf()) {
ctx.addResult(evalPath, evalHit);
ctx.addResult(evalPath, pathRef, evalHit);
} else {
next().evaluate(evalPath, evalHit, ctx);
next().evaluate(evalPath, pathRef, evalHit, ctx);
}
} catch (IndexOutOfBoundsException e) {
throw new PathNotFoundException("Index out of bounds when evaluating path " + evalPath);
@ -198,7 +202,7 @@ public abstract class PathToken {
return super.equals(obj);
}
public abstract void evaluate(String currentPath, Object model, EvaluationContextImpl ctx);
public abstract void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx);
abstract boolean isTokenDefinite();

8
json-path/src/main/java/com/jayway/jsonpath/internal/token/PredicatePathToken.java

@ -17,6 +17,7 @@ package com.jayway.jsonpath.internal.token;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.internal.PathRef;
import java.util.Collection;
@ -47,13 +48,14 @@ public class PredicatePathToken extends PathToken {
}
@Override
public void evaluate(String currentPath, Object model, EvaluationContextImpl ctx) {
public void evaluate(String currentPath, PathRef ref, Object model, EvaluationContextImpl ctx) {
if (ctx.jsonProvider().isMap(model)) {
if (accept(model, ctx.rootDocument(), ctx.configuration(), ctx)) {
PathRef op = ctx.forUpdate() ? ref : PathRef.NO_OP;
if (isLeaf()) {
ctx.addResult(currentPath, model);
ctx.addResult(currentPath, op, model);
} else {
next().evaluate(currentPath, model, ctx);
next().evaluate(currentPath, op, model, ctx);
}
}
} else if (ctx.jsonProvider().isArray(model)){

3
json-path/src/main/java/com/jayway/jsonpath/internal/token/PropertyPathToken.java

@ -15,6 +15,7 @@
package com.jayway.jsonpath.internal.token;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.internal.Utils;
import java.util.List;
@ -35,7 +36,7 @@ public class PropertyPathToken extends PathToken {
}
@Override
public void evaluate(String currentPath, Object model, EvaluationContextImpl ctx) {
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if (!ctx.jsonProvider().isMap(model)) {
throw new PathNotFoundException("Property " + getPathFragment() + " not found in path " + currentPath);
}

8
json-path/src/main/java/com/jayway/jsonpath/internal/token/RootPathToken.java

@ -14,6 +14,7 @@
*/
package com.jayway.jsonpath.internal.token;
import com.jayway.jsonpath.internal.PathRef;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -44,11 +45,12 @@ public class RootPathToken extends PathToken {
}
@Override
public void evaluate(String currentPath, Object model, EvaluationContextImpl ctx) {
public void evaluate(String currentPath, PathRef pathRef, Object model, EvaluationContextImpl ctx) {
if (isLeaf()) {
ctx.addResult("$", model);
PathRef op = ctx.forUpdate() ? pathRef : PathRef.NO_OP;
ctx.addResult("$", op, model);
} else {
next().evaluate("$", model, ctx);
next().evaluate("$", pathRef, model, ctx);
}
}

34
json-path/src/main/java/com/jayway/jsonpath/internal/token/ScanPathToken.java

@ -14,6 +14,7 @@
*/
package com.jayway.jsonpath.internal.token;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.Collection;
@ -24,37 +25,33 @@ import java.util.Collection;
public class ScanPathToken extends PathToken {
@Override
public void evaluate(String currentPath, Object model, EvaluationContextImpl ctx) {
if (isLeaf()) {
ctx.addResult(currentPath, model);
}
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
PathToken pt = next();
walk(pt, currentPath, model, ctx, createScanPredicate(pt, ctx));
walk(pt, currentPath, parent, model, ctx, createScanPredicate(pt, ctx));
}
public static void walk(PathToken pt, String currentPath, Object model, EvaluationContextImpl ctx, Predicate predicate) {
public static void walk(PathToken pt, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx, Predicate predicate) {
if (ctx.jsonProvider().isMap(model)) {
walkObject(pt, currentPath, model, ctx, predicate);
walkObject(pt, currentPath, parent, model, ctx, predicate);
} else if (ctx.jsonProvider().isArray(model)) {
walkArray(pt, currentPath, model, ctx, predicate);
walkArray(pt, currentPath, parent, model, ctx, predicate);
}
}
public static void walkArray(PathToken pt, String currentPath, Object model, EvaluationContextImpl ctx, Predicate predicate) {
public static void walkArray(PathToken pt, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx, Predicate predicate) {
if (predicate.matches(model)) {
if (pt.isLeaf()) {
pt.evaluate(currentPath, model, ctx);
pt.evaluate(currentPath, parent, model, ctx);
} else {
PathToken next = pt.next();
Iterable<?> models = ctx.jsonProvider().toIterable(model);
int idx = 0;
for (Object evalModel : models) {
String evalPath = currentPath + "[" + idx + "]";
next.evaluate(evalPath, evalModel, ctx);
next.evaluate(evalPath, parent, evalModel, ctx);
idx++;
}
}
@ -64,28 +61,23 @@ public class ScanPathToken extends PathToken {
int idx = 0;
for (Object evalModel : models) {
String evalPath = currentPath + "[" + idx + "]";
walk(pt, evalPath, evalModel, ctx, predicate);
walk(pt, evalPath, PathRef.create(model, idx), evalModel, ctx, predicate);
idx++;
}
}
public static void walkObject(PathToken pt, String currentPath, Object model, EvaluationContextImpl ctx, Predicate predicate) {
public static void walkObject(PathToken pt, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx, Predicate predicate) {
if (predicate.matches(model)) {
if (pt.isLeaf()) {
pt.evaluate(currentPath, model, ctx);
} else {
pt.evaluate(currentPath, model, ctx);
}
pt.evaluate(currentPath, parent, model, ctx);
}
Collection<String> properties = ctx.jsonProvider().getPropertyKeys(model);
for (String property : properties) {
String evalPath = currentPath + "['" + property + "']";
Object propertyModel = ctx.jsonProvider().getMapValue(model, property);
if (propertyModel != JsonProvider.UNDEFINED) {
walk(pt, evalPath, propertyModel, ctx, predicate);
walk(pt, evalPath, PathRef.create(model, property), propertyModel, ctx, predicate);
}
}
}

3
json-path/src/main/java/com/jayway/jsonpath/internal/token/WildcardPathToken.java

@ -16,6 +16,7 @@ package com.jayway.jsonpath.internal.token;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.internal.PathRef;
import static java.util.Arrays.asList;
@ -25,7 +26,7 @@ import static java.util.Arrays.asList;
public class WildcardPathToken extends PathToken {
@Override
public void evaluate(String currentPath, Object model, EvaluationContextImpl ctx) {
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if (ctx.jsonProvider().isMap(model)) {
for (String property : ctx.jsonProvider().getPropertyKeys(model)) {
handleObjectProperty(currentPath, model, ctx, asList(property));

17
json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java

@ -101,6 +101,15 @@ public interface JsonProvider {
*/
Object getArrayIndex(Object obj, int idx);
/**
* Sets a value in an array
*
* @param array an array
* @param idx index
* @param newValue the new value
*/
void setArrayIndex(Object array, int idx, Object newValue);
/**
* Extracts a value from an map
*
@ -119,6 +128,14 @@ public interface JsonProvider {
*/
void setProperty(Object obj, Object key, Object value);
/**
* Removes a value in an object or array
*
* @param obj an array or an object
* @param key a String key or a numerical index to remove
*/
void removeProperty(Object obj, Object key);
/**
* checks if object is a map (i.e. no array)
*

219
json-path/src/test/java/com/jayway/jsonpath/WriteTest.java

@ -0,0 +1,219 @@
package com.jayway.jsonpath;
import org.junit.Test;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static com.jayway.jsonpath.JsonPath.parse;
import static java.util.Collections.emptyMap;
import static org.assertj.core.api.Assertions.assertThat;
public class WriteTest extends BaseTest {
private static final Map<String, Object> EMPTY_MAP = emptyMap();
@Test
public void an_array_child_property_can_be_updated() {
Object o = parse(JSON_DOCUMENT).set("$.store.book[*].display-price", 1).json();
List<Integer> result = parse(o).read("$.store.book[*].display-price");
assertThat(result).containsExactly(1, 1, 1, 1);
}
@Test
public void an_root_property_can_be_updated() {
Object o = parse(JSON_DOCUMENT).set("$.int-max-property", 1).json();
Integer result = parse(o).read("$.int-max-property");
assertThat(result).isEqualTo(1);
}
@Test
public void an_deep_scan_can_update() {
Object o = parse(JSON_DOCUMENT).set("$..display-price", 1).json();
List<Integer> result = parse(o).read("$..display-price");
assertThat(result).containsExactly(1, 1, 1, 1, 1);
}
@Test
public void an_filter_can_update() {
Object o = parse(JSON_DOCUMENT).set("$.store.book[?(@.display-price)].display-price", 1).json();
List<Integer> result = parse(o).read("$.store.book[?(@.display-price)].display-price");
assertThat(result).containsExactly(1, 1, 1, 1);
}
@Test
public void a_path_can_be_deleted() {
Object o = parse(JSON_DOCUMENT).delete("$.store.book[*].display-price").json();
List<Integer> result = parse(o).read("$.store.book[*].display-price");
assertThat(result).isEmpty();
}
@Test
public void operations_can_chained() {
Object o = parse(JSON_DOCUMENT)
.delete("$.store.book[*].display-price")
.set("$.store.book[*].category", "A")
.json();
List<Integer> prices = parse(o).read("$.store.book[*].display-price");
List<String> categories = parse(o).read("$.store.book[*].category");
assertThat(prices).isEmpty();
assertThat(categories).containsExactly("A", "A", "A", "A");
}
@Test
public void an_array_can_be_updated() {
List<Integer> ints = parse("[0,1,2,3]").set("$[?(@ == 1)]", 9).json();
assertThat(ints).containsExactly(0, 9, 2, 3);
}
@Test
public void an_array_index_can_be_updated() {
String res = parse(JSON_DOCUMENT).set("$.store.book[0]", "a").read("$.store.book[0]");
assertThat(res).isEqualTo("a");
}
@Test
public void an_array_slice_can_be_updated() {
List<String> res = parse(JSON_DOCUMENT).set("$.store.book[0:2]", "a").read("$.store.book[0:2]");
assertThat(res).containsExactly("a", "a");
}
@Test
public void an_array_criteria_can_be_updated() {
List<String> res = parse(JSON_DOCUMENT)
.set("$.store.book[?(@.category == 'fiction')]", "a")
.read("$.store.book[?(@ == 'a')]");
assertThat(res).containsExactly("a", "a", "a");
}
@Test
public void an_array_criteria_can_be_deleted() {
List<String> res = parse(JSON_DOCUMENT)
.delete("$.store.book[?(@.category == 'fiction')]")
.read("$.store.book[*].category");
assertThat(res).containsExactly("reference");
}
@Test
public void multi_prop_delete() {
List<Map<String, Object>> res = parse(JSON_DOCUMENT).delete("$.store.book[*]['author', 'category']").read("$.store.book[*]['author', 'category']");
assertThat(res).containsExactly(EMPTY_MAP, EMPTY_MAP, EMPTY_MAP, EMPTY_MAP);
}
@Test
public void multi_prop_update() {
Map<String, Object> expected = new HashMap<String, Object>(){{
put("author", "a");
put("category", "a");
}};
List<Map<String, Object>> res = parse(JSON_DOCUMENT).set("$.store.book[*]['author', 'category']", "a").read("$.store.book[*]['author', 'category']");
assertThat(res).containsExactly(expected, expected, expected, expected);
}
@Test
public void multi_prop_update_not_all_defined() {
Map<String, Object> expected = new HashMap<String, Object>(){{
put("author", "a");
put("isbn", "a");
}};
List<Map<String, Object>> res = parse(JSON_DOCUMENT).set("$.store.book[*]['author', 'isbn']", "a").read("$.store.book[*]['author', 'isbn']");
assertThat(res).containsExactly(expected, expected, expected, expected);
}
@Test
public void add_to_array() {
Object res = parse(JSON_DOCUMENT).add("$.store.book", 1).read("$.store.book[4]");
assertThat(res).isEqualTo(1);
}
@Test
public void add_to_object() {
Object res = parse(JSON_DOCUMENT).put("$.store.book[0]", "new-key", "new-value").read("$.store.book[0].new-key");
assertThat(res).isEqualTo("new-value");
}
@Test
public void item_can_be_added_to_root_array() {
List<Integer> model = new LinkedList<Integer>();
model.add(1);
model.add(2);
List<Integer> ints = parse(model).add("$", 3).read("$");
assertThat(ints).containsExactly(1,2,3);
}
@Test
public void key_val_can_be_added_to_root_object() {
Map model = new HashMap();
model.put("a", "a-val");
String newVal = parse(model).put("$", "new-key", "new-val").read("$.new-key");
assertThat(newVal).isEqualTo("new-val");
}
@Test(expected = InvalidModificationException.class)
public void add_to_object_on_array() {
parse(JSON_DOCUMENT).put("$.store.book", "new-key", "new-value");
}
@Test(expected = InvalidModificationException.class)
public void add_to_array_on_object() {
parse(JSON_DOCUMENT).add("$.store.book[0]", "new-value");
}
@Test(expected = InvalidModificationException.class)
public void root_object_can_not_be_updated() {
Map model = new HashMap();
model.put("a", "a-val");
parse(model).set("$[?(@.a == 'a-val')]", 1);
}
}

6
json-path/src/test/java/com/jayway/jsonpath/old/ArraySlicingTest.java

@ -59,6 +59,12 @@ public class ArraySlicingTest {
assertThat(result, Matchers.contains(1));
}
@Test
public void get_between_index_3(){
List<Integer> result = JsonPath.read(JSON_ARRAY, "$[0:2]");
assertThat(result, Matchers.contains(1,3));
}
@Test
public void get_between_index_out_of_bounds(){
List<Integer> result = JsonPath.read(JSON_ARRAY, "$[1:15]");

Loading…
Cancel
Save