diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Length.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Length.java index 785938c9..1dcb6a22 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Length.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Length.java @@ -1,77 +1,77 @@ -package com.jayway.jsonpath.internal.function.text; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.jayway.jsonpath.internal.EvaluationContext; -import com.jayway.jsonpath.internal.Path; -import com.jayway.jsonpath.internal.PathRef; -import com.jayway.jsonpath.internal.function.Parameter; -import com.jayway.jsonpath.internal.function.PathFunction; -import com.jayway.jsonpath.internal.path.CompiledPath; -import com.jayway.jsonpath.internal.path.PathToken; -import com.jayway.jsonpath.internal.path.RootPathToken; -import com.jayway.jsonpath.internal.path.WildcardPathToken; - -import java.util.List; - -/** - * Provides the length of a JSONArray Object - * - * Created by mattg on 6/26/15. - */ -public class Length implements PathFunction { - - public static final String TOKEN_NAME = "length"; - - /** - * When we calculate the length of a path, what we're asking is given the node we land on how many children does it - * have. Thus when we wrote the original query what we really wanted was $..book.length() or $.length($..book.*) - * - * @param currentPath - * The current path location inclusive of the function name - * @param parent - * The path location above the current function - * - * @param model - * The JSON model as input to this particular function - * - * @param ctx - * Eval context, state bag used as the path is traversed, maintains the result of executing - * - * @param parameters - * @return - */ - @Override - public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { - if (null != parameters && parameters.size() > 0) { - - // Set the tail of the first parameter, when its not a function path parameter (which wouldn't make sense - // for length - to the wildcard such that we request all of its children so we can get back an array and - // take its length. - Parameter lengthOfParameter = parameters.get(0); - if (!lengthOfParameter.getPath().isFunctionPath()) { - Path path = lengthOfParameter.getPath(); - if (path instanceof CompiledPath) { - RootPathToken root = ((CompiledPath) path).getRoot(); - PathToken tail = root.getNext(); - while (null != tail && null != tail.getNext()) { - tail = tail.getNext(); - } - if (null != tail) { - tail.setNext(new WildcardPathToken()); - } - } - } - Object innerModel = parameters.get(0).getPath().evaluate(model, model, ctx.configuration()).getValue(); - if (ctx.configuration().jsonProvider().isArray(innerModel)) { - return ctx.configuration().jsonProvider().length(innerModel); - } - } - if (ctx.configuration().jsonProvider().isArray(model)) { - return ctx.configuration().jsonProvider().length(model); - } else if(ctx.configuration().jsonProvider().isMap(model)){ - return ctx.configuration().jsonProvider().length(model); - } - return null; - } +package com.jayway.jsonpath.internal.function.text; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.jayway.jsonpath.internal.EvaluationContext; +import com.jayway.jsonpath.internal.Path; +import com.jayway.jsonpath.internal.PathRef; +import com.jayway.jsonpath.internal.function.Parameter; +import com.jayway.jsonpath.internal.function.PathFunction; +import com.jayway.jsonpath.internal.path.CompiledPath; +import com.jayway.jsonpath.internal.path.PathToken; +import com.jayway.jsonpath.internal.path.RootPathToken; +import com.jayway.jsonpath.internal.path.WildcardPathToken; + +import java.util.List; + +/** + * Provides the length of a JSONArray Object + * + * Created by mattg on 6/26/15. + */ +public class Length implements PathFunction { + + public static final String TOKEN_NAME = "length"; + + /** + * When we calculate the length of a path, what we're asking is given the node we land on how many children does it + * have. Thus when we wrote the original query what we really wanted was $..book.length() or $.length($..book.*) + * + * @param currentPath + * The current path location inclusive of the function name + * @param parent + * The path location above the current function + * + * @param model + * The JSON model as input to this particular function + * + * @param ctx + * Eval context, state bag used as the path is traversed, maintains the result of executing + * + * @param parameters + * @return + */ + @Override + public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { + if (null != parameters && parameters.size() > 0) { + + // Set the tail of the first parameter, when its not a function path parameter (which wouldn't make sense + // for length - to the wildcard such that we request all of its children so we can get back an array and + // take its length. + Parameter lengthOfParameter = parameters.get(0); + if (!lengthOfParameter.getPath().isFunctionPath()) { + Path path = lengthOfParameter.getPath(); + if (path instanceof CompiledPath) { + RootPathToken root = ((CompiledPath) path).getRoot(); + PathToken tail = root.getNext(); + while (null != tail && null != tail.getNext()) { + tail = tail.getNext(); + } + if (ctx.configuration().jsonProvider().isMap(model) && null != tail) { + tail.setNext(new WildcardPathToken()); + } + } + } + Object innerModel = parameters.get(0).getPath().evaluate(model, model, ctx.configuration()).getValue(); + if (ctx.configuration().jsonProvider().isArray(innerModel)) { + return ctx.configuration().jsonProvider().length(innerModel); + } + } + if (ctx.configuration().jsonProvider().isArray(model)) { + return ctx.configuration().jsonProvider().length(model); + } else if(ctx.configuration().jsonProvider().isMap(model)){ + return ctx.configuration().jsonProvider().length(model); + } + return null; + } } \ No newline at end of file diff --git a/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java index 47ce0c1e..61c40f26 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java @@ -1,79 +1,154 @@ -package com.jayway.jsonpath; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.Test; - -import java.util.List; -import java.util.Map; - -import static com.jayway.jsonpath.JsonPath.using; -import static org.assertj.core.api.Assertions.assertThat; - -public class JsonOrgJsonProviderTest extends BaseTest { - - - @Test - public void an_object_can_be_read() { - - JSONObject book = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0]"); - - assertThat(book.get("author").toString()).isEqualTo("Nigel Rees"); - } - - @Test - public void a_property_can_be_read() { - - String category = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0].category"); - - assertThat(category).isEqualTo("reference"); - } - - @Test - public void a_filter_can_be_applied() { - - JSONArray fictionBooks = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[?(@.category == 'fiction')]"); - - assertThat(fictionBooks.length()).isEqualTo(3); - } - - @Test - public void result_can_be_mapped_to_object() { - - List> books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book", List.class); - - assertThat(books.size()).isEqualTo(4); - } - - @Test - public void read_books_with_isbn() { - - JSONArray books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$..book[?(@.isbn)]"); - - assertThat(books.length()).isEqualTo(2); - } - - /** - * Functions take parameters, the length parameter for example takes an entire document which we anticipate - * will compute to a document that is an array of elements which can determine its length. - * - * Since we translate this query from $..books.length() to length($..books) verify that this particular translation - * works as anticipated. - */ - @Test - public void read_book_length_using_translated_query() { - Integer result = using(Configuration.defaultConfiguration()) - .parse(JSON_BOOK_STORE_DOCUMENT) - .read("$..book.length()"); - assertThat(result).isEqualTo(4); - } - - @Test - public void read_book_length() { - Object result = using(Configuration.defaultConfiguration()) - .parse(JSON_BOOK_STORE_DOCUMENT) - .read("$.length($..book)"); - assertThat(result).isEqualTo(4); - } - -} +package com.jayway.jsonpath; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; + +import java.util.List; +import java.util.Map; + +import static com.jayway.jsonpath.JsonPath.using; +import static org.assertj.core.api.Assertions.assertThat; + +public class JsonOrgJsonProviderTest extends BaseTest { + + + @Test + public void an_object_can_be_read() { + + JSONObject book = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0]"); + + assertThat(book.get("author").toString()).isEqualTo("Nigel Rees"); + } + + @Test + public void a_property_can_be_read() { + + String category = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0].category"); + + assertThat(category).isEqualTo("reference"); + } + + @Test + public void a_filter_can_be_applied() { + + JSONArray fictionBooks = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[?(@.category == 'fiction')]"); + + assertThat(fictionBooks.length()).isEqualTo(3); + } + + @Test + public void result_can_be_mapped_to_object() { + + List> books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book", List.class); + + assertThat(books.size()).isEqualTo(4); + } + + @Test + public void read_books_with_isbn() { + + JSONArray books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$..book[?(@.isbn)]"); + + assertThat(books.length()).isEqualTo(2); + } + + /** + * Functions take parameters, the length parameter for example takes an entire document which we anticipate + * will compute to a document that is an array of elements which can determine its length. + * + * Since we translate this query from $..books.length() to length($..books) verify that this particular translation + * works as anticipated. + */ + @Test + public void read_book_length_using_translated_query() { + Integer result = using(Configuration.defaultConfiguration()) + .parse(JSON_BOOK_STORE_DOCUMENT) + .read("$..book.length()"); + assertThat(result).isEqualTo(4); + } + + @Test + public void read_book_length_using_translated_query_with_filter() { + Object result = using(Configuration.defaultConfiguration()) + .parse(JSON_BOOK_STORE_DOCUMENT) + .read("$..[?(@.category == \"fiction\")].length()"); + assertThat(result).isEqualTo(3); + } + + @Test + public void read_book_length() { + Object result = using(Configuration.defaultConfiguration()) + .parse(JSON_BOOK_STORE_DOCUMENT) + .read("$.length($..book)"); + assertThat(result).isEqualTo(4); + } + + @Test + public void test(){ + String json = "[\n" + + " {\n" + + " \"author\": \"Nigel Rees\",\n" + + " \"category\": \"reference\",\n" + + " \"price\": 8.95,\n" + + " \"title\": \"Sayings of the Century\"\n" + + " },\n" + + " {\n" + + " \"author\": \"Evelyn Waugh\",\n" + + " \"category\": \"fiction\",\n" + + " \"price\": 12.99,\n" + + " \"title\": \"Sword of Honour\"\n" + + " },\n" + + " {\n" + + " \"author\": \"Herman Melville\",\n" + + " \"category\": \"fiction\",\n" + + " \"isbn\": \"0-553-21311-3\",\n" + + " \"price\": 8.99,\n" + + " \"title\": \"Moby Dick\"\n" + + " },\n" + + " {\n" + + " \"author\": \"J. R. R. Tolkien\",\n" + + " \"category\": \"fiction\",\n" + + " \"isbn\": \"0-395-19395-8\",\n" + + " \"price\": 22.99,\n" + + " \"title\": \"The Lord of the Rings\"\n" + + " }\n" + + "]"; + Object result = JsonPath.read(json,"$..[?(@.price < 10)].length()"); + assertThat(result).isEqualTo(2); + } + + @Test + public void test2(){ + String json = "[\n" + + " {\n" + + " \"author\": \"Nigel Rees\",\n" + + " \"category\": \"reference\",\n" + + " \"price\": 8.95,\n" + + " \"title\": \"Sayings of the Century\"\n" + + " },\n" + + " {\n" + + " \"author\": \"Evelyn Waugh\",\n" + + " \"category\": \"fiction\",\n" + + " \"price\": 12.99,\n" + + " \"title\": \"Sword of Honour\"\n" + + " },\n" + + " {\n" + + " \"author\": \"Herman Melville\",\n" + + " \"category\": \"fiction\",\n" + + " \"isbn\": \"0-553-21311-3\",\n" + + " \"price\": 8.99,\n" + + " \"title\": \"Moby Dick\"\n" + + " },\n" + + " {\n" + + " \"author\": \"J. R. R. Tolkien\",\n" + + " \"category\": \"fiction\",\n" + + " \"isbn\": \"0-395-19395-8\",\n" + + " \"price\": 22.99,\n" + + " \"title\": \"The Lord of the Rings\"\n" + + " }\n" + + "]"; + Object result = JsonPath.read(json,"$..[?(@.price == 22.99)].length()"); + assertThat(result).isEqualTo(1); + } +}