diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java index 80ac2bd4..851fad48 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java @@ -24,8 +24,10 @@ 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); @@ -36,7 +38,8 @@ public class CompiledPath implements Path { public CompiledPath(RootPathToken root, boolean isRootPath) { - this.root = invertScannerFunctionRelationship(root); + ScannerFunctionInverter inverter = new ScannerFunctionInverter(root); + this.root = inverter.invert(); this.isRootPath = isRootPath; } @@ -47,45 +50,8 @@ public class CompiledPath implements Path { - /** - * 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) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java index 34cf1402..0b51672f 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java @@ -150,7 +150,7 @@ public abstract class PathToken { return prev; } - PathToken next() { + public PathToken next() { if (isLeaf()) { throw new IllegalStateException("Current path token is a leaf"); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java index 1a786ac6..d67988ba 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java @@ -26,7 +26,7 @@ public class RootPathToken extends PathToken { private final String rootToken; - RootPathToken(char rootToken) { + public RootPathToken(char rootToken) { this.rootToken = Character.toString(rootToken); this.tail = this; this.tokenCount = 1; diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/ScannerFunctionInverter.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/ScannerFunctionInverter.java new file mode 100644 index 00000000..567dbee6 --- /dev/null +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/ScannerFunctionInverter.java @@ -0,0 +1,40 @@ +package com.jayway.jsonpath.internal.path; + +import com.jayway.jsonpath.internal.function.ParamType; +import com.jayway.jsonpath.internal.function.Parameter; + +import java.util.Arrays; + +public class ScannerFunctionInverter { + + private final RootPathToken path; + + public ScannerFunctionInverter(RootPathToken path) { + this.path = path; + } + + public RootPathToken invert() { + if (path.isFunctionPath() && path.next() instanceof ScanPathToken) { + PathToken token = path; + PathToken prior = null; + while (null != (token = token.next()) && !(token instanceof FunctionPathToken)) { + prior = token; + } + if (token instanceof FunctionPathToken) { + prior.setNext(null); + path.setTail(prior); + + 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); + + return functionRoot; + } + } + return path; + } +}