Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added test cases for JsonFormatter class and refactored the code base #1008

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

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
Loading