From b5c175d04d78a8ba63d6bd7b7371d26d682e952b Mon Sep 17 00:00:00 2001 From: Tamas Adam Date: Wed, 29 Apr 2015 20:11:17 +0200 Subject: [PATCH] Added convert method for path value in-situ conversion. --- .../java/com/jayway/jsonpath/JsonPath.java | 18 ++++--- .../com/jayway/jsonpath/WriteContext.java | 21 ++++++++ .../jayway/jsonpath/internal/JsonReader.java | 13 +++++ .../com/jayway/jsonpath/internal/PathRef.java | 28 ++++++++++ .../jsonpath/internal/ValueConverter.java | 10 ++++ .../java/com/jayway/jsonpath/WriteTest.java | 54 +++++++++++++++++++ 6 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 json-path/src/main/java/com/jayway/jsonpath/internal/ValueConverter.java diff --git a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java index 65b16e7a..454bb141 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java @@ -15,12 +15,7 @@ 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.internal.*; import com.jayway.jsonpath.spi.json.JsonProvider; import java.io.File; @@ -218,6 +213,17 @@ public class JsonPath { return resultByConfiguration(jsonObject, configuration, evaluationContext); } + public T convert(Object jsonObject, ValueConverter valueConverter, Configuration configuration) { + notNull(jsonObject, "json can not be null"); + notNull(configuration, "configuration can not be null"); + EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true); + for (PathRef updateOperation : evaluationContext.updateOperations()) { + updateOperation.convert(valueConverter, configuration); + } + return resultByConfiguration(jsonObject, configuration, evaluationContext); + } + + /** * Deletes the object this path points to in the provided jsonObject * diff --git a/json-path/src/main/java/com/jayway/jsonpath/WriteContext.java b/json-path/src/main/java/com/jayway/jsonpath/WriteContext.java index 29a87bc7..4c617a71 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/WriteContext.java +++ b/json-path/src/main/java/com/jayway/jsonpath/WriteContext.java @@ -14,6 +14,8 @@ */ package com.jayway.jsonpath; +import com.jayway.jsonpath.internal.ValueConverter; + public interface WriteContext { /** @@ -56,6 +58,25 @@ public interface WriteContext { */ DocumentContext set(JsonPath path, Object newValue); + /** + * Converts the value on the given path. + * + * @param path path to be converted set + * @param valueConverter Converter object to be invoked (or lambda:)) + * @param filters filters + * @return a document context + */ + DocumentContext convert(String path, ValueConverter valueConverter, Predicate... filters); + + /** + * Converts the value on the given path. + * + * @param path path to be converted set + * @param valueConverter Converter object to be invoked (or lambda:)) + * @return a document context + */ + DocumentContext convert(JsonPath path, ValueConverter valueConverter); + /** * Deletes the given path * diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java index b755f5fb..b4043b53 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java @@ -33,6 +33,7 @@ import java.io.InputStream; import java.util.List; import static com.jayway.jsonpath.JsonPath.compile; +import static com.jayway.jsonpath.JsonPath.parse; import static com.jayway.jsonpath.internal.Utils.notEmpty; import static com.jayway.jsonpath.internal.Utils.notNull; @@ -194,6 +195,18 @@ public class JsonReader implements ParseContext, DocumentContext { return this; } + @Override + public DocumentContext convert(String path, ValueConverter valueConverter, Predicate... filters) { + convert(compile(path, filters), valueConverter); + return this; + } + + @Override + public DocumentContext convert(JsonPath path, ValueConverter valueConverter) { + path.convert(json, valueConverter, configuration); + return this; + } + @Override public DocumentContext delete(String path, Predicate... filters) { return delete(compile(path, filters)); diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java b/json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java index 50c03d79..36a61cf3 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java @@ -17,6 +17,9 @@ public abstract class PathRef implements Comparable { @Override public void set(Object newVal, Configuration configuration) {} + @Override + public void convert(ValueConverter valueConverter, Configuration configuration) {} + @Override public void delete(Configuration configuration) {} @@ -42,6 +45,8 @@ public abstract class PathRef implements Comparable { public abstract void set(Object newVal, Configuration configuration); + public abstract void convert(ValueConverter valueConverter, Configuration configuration); + public abstract void delete(Configuration configuration); public abstract void add(Object newVal, Configuration configuration); @@ -103,6 +108,10 @@ public abstract class PathRef implements Comparable { throw new InvalidModificationException("Invalid delete operation"); } + public void convert(ValueConverter valueConverter, Configuration configuration){ + throw new InvalidModificationException("Invalid convert operation"); + } + @Override public void delete(Configuration configuration) { throw new InvalidModificationException("Invalid delete operation"); @@ -136,6 +145,7 @@ public abstract class PathRef implements Comparable { } } + private static class ArrayIndexPathRef extends PathRef { private int index; @@ -151,6 +161,11 @@ public abstract class PathRef implements Comparable { configuration.jsonProvider().setArrayIndex(parent, index, newVal); } + public void convert(ValueConverter valueConverter, Configuration configuration){ + Object currentValue = configuration.jsonProvider().getArrayIndex(parent, index); + configuration.jsonProvider().setArrayIndex(parent, index, valueConverter.convert(currentValue)); + } + public void delete(Configuration configuration){ configuration.jsonProvider().removeProperty(parent, value); } @@ -209,6 +224,13 @@ public abstract class PathRef implements Comparable { configuration.jsonProvider().setProperty(parent, property, newVal); } + @Override + public void convert(ValueConverter valueConverter, Configuration configuration) { + Object currentValue = configuration.jsonProvider().getMapValue(parent, property); + configuration.jsonProvider().setProperty(parent, property, valueConverter.convert(currentValue)); + } + + public void delete(Configuration configuration){ configuration.jsonProvider().removeProperty(parent, property); } @@ -266,6 +288,12 @@ public abstract class PathRef implements Comparable { configuration.jsonProvider().setProperty(parent, property, newVal); } } + public void convert(ValueConverter valueConverter, Configuration configuration) { + for (String property : properties) { + Object currentValue = configuration.jsonProvider().getMapValue(parent, property); + configuration.jsonProvider().setProperty(parent, property, valueConverter.convert(currentValue)); + } + } public void delete(Configuration configuration){ for (String property : properties) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/ValueConverter.java b/json-path/src/main/java/com/jayway/jsonpath/internal/ValueConverter.java new file mode 100644 index 00000000..ca2b31b3 --- /dev/null +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/ValueConverter.java @@ -0,0 +1,10 @@ +package com.jayway.jsonpath.internal; + +/** + * Created by tom on 29/04/15. + */ +public interface ValueConverter { + + public Object convert(Object currentValue); + +} diff --git a/json-path/src/test/java/com/jayway/jsonpath/WriteTest.java b/json-path/src/test/java/com/jayway/jsonpath/WriteTest.java index 2924d956..aa4e2446 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/WriteTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/WriteTest.java @@ -1,5 +1,6 @@ package com.jayway.jsonpath; +import com.jayway.jsonpath.internal.ValueConverter; import org.junit.Test; import java.util.*; @@ -259,4 +260,57 @@ public class WriteTest extends BaseTest { public void non_existent_key_rename_not_allowed(){ Object o = parse(JSON_DOCUMENT).renameKey("$", "fake", "new-fake").json(); } + + @Test(expected = InvalidModificationException.class) + public void rootCannotBeConverted(){ + ValueConverter valueConverter = new ValueConverter() { + @Override + public Object convert(Object currentValue) { + return currentValue.toString()+"converted"; + } + }; + Object o = parse(JSON_DOCUMENT).convert("$", valueConverter).json(); + } + + @Test + public void single_match_value_can_be_converted(){ + ValueConverter valueConverter = new ToStringValueConverterImpl(); + String stringResult = parse(JSON_DOCUMENT).convert("$.string-property", valueConverter).read("$.string-property"); + assertThat(stringResult.endsWith("converted")).isTrue(); + } + + @Test + public void object_can_be_converted(){ + ValueConverter valueConverter = new ToStringValueConverterImpl(); + DocumentContext documentContext = parse(JSON_DOCUMENT); + Object list = documentContext.read("$..book"); + assertThat(list).isInstanceOf(List.class); + String result = ((List)documentContext.convert("$..book", valueConverter).read("$..book")).get(0); + assertThat(result).isInstanceOf(String.class); + assertThat(((String)result).endsWith("converted")).isTrue(); + } + + @Test + public void multi_match_path_can_be_converted(){ + ValueConverter valueConverter = new ToStringValueConverterImpl(); + List doubleResult = parse(JSON_DOCUMENT).read("$..display-price"); + for(Double dRes : doubleResult){ + assertThat(dRes).isInstanceOf(Double.class); + } + List stringResult = parse(JSON_DOCUMENT).convert("$..display-price", valueConverter).read("$..display-price"); + for(String sRes : stringResult){ + assertThat(sRes).isInstanceOf(String.class); + assertThat(sRes.endsWith("converted")).isTrue(); + } + } + + // Helper converter implementation for test cases. + private class ToStringValueConverterImpl implements ValueConverter{ + + @Override + public Object convert(Object currentValue) { + return currentValue.toString()+"converted"; + } + } + } \ No newline at end of file