2 changed files with 230 additions and 155 deletions
@ -1,77 +1,77 @@ |
|||||||
package com.jayway.jsonpath.internal.function.text; |
package com.jayway.jsonpath.internal.function.text; |
||||||
|
|
||||||
import com.google.gson.Gson; |
import com.google.gson.Gson; |
||||||
import com.google.gson.GsonBuilder; |
import com.google.gson.GsonBuilder; |
||||||
import com.jayway.jsonpath.internal.EvaluationContext; |
import com.jayway.jsonpath.internal.EvaluationContext; |
||||||
import com.jayway.jsonpath.internal.Path; |
import com.jayway.jsonpath.internal.Path; |
||||||
import com.jayway.jsonpath.internal.PathRef; |
import com.jayway.jsonpath.internal.PathRef; |
||||||
import com.jayway.jsonpath.internal.function.Parameter; |
import com.jayway.jsonpath.internal.function.Parameter; |
||||||
import com.jayway.jsonpath.internal.function.PathFunction; |
import com.jayway.jsonpath.internal.function.PathFunction; |
||||||
import com.jayway.jsonpath.internal.path.CompiledPath; |
import com.jayway.jsonpath.internal.path.CompiledPath; |
||||||
import com.jayway.jsonpath.internal.path.PathToken; |
import com.jayway.jsonpath.internal.path.PathToken; |
||||||
import com.jayway.jsonpath.internal.path.RootPathToken; |
import com.jayway.jsonpath.internal.path.RootPathToken; |
||||||
import com.jayway.jsonpath.internal.path.WildcardPathToken; |
import com.jayway.jsonpath.internal.path.WildcardPathToken; |
||||||
|
|
||||||
import java.util.List; |
import java.util.List; |
||||||
|
|
||||||
/** |
/** |
||||||
* Provides the length of a JSONArray Object |
* Provides the length of a JSONArray Object |
||||||
* |
* |
||||||
* Created by mattg on 6/26/15. |
* Created by mattg on 6/26/15. |
||||||
*/ |
*/ |
||||||
public class Length implements PathFunction { |
public class Length implements PathFunction { |
||||||
|
|
||||||
public static final String TOKEN_NAME = "length"; |
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 |
* 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.*) |
* have. Thus when we wrote the original query what we really wanted was $..book.length() or $.length($..book.*) |
||||||
* |
* |
||||||
* @param currentPath |
* @param currentPath |
||||||
* The current path location inclusive of the function name |
* The current path location inclusive of the function name |
||||||
* @param parent |
* @param parent |
||||||
* The path location above the current function |
* The path location above the current function |
||||||
* |
* |
||||||
* @param model |
* @param model |
||||||
* The JSON model as input to this particular function |
* The JSON model as input to this particular function |
||||||
* |
* |
||||||
* @param ctx |
* @param ctx |
||||||
* Eval context, state bag used as the path is traversed, maintains the result of executing |
* Eval context, state bag used as the path is traversed, maintains the result of executing |
||||||
* |
* |
||||||
* @param parameters |
* @param parameters |
||||||
* @return |
* @return |
||||||
*/ |
*/ |
||||||
@Override |
@Override |
||||||
public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List<Parameter> parameters) { |
public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List<Parameter> parameters) { |
||||||
if (null != parameters && parameters.size() > 0) { |
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
|
// 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
|
// for length - to the wildcard such that we request all of its children so we can get back an array and
|
||||||
// take its length.
|
// take its length.
|
||||||
Parameter lengthOfParameter = parameters.get(0); |
Parameter lengthOfParameter = parameters.get(0); |
||||||
if (!lengthOfParameter.getPath().isFunctionPath()) { |
if (!lengthOfParameter.getPath().isFunctionPath()) { |
||||||
Path path = lengthOfParameter.getPath(); |
Path path = lengthOfParameter.getPath(); |
||||||
if (path instanceof CompiledPath) { |
if (path instanceof CompiledPath) { |
||||||
RootPathToken root = ((CompiledPath) path).getRoot(); |
RootPathToken root = ((CompiledPath) path).getRoot(); |
||||||
PathToken tail = root.getNext(); |
PathToken tail = root.getNext(); |
||||||
while (null != tail && null != tail.getNext()) { |
while (null != tail && null != tail.getNext()) { |
||||||
tail = tail.getNext(); |
tail = tail.getNext(); |
||||||
} |
} |
||||||
if (null != tail) { |
if (ctx.configuration().jsonProvider().isMap(model) && null != tail) { |
||||||
tail.setNext(new WildcardPathToken()); |
tail.setNext(new WildcardPathToken()); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
Object innerModel = parameters.get(0).getPath().evaluate(model, model, ctx.configuration()).getValue(); |
Object innerModel = parameters.get(0).getPath().evaluate(model, model, ctx.configuration()).getValue(); |
||||||
if (ctx.configuration().jsonProvider().isArray(innerModel)) { |
if (ctx.configuration().jsonProvider().isArray(innerModel)) { |
||||||
return ctx.configuration().jsonProvider().length(innerModel); |
return ctx.configuration().jsonProvider().length(innerModel); |
||||||
} |
} |
||||||
} |
} |
||||||
if (ctx.configuration().jsonProvider().isArray(model)) { |
if (ctx.configuration().jsonProvider().isArray(model)) { |
||||||
return ctx.configuration().jsonProvider().length(model); |
return ctx.configuration().jsonProvider().length(model); |
||||||
} else if(ctx.configuration().jsonProvider().isMap(model)){ |
} else if(ctx.configuration().jsonProvider().isMap(model)){ |
||||||
return ctx.configuration().jsonProvider().length(model); |
return ctx.configuration().jsonProvider().length(model); |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
@ -1,79 +1,154 @@ |
|||||||
package com.jayway.jsonpath; |
package com.jayway.jsonpath; |
||||||
|
|
||||||
import org.json.JSONArray; |
import org.json.JSONArray; |
||||||
import org.json.JSONObject; |
import org.json.JSONObject; |
||||||
import org.junit.Test; |
import org.junit.Test; |
||||||
|
|
||||||
import java.util.List; |
import java.util.List; |
||||||
import java.util.Map; |
import java.util.Map; |
||||||
|
|
||||||
import static com.jayway.jsonpath.JsonPath.using; |
import static com.jayway.jsonpath.JsonPath.using; |
||||||
import static org.assertj.core.api.Assertions.assertThat; |
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
public class JsonOrgJsonProviderTest extends BaseTest { |
public class JsonOrgJsonProviderTest extends BaseTest { |
||||||
|
|
||||||
|
|
||||||
@Test |
@Test |
||||||
public void an_object_can_be_read() { |
public void an_object_can_be_read() { |
||||||
|
|
||||||
JSONObject book = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0]"); |
JSONObject book = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0]"); |
||||||
|
|
||||||
assertThat(book.get("author").toString()).isEqualTo("Nigel Rees"); |
assertThat(book.get("author").toString()).isEqualTo("Nigel Rees"); |
||||||
} |
} |
||||||
|
|
||||||
@Test |
@Test |
||||||
public void a_property_can_be_read() { |
public void a_property_can_be_read() { |
||||||
|
|
||||||
String category = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0].category"); |
String category = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0].category"); |
||||||
|
|
||||||
assertThat(category).isEqualTo("reference"); |
assertThat(category).isEqualTo("reference"); |
||||||
} |
} |
||||||
|
|
||||||
@Test |
@Test |
||||||
public void a_filter_can_be_applied() { |
public void a_filter_can_be_applied() { |
||||||
|
|
||||||
JSONArray fictionBooks = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[?(@.category == 'fiction')]"); |
JSONArray fictionBooks = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[?(@.category == 'fiction')]"); |
||||||
|
|
||||||
assertThat(fictionBooks.length()).isEqualTo(3); |
assertThat(fictionBooks.length()).isEqualTo(3); |
||||||
} |
} |
||||||
|
|
||||||
@Test |
@Test |
||||||
public void result_can_be_mapped_to_object() { |
public void result_can_be_mapped_to_object() { |
||||||
|
|
||||||
List<Map<String, Object>> books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book", List.class); |
List<Map<String, Object>> books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book", List.class); |
||||||
|
|
||||||
assertThat(books.size()).isEqualTo(4); |
assertThat(books.size()).isEqualTo(4); |
||||||
} |
} |
||||||
|
|
||||||
@Test |
@Test |
||||||
public void read_books_with_isbn() { |
public void read_books_with_isbn() { |
||||||
|
|
||||||
JSONArray books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$..book[?(@.isbn)]"); |
JSONArray books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$..book[?(@.isbn)]"); |
||||||
|
|
||||||
assertThat(books.length()).isEqualTo(2); |
assertThat(books.length()).isEqualTo(2); |
||||||
} |
} |
||||||
|
|
||||||
/** |
/** |
||||||
* Functions take parameters, the length parameter for example takes an entire document which we anticipate |
* 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. |
* 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 |
* Since we translate this query from $..books.length() to length($..books) verify that this particular translation |
||||||
* works as anticipated. |
* works as anticipated. |
||||||
*/ |
*/ |
||||||
@Test |
@Test |
||||||
public void read_book_length_using_translated_query() { |
public void read_book_length_using_translated_query() { |
||||||
Integer result = using(Configuration.defaultConfiguration()) |
Integer result = using(Configuration.defaultConfiguration()) |
||||||
.parse(JSON_BOOK_STORE_DOCUMENT) |
.parse(JSON_BOOK_STORE_DOCUMENT) |
||||||
.read("$..book.length()"); |
.read("$..book.length()"); |
||||||
assertThat(result).isEqualTo(4); |
assertThat(result).isEqualTo(4); |
||||||
} |
} |
||||||
|
|
||||||
@Test |
@Test |
||||||
public void read_book_length() { |
public void read_book_length_using_translated_query_with_filter() { |
||||||
Object result = using(Configuration.defaultConfiguration()) |
Object result = using(Configuration.defaultConfiguration()) |
||||||
.parse(JSON_BOOK_STORE_DOCUMENT) |
.parse(JSON_BOOK_STORE_DOCUMENT) |
||||||
.read("$.length($..book)"); |
.read("$..[?(@.category == \"fiction\")].length()"); |
||||||
assertThat(result).isEqualTo(4); |
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); |
||||||
|
} |
||||||
|
} |
||||||
|
Loading…
Reference in new issue