Browse Source

Support for running functions over a result set.

pull/197/head
Nicholas Rahn 9 years ago
parent
commit
a998881858
  1. 18
      json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java
  2. 9
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java
  3. 7
      json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java
  4. 5
      json-path/src/test/java/com/jayway/jsonpath/internal/function/BaseFunctionTest.java
  5. 45
      json-path/src/test/java/com/jayway/jsonpath/internal/function/ResultSetFunctionTest.java

18
json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java

@ -50,7 +50,25 @@ public class CompiledPath implements Path {
EvaluationContextImpl ctx = new EvaluationContextImpl(this, rootDocument, configuration, forUpdate);
try {
PathRef op = ctx.forUpdate() ? PathRef.createRoot(rootDocument) : PathRef.NO_OP;
if (root.isFunctionPath()) {
// Remove the functionPath and evaluate the resulting path.
PathToken funcToken = root.chop();
root.evaluate("", op, document, ctx);
// Get the value of the evaluation to use as model when evaluating the function.
Object arrayModel = ctx.getValue(false);
// Evaluate the function on the model from the first evaluation.
RootPathToken newRoot = new RootPathToken('x');
newRoot.append(funcToken);
CompiledPath newCPath = new CompiledPath(newRoot, true);
EvaluationContextImpl newCtx = new EvaluationContextImpl(newCPath, arrayModel, configuration, false);
funcToken.evaluate("", op, arrayModel, newCtx);
return newCtx;
} else {
root.evaluate("", op, document, ctx);
return ctx;
}
} catch (EvaluationAbortException abort){};
return ctx;

9
json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java

@ -36,6 +36,15 @@ public abstract class PathToken {
return next;
}
PathToken remove() {
prev.next = next;
if (next == null) {
return prev;
}
next.prev = prev;
return next;
}
void handleObjectProperty(String currentPath, Object model, EvaluationContextImpl ctx, List<String> properties) {
if(properties.size() == 1) {

7
json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java

@ -43,6 +43,13 @@ public class RootPathToken extends PathToken {
return this;
}
public PathToken chop() {
// Remove tail.
PathToken oldTail = tail;
tail = tail.remove();
return oldTail;
}
public PathTokenAppender getPathTokenAppender(){
return new PathTokenAppender(){
@Override

5
json-path/src/test/java/com/jayway/jsonpath/internal/function/BaseFunctionTest.java

@ -14,6 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class BaseFunctionTest {
protected static final String NUMBER_SERIES = "{\"empty\": [], \"numbers\" : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}";
protected static final String TEXT_SERIES = "{\"urls\": [\"http://api.worldbank.org/countries/all/?format=json\", \"http://api.worldbank.org/countries/all/?format=json\"], \"text\" : [ \"a\", \"b\", \"c\", \"d\", \"e\", \"f\" ]}";
protected static final String EXAMPLE_SERIES = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";
/**
* Verify the function returns the correct result based on the input expectedValue
@ -40,6 +41,10 @@ public class BaseFunctionTest {
verifyFunction(conf, pathExpr, TEXT_SERIES, expectedValue);
}
protected void verifyExampleFunction(Configuration conf, String pathExpr, Object expectedValue) {
verifyFunction(conf, pathExpr, EXAMPLE_SERIES, expectedValue);
}
protected String getResourceAsText(String resourceName) throws IOException {
return new Scanner(BaseFunctionTest.class.getResourceAsStream(resourceName), "UTF-8").useDelimiter("\\A").next();
}

45
json-path/src/test/java/com/jayway/jsonpath/internal/function/ResultSetFunctionTest.java

@ -0,0 +1,45 @@
package com.jayway.jsonpath.internal.function;
import static org.junit.Assert.assertEquals;
import static org.junit.runners.Parameterized.Parameters;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Configurations;
import com.jayway.jsonpath.JsonPathException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Defines functional tests around executing functions on result sets.
*/
@RunWith(Parameterized.class)
public class ResultSetFunctionTest extends BaseFunctionTest {
private static final Logger logger = LoggerFactory.getLogger(ResultSetFunctionTest.class);
private Configuration conf = Configurations.GSON_CONFIGURATION;
public ResultSetFunctionTest(Configuration conf) {
logger.debug("Testing with configuration {}", conf.getClass().getName());
this.conf = conf;
}
@Parameters
public static Iterable<Configuration> configurations() {
return Configurations.configurations();
}
@Test
public void testMaxOfDoublesResultSet() {
verifyExampleFunction(conf, "$.store.book[*].price.max()", 22.99);
}
@Test
public void testSumOfDoublesResultSet() {
verifyExampleFunction(conf, "$.store.book[*].price.sum()", 53.92);
}
}
Loading…
Cancel
Save