diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java index 15775dcd..e6b73385 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java @@ -50,38 +50,38 @@ public class PathCompiler { private static final Cache cache = new Cache(200); - public static Path compile(String path, Predicate... filters) { + public static Path compile(final String path, final Predicate... filters) { notEmpty(path, "Path may not be null empty"); try { - path = path.trim(); + String trimmedPath = path.trim(); - if (path.endsWith("..")) { + if (trimmedPath.endsWith("..")) { throw new InvalidPathException("A path can not end with a scan."); } LinkedList filterList = new LinkedList(asList(filters)); - if (path.charAt(0) != '$' && path.charAt(0) != '@') { - path = "$." + path; + if (trimmedPath.charAt(0) != '$' && trimmedPath.charAt(0) != '@') { + trimmedPath = Utils.concat("$.", trimmedPath); } - boolean isRootPath = (path.charAt(0) == '$'); + boolean isRootPath = (trimmedPath.charAt(0) == '$'); - if (path.charAt(0) == '@') { - path = "$" + path.substring(1); + if (trimmedPath.charAt(0) == '@') { + trimmedPath = Utils.concat("$", trimmedPath.substring(1)); } - if (path.length() > 1 && - path.charAt(1) != '.' && - path.charAt(1) != '[') { - throw new InvalidPathException("Invalid path " + path); + if (trimmedPath.length() > 1 && + trimmedPath.charAt(1) != '.' && + trimmedPath.charAt(1) != '[') { + throw new InvalidPathException("Invalid path " + trimmedPath); } - String cacheKey = path + isRootPath + filterList.toString(); + String cacheKey = Utils.concat(trimmedPath, Boolean.toString(isRootPath), filterList.toString()); Path p = cache.get(cacheKey); if (p != null) { - if (logger.isDebugEnabled()) logger.debug("Using cached path: " + cacheKey); + if (logger.isDebugEnabled()) logger.debug("Using cached path: {}", cacheKey); return p; } @@ -93,7 +93,7 @@ public class PathCompiler { String fragment = ""; do { - char current = path.charAt(i); + char current = trimmedPath.charAt(i); switch (current) { case SPACE: @@ -103,27 +103,27 @@ public class PathCompiler { i++; break; case BRACKET_OPEN: - positions = fastForwardUntilClosed(path, i); - fragment = path.substring(i, i + positions); + positions = fastForwardUntilClosed(trimmedPath, i); + fragment = trimmedPath.substring(i, i + positions); i += positions; break; case PERIOD: i++; - if ( i < path.length() && path.charAt(i) == PERIOD) { + if ( i < trimmedPath.length() && trimmedPath.charAt(i) == PERIOD) { //This is a deep scan fragment = ".."; i++; } else { - positions = fastForward(path, i); + positions = fastForward(trimmedPath, i); if (positions == 0) { continue; - } else if (positions == 1 && path.charAt(i) == '*') { + } else if (positions == 1 && trimmedPath.charAt(i) == '*') { fragment = new String("[*]"); } else { - assertValidFieldChars(path, i, positions); + assertValidFieldChars(trimmedPath, i, positions); - fragment = PROPERTY_OPEN + path.substring(i, i + positions) + PROPERTY_CLOSE; + fragment = Utils.concat(PROPERTY_OPEN, trimmedPath.substring(i, i + positions), PROPERTY_CLOSE); } i += positions; } @@ -133,9 +133,9 @@ public class PathCompiler { i++; break; default: - positions = fastForward(path, i); + positions = fastForward(trimmedPath, i); - fragment = PROPERTY_OPEN + path.substring(i, i + positions) + PROPERTY_CLOSE; + fragment = Utils.concat(PROPERTY_OPEN, trimmedPath.substring(i, i + positions), PROPERTY_CLOSE); i += positions; break; } @@ -145,7 +145,7 @@ public class PathCompiler { root.append(PathComponentAnalyzer.analyze(fragment, filterList)); } - } while (i < path.length()); + } while (i < trimmedPath.length()); Path pa = new CompiledPath(root, isRootPath); diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/Utils.java b/json-path/src/main/java/com/jayway/jsonpath/internal/Utils.java index ce6e24ef..dd46f40b 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/Utils.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/Utils.java @@ -74,6 +74,42 @@ public final class Utils { public static String join(String delimiter, Iterable objs) { return join(delimiter, "", objs); } + + public static String concat(CharSequence... strings) { + if (strings.length == 0){ + return ""; + } + if (strings.length == 1){ + return strings[0].toString(); + } + int length = 0; + // -1 = no result, -2 = multiple results + int indexOfSingleNonEmptyString = -1; + for (int i = 0; i< strings.length; i++) { + CharSequence charSequence = strings[i]; + int len = charSequence.length(); + length += len; + if (indexOfSingleNonEmptyString != -2 && len > 0){ + if (indexOfSingleNonEmptyString == -1){ + indexOfSingleNonEmptyString = i; + } else { + indexOfSingleNonEmptyString = -2; + } + } + } + if (length == 0){ + return ""; + } + if (indexOfSingleNonEmptyString > 0){ + return strings[indexOfSingleNonEmptyString].toString(); + } + StringBuilder sb = new StringBuilder(length); + for (CharSequence charSequence : strings) { + sb.append(charSequence); + } + return sb.toString(); + + } //--------------------------------------------------------- // diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/token/PathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/token/PathToken.java index 720728a2..7a4e2e15 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/token/PathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/token/PathToken.java @@ -40,7 +40,7 @@ public abstract class PathToken { if(properties.size() == 1) { String property = properties.get(0); - String evalPath = currentPath + "['" + property + "']"; + String evalPath = Utils.concat(currentPath, "['", property, "']"); Object propertyVal = readObjectProperty(property, model, ctx); if(propertyVal == JsonProvider.UNDEFINED){ if(isLeaf()) { @@ -115,7 +115,7 @@ public abstract class PathToken { void handleArrayIndex(int index, String currentPath, Object model, EvaluationContextImpl ctx) { - String evalPath = currentPath + "[" + index + "]"; + String evalPath = Utils.concat(currentPath, "[", String.valueOf(index), "]"); PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, index) : PathRef.NO_OP; try { Object evalHit = ctx.jsonProvider().getArrayIndex(model, index);