You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2021/03/25 08:41:18 UTC
[camel] branch master updated: CAMEL-16242: camel-core - Language
expressions with single quoted property placeholder values should be
replaced as double quotes to fix the O'Niel problem and other inputs that
can use single quotes in names/text.
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push:
new c55e70c CAMEL-16242: camel-core - Language expressions with single quoted property placeholder values should be replaced as double quotes to fix the O'Niel problem and other inputs that can use single quotes in names/text.
c55e70c is described below
commit c55e70cd692797cbf271ac5079553db9e2092269
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Mar 25 09:37:28 2021 +0100
CAMEL-16242: camel-core - Language expressions with single quoted property placeholder values should be replaced as double quotes to fix the O'Niel problem and other inputs that can use single quotes in names/text.
---
.../apache/camel/jsonpath/JsonPathSplitTest.java | 2 +-
.../JsonPathTransformONielEscapedTest.java | 2 +-
... => JsonPathTransformONielPlaceholderTest.java} | 24 ++++++++++--
.../camel/jsonpath/JsonPathTransformONielTest.java | 2 +-
.../camel-jsonpath/src/test/resources/books.json | 4 +-
.../camel/reifier/language/ExpressionReifier.java | 43 ++++++++++++++++++++++
...st.java => XPathFunctionsONielProblemTest.java} | 10 ++---
.../camel/builder/xml/XPathFunctionsTest.java | 2 +-
8 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSplitTest.java b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSplitTest.java
index a392985..1e996f4 100644
--- a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSplitTest.java
+++ b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSplitTest.java
@@ -75,7 +75,7 @@ public class JsonPathSplitTest extends CamelTestSupport {
// should preserve quotes etc
assertTrue(out.contains("\"author\": \"Nigel Rees\""));
assertTrue(out.contains("\"price\": 8.95"));
- assertTrue(out.contains("\"title\": \"Sword of Honour\""));
+ assertTrue(out.contains("\"title\": \"Sword's of Honour\""));
assertTrue(out.contains("\"price\": 12.99,"));
}
diff --git a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielEscapedTest.java b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielEscapedTest.java
index 8031a2f..95fe395 100644
--- a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielEscapedTest.java
+++ b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielEscapedTest.java
@@ -48,7 +48,7 @@ public class JsonPathTransformONielEscapedTest extends CamelTestSupport {
assertMockEndpointsSatisfied();
List<?> titles = getMockEndpoint("mock:authors").getReceivedExchanges().get(0).getIn().getBody(List.class);
- assertEquals("Camel in Space", titles.get(0));
+ assertEquals("Camels in Space", titles.get(0));
}
}
diff --git a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielTest.java b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielPlaceholderTest.java
similarity index 69%
copy from components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielTest.java
copy to components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielPlaceholderTest.java
index a9543c7..08f4c3b 100644
--- a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielTest.java
+++ b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielPlaceholderTest.java
@@ -18,14 +18,30 @@ package org.apache.camel.jsonpath;
import java.io.File;
import java.util.List;
+import java.util.Properties;
+import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.PropertiesComponent;
import org.apache.camel.test.junit5.CamelTestSupport;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
-public class JsonPathTransformONielTest extends CamelTestSupport {
+public class JsonPathTransformONielPlaceholderTest extends CamelTestSupport {
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext context = super.createCamelContext();
+
+ PropertiesComponent pc = context.getPropertiesComponent();
+ Properties props = new Properties();
+ props.put("who", "John O'Niel");
+ props.put("search", "Sword's of Honour");
+ pc.setInitialProperties(props);
+
+ return context;
+ }
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
@@ -33,7 +49,7 @@ public class JsonPathTransformONielTest extends CamelTestSupport {
@Override
public void configure() throws Exception {
from("direct:start")
- .transform().jsonpath("$.store.book[?(@.author == \"John O'Niel\")].title")
+ .transform().jsonpath("$.store.book[?(@.author == '{{who}}' || @.title == '{{search}}')].title")
.to("mock:authors");
}
};
@@ -48,7 +64,9 @@ public class JsonPathTransformONielTest extends CamelTestSupport {
assertMockEndpointsSatisfied();
List<?> titles = getMockEndpoint("mock:authors").getReceivedExchanges().get(0).getIn().getBody(List.class);
- assertEquals("Camel in Space", titles.get(0));
+ assertEquals(2, titles.size());
+ assertEquals("Sword's of Honour", titles.get(0));
+ assertEquals("Camels in Space", titles.get(1));
}
}
diff --git a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielTest.java b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielTest.java
index a9543c7..75c5b9f 100644
--- a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielTest.java
+++ b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathTransformONielTest.java
@@ -48,7 +48,7 @@ public class JsonPathTransformONielTest extends CamelTestSupport {
assertMockEndpointsSatisfied();
List<?> titles = getMockEndpoint("mock:authors").getReceivedExchanges().get(0).getIn().getBody(List.class);
- assertEquals("Camel in Space", titles.get(0));
+ assertEquals("Camels in Space", titles.get(0));
}
}
diff --git a/components/camel-jsonpath/src/test/resources/books.json b/components/camel-jsonpath/src/test/resources/books.json
index a412426..ff2a384 100644
--- a/components/camel-jsonpath/src/test/resources/books.json
+++ b/components/camel-jsonpath/src/test/resources/books.json
@@ -10,14 +10,14 @@
{
"category": "fiction",
"author": "Evelyn Waugh",
- "title": "Sword of Honour",
+ "title": "Sword's of Honour",
"price": 12.99,
"isbn": "0-553-21311-3"
},
{
"category": "fiction",
"author": "John O'Niel",
- "title": "Camel in Space",
+ "title": "Camels in Space",
"price": 9.99,
"isbn": "0-555-12345-6"
}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java
index 0fb98a5..44aca6b 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java
@@ -19,6 +19,8 @@ package org.apache.camel.reifier.language;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.apache.camel.AfterPropertiesConfigured;
import org.apache.camel.CamelContext;
@@ -50,6 +52,7 @@ import org.apache.camel.model.language.XPathExpression;
import org.apache.camel.model.language.XQueryExpression;
import org.apache.camel.reifier.AbstractReifier;
import org.apache.camel.spi.Language;
+import org.apache.camel.spi.PropertiesComponent;
import org.apache.camel.spi.PropertyConfigurer;
import org.apache.camel.spi.PropertyConfigurerAware;
import org.apache.camel.spi.ReifierStrategy;
@@ -60,6 +63,8 @@ import org.apache.camel.util.ObjectHelper;
public class ExpressionReifier<T extends ExpressionDefinition> extends AbstractReifier {
+ private static final Pattern SINGLE_TO_DOUBLE = Pattern.compile("'(\\{\\{.*?}})'"); // non-greedy mode
+
// for custom reifiers
private static final Map<Class<?>, BiFunction<CamelContext, ExpressionDefinition, ExpressionReifier<? extends ExpressionDefinition>>> EXPRESSIONS
= new HashMap<>(0);
@@ -165,6 +170,8 @@ public class ExpressionReifier<T extends ExpressionDefinition> extends AbstractR
public Expression createExpression() {
Expression expression = definition.getExpressionValue();
if (expression == null) {
+ // prepare before creating
+ prepareExpression();
if (definition.getExpressionType() != null) {
expression = reifier(camelContext, definition.getExpressionType()).createExpression();
} else {
@@ -201,6 +208,8 @@ public class ExpressionReifier<T extends ExpressionDefinition> extends AbstractR
public Predicate createPredicate() {
Predicate predicate = definition.getPredicate();
if (predicate == null) {
+ // prepare before creating
+ prepareExpression();
if (definition.getExpressionType() != null) {
predicate = reifier(camelContext, definition.getExpressionType()).createPredicate();
} else if (definition.getExpressionValue() != null) {
@@ -265,6 +274,40 @@ public class ExpressionReifier<T extends ExpressionDefinition> extends AbstractR
}
}
+ /**
+ * Prepares the expression/predicate before being created by the reifier
+ */
+ protected void prepareExpression() {
+ // when using languages with property placeholders then we have a single vs double quote problem
+ // where it may be common to use single quote inside a Java string, eg
+ // "${header.name} == '{{who}}'"
+ // and then the who property placeholder may contain a single quote such as John O'Niel which
+ // is extrapolated as "${header.name} == 'John O'Niel'" which causes a parsing problem
+ // so what Camel does is to replace all '{{key}}' placeholders with double quoted instead
+ // that resolves the parsing problem
+
+ String text = definition.getExpression();
+ if (text != null && text.contains(PropertiesComponent.PREFIX_TOKEN)) {
+ boolean changed = false;
+ Matcher matcher = SINGLE_TO_DOUBLE.matcher(text);
+ while (matcher.find()) {
+ String group = matcher.group(1);
+ // is there a single quote in the resolved placeholder
+ String resolved = camelContext.resolvePropertyPlaceholders(group);
+ if (resolved != null && resolved.indexOf('\'') != -1) {
+ // replace single quoted with double quoted
+ text = matcher.replaceFirst("\"$1\"");
+ // we changed so reset matcher so it can find more
+ matcher.reset(text);
+ changed = true;
+ }
+ }
+ if (changed) {
+ definition.setExpression(text);
+ }
+ }
+ }
+
@Deprecated
protected void setProperties(Object target, Map<String, Object> properties) {
properties.entrySet().removeIf(e -> e.getValue() == null);
diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsONielProblemTest.java
similarity index 91%
copy from core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java
copy to core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsONielProblemTest.java
index a1e78b1..b92252b 100644
--- a/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsONielProblemTest.java
@@ -24,7 +24,7 @@ import org.junit.jupiter.api.Test;
/**
* XPath with and without header test.
*/
-public class XPathFunctionsTest extends ContextTestSupport {
+public class XPathFunctionsONielProblemTest extends ContextTestSupport {
@Test
public void testChoiceWithHeaderAndPropertiesSelectCamel() throws Exception {
@@ -40,9 +40,9 @@ public class XPathFunctionsTest extends ContextTestSupport {
@Test
public void testChoiceWithNoHeaderAndPropertiesSelectDonkey() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:donkey");
- mock.expectedBodiesReceived("<name>Donkey Kong</name>");
+ mock.expectedBodiesReceived("<name>Kong</name>");
- template.sendBody("direct:in", "<name>Donkey Kong</name>");
+ template.sendBody("direct:in", "<name>Kong</name>");
mock.assertIsSatisfied();
}
@@ -73,12 +73,12 @@ public class XPathFunctionsTest extends ContextTestSupport {
// $type is a variable for the header with key type
// here we use the properties function to lookup foo from
// the properties files
- // which at runtime will be evaluted to 'Camel'
+ // which at runtime will be evaluated to 'Camel'
.when().xpath("$type = function:properties('foo')").to("mock:camel")
// here we use the simple language to evaluate the
// expression
// which at runtime will be evaluated to 'Donkey Kong'
- .when().xpath("//name = function:simple('Donkey {{bar}}')").to("mock:donkey").otherwise()
+ .when().xpath("//name = function:simple('{{bar}}')").to("mock:donkey").otherwise()
.to("mock:other").end();
// END SNIPPET: ex
}
diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java
index a1e78b1..3abf21f 100644
--- a/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java
@@ -73,7 +73,7 @@ public class XPathFunctionsTest extends ContextTestSupport {
// $type is a variable for the header with key type
// here we use the properties function to lookup foo from
// the properties files
- // which at runtime will be evaluted to 'Camel'
+ // which at runtime will be evaluated to 'Camel'
.when().xpath("$type = function:properties('foo')").to("mock:camel")
// here we use the simple language to evaluate the
// expression