Browse Source

inverting the relationship between root scanner and function such that the function takes a parameter which is the scanner expression

pull/377/head
Greenwood 8 years ago
parent
commit
a2936ebd68
  1. 48
      json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java
  2. 5
      json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java
  3. 3
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java
  4. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java
  5. 8
      json-path/src/test/java/com/jayway/jsonpath/internal/function/Issue191.java

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

@ -19,9 +19,13 @@ import com.jayway.jsonpath.internal.EvaluationAbortException;
import com.jayway.jsonpath.internal.EvaluationContext;
import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.internal.function.ParamType;
import com.jayway.jsonpath.internal.function.Parameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
public class CompiledPath implements Path {
private static final Logger logger = LoggerFactory.getLogger(CompiledPath.class);
@ -32,7 +36,7 @@ public class CompiledPath implements Path {
public CompiledPath(RootPathToken root, boolean isRootPath) {
this.root = root;
this.root = invertScannerFunctionRelationship(root);
this.isRootPath = isRootPath;
}
@ -41,6 +45,48 @@ public class CompiledPath implements Path {
return isRootPath;
}
/**
* In the event the writer of the path referenced a function at the tail end of a scanner, augment the query such
* that the root node is the function and the parameter to the function is the scanner. This way we maintain
* relative sanity in the path expression, functions either evaluate scalar values or arrays, they're
* not re-entrant nor should they maintain state, they do however take parameters.
*
* @param path
* this is our old root path which will become a parameter (assuming there's a scanner terminated by a function
*
* @return
* A function with the scanner as input, or if this situation doesn't exist just the input path
*/
private RootPathToken invertScannerFunctionRelationship(final RootPathToken path) {
if (path.isFunctionPath() && path.next() instanceof ScanPathToken) {
PathToken token = path;
PathToken prior = null;
while (null != (token = token.next()) && !(token instanceof FunctionPathToken)) {
prior = token;
}
// Invert the relationship $..path.function() to $.function($..path)
if (token instanceof FunctionPathToken) {
prior.setNext(null);
path.setTail(prior);
// Now generate a new parameter from our path
Parameter parameter = new Parameter();
parameter.setPath(new CompiledPath(path, true));
parameter.setType(ParamType.PATH);
((FunctionPathToken)token).setParameters(Arrays.asList(parameter));
RootPathToken functionRoot = new RootPathToken('$');
functionRoot.setTail(token);
functionRoot.setNext(token);
// Define the function as the root
return functionRoot;
}
}
return path;
}
@Override
public EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration, boolean forUpdate) {
if (logger.isDebugEnabled()) {

5
json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java

@ -20,7 +20,7 @@ public class FunctionPathToken extends PathToken {
private final String functionName;
private final String pathFragment;
private final List<Parameter> functionParams;
private List<Parameter> functionParams;
public FunctionPathToken(String pathFragment, List<Parameter> parameters) {
this.pathFragment = pathFragment + ((parameters != null && parameters.size() > 0) ? "(...)" : "()");
@ -81,4 +81,7 @@ public class FunctionPathToken extends PathToken {
}
public void setParameters(List<Parameter> parameters) {
this.functionParams = parameters;
}
}

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

@ -215,4 +215,7 @@ public abstract class PathToken {
protected abstract String getPathFragment();
public void setNext(final PathToken next) {
this.next = next;
}
}

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

@ -76,4 +76,8 @@ public class RootPathToken extends PathToken {
public boolean isFunctionPath() {
return (tail instanceof FunctionPathToken);
}
public void setTail(PathToken token) {
this.tail = token;
}
}

8
json-path/src/test/java/com/jayway/jsonpath/internal/function/Issue191.java

@ -27,6 +27,14 @@ public class Issue191 {
Long.valueOf(35679716813L), value);
}
@Test
public void testResultSetNumericComputationTail() {
InputStream stream = ClassLoader.getSystemResourceAsStream("issue_191.json");
Long value = JsonPath.parse(stream).read("$..timestamp.sum()", Long.class);
assertEquals("Expected the max function to consume the aggregation parameters and calculate the max over the result set",
Long.valueOf(35679716813L), value);
}
@Test
public void testMultipleResultSetSums() {
InputStream stream = ClassLoader.getSystemResourceAsStream("issue_191.json");

Loading…
Cancel
Save