Skip to content
Open

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
public class JsonPathException extends RuntimeException {

public JsonPathException() {
super();
}

public JsonPathException(String message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.jayway.jsonpath.InvalidPathException;

public class CharacterIndex {

private static final char OPEN_PARENTHESIS = '(';
private static final char CLOSE_PARENTHESIS = ')';
private static final char CLOSE_SQUARE_BRACKET = ']';
Expand All @@ -29,6 +28,7 @@ public CharacterIndex(CharSequence charSequence) {
this.endPosition = charSequence.length() - 1;
}


public int length() {
return endPosition + 1;
}
Expand Down Expand Up @@ -320,4 +320,15 @@ public CharacterIndex trim() {
skipBlanksAtEnd();
return this;
}

public void readWhitespace() {
while (inBounds()) {
char c = currentChar();
if (!Character.isWhitespace(c)) {
break;
}
incrementPosition(1);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,15 @@ public static String unescape(String str) {
}
int len = str.length();
StringWriter writer = new StringWriter(len);
StringBuilder unicode = new StringBuilder(4);
final int UNICODE_LENGTH = 4;
StringBuilder unicode = new StringBuilder(UNICODE_LENGTH);
boolean hadSlash = false;
boolean inUnicode = false;
for (int i = 0; i < len; i++) {
char ch = str.charAt(i);
if (inUnicode) {
unicode.append(ch);
if (unicode.length() == 4) {
if (unicode.length() == UNICODE_LENGTH) {
try {
int value = Integer.parseInt(unicode.toString(), 16);
writer.write((char) value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,23 +205,28 @@ private RelationalExpressionNode readExpression() {
return new RelationalExpressionNode(left, operator, right);
}

private LogicalOperator readLogicalOperator(){
int begin = filter.skipBlanks().position();
int end = begin+1;
private LogicalOperator readLogicalOperator(CharSequence charSequence, int position) {
int begin = position;
int end = begin + 1;

if(!filter.inBounds(end)){
if (!inBounds(charSequence, end)) {
throw new InvalidPathException("Expected boolean literal");
}
CharSequence logicalOperator = filter.subSequence(begin, end+1);
if(!logicalOperator.equals("||") && !logicalOperator.equals("&&")){

CharSequence logicalOperator = charSequence.subSequence(begin, end + 1);
if (!logicalOperator.equals("||") && !logicalOperator.equals("&&")) {
throw new InvalidPathException("Expected logical operator");
}
filter.incrementPosition(logicalOperator.length());

logger.trace("LogicalOperator from {} to {} -> [{}]", begin, end, logicalOperator);

return LogicalOperator.fromString(logicalOperator.toString());
}

private boolean inBounds(CharSequence charSequence, int index) {
return index >= 0 && index < charSequence.length();
}

private RelationalOperator readRelationalOperator() {
int begin = filter.skipBlanks().position();

Expand Down Expand Up @@ -379,6 +384,7 @@ private PathNode readPath() {
return ValueNode.createPathNode(path, false, shouldExists);
}


private boolean expressionIsTerminated(){
char c = filter.currentChar();
if(c == CLOSE_PARENTHESIS || isLogicalOperatorChar(c)){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
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);
Expand All @@ -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;
}

Expand All @@ -47,45 +50,8 @@ public boolean 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,7 @@ public static Path compile(String path, final Predicate... filters) {
}

private void readWhitespace() {
while (path.inBounds()) {
char c = path.currentChar();
if (!isWhitespace(c)) {
break;
}
path.incrementPosition(1);
}
path.readWhitespace();
}

private Boolean isPathContext(char c) {
Expand All @@ -101,7 +95,7 @@ private Boolean isPathContext(char c) {
//[$ | @]
private RootPathToken readContextToken() {

readWhitespace();
path.readWhitespace();

if (!isPathContext(path.currentChar())) {
throw new InvalidPathException("Path must start with '$' or '@'");
Expand Down Expand Up @@ -305,7 +299,7 @@ private List<Parameter> parseFunctionParameters(String funcName) {
continue;
}

if (c == OPEN_BRACE || isDigit(c) || DOUBLE_QUOTE == c || MINUS == c) {
if (isJsonParam(c)) {
type = ParamType.JSON;
}
else if (isPathContext(c)) {
Expand Down Expand Up @@ -394,6 +388,26 @@ else if (isPathContext(c)) {
return parameters;
}

private boolean isOpenBrace(char c) {
return c == OPEN_BRACE;
}

private boolean isDigit(char c) {
return Character.isDigit(c);
}

private boolean isDoubleQuote(char c) {
return c == DOUBLE_QUOTE;
}

private boolean isMinus(char c) {
return c == MINUS;
}

private boolean isJsonParam(char c) {
return isOpenBrace(c) || isDigit(c) || isDoubleQuote(c) || isMinus(c);
}

private boolean isWhitespace(char c) {
return (c == SPACE || c == TAB || c == LF || c == CR);
}
Expand Down Expand Up @@ -519,12 +533,11 @@ private boolean readWildCardToken(PathTokenAppender appender) {
// [1], [1,2, n], [1:], [1:2], [:2]
//
private boolean readArrayToken(PathTokenAppender appender) {

if (!path.currentCharIs(OPEN_SQUARE_BRACKET)) {
if (!isOpeningSquareBracket()) {
return false;
}
char nextSignificantChar = path.nextSignificantChar();
if (!isDigit(nextSignificantChar) && nextSignificantChar != MINUS && nextSignificantChar != SPLIT) {
char nextSignificantChar = getNextSignificantChar();
if (!isValidNextChar(nextSignificantChar)) {
return false;
}

Expand All @@ -535,35 +548,66 @@ private boolean readArrayToken(PathTokenAppender appender) {
return false;
}

String expression = path.subSequence(expressionBeginIndex, expressionEndIndex).toString().trim();
String expression = extractExpression(expressionBeginIndex, expressionEndIndex);

if ("*".equals(expression)) {
if (!isValidExpression(expression)) {
return false;
}

//check valid chars
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
if (!isDigit(c) && c != COMMA && c != MINUS && c != SPLIT && c != SPACE) {
return false;
}
}

boolean isSliceOperation = expression.contains(":");

if (isSliceOperation) {
ArraySliceOperation arraySliceOperation = ArraySliceOperation.parse(expression);
appender.appendPathToken(PathTokenFactory.createSliceArrayPathToken(arraySliceOperation));
processSliceOperation(expression, appender);
} else {
ArrayIndexOperation arrayIndexOperation = ArrayIndexOperation.parse(expression);
appender.appendPathToken(PathTokenFactory.createIndexArrayPathToken(arrayIndexOperation));
processIndexOperation(expression, appender);
}

path.setPosition(expressionEndIndex + 1);

return path.currentIsTail() || readNextToken(appender);
}

private boolean isOpeningSquareBracket() {
return path.currentCharIs(OPEN_SQUARE_BRACKET);
}

private char getNextSignificantChar() {
return path.nextSignificantChar();
}

private boolean isValidNextChar(char nextChar) {
return isDigit(nextChar) || nextChar == MINUS || nextChar == SPLIT;
}

private String extractExpression(int beginIndex, int endIndex) {
return path.subSequence(beginIndex, endIndex).toString().trim();
}

private boolean isValidExpression(String expression) {
return !"*".equals(expression) && containsValidChars(expression);
}

private boolean containsValidChars(String expression) {
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
if (!isDigit(c) && c != COMMA && c != MINUS && c != SPLIT && c != SPACE) {
return false;
}
}
return true;
}

private void processSliceOperation(String expression, PathTokenAppender appender) {
ArraySliceOperation arraySliceOperation = ArraySliceOperation.parse(expression);
appender.appendPathToken(PathTokenFactory.createSliceArrayPathToken(arraySliceOperation));
}

private void processIndexOperation(String expression, PathTokenAppender appender) {
ArrayIndexOperation arrayIndexOperation = ArrayIndexOperation.parse(expression);
appender.appendPathToken(PathTokenFactory.createIndexArrayPathToken(arrayIndexOperation));
}


//
// ['foo']
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ PathToken prev(){
return prev;
}

PathToken next() {
public PathToken next() {
if (isLeaf()) {
throw new IllegalStateException("Current path token is a leaf");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading