diff --git a/changelog.md b/changelog.md index 06cef739..0e881069 100644 --- a/changelog.md +++ b/changelog.md @@ -13,12 +13,14 @@ In The Pipe * Support regex in inline filters (ruby syntax) `parse(JSON_DOCUMENT).read("$.store.book[?(@.category =~ /reference/)].author")` `parse(JSON_DOCUMENT).read("$.store.book[?(@.category =~ /REFERENCE/i)].author")` -* Inline filter does not force path first +* Inline filter does not require path statement on left side of operator `parse(JSON_DOCUMENT).read("$.store.book[?(@.category == 'reference')].author")` `parse(JSON_DOCUMENT).read("$.store.book[?('reference' == @.category)].author")` * Negate exist checks in inline filters (not defined or null) `parse(JSON_DOCUMENT).read("$.store.book[?(!@.isbn)]")` - +* Improved object mapping with Jackson and Gson (now handles generic types) +* Exceptions thrown by JsonPath.compile are now wrapped in an InvalidPathException +* Fixed Deep scanning issue (#60) 1.1.0 (2014-10-01) ================== 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 ddf2eb0e..3b6d55f1 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java +++ b/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java @@ -70,6 +70,36 @@ public interface ReadContext { */ T read(JsonPath path, Class type); + /** + * Reads the given path from this context + * + * Sample code to create a TypeRef + * + * TypeRef ref = new TypeRef>() {}; + * + * + * @param path path to apply + * @param typeRef expected return type (will try to map) + * @param + * @return result + */ + T read(JsonPath path, TypeRef typeRef); + + /** + * Reads the given path from this context + * + * Sample code to create a TypeRef + * + * TypeRef ref = new TypeRef>() {}; + * + * + * @param path path to apply + * @param typeRef expected return type (will try to map) + * @param + * @return result + */ + T read(String path, TypeRef typeRef); + /** * Stops evaluation when maxResults limit has been reached * @param maxResults diff --git a/json-path/src/main/java/com/jayway/jsonpath/TypeRef.java b/json-path/src/main/java/com/jayway/jsonpath/TypeRef.java new file mode 100644 index 00000000..fce40e6d --- /dev/null +++ b/json-path/src/main/java/com/jayway/jsonpath/TypeRef.java @@ -0,0 +1,54 @@ +/* + * 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; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + + +/** + * Used to specify generic type information in {@link com.jayway.jsonpath.ReadContext} + * + * + * TypeRef ref = new TypeRef>() { }; + * + * + * @param + */ +public abstract class TypeRef implements Comparable> { + protected final Type type; + + protected TypeRef() + { + Type superClass = getClass().getGenericSuperclass(); + if (superClass instanceof Class) { + throw new IllegalArgumentException("No type info in TypeRef"); + } + type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; + } + + public Type getType() { return type; } + + /** + * The only reason we define this method (and require implementation + * of Comparable) is to prevent constructing a + * reference without type information. + */ + @Override + public int compareTo(TypeRef o) { + return 0; + } +} + 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 e82835c9..125eb862 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 @@ -21,6 +21,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.TypeRef; import com.jayway.jsonpath.spi.http.HttpProviderFactory; import java.io.File; @@ -147,6 +148,16 @@ public class JsonReader implements ParseContext, DocumentContext { return convert(read(path), type, configuration); } + @Override + public T read(JsonPath path, TypeRef type) { + return convert(read(path), type, configuration); + } + + @Override + public T read(String path, TypeRef type) { + return convert(read(path), type, configuration); + } + public ReadContext limit(int maxResults){ return withListeners(new LimitingEvaluationListener(maxResults)); } @@ -160,6 +171,10 @@ public class JsonReader implements ParseContext, DocumentContext { return configuration.mappingProvider().map(obj, targetType, configuration); } + private T convert(Object obj, TypeRef targetType, Configuration configuration){ + return configuration.mappingProvider().map(obj, targetType, configuration); + } + @Override public DocumentContext set(String path, Object newValue, Predicate... filters) { return set(compile(path, filters), newValue); diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java index fbaa5abf..d59c171d 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java @@ -51,105 +51,111 @@ public class PathCompiler { public static Path compile(String path, Predicate... filters) { + notEmpty(path, "Path may not be null empty"); - path = path.trim(); + try { + path = path.trim(); - if(path.endsWith("..")){ - throw new InvalidPathException("A path can not end with a scan."); - } + if (path.endsWith("..")) { + throw new InvalidPathException("A path can not end with a scan."); + } - LinkedList filterList = new LinkedList(asList(filters)); + LinkedList filterList = new LinkedList(asList(filters)); - if (path.charAt(0) != '$' && path.charAt(0) != '@') { - path = "$." + path; - } + if (path.charAt(0) != '$' && path.charAt(0) != '@') { + path = "$." + path; + } - boolean isRootPath = (path.charAt(0) == '$'); + boolean isRootPath = (path.charAt(0) == '$'); - if(path.charAt(0) == '@'){ - path = "$" + path.substring(1); - } + if (path.charAt(0) == '@') { + path = "$" + path.substring(1); + } - if(path.length() > 1 && - path.charAt(1) != '.' && - path.charAt(1) != '['){ - throw new InvalidPathException("Invalid path " + path); - } + if (path.length() > 1 && + path.charAt(1) != '.' && + path.charAt(1) != '[') { + throw new InvalidPathException("Invalid path " + path); + } - String cacheKey = path + isRootPath + filterList.toString(); - Path p = cache.get(cacheKey); - if (p != null) { - if(logger.isDebugEnabled()) logger.debug("Using cached path: " + cacheKey); - return p; - } + String cacheKey = path + isRootPath + filterList.toString(); + Path p = cache.get(cacheKey); + if (p != null) { + if (logger.isDebugEnabled()) logger.debug("Using cached path: " + cacheKey); + return p; + } - RootPathToken root = null; - - - int i = 0; - int positions; - String fragment = ""; - - do { - char current = path.charAt(i); - - switch (current) { - case SPACE: - throw new InvalidPathException("Space not allowed in path"); - case DOCUMENT: - fragment = "$"; - i++; - break; - case BRACKET_OPEN: - positions = fastForwardUntilClosed(path, i); - fragment = path.substring(i, i + positions); - i += positions; - break; - case PERIOD: - i++; - if (path.charAt(i) == PERIOD) { - //This is a deep scan - fragment = ".."; - i++; - } else { - positions = fastForward(path, i); - if (positions == 0) { - continue; + RootPathToken root = null; + + + int i = 0; + int positions; + String fragment = ""; + + do { + char current = path.charAt(i); - } else if (positions == 1 && path.charAt(i) == '*') { - fragment = new String("[*]"); + switch (current) { + case SPACE: + throw new InvalidPathException("Space not allowed in path"); + case DOCUMENT: + fragment = "$"; + i++; + break; + case BRACKET_OPEN: + positions = fastForwardUntilClosed(path, i); + fragment = path.substring(i, i + positions); + i += positions; + break; + case PERIOD: + i++; + if (path.charAt(i) == PERIOD) { + //This is a deep scan + fragment = ".."; + i++; } else { - assertValidFieldChars(path, i, positions); + positions = fastForward(path, i); + if (positions == 0) { + continue; - fragment = PROPERTY_OPEN + path.substring(i, i + positions) + PROPERTY_CLOSE; + } else if (positions == 1 && path.charAt(i) == '*') { + fragment = new String("[*]"); + } else { + assertValidFieldChars(path, i, positions); + + fragment = PROPERTY_OPEN + path.substring(i, i + positions) + PROPERTY_CLOSE; + } + i += positions; } + break; + case ANY: + fragment = new String("[*]"); + i++; + break; + default: + positions = fastForward(path, i); + + fragment = PROPERTY_OPEN + path.substring(i, i + positions) + PROPERTY_CLOSE; i += positions; - } - break; - case ANY: - fragment = new String("[*]"); - i++; - break; - default: - positions = fastForward(path, i); - - fragment = PROPERTY_OPEN + path.substring(i, i + positions) + PROPERTY_CLOSE; - i += positions; - break; - } - if (root == null) { - root = (RootPathToken) PathComponentAnalyzer.analyze(fragment, filterList); - } else { - root.append(PathComponentAnalyzer.analyze(fragment, filterList)); - } + break; + } + if (root == null) { + root = (RootPathToken) PathComponentAnalyzer.analyze(fragment, filterList); + } else { + root.append(PathComponentAnalyzer.analyze(fragment, filterList)); + } - } while (i < path.length()); + } while (i < path.length()); - Path pa = new CompiledPath(root, isRootPath); + Path pa = new CompiledPath(root, isRootPath); - cache.put(cacheKey, pa); + cache.put(cacheKey, pa); - return pa; + return pa; + + } catch (Exception ex){ + throw new InvalidPathException(ex); + } } private static void assertValidFieldChars(String s, int start, int positions) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/GsonMappingProvider.java b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/GsonMappingProvider.java index 1c04ed4c..51bee874 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/GsonMappingProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/GsonMappingProvider.java @@ -16,8 +16,12 @@ package com.jayway.jsonpath.internal.spi.mapper; import com.google.gson.Gson; import com.google.gson.JsonElement; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPathException; +import com.jayway.jsonpath.TypeRef; +import com.jayway.jsonpath.spi.mapper.MappingException; import com.jayway.jsonpath.spi.mapper.MappingProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,6 +63,19 @@ public class GsonMappingProvider implements MappingProvider { @Override public T map(Object source, Class targetType, Configuration configuration) { - return factory.createInstance().getAdapter(targetType).fromJsonTree((JsonElement) source); + try { + return factory.createInstance().getAdapter(targetType).fromJsonTree((JsonElement) source); + } catch (Exception e){ + throw new MappingException(e); + } + } + + @Override + public T map(Object source, TypeRef targetType, Configuration configuration) { + try { + return (T) factory.createInstance().getAdapter(TypeToken.get(targetType.getType())).fromJsonTree((JsonElement) source); + } catch (Exception e){ + throw new MappingException(e); + } } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/JacksonMappingProvider.java b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/JacksonMappingProvider.java index 438573b0..90a12ca2 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/JacksonMappingProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/JacksonMappingProvider.java @@ -14,15 +14,17 @@ */ package com.jayway.jsonpath.internal.spi.mapper; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.TypeRef; +import com.jayway.jsonpath.spi.mapper.MappingException; import com.jayway.jsonpath.spi.mapper.MappingProvider; public class JacksonMappingProvider implements MappingProvider { private final ObjectMapper objectMapper; - public JacksonMappingProvider() { this(new ObjectMapper()); } @@ -32,12 +34,31 @@ public class JacksonMappingProvider implements MappingProvider { } - @Override public T map(Object source, Class targetType, Configuration configuration) { if(source == null){ return null; } - return objectMapper.convertValue(source, targetType); + try { + return objectMapper.convertValue(source, targetType); + } catch (Exception e) { + throw new MappingException(e); + } + + } + + @Override + public T map(Object source, final TypeRef targetType, Configuration configuration) { + if(source == null){ + return null; + } + JavaType type = objectMapper.getTypeFactory().constructType(targetType.getType()); + + try { + return (T)objectMapper.convertValue(source, type); + } catch (Exception e) { + throw new MappingException(e); + } + } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/JsonSmartMappingProvider.java b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/JsonSmartMappingProvider.java index 731165b3..8f3751f1 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/JsonSmartMappingProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/mapper/JsonSmartMappingProvider.java @@ -15,17 +15,24 @@ package com.jayway.jsonpath.internal.spi.mapper; import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.TypeRef; import com.jayway.jsonpath.spi.mapper.MappingException; import com.jayway.jsonpath.spi.mapper.MappingProvider; +import net.minidev.json.JSONUtil; +import net.minidev.json.JSONValue; import net.minidev.json.writer.JsonReader; import net.minidev.json.writer.JsonReaderI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.math.BigDecimal; import java.text.DateFormat; import java.text.ParseException; +import java.util.Collection; import java.util.Date; +import java.util.Map; public class JsonSmartMappingProvider implements MappingProvider { @@ -73,7 +80,21 @@ public class JsonSmartMappingProvider implements MappingProvider { if (targetType.isAssignableFrom(source.getClass())) { return (T) source; } - return factory.createInstance().getMapper(targetType).convert(source); + try { + if(!configuration.jsonProvider().isMap(source) && !configuration.jsonProvider().isArray(source)){ + return factory.createInstance().getMapper(targetType).convert(source); + } + String s = configuration.jsonProvider().toJson(source); + return (T) JSONValue.parse(s, targetType); + } catch (Exception e) { + throw new MappingException(e); + } + + } + + @Override + public T map(Object source, TypeRef targetType, Configuration configuration) { + throw new UnsupportedOperationException("Not supported! Use Jackson or Gson provider"); } private static class StringReader extends JsonReaderI { diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/mapper/MappingProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/mapper/MappingProvider.java index 5bdc7016..a0e8597a 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/mapper/MappingProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/mapper/MappingProvider.java @@ -15,6 +15,7 @@ package com.jayway.jsonpath.spi.mapper; import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.TypeRef; /** * Maps object between different Types @@ -31,4 +32,14 @@ public interface MappingProvider { * @return return the mapped object */ T map(Object source, Class targetType, Configuration configuration); + + /** + * + * @param source object to map + * @param targetType the type the source object should be mapped to + * @param configuration current configuration + * @param the mapped result type + * @return return the mapped object + */ + T map(Object source, TypeRef targetType, Configuration configuration); } diff --git a/json-path/src/test/java/com/jayway/jsonpath/GsonJsonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/GsonJsonProviderTest.java index 000af9db..08054810 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/GsonJsonProviderTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/GsonJsonProviderTest.java @@ -3,13 +3,40 @@ package com.jayway.jsonpath; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import com.jayway.jsonpath.spi.mapper.MappingException; import org.junit.Test; +import java.io.IOException; +import java.util.List; + import static com.jayway.jsonpath.JsonPath.using; import static org.assertj.core.api.Assertions.assertThat; public class GsonJsonProviderTest extends BaseTest { + private static final String JSON = + "[" + + "{\n" + + " \"foo\" : \"foo0\",\n" + + " \"bar\" : 0,\n" + + " \"baz\" : true,\n" + + " \"gen\" : {\"eric\" : \"yepp\"}" + + "}," + + "{\n" + + " \"foo\" : \"foo1\",\n" + + " \"bar\" : 1,\n" + + " \"baz\" : true,\n" + + " \"gen\" : {\"eric\" : \"yepp\"}" + + "}," + + "{\n" + + " \"foo\" : \"foo2\",\n" + + " \"bar\" : 2,\n" + + " \"baz\" : true,\n" + + " \"gen\" : {\"eric\" : \"yepp\"}" + + "}" + + "]"; + @Test public void json_can_be_parsed() { JsonObject node = using(GSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$"); @@ -28,7 +55,7 @@ public class GsonJsonProviderTest extends BaseTest { @Test public void ints_are_unwrapped() { JsonElement node = using(GSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property"); - int unwrapped = using(GSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", Integer.class); + int unwrapped = using(GSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", int.class); assertThat(unwrapped).isEqualTo(Integer.MAX_VALUE); assertThat(unwrapped).isEqualTo(node.getAsInt()); @@ -71,19 +98,49 @@ public class GsonJsonProviderTest extends BaseTest { "}"; - FooBarBaz fooBarBaz = JsonPath.using(GSON_CONFIGURATION).parse(json).read("$", FooBarBaz.class); + TestClazz testClazz = JsonPath.using(GSON_CONFIGURATION).parse(json).read("$", TestClazz.class); + + assertThat(testClazz.foo).isEqualTo("foo"); + assertThat(testClazz.bar).isEqualTo(10L); + assertThat(testClazz.baz).isEqualTo(true); + + } + + @Test + public void test_type_ref() throws IOException { + TypeRef>> typeRef = new TypeRef>>() {}; + + List> list = JsonPath.using(GSON_CONFIGURATION).parse(JSON).read("$", typeRef); + + assertThat(list.get(0).gen.eric).isEqualTo("yepp"); + } + + @Test(expected = MappingException.class) + public void test_type_ref_fail() throws IOException { + TypeRef>> typeRef = new TypeRef>>() {}; + + using(GSON_CONFIGURATION).parse(JSON).read("$", typeRef); + } + + public static class FooBarBaz { + public T gen; + public String foo; + public Long bar; + public boolean baz; + } - assertThat(fooBarBaz.foo).isEqualTo("foo"); - assertThat(fooBarBaz.bar).isEqualTo(10L); - assertThat(fooBarBaz.baz).isEqualTo(true); + public static class Gen { + public String eric; } - public static class FooBarBaz { + public static class TestClazz { public String foo; public Long bar; public boolean baz; } + + } diff --git a/json-path/src/test/java/com/jayway/jsonpath/JacksonTreeJsonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/JacksonTreeJsonProviderTest.java index 46e91cfa..568071fb 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/JacksonTreeJsonProviderTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/JacksonTreeJsonProviderTest.java @@ -3,23 +3,49 @@ package com.jayway.jsonpath; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.jayway.jsonpath.spi.mapper.MappingException; import org.junit.Test; +import java.io.IOException; +import java.util.List; + import static com.jayway.jsonpath.JsonPath.using; import static org.assertj.core.api.Assertions.assertThat; public class JacksonTreeJsonProviderTest extends BaseTest { + private static final String JSON = + "[" + + "{\n" + + " \"foo\" : \"foo0\",\n" + + " \"bar\" : 0,\n" + + " \"baz\" : true,\n" + + " \"gen\" : {\"eric\" : \"yepp\"}" + + "}," + + "{\n" + + " \"foo\" : \"foo1\",\n" + + " \"bar\" : 1,\n" + + " \"baz\" : true,\n" + + " \"gen\" : {\"eric\" : \"yepp\"}" + + "}," + + "{\n" + + " \"foo\" : \"foo2\",\n" + + " \"bar\" : 2,\n" + + " \"baz\" : true,\n" + + " \"gen\" : {\"eric\" : \"yepp\"}" + + "}" + + "]"; + @Test public void json_can_be_parsed() { - ObjectNode node = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$"); + ObjectNode node = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$"); assertThat(node.get("string-property").asText()).isEqualTo("string-value"); } @Test public void strings_are_unwrapped() { - JsonNode node = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.string-property"); - String unwrapped = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.string-property", String.class); + JsonNode node = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.string-property"); + String unwrapped = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.string-property", String.class); assertThat(unwrapped).isEqualTo("string-value"); assertThat(unwrapped).isEqualTo(node.asText()); @@ -27,16 +53,16 @@ public class JacksonTreeJsonProviderTest extends BaseTest { @Test public void ints_are_unwrapped() { - JsonNode node = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property"); - int unwrapped = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", int.class); + JsonNode node = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property"); + int unwrapped = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", int.class); assertThat(unwrapped).isEqualTo(Integer.MAX_VALUE); assertThat(unwrapped).isEqualTo(node.asInt()); } @Test public void longs_are_unwrapped() { - JsonNode node = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.long-max-property"); - long unwrapped = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.long-max-property", long.class); + JsonNode node = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.long-max-property"); + long unwrapped = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.long-max-property", long.class); assertThat(unwrapped).isEqualTo(Long.MAX_VALUE); assertThat(unwrapped).isEqualTo(node.asLong()); @@ -45,12 +71,36 @@ public class JacksonTreeJsonProviderTest extends BaseTest { @Test public void list_of_numbers() { - ArrayNode objs = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[*].display-price"); + ArrayNode objs = using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[*].display-price"); + System.out.println(objs.toString()); + } + @Test + public void test_type_ref() throws IOException { + TypeRef>> typeRef = new TypeRef>>() {}; - System.out.println(objs.toString()); + List> list = using(JACKSON_TREE_CONFIGURATION).parse(JSON).read("$", typeRef); + assertThat(list.get(0).gen.eric).isEqualTo("yepp"); } + @Test(expected = MappingException.class) + public void test_type_ref_fail() throws IOException { + TypeRef>> typeRef = new TypeRef>>() {}; + + using(JACKSON_TREE_CONFIGURATION).parse(JSON).read("$", typeRef); + } + + public static class FooBarBaz { + public T gen; + public String foo; + public Long bar; + public boolean baz; + } + + + public static class Gen { + public String eric; + } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/JsonSmartMappingProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/JsonSmartMappingProviderTest.java new file mode 100644 index 00000000..7c7b4ad9 --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/JsonSmartMappingProviderTest.java @@ -0,0 +1,69 @@ +package com.jayway.jsonpath; + +import org.junit.Test; + +import java.io.IOException; +import java.util.List; + +import static com.jayway.jsonpath.JsonPath.parse; +import static com.jayway.jsonpath.JsonPath.using; +import static org.assertj.core.api.Assertions.assertThat; + +public class JsonSmartMappingProviderTest { + + private static final String JSON = + "[" + + "{\n" + + " \"foo\" : \"foo0\",\n" + + " \"bar\" : 0,\n" + + " \"baz\" : true,\n" + + " \"gen\" : {\"eric\" : \"yepp\"}" + + "}," + + "{\n" + + " \"foo\" : \"foo1\",\n" + + " \"bar\" : 1,\n" + + " \"baz\" : true,\n" + + " \"gen\" : {\"eric\" : \"yepp\"}" + + "}," + + "{\n" + + " \"foo\" : \"foo2\",\n" + + " \"bar\" : 2,\n" + + " \"baz\" : true,\n" + + " \"gen\" : {\"eric\" : \"yepp\"}" + + "}" + + "]"; + + @Test + public void class_mapping() { + + Object map = Configuration.defaultConfiguration().jsonProvider().createMap(); + Configuration.defaultConfiguration().jsonProvider().setProperty(map, "eric", "eric-val"); + + + Gen gen = parse(map).read("$", Gen.class); + + assertThat(gen.eric).isEqualTo("eric-val"); + + } + + @Test(expected = UnsupportedOperationException.class) + public void test_type_ref() throws IOException { + + TypeRef> typeRef = new TypeRef>() {}; + + List gen = parse(JSON).read("$", typeRef); + } + + + public static class FooBarBaz { + public Gen gen; + public String foo; + public Long bar; + public boolean baz; + } + + + public static class Gen { + public String eric; + } +} diff --git a/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java b/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java index d9bcfcfe..2eb140ef 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java @@ -442,4 +442,59 @@ public class IssuesTest { Assertions.assertThat(result).containsExactly("foo"); } + + @Test + public void issue_60() { + + + String json ="[\n" + + "{\n" + + " \"mpTransactionId\": \"542986eae4b001fd500fdc5b-coreDisc_50-title\",\n" + + " \"resultType\": \"FAIL\",\n" + + " \"narratives\": [\n" + + " {\n" + + " \"ruleProcessingDate\": \"Nov 2, 2014 7:30:20 AM\",\n" + + " \"area\": \"Discovery\",\n" + + " \"phase\": \"Validation\",\n" + + " \"message\": \"Chain does not have a discovery event. Possible it was cut by the date that was picked\",\n" + + " \"ruleName\": \"Validate chain\\u0027s discovery event existence\",\n" + + " \"lastRule\": true\n" + + " }\n" + + " ]\n" + + "},\n" + + "{\n" + + " \"mpTransactionId\": \"54298649e4b001fd500fda3e-fixCoreDiscovery_3-title\",\n" + + " \"resultType\": \"FAIL\",\n" + + " \"narratives\": [\n" + + " {\n" + + " \"ruleProcessingDate\": \"Nov 2, 2014 7:30:20 AM\",\n" + + " \"area\": \"Discovery\",\n" + + " \"phase\": \"Validation\",\n" + + " \"message\": \"There is one and only discovery event ContentDiscoveredEvent(230) found.\",\n" + + " \"ruleName\": \"Marks existence of discovery event (230)\",\n" + + " \"lastRule\": false\n" + + " },\n" + + " {\n" + + " \"ruleProcessingDate\": \"Nov 2, 2014 7:30:20 AM\",\n" + + " \"area\": \"Discovery/Processing\",\n" + + " \"phase\": \"Validation\",\n" + + " \"message\": \"Chain does not have SLA start event (204) in Discovery or Processing. \",\n" + + " \"ruleName\": \"Check if SLA start event is not present (204). \",\n" + + " \"lastRule\": false\n" + + " },\n" + + " {\n" + + " \"ruleProcessingDate\": \"Nov 2, 2014 7:30:20 AM\",\n" + + " \"area\": \"Processing\",\n" + + " \"phase\": \"Transcode\",\n" + + " \"message\": \"No start transcoding events found\",\n" + + " \"ruleName\": \"Start transcoding events missing (240)\",\n" + + " \"lastRule\": true\n" + + " }\n" + + " ]\n" + + "}]"; + + List problems = JsonPath.read(json, "$..narratives[?(@.lastRule==true)].message"); + + Assertions.assertThat(problems).containsExactly("Chain does not have a discovery event. Possible it was cut by the date that was picked", "No start transcoding events found"); + } }