From 77cb73091aeb7b321015b8dd3fed2d42054bb6d4 Mon Sep 17 00:00:00 2001 From: Gabriele Cardosi Date: Fri, 12 Jul 2024 10:09:26 +0200 Subject: [PATCH] [incubator-kie-issues#1382] Fix identifier retrieval for quoted strings (#6021) Co-authored-by: Gabriele-Cardosi --- .../java/org/drools/mvel/MVELConstraint.java | 2 +- .../java/org/drools/util/StringUtils.java | 22 +++- .../java/org/drools/util/StringUtilsTest.java | 105 ++++++++++++++++++ 3 files changed, 126 insertions(+), 3 deletions(-) diff --git a/drools-mvel/src/main/java/org/drools/mvel/MVELConstraint.java b/drools-mvel/src/main/java/org/drools/mvel/MVELConstraint.java index 515d3f13021..932c3bcde9d 100644 --- a/drools-mvel/src/main/java/org/drools/mvel/MVELConstraint.java +++ b/drools-mvel/src/main/java/org/drools/mvel/MVELConstraint.java @@ -553,7 +553,7 @@ private List getPropertyNamesFromSimpleExpression(String expression) { private int nextPropertyName(String expression, List names, int cursor) { StringBuilder propertyNameBuilder = new StringBuilder(); cursor = extractFirstIdentifier(expression, propertyNameBuilder, cursor); - if (propertyNameBuilder.length() == 0) { + if (propertyNameBuilder.isEmpty()) { return cursor; } diff --git a/drools-util/src/main/java/org/drools/util/StringUtils.java b/drools-util/src/main/java/org/drools/util/StringUtils.java index f94ce49b83a..e73555c7bda 100644 --- a/drools-util/src/main/java/org/drools/util/StringUtils.java +++ b/drools-util/src/main/java/org/drools/util/StringUtils.java @@ -964,8 +964,23 @@ public static String extractFirstIdentifier(String string, int start) { return builder.toString(); } + /** + * Method that tries to extract identifiers from a Srting. + * First, it tries to identify "quoted" part, that should be ignored. + * Then, it tries to extract a String that is valid as java identifier. + * If an identifier is found, returns the last index of the identifier itself, otherwise the length of the string itself + * + * {@link Character#isJavaIdentifierStart} + * {@link Character#isJavaIdentifierPart} + * @param string + * @param builder + * @param start + * @return + */ public static int extractFirstIdentifier(String string, StringBuilder builder, int start) { boolean isQuoted = false; + boolean isDoubleQuoted = false; + boolean isSingleQuoted = false; boolean started = false; int i = start; for (; i < string.length(); i++) { @@ -973,13 +988,16 @@ public static int extractFirstIdentifier(String string, StringBuilder builder, i if (!isQuoted && Character.isJavaIdentifierStart(ch)) { builder.append(ch); started = true; - } else if (ch == '"' || ch == '\'') { - isQuoted = !isQuoted; + } else if (ch == '"') { + isDoubleQuoted = !isQuoted && !isDoubleQuoted; + } else if (ch == '\'') { + isSingleQuoted = !isQuoted && !isSingleQuoted; } else if (started && Character.isJavaIdentifierPart(ch)) { builder.append(ch); } else if (started) { break; } + isQuoted = isDoubleQuoted || isSingleQuoted; } return i; } diff --git a/drools-util/src/test/java/org/drools/util/StringUtilsTest.java b/drools-util/src/test/java/org/drools/util/StringUtilsTest.java index 2f41589a179..7fca6c14fe5 100644 --- a/drools-util/src/test/java/org/drools/util/StringUtilsTest.java +++ b/drools-util/src/test/java/org/drools/util/StringUtilsTest.java @@ -239,6 +239,111 @@ public void getPkgUUIDFromGAV() { assertThat(retrieved).isEqualTo(expected); } + @Test + public void testExtractFirstIdentifierWithStringBuilder() { + // Not-quoted string, interpreted as identifier + String string = "IDENTIFIER"; + String expected = string; + StringBuilder builder = new StringBuilder(); + int start = 0; + int retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); // retrieved size is equals to the length of given string + assertThat(builder.toString()).isEqualTo(expected); + + // Quoted string, not interpreted as identifier + string = "\"IDENTIFIER\""; + expected = ""; + builder = new StringBuilder(); + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); + assertThat(builder.toString()).isEqualTo(expected); + + // Only the not-quoted string, and its size, is returned + string = "IDENTIFIER \""; + expected = "IDENTIFIER"; + builder = new StringBuilder(); + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(expected.length()); // it returns the index where the identifier ends + assertThat(builder.toString()).isEqualTo(expected); + + string = "IDENTIFIER \"the_identifier"; + expected = "IDENTIFIER"; + builder = new StringBuilder(); + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(expected.length()); // it returns the index where the identifier ends + assertThat(builder.toString()).isEqualTo(expected); + + string = "\"the_identifier\" IDENTIFIER"; + expected = "IDENTIFIER"; + builder = new StringBuilder(); + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); // it returns the index where the identifier ends + assertThat(builder.toString()).isEqualTo(expected); + + // Quoted string, not interpreted as identifier, starting at arbitrary position + string = "THIS IS BEFORE \"IDENTIFIER\""; + expected = ""; + builder = new StringBuilder(); + start = 14; + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); + assertThat(builder.toString()).isEqualTo(expected); + + // Only the not-quoted string, and its size, is returned, starting at arbitrary position + string = "THIS IS BEFORE IDENTIFIER \""; + expected = "IDENTIFIER"; + builder = new StringBuilder(); + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(25); // it returns the index where the identifier ends + assertThat(builder.toString()).isEqualTo(expected); + + string = "IDENTIFIER \"the_identifier"; + expected = ""; + builder = new StringBuilder(); + start = 10; + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); // it returns the index where the identifier ends + assertThat(builder.toString()).isEqualTo(expected); + + string = "IDENTIFIER \"the_identifier"; + expected = ""; + builder = new StringBuilder(); + start = 10; + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); // it returns the index where the identifier ends + assertThat(builder.toString()).isEqualTo(expected); + + string = "\"not an ' identifier\""; + expected = ""; + builder = new StringBuilder(); + start = 0; + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); // it returns the whole string length + assertThat(builder.toString()).isEqualTo(expected); + + string = "'not an \" identifier'"; + expected = ""; + builder = new StringBuilder(); + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); // it returns the whole string length + assertThat(builder.toString()).isEqualTo(expected); + + string = "'not an \" identifier\"'"; + expected = ""; + builder = new StringBuilder(); + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); // it returns the whole string length + assertThat(builder.toString()).isEqualTo(expected); + + string = "\"an \" IDENTIFIER"; + expected = "IDENTIFIER"; + builder = new StringBuilder(); + retrieved = StringUtils.extractFirstIdentifier(string, builder, start); + assertThat(retrieved).isEqualTo(string.length()); // it returns the index where the identifier ends + assertThat(builder.toString()).isEqualTo(expected); + + } + @Test public void testSplitStatements() { String text =