From 2910c5a254dda9fef779295565787440d31d2bb9 Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Sat, 2 Mar 2024 13:06:46 -0400 Subject: [PATCH 01/10] feat: Add test cases for JsonFormatter class This class is in com.jayway.jsonpath.internal package.Add cases to cover the following: -Simple Json Object, Json Object Array -Json With Escaped Characters,Json Object with Escaped Characters --- .../jsonpath/internal/JsonFormatterTest.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java new file mode 100644 index 00000000..b0172cfc --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java @@ -0,0 +1,61 @@ +package com.jayway.jsonpath.internal; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +public class JsonFormatterTest { + + // Test case for pretty printing a simple JSON object + // The input is a simple JSON object + // The expected output is the same JSON object with proper indentation + @Test + public void testPrettyPrint_SimpleJson() { + JsonFormatter jsonFormatter = new JsonFormatter(); + String input = "{\"name\":\"Vaibhav Ramchandani\",\"age\":23,\"city\":\"Halifax\"}"; + String actualOutput = jsonFormatter.prettyPrint(input); + String expectedOutput = "{\n \"name\" : \"Vaibhav Ramchandani\",\n \"age\" : 23,\n \"city\" : \"Halifax\"\n}"; + assertEquals(expectedOutput.replaceAll("\\s", ""), actualOutput.replaceAll("\\s", "")); + } + + // Test case for pretty printing a JSON object with escaped characters + // The input is a JSON object with escaped characters + // The expected output is the same JSON object with proper indentation + + @Test + public void testPrettyPrint_JsonWithEscapedCharacters() { + JsonFormatter jsonFormatter = new JsonFormatter(); + String input = "{\"message\":\"This is ,\\nJsonPath Repo!\"}"; + String actualOutput = jsonFormatter.prettyPrint(input); + String expectedOutput = "{\n \"message\" : \"This is ,\\nJsonPath Repo!\"\n}"; + assertEquals(expectedOutput.replaceAll("\\s", ""), actualOutput.replaceAll("\\s", "")); + } + + // Test case for pretty printing a JSON array + // The input is a JSON array + // The expected output is the same JSON array with proper indentation + @Test + public void testPrettyPrint_JsonWithArray() { + + JsonFormatter jsonFormatter = new JsonFormatter(); + String input = "[{\"name\":\"Vaibhav R\",\"age\":23},{\"name\":\"Sanskar K\",\"age\":24}]"; + String actualOutput=jsonFormatter.prettyPrint(input); + String expectedOutput = "[\n {\n \"name\" : \"Vaibhav R\",\n \"age\" : 23\n },\n {\n \"name\" : \"Sanskar K\",\n \"age\" : 24\n }\n]"; + assertEquals(expectedOutput.replaceAll("\\s", ""), actualOutput.replaceAll("\\s", "")); + } + + // Test case for pretty printing a JSON object with single quotes + // The input is a JSON object with single quotes + // The expected output is the same JSON object with proper indentation + @Test + public void testPrettyPrint_JsonWithSingleQuotes() { + + JsonFormatter jsonFormatter = new JsonFormatter(); + String input = "{'name':'Vaibhav Ramchandani','age':23,'city':'Halifax'}"; + String actualOutput = jsonFormatter.prettyPrint(input); + String expectedOutput = "{\n 'name' : 'Vaibhav Ramchandani',\n 'age' : 23,\n 'city' : 'Halifax'\n}"; + assertEquals(expectedOutput.replaceAll("\\s", ""), actualOutput.replaceAll("\\s", "")); + } +} + From ddaf298143e25fc190fe86e7e459dbf7178bc9df Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Sat, 2 Mar 2024 13:13:32 -0400 Subject: [PATCH 02/10] feat: Add test cases for JsonFormatter class This class is in com.jayway.jsonpath.internal package.Add cases to cover the following: -Simple Json Object, Json Object Array -Json With Escaped Characters,Json Object with Escaped Characters --- .../java/com/jayway/jsonpath/internal/JsonFormatterTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java index b0172cfc..2152b14b 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java @@ -22,7 +22,7 @@ public void testPrettyPrint_SimpleJson() { // Test case for pretty printing a JSON object with escaped characters // The input is a JSON object with escaped characters // The expected output is the same JSON object with proper indentation - + // @Test public void testPrettyPrint_JsonWithEscapedCharacters() { JsonFormatter jsonFormatter = new JsonFormatter(); From fd5682b732c7cd5132389f6a27c63788826b9c62 Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Mon, 25 Mar 2024 21:46:19 -0300 Subject: [PATCH 03/10] Fetch the changes from remote --- .../java/com/jayway/jsonpath/internal/JsonFormatterTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java index 2152b14b..9dbae939 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/JsonFormatterTest.java @@ -37,7 +37,7 @@ public void testPrettyPrint_JsonWithEscapedCharacters() { // The expected output is the same JSON array with proper indentation @Test public void testPrettyPrint_JsonWithArray() { - + // JsonFormatter jsonFormatter = new JsonFormatter(); String input = "[{\"name\":\"Vaibhav R\",\"age\":23},{\"name\":\"Sanskar K\",\"age\":24}]"; String actualOutput=jsonFormatter.prettyPrint(input); From 739699deb3eb4e2be9be6afaee42eded5e130ff3 Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Fri, 29 Mar 2024 23:36:07 -0300 Subject: [PATCH 04/10] refactor: Implementation smells refactored --- .../com/jayway/jsonpath/internal/Utils.java | 5 +- .../internal/filter/FilterCompiler.java | 32 +++++---- .../jsonpath/internal/path/PathCompiler.java | 66 ++++++++++++++----- 3 files changed, 72 insertions(+), 31 deletions(-) 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 e51c874f..02a082d0 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 @@ -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); diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java index ecec3709..231309f6 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java @@ -357,17 +357,8 @@ private PathNode readPath() { filter.incrementPosition(1); //skip $ and @ while (filter.inBounds()) { if (filter.currentChar() == OPEN_SQUARE_BRACKET) { - int closingSquareBracketIndex = filter.indexOfMatchingCloseChar(filter.position(), OPEN_SQUARE_BRACKET, CLOSE_SQUARE_BRACKET, true, false); - if (closingSquareBracketIndex == -1) { - throw new InvalidPathException("Square brackets does not match in filter " + filter); - } else { - filter.setPosition(closingSquareBracketIndex + 1); - } - } - boolean closingFunctionBracket = (filter.currentChar() == CLOSE_PARENTHESIS && currentCharIsClosingFunctionBracket(begin)); - boolean closingLogicalBracket = (filter.currentChar() == CLOSE_PARENTHESIS && !closingFunctionBracket); - - if (!filter.inBounds() || isRelationalOperatorChar(filter.currentChar()) || filter.currentChar() == SPACE || closingLogicalBracket) { + handleSquareBracket(); + } else if (shouldBreakParsing()) { break; } else { filter.incrementPosition(1); @@ -379,6 +370,25 @@ private PathNode readPath() { return ValueNode.createPathNode(path, false, shouldExists); } + private void handleSquareBracket() { + int closingSquareBracketIndex = filter.indexOfMatchingCloseChar(filter.position(), OPEN_SQUARE_BRACKET, CLOSE_SQUARE_BRACKET, true, false); + if (closingSquareBracketIndex == -1) { + throw new InvalidPathException("Square brackets do not match in filter " + filter); + } else { + filter.setPosition(closingSquareBracketIndex + 1); + } + } + + private boolean shouldBreakParsing() { + return !filter.inBounds() || isRelationalOperatorChar(filter.currentChar()) || filter.currentChar() == SPACE || closingLogicalBracket(); + } + + private boolean closingLogicalBracket() { + boolean closingFunctionBracket = (filter.currentChar() == CLOSE_PARENTHESIS && currentCharIsClosingFunctionBracket(filter.position())); + return (filter.currentChar() == CLOSE_PARENTHESIS && !closingFunctionBracket); + } + + private boolean expressionIsTerminated(){ char c = filter.currentChar(); if(c == CLOSE_PARENTHESIS || isLogicalOperatorChar(c)){ diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java index 27b6e063..a9cc86cb 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java @@ -519,12 +519,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; } @@ -535,28 +534,18 @@ 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); @@ -564,6 +553,47 @@ private boolean readArrayToken(PathTokenAppender appender) { 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'] // From 5b33010609272c4b9a242d6f915b20363dd53954 Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Sat, 30 Mar 2024 01:15:38 -0300 Subject: [PATCH 05/10] refactor: Design Smells --- .../jsonpath/internal/CharacterIndex.java | 13 ++++- .../jsonpath/internal/path/PathCompiler.java | 10 +--- .../com/jayway/jsonpath/Configurations.java | 57 +++++++++++++------ .../jsonpath/internal/function/Issue191.java | 3 +- .../function/JSONEntityPathFunctionTest.java | 3 +- .../internal/function/KeySetFunctionTest.java | 2 +- .../function/SequentialPathFunctionTest.java | 2 +- 7 files changed, 61 insertions(+), 29 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java b/json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java index 72da4ffc..5e358af2 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java @@ -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 = ']'; @@ -29,6 +28,7 @@ public CharacterIndex(CharSequence charSequence) { this.endPosition = charSequence.length() - 1; } + public int length() { return endPosition + 1; } @@ -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); + } + } + } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java index a9cc86cb..ec3f4a7a 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java @@ -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) { @@ -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 '@'"); diff --git a/json-path/src/test/java/com/jayway/jsonpath/Configurations.java b/json-path/src/test/java/com/jayway/jsonpath/Configurations.java index 537d2be0..cd89b2db 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/Configurations.java +++ b/json-path/src/test/java/com/jayway/jsonpath/Configurations.java @@ -16,37 +16,37 @@ public class Configurations { - public static final Configuration JSON_ORG_CONFIGURATION = Configuration + private static final Configuration JSON_ORG_CONFIGURATION = Configuration .builder() .mappingProvider(new JsonOrgMappingProvider()) .jsonProvider(new JsonOrgJsonProvider()) .build(); - public static final Configuration GSON_CONFIGURATION = Configuration + private static final Configuration GSON_CONFIGURATION = Configuration .builder() .mappingProvider(new GsonMappingProvider()) .jsonProvider(new GsonJsonProvider()) .build(); - public static final Configuration JACKSON_CONFIGURATION = Configuration + private static final Configuration JACKSON_CONFIGURATION = Configuration .builder() .mappingProvider(new JacksonMappingProvider()) .jsonProvider(new JacksonJsonProvider()) .build(); - public static final Configuration JACKSON_JSON_NODE_CONFIGURATION = Configuration + private static final Configuration JACKSON_JSON_NODE_CONFIGURATION = Configuration .builder() .mappingProvider(new JacksonMappingProvider()) .jsonProvider(new JacksonJsonNodeJsonProvider()) .build(); - public static final Configuration JSON_SMART_CONFIGURATION = Configuration + private static final Configuration JSON_SMART_CONFIGURATION = Configuration .builder() .mappingProvider(new JsonSmartMappingProvider()) .jsonProvider(new JsonSmartJsonProvider()) .build(); - public static final Configuration JAKARTA_CONFIGURATION = Configuration + private static final Configuration JAKARTA_CONFIGURATION = Configuration .builder() .mappingProvider(new JakartaMappingProvider()) .jsonProvider(new JakartaJsonProvider()) @@ -54,21 +54,46 @@ public class Configurations { public static Iterable configurations() { return Arrays.asList( - JSON_SMART_CONFIGURATION - ,GSON_CONFIGURATION - ,JACKSON_CONFIGURATION - ,JACKSON_JSON_NODE_CONFIGURATION - ,JSON_ORG_CONFIGURATION - ,JAKARTA_CONFIGURATION + JSON_SMART_CONFIGURATION, + GSON_CONFIGURATION, + JACKSON_CONFIGURATION, + JACKSON_JSON_NODE_CONFIGURATION, + JSON_ORG_CONFIGURATION, + JAKARTA_CONFIGURATION ); } public static Iterable objectMappingConfigurations() { return Arrays.asList( - GSON_CONFIGURATION - ,JACKSON_CONFIGURATION - ,JACKSON_JSON_NODE_CONFIGURATION - ,JAKARTA_CONFIGURATION + GSON_CONFIGURATION, + JACKSON_CONFIGURATION, + JACKSON_JSON_NODE_CONFIGURATION, + JAKARTA_CONFIGURATION ); } + + // Public getter methods for accessing configurations + public static Configuration getJsonOrgConfiguration() { + return JSON_ORG_CONFIGURATION; + } + + public static Configuration getGsonConfiguration() { + return GSON_CONFIGURATION; + } + + public static Configuration getJacksonConfiguration() { + return JACKSON_CONFIGURATION; + } + + public static Configuration getJacksonJsonNodeConfiguration() { + return JACKSON_JSON_NODE_CONFIGURATION; + } + + public static Configuration getJsonSmartConfiguration() { + return JSON_SMART_CONFIGURATION; + } + + public static Configuration getJakartaConfiguration() { + return JAKARTA_CONFIGURATION; + } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/function/Issue191.java b/json-path/src/test/java/com/jayway/jsonpath/internal/function/Issue191.java index 010ef96f..483c6f1d 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/internal/function/Issue191.java +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/function/Issue191.java @@ -16,7 +16,8 @@ */ public class Issue191 { - private Configuration conf = Configurations.GSON_CONFIGURATION; + private Configuration conf = Configurations.getGsonConfiguration(); + @Test public void testResultSetNumericComputation() { diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/function/JSONEntityPathFunctionTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/function/JSONEntityPathFunctionTest.java index 4c6dff22..97b5a9af 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/internal/function/JSONEntityPathFunctionTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/function/JSONEntityPathFunctionTest.java @@ -52,7 +52,8 @@ public class JSONEntityPathFunctionTest extends BaseFunctionTest { - private Configuration conf = Configurations.JSON_SMART_CONFIGURATION; + + private Configuration conf= Configurations.getJsonSmartConfiguration(); @Test public void testLengthOfTextArray() { diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/function/KeySetFunctionTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/function/KeySetFunctionTest.java index 0d52202b..7c4770f0 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/internal/function/KeySetFunctionTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/function/KeySetFunctionTest.java @@ -14,7 +14,7 @@ */ public class KeySetFunctionTest extends BaseFunctionTest { - private Configuration conf = Configurations.JACKSON_CONFIGURATION; + private Configuration conf = Configurations.getJsonSmartConfiguration(); @Test public void testKeySet() throws Exception { diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/function/SequentialPathFunctionTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/function/SequentialPathFunctionTest.java index d3785dc2..6d8d4e37 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/internal/function/SequentialPathFunctionTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/function/SequentialPathFunctionTest.java @@ -15,7 +15,7 @@ */ public class SequentialPathFunctionTest extends BaseFunctionTest { - private Configuration conf = Configurations.JACKSON_CONFIGURATION; + private Configuration conf = Configurations.getJsonSmartConfiguration(); @Test public void testFirstOfNumbers() throws Exception { From f9054b56f4f4859aea1f2678af704fa12e83e7f9 Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Sat, 30 Mar 2024 01:56:26 -0300 Subject: [PATCH 06/10] refactor:desgin smells refactored --- .../jsonpath/InvalidCriteriaException.java | 33 ------------------- .../jayway/jsonpath/JsonPathException.java | 1 + .../internal/filter/FilterCompiler.java | 31 +++++++---------- 3 files changed, 12 insertions(+), 53 deletions(-) delete mode 100644 json-path/src/main/java/com/jayway/jsonpath/InvalidCriteriaException.java diff --git a/json-path/src/main/java/com/jayway/jsonpath/InvalidCriteriaException.java b/json-path/src/main/java/com/jayway/jsonpath/InvalidCriteriaException.java deleted file mode 100644 index 54733253..00000000 --- a/json-path/src/main/java/com/jayway/jsonpath/InvalidCriteriaException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011 the original author or authors. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jayway.jsonpath; - -@SuppressWarnings("serial") -public class InvalidCriteriaException extends JsonPathException { - public InvalidCriteriaException() { - } - - public InvalidCriteriaException(String message) { - super(message); - } - - public InvalidCriteriaException(String message, Throwable cause) { - super(message, cause); - } - - public InvalidCriteriaException(Throwable cause) { - super(cause); - } -} diff --git a/json-path/src/main/java/com/jayway/jsonpath/JsonPathException.java b/json-path/src/main/java/com/jayway/jsonpath/JsonPathException.java index 37d21ac7..d11d348d 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonPathException.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonPathException.java @@ -17,6 +17,7 @@ public class JsonPathException extends RuntimeException { public JsonPathException() { + super(); } public JsonPathException(String message) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java index 231309f6..ebd1d66d 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java @@ -357,8 +357,17 @@ private PathNode readPath() { filter.incrementPosition(1); //skip $ and @ while (filter.inBounds()) { if (filter.currentChar() == OPEN_SQUARE_BRACKET) { - handleSquareBracket(); - } else if (shouldBreakParsing()) { + int closingSquareBracketIndex = filter.indexOfMatchingCloseChar(filter.position(), OPEN_SQUARE_BRACKET, CLOSE_SQUARE_BRACKET, true, false); + if (closingSquareBracketIndex == -1) { + throw new InvalidPathException("Square brackets does not match in filter " + filter); + } else { + filter.setPosition(closingSquareBracketIndex + 1); + } + } + boolean closingFunctionBracket = (filter.currentChar() == CLOSE_PARENTHESIS && currentCharIsClosingFunctionBracket(begin)); + boolean closingLogicalBracket = (filter.currentChar() == CLOSE_PARENTHESIS && !closingFunctionBracket); + + if (!filter.inBounds() || isRelationalOperatorChar(filter.currentChar()) || filter.currentChar() == SPACE || closingLogicalBracket) { break; } else { filter.incrementPosition(1); @@ -370,24 +379,6 @@ private PathNode readPath() { return ValueNode.createPathNode(path, false, shouldExists); } - private void handleSquareBracket() { - int closingSquareBracketIndex = filter.indexOfMatchingCloseChar(filter.position(), OPEN_SQUARE_BRACKET, CLOSE_SQUARE_BRACKET, true, false); - if (closingSquareBracketIndex == -1) { - throw new InvalidPathException("Square brackets do not match in filter " + filter); - } else { - filter.setPosition(closingSquareBracketIndex + 1); - } - } - - private boolean shouldBreakParsing() { - return !filter.inBounds() || isRelationalOperatorChar(filter.currentChar()) || filter.currentChar() == SPACE || closingLogicalBracket(); - } - - private boolean closingLogicalBracket() { - boolean closingFunctionBracket = (filter.currentChar() == CLOSE_PARENTHESIS && currentCharIsClosingFunctionBracket(filter.position())); - return (filter.currentChar() == CLOSE_PARENTHESIS && !closingFunctionBracket); - } - private boolean expressionIsTerminated(){ char c = filter.currentChar(); From b3febe2370dd6dc83cedbfb362237c201b629350 Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Sat, 30 Mar 2024 02:12:28 -0300 Subject: [PATCH 07/10] refactor:complex conditional statement in parseFunctionParameters in PathCompiler.java --- .../com/jayway/jsonpath/internal/path/PathCompiler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java index ec3f4a7a..934770e9 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java @@ -299,7 +299,7 @@ private List 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)) { @@ -388,6 +388,12 @@ else if (isPathContext(c)) { return parameters; } + private boolean isJsonParam(char c) { + + return c == OPEN_BRACE || Character.isDigit(c) || c == DOUBLE_QUOTE || c == MINUS; + + } + private boolean isWhitespace(char c) { return (c == SPACE || c == TAB || c == LF || c == CR); } From 4ae4833c7d35091efbd4c86a3159e8c0e3db3012 Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Sat, 30 Mar 2024 12:30:29 -0300 Subject: [PATCH 08/10] refactor:Refactor using extract class in CompiledPath.java --- .../jsonpath/internal/path/CompiledPath.java | 46 +++---------------- .../jsonpath/internal/path/PathToken.java | 2 +- .../jsonpath/internal/path/RootPathToken.java | 2 +- .../path/ScannerFunctionInverter.java | 40 ++++++++++++++++ 4 files changed, 48 insertions(+), 42 deletions(-) create mode 100644 json-path/src/main/java/com/jayway/jsonpath/internal/path/ScannerFunctionInverter.java 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 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 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) { 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 @@ PathToken prev(){ 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; + } +} From 404f2bcf44e9742245af88f115d9c6bb1eeae3bb Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Sat, 30 Mar 2024 21:47:07 -0300 Subject: [PATCH 09/10] refactor:Refactor using Change bidirectional association to unidirectional association refactor technique --- .../internal/filter/FilterCompiler.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java index ebd1d66d..986cc17a 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java @@ -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(); From 84c93f9e8122d94958f6809bc3dea7f572f81408 Mon Sep 17 00:00:00 2001 From: Vaibhav Ramchandani Date: Sat, 30 Mar 2024 21:52:31 -0300 Subject: [PATCH 10/10] refactor:Refactor using Decompose conditional in PathCompiler.java --- .../jsonpath/internal/path/PathCompiler.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java index 934770e9..0cd22d5e 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java @@ -388,10 +388,24 @@ else if (isPathContext(c)) { return parameters; } - private boolean isJsonParam(char c) { - - return c == OPEN_BRACE || Character.isDigit(c) || c == DOUBLE_QUOTE || c == MINUS; + 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) {