From ecde41a1e15d04512d26f6dbc15d9f5df59e7f92 Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Wed, 10 Sep 2014 11:33:14 +0200 Subject: [PATCH] Added Converter to support type conversion. --- json-path-web-test/pom.xml | 2 +- .../java/com/jayway/jsonpath/ReadContext.java | 23 +++ .../jayway/jsonpath/internal/JsonReader.java | 15 ++ .../jsonpath/spi/converter/Converter.java | 7 + .../spi/converter/ConverterFactory.java | 174 ++++++++++++++++++ .../jsonpath/spi/json/JsonProvider.java | 2 - .../java/com/jayway/jsonpath/BaseTest.java | 6 +- .../com/jayway/jsonpath/ConverterTest.java | 45 +++++ .../java/com/jayway/jsonpath/OptionsTest.java | 16 ++ .../com/jayway/jsonpath/ReturnTypeTest.java | 25 +-- 10 files changed, 298 insertions(+), 17 deletions(-) create mode 100644 json-path/src/main/java/com/jayway/jsonpath/spi/converter/Converter.java create mode 100644 json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConverterFactory.java create mode 100644 json-path/src/test/java/com/jayway/jsonpath/ConverterTest.java create mode 100644 json-path/src/test/java/com/jayway/jsonpath/OptionsTest.java diff --git a/json-path-web-test/pom.xml b/json-path-web-test/pom.xml index a072a03b..59ba2bf3 100644 --- a/json-path-web-test/pom.xml +++ b/json-path-web-test/pom.xml @@ -59,7 +59,7 @@ com.jayway.jsonpath json-path - 0.9.2-SNAPSHOT + ${project.version} diff --git a/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java b/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java index 01e54a71..9fb8c6a3 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java +++ b/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java @@ -33,6 +33,17 @@ public interface ReadContext { */ T read(String path, Predicate... filters); + /** + * Reads the given path from this context + * + * @param path path to read + * @param type expected return type (will try to convert) + * @param filters filters + * @param + * @return result + */ + T read(String path, Class type, Predicate... filters); + /** * Reads the given path from this context * @@ -42,4 +53,16 @@ public interface ReadContext { */ T read(JsonPath path); + /** + * Reads the given path from this context + * + * @param path path to apply + * @param type expected return type (will try to convert) + * @param + * @return result + */ + T read(JsonPath path, Class type); + + + } 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 db04142a..526e12c6 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 @@ -5,6 +5,7 @@ import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.ParseContext; import com.jayway.jsonpath.Predicate; import com.jayway.jsonpath.ReadContext; +import com.jayway.jsonpath.spi.converter.ConverterFactory; import com.jayway.jsonpath.spi.http.HttpProviderFactory; import java.io.File; @@ -92,10 +93,24 @@ public class JsonReader implements ParseContext, ReadContext { return read(JsonPath.compile(path, filters)); } + @Override + public T read(String path, Class type, Predicate... filters) { + return convert(read(path, filters), type); + } + @Override public T read(JsonPath path) { notNull(path, "path can not be null"); return path.read(json, configuration); } + @Override + public T read(JsonPath path, Class type) { + return convert(read(path), type); + } + + private T convert(Object obj, Class type){ + return ConverterFactory.createConverter(type).convert(obj, configuration); + } + } diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/converter/Converter.java b/json-path/src/main/java/com/jayway/jsonpath/spi/converter/Converter.java new file mode 100644 index 00000000..7271c913 --- /dev/null +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/converter/Converter.java @@ -0,0 +1,7 @@ +package com.jayway.jsonpath.spi.converter; + +import com.jayway.jsonpath.Configuration; + +public interface Converter{ + T convert(Object o, Configuration conf); +} \ No newline at end of file diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConverterFactory.java b/json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConverterFactory.java new file mode 100644 index 00000000..de7f87a1 --- /dev/null +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConverterFactory.java @@ -0,0 +1,174 @@ +package com.jayway.jsonpath.spi.converter; + +import com.jayway.jsonpath.Configuration; + +import java.math.BigDecimal; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ConverterFactory { + + private static Map, Converter> converters = new ConcurrentHashMap, Converter>(); + + static { + registerConverter(Long.class, new LongConverter()); + registerConverter(Integer.class, new IntegerConverter()); + registerConverter(BigDecimal.class, new BigDecimalConverter()); + registerConverter(Double.class, new DoubleConverter()); + registerConverter(Date.class, new DateConverter()); + registerConverter(String.class, new StringConverter()); + } + + public static Converter createConverter(Class target){ + Converter converter = (Converter) converters.get(target); + if(converter == null){ + converter = new Converter() { + @Override + public T convert(Object o, Configuration conf) { + return (T)o; + } + }; + } + return converter; + } + + public static void registerConverter(Class target, Converter converter){ + converters.put(target, converter); + } + + public static void unRegisterConverter(Class target){ + converters.remove(target); + } + + private static class StringConverter implements Converter { + @Override + public String convert(Object o, Configuration conf) { + if(o == null){ + return null; + } else { + return o.toString(); + } + } + } + + private static class DateConverter implements Converter { + @Override + public Date convert(Object o, Configuration conf) { + + if(o == null){ + return null; + } else if(o instanceof Date){ + return (Date)o; + } else if(o instanceof Long){ + return new Date(((Long)o).longValue()); + } else if(o instanceof String){ + try { + return DateFormat.getInstance().parse(o.toString()); + } catch (ParseException e) { + throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Integer.class.getName(), e); + } + } + throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Integer.class.getName()); + } + } + + private static class IntegerConverter implements Converter { + @Override + public Integer convert(Object o, Configuration conf) { + + if(o == null){ + return null; + } else if(o instanceof Integer){ + return (Integer)o; + } else if(o instanceof Long){ + return ((Long)o).intValue(); + } else if(o instanceof Double){ + return ((Double)o).intValue(); + } else if(o instanceof BigDecimal){ + return ((BigDecimal)o).intValue(); + } else if(o instanceof Float){ + return ((Float)o).intValue(); + } else if(o instanceof String){ + return Integer.parseInt(o.toString()); + } + throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Integer.class.getName()); + } + } + + private static class LongConverter implements Converter { + @Override + public Long convert(Object o, Configuration conf) { + + if(o == null){ + return null; + } else if(o instanceof Long){ + return (Long)o; + } else if(o instanceof Integer){ + return ((Integer)o).longValue(); + } else if(o instanceof Double){ + return ((Double)o).longValue(); + } else if(o instanceof BigDecimal){ + return ((BigDecimal)o).longValue(); + } else if(o instanceof Float){ + return ((Float)o).longValue(); + } else if(o instanceof String){ + return Long.parseLong(o.toString()); + } + throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Long.class.getName()); + } + } + + private static class DoubleConverter implements Converter { + @Override + public Double convert(Object o, Configuration conf) { + + if(o == null){ + return null; + } else if(o instanceof Double){ + return (Double)o; + } else if(o instanceof Integer){ + return Double.valueOf(o.toString()); + } else if(o instanceof Long){ + return Double.valueOf(o.toString()); + } else if(o instanceof BigDecimal){ + return ((BigDecimal)o).doubleValue(); + } else if(o instanceof Float){ + return ((Float)o).doubleValue(); + } else if(o instanceof String){ + return Double.parseDouble(o.toString()); + } + throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Double.class.getName()); + } + } + + private static class BigDecimalConverter implements Converter { + @Override + public BigDecimal convert(Object o, Configuration conf) { + + if(o == null){ + return null; + } else if(o instanceof BigDecimal){ + return (BigDecimal)o; + } else if(o instanceof Integer){ + return new BigDecimal(o.toString()); + } else if(o instanceof Long){ + return new BigDecimal(o.toString()); + } else if(o instanceof Float){ + return BigDecimal.valueOf(((Float)o).doubleValue()); + } else if(o instanceof String){ + return new BigDecimal(o.toString()); + } + throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + BigDecimal.class.getName()); + } + } +} + + + + + + + diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java index 599bbf06..726bbc50 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java @@ -32,14 +32,12 @@ public interface JsonProvider { Object parse(InputStream jsonStream) throws InvalidJsonException; - String toJson(Object obj); Object createMap(); Object createArray(); - Object clone(Object model); /** diff --git a/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java b/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java index a2c81b73..4aed81a4 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java @@ -4,10 +4,12 @@ public class BaseTest { public static final String JSON_DOCUMENT = "{\n" + " \"string-property\" : \"string-value\", \n" + - " \"int-property\" : " + Integer.MAX_VALUE + ", \n" + - " \"long-property\" : " + Long.MAX_VALUE + ", \n" + + " \"int-max-property\" : " + Integer.MAX_VALUE + ", \n" + + " \"long-max-property\" : " + Long.MAX_VALUE + ", \n" + + " \"long-max-property\" : " + Long.MAX_VALUE + ", \n" + " \"boolean-property\" : true, \n" + " \"null-property\" : null, \n" + + " \"int-small-property\" : 1, \n" + " \"store\" : {\n" + " \"book\" : [\n" + " {\n" + diff --git a/json-path/src/test/java/com/jayway/jsonpath/ConverterTest.java b/json-path/src/test/java/com/jayway/jsonpath/ConverterTest.java new file mode 100644 index 00000000..95294aee --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/ConverterTest.java @@ -0,0 +1,45 @@ +package com.jayway.jsonpath; + +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Date; + +import static com.jayway.jsonpath.JsonPath.parse; +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThat; + +public class ConverterTest extends BaseTest { + + @Test + public void an_Integer_can_be_converted_to_a_Long() { + assertThat(parse(singletonMap("val", 1)).read("val", Long.class)).isEqualTo(1L); + } + + @Test + public void an_String_can_be_converted_to_a_Long() { + assertThat(parse(singletonMap("val", "1")).read("val", Long.class)).isEqualTo(1L); + } + + @Test + public void an_Integer_can_be_converted_to_a_String() { + assertThat(parse(singletonMap("val", 1)).read("val", String.class)).isEqualTo("1"); + } + + @Test + public void an_Integer_can_be_converted_to_a_Double() { + assertThat(parse(singletonMap("val", 1)).read("val", Double.class)).isEqualTo(1D); + } + + @Test + public void a_BigDecimal_can_be_converted_to_a_Long() { + assertThat(parse(singletonMap("val", new BigDecimal(1.5D))).read("val", Long.class)).isEqualTo(1L); + } + + @Test + public void a_Long_can_be_converted_to_a_Date() { + Date now = new Date(); + assertThat(parse(singletonMap("val", now.getTime())).read("val", Date.class)).isEqualTo(now); + } + +} diff --git a/json-path/src/test/java/com/jayway/jsonpath/OptionsTest.java b/json-path/src/test/java/com/jayway/jsonpath/OptionsTest.java new file mode 100644 index 00000000..672f33b6 --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/OptionsTest.java @@ -0,0 +1,16 @@ +package com.jayway.jsonpath; + +import org.junit.Test; + +public class OptionsTest extends BaseTest { + + + @Test + public void leafs_can_be_defaulted_to_null() { + + //assertThat(parse(singletonMap("foo", "bar"))). + + } + + +} diff --git a/json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java b/json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java index d54071b5..8a6bc601 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java @@ -3,52 +3,53 @@ package com.jayway.jsonpath; import org.junit.Test; import java.util.List; +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; @SuppressWarnings("ALL") public class ReturnTypeTest extends BaseTest { + private static ReadContext reader = JsonPath.parse(JSON_DOCUMENT); + @Test public void assert_strings_can_be_read() { - assertThat(JsonPath.read(JSON_DOCUMENT, "$.string-property")).isEqualTo("string-value"); + assertThat(reader.read("$.string-property")).isEqualTo("string-value"); } @Test public void assert_ints_can_be_read() { - assertThat(JsonPath.read(JSON_DOCUMENT, "$.int-property")).isEqualTo(Integer.MAX_VALUE); + assertThat(reader.read("$.int-max-property")).isEqualTo(Integer.MAX_VALUE); } @Test public void assert_longs_can_be_read() { - assertThat(JsonPath.read(JSON_DOCUMENT, "$.long-property")).isEqualTo(Long.MAX_VALUE); + assertThat(reader.read("$.long-max-property")).isEqualTo(Long.MAX_VALUE); } @Test public void assert_boolean_values_can_be_read() { - assertThat(JsonPath.read(JSON_DOCUMENT, "$.boolean-property")).isEqualTo(true); + assertThat(reader.read("$.boolean-property")).isEqualTo(true); } @Test public void assert_null_values_can_be_read() { - assertThat(JsonPath.read(JSON_DOCUMENT, "$.null-property")).isNull(); + assertThat(reader.read("$.null-property")).isNull(); } @Test - public void assert_arrays_can_be_read_2() { - List list = JsonPath.read(JSON_DOCUMENT, "$.store.book"); - - assertThat(list).hasSize(4); + public void assert_arrays_can_be_read() { + assertThat(reader.read("$.store.book", List.class)).hasSize(4); } @Test public void assert_maps_can_be_read() { - /* - assertThat(JsonPath.parse(JSON_DOCUMENT).read("$.store.book[0]", Map.class) + + assertThat(reader.read("$.store.book[0]", Map.class)) .containsEntry("category", "reference") .containsEntry("author", "Nigel Rees") .containsEntry("title", "Sayings of the Century") .containsEntry("display-price", 8.95D); - */ + } }