This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 4590671b5cf7 CAMEL-25077: camel-xml-io - XML DSL parser and dumper:
fix bugs found in a deep review (#26967)
4590671b5cf7 is described below
commit 4590671b5cf759bed09ab35e8b9d8d1880234d4c
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Sep 29 08:11:25 2026 +0200
CAMEL-25077: camel-xml-io - XML DSL parser and dumper: fix bugs found in a
deep review (#26967)
- two CDATA sections followed by text no longer duplicate the second one
(or fail the parser)
- character references above U+FFFF are no longer truncated; an invalid
reference fails
- dumpBeansAsXml writes the script as an element and escapes the values
(also camel-xml-jaxb)
- the XML and YAML dumpers write the note of routes and EIPs
- an encoding declared on another line of the XML declaration is detected
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../apache/camel/util/DumpModelEdgeCasesTest.java | 83 ++++++++++++++++++++++
.../apache/camel/xml/io/util/XmlStreamReader.java | 2 +-
.../camel/xml/io/util/XmlStreamReaderTest.java | 36 ++++++++++
.../org/apache/camel/xml/LwModelToXMLDumper.java | 60 ++++++++--------
.../java/org/apache/camel/xml/io/MXParser.java | 37 +++++++---
.../apache/camel/xml/in/MXParserEdgeCasesTest.java | 53 ++++++++++++++
.../camel/xml/jaxb/JaxbModelToXMLDumper.java | 55 +++++++-------
.../org/apache/camel/yaml/LwModelToYAMLDumper.java | 1 +
8 files changed, 262 insertions(+), 65 deletions(-)
diff --git
a/core/camel-core/src/test/java/org/apache/camel/util/DumpModelEdgeCasesTest.java
b/core/camel-core/src/test/java/org/apache/camel/util/DumpModelEdgeCasesTest.java
new file mode 100644
index 000000000000..a011e92cd656
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/util/DumpModelEdgeCasesTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.util;
+
+import java.io.StringReader;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+
+import org.xml.sax.InputSource;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.BeanFactoryDefinition;
+import org.apache.camel.support.PluginHelper;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DumpModelEdgeCasesTest extends ContextTestSupport {
+
+ @Test
+ public void testDumpBeansAsXmlIsWellFormed() throws Exception {
+ BeanFactoryDefinition<?> bean = new BeanFactoryDefinition<>();
+ bean.setName("myBean");
+ bean.setType("com.foo.MyBean");
+ bean.setScriptLanguage("groovy");
+ bean.setScript("return a < b && c");
+ Map<String, Object> props = new LinkedHashMap<>();
+ props.put("url", "http://host?a=1&b=2");
+ props.put("text", "say \"hi\"");
+ bean.setProperties(props);
+
+ String xml =
PluginHelper.getModelToXMLDumper(context).dumpBeansAsXml(context,
List.of(bean));
+ Document doc =
DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ .parse(new InputSource(new StringReader("<beans>" + xml +
"</beans>")));
+
assertThat(doc.getElementsByTagName("bean").item(0).getAttributes().getNamedItem("scriptLanguage").getNodeValue())
+ .isEqualTo("groovy");
+
assertThat(doc.getElementsByTagName("script").item(0).getTextContent().trim()).isEqualTo("return
a < b && c");
+
assertThat(doc.getElementsByTagName("property").item(0).getAttributes().getNamedItem("value").getNodeValue())
+ .isEqualTo("http://host?a=1&b=2");
+ }
+
+ @Test
+ public void testDumpNote() throws Exception {
+ String xml =
PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context,
context.getRouteDefinition("myRoute"));
+ assertThat(xml).contains("note=\"my route note\"").contains("note=\"my
log note\"");
+
+ String yaml
+ =
PluginHelper.getModelToYAMLDumper(context).dumpModelAsYaml(context,
context.getRouteDefinition("myRoute"));
+ assertThat(yaml).contains("note: my route note").contains("note: my
log note");
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:start").routeId("myRoute").note("my route note")
+ .log("Hello").note("my log note")
+ .to("mock:result");
+ }
+ };
+ }
+}
diff --git
a/core/camel-xml-io-util/src/main/java/org/apache/camel/xml/io/util/XmlStreamReader.java
b/core/camel-xml-io-util/src/main/java/org/apache/camel/xml/io/util/XmlStreamReader.java
index f86a9587aa74..af2f039eed46 100644
---
a/core/camel-xml-io-util/src/main/java/org/apache/camel/xml/io/util/XmlStreamReader.java
+++
b/core/camel-xml-io-util/src/main/java/org/apache/camel/xml/io/util/XmlStreamReader.java
@@ -80,7 +80,7 @@ public class XmlStreamReader extends Reader {
private static final String CP1047 = "CP1047";
private static final Pattern CHARSET_PATTERN =
Pattern.compile("charset=([.[^; ]]*)");
private static final Pattern ENCODING_PATTERN
- =
Pattern.compile("<\\?xml.*encoding[\\s]*=[\\s]*(\".[^\"]*\"|'.[^']*')",
Pattern.MULTILINE);
+ =
Pattern.compile("<\\?xml.*encoding[\\s]*=[\\s]*(\".[^\"]*\"|'.[^']*')",
Pattern.MULTILINE | Pattern.DOTALL);
private static final MessageFormat RAW_EX_1
= new MessageFormat("Invalid encoding, BOM [{0}] XML guess [{1}]
XML prolog [{2}] encoding mismatch");
private static final MessageFormat RAW_EX_2
diff --git
a/core/camel-xml-io-util/src/test/java/org/apache/camel/xml/io/util/XmlStreamReaderTest.java
b/core/camel-xml-io-util/src/test/java/org/apache/camel/xml/io/util/XmlStreamReaderTest.java
new file mode 100644
index 000000000000..8aff6c9918a8
--- /dev/null
+++
b/core/camel-xml-io-util/src/test/java/org/apache/camel/xml/io/util/XmlStreamReaderTest.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.xml.io.util;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class XmlStreamReaderTest {
+
+ @Test
+ public void testEncodingOnNextLineOfDeclaration() throws Exception {
+ byte[] xml = "<?xml version=\"1.0\"\n
encoding=\"ISO-8859-1\"?><a>café</a>"
+ .getBytes(StandardCharsets.ISO_8859_1);
+ try (XmlStreamReader reader = new XmlStreamReader(new
ByteArrayInputStream(xml))) {
+ assertEquals("ISO-8859-1", reader.getEncoding());
+ }
+ }
+}
diff --git
a/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
b/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
index 11f8aa7cb7a7..842c451ade16 100644
---
a/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
+++
b/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
@@ -51,6 +51,7 @@ import org.apache.camel.spi.ModelToXMLDumper;
import org.apache.camel.spi.NamespaceAware;
import org.apache.camel.spi.annotations.JdkService;
import org.apache.camel.util.KeyValueHolder;
+import org.apache.camel.util.StringHelper;
import org.apache.camel.xml.out.BaseWriter;
import org.apache.camel.xml.out.ModelWriter;
@@ -105,6 +106,10 @@ public class LwModelToXMLDumper implements
ModelToXMLDumper {
if (def.getDescriptionText() != null) {
doWriteAttribute("description", def.getDescriptionText());
}
+ // write note
+ if (def.getNote() != null) {
+ doWriteAttribute("note", def.getNote());
+ }
// write location information
if (sourceLocation || context.isDebugging()) {
int line = (def instanceof RouteDefinition ?
((RouteDefinition) def).getInput() : def).getLineNumber();
@@ -387,46 +392,38 @@ public class LwModelToXMLDumper implements
ModelToXMLDumper {
}
private void doWriteBeanFactoryDefinition(BeanFactoryDefinition<?> b) {
+ // the values are escaped as they can have characters such as &
and quotes (such as urls)
+ buffer.write(" <bean");
+ writeAttribute("name", b.getName());
String type = b.getType();
- if (type.startsWith("#class:")) {
+ if (type != null && type.startsWith("#class:")) {
type = type.substring(7);
}
- buffer.write(String.format(" <bean name=\"%s\" type=\"%s\"",
b.getName(), type));
- if (b.getFactoryBean() != null) {
- buffer.write(String.format(" factoryBean=\"%s\"",
b.getFactoryBean()));
- }
- if (b.getFactoryMethod() != null) {
- buffer.write(String.format(" factoryMethod=\"%s\"",
b.getFactoryMethod()));
- }
- if (b.getBuilderClass() != null) {
- buffer.write(String.format(" builderClass=\"%s\"",
b.getBuilderClass()));
- }
- if (b.getBuilderMethod() != null) {
- buffer.write(String.format(" builderMethod=\"%s\"",
b.getBuilderMethod()));
- }
- if (b.getInitMethod() != null) {
- buffer.write(String.format(" initMethod=\"%s\"",
b.getInitMethod()));
- }
- if (b.getDestroyMethod() != null) {
- buffer.write(String.format(" destroyMethod=\"%s\"",
b.getDestroyMethod()));
- }
- if (b.getScriptLanguage() != null) {
- buffer.write(String.format(" scriptLanguage=\"%s\"",
b.getScriptLanguage()));
- }
+ writeAttribute("type", type);
+ writeAttribute("factoryBean", b.getFactoryBean());
+ writeAttribute("factoryMethod", b.getFactoryMethod());
+ writeAttribute("builderClass", b.getBuilderClass());
+ writeAttribute("builderMethod", b.getBuilderMethod());
+ writeAttribute("initMethod", b.getInitMethod());
+ writeAttribute("destroyMethod", b.getDestroyMethod());
+ writeAttribute("scriptLanguage", b.getScriptLanguage());
+ buffer.write(">\n");
if (b.getScript() != null) {
+ // the script is an element (and not an attribute)
buffer.write(String.format(" <script>%n"));
- buffer.write(b.getScript());
+ buffer.write(StringHelper.xmlEncode(b.getScript()));
buffer.write("\n");
buffer.write(String.format(" </script>%n"));
}
- buffer.write(">\n");
if (b.getConstructors() != null && !b.getConstructors().isEmpty())
{
buffer.write(String.format(" <constructors>%n"));
b.getConstructors().forEach((idx, value) -> {
if (idx != null) {
- buffer.write(String.format(" <constructor
index=\"%d\" value=\"%s\"/>%n", idx, value));
+ buffer.write(String.format(" <constructor
index=\"%d\" value=\"%s\"/>%n", idx,
+
StringHelper.xmlEncode(String.valueOf(value))));
} else {
- buffer.write(String.format(" <constructor
value=\"%s\"/>%n", value));
+ buffer.write(String.format(" <constructor
value=\"%s\"/>%n",
+
StringHelper.xmlEncode(String.valueOf(value))));
}
});
buffer.write(String.format(" </constructors>%n"));
@@ -434,12 +431,19 @@ public class LwModelToXMLDumper implements
ModelToXMLDumper {
if (b.getProperties() != null && !b.getProperties().isEmpty()) {
buffer.write(String.format(" <properties>%n"));
b.getProperties().forEach((key, value) -> {
- buffer.write(String.format(" <property
key=\"%s\" value=\"%s\"/>%n", key, value));
+ buffer.write(String.format(" <property
key=\"%s\" value=\"%s\"/>%n",
+ StringHelper.xmlEncode(key),
StringHelper.xmlEncode(String.valueOf(value))));
});
buffer.write(String.format(" </properties>%n"));
}
buffer.write(String.format(" </bean>%n"));
}
+
+ private void writeAttribute(String name, String value) {
+ if (value != null) {
+ buffer.write(String.format(" %s=\"%s\"", name,
StringHelper.xmlEncode(value)));
+ }
+ }
}
private static class DataFormatModelWriter implements CamelContextAware {
diff --git
a/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java
b/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java
index f19457d9ae88..b9fe0ba2d037 100644
--- a/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java
+++ b/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java
@@ -1157,6 +1157,11 @@ public class MXParser implements XmlPullParser {
needsMerging = true;
}
}
+ if (usePC) {
+ // the earlier content has been joined into pc
(by parseCDSect), so it must not be
+ // joined again by the following text (which
would duplicate it)
+ needsMerging = false;
+ }
// posStart = oldStart;
// posEnd = oldEnd;
@@ -2099,6 +2104,11 @@ public class MXParser implements XmlPullParser {
protected char[] charRefOneCharBuf = new char[1];
+ private static int hexDigit(int charRef, int digit) {
+ // cap so a long reference cannot overflow into a valid code point
+ return Math.min(charRef * 16 + digit, Character.MAX_CODE_POINT + 1);
+ }
+
protected char[] parseEntityRef() throws XmlPullParserException,
IOException {
// entity reference
// http://www.w3.org/TR/2000/REC-xml-20001006#NT-Reference
@@ -2110,18 +2120,19 @@ public class MXParser implements XmlPullParser {
char ch = more();
if (ch == '#') {
// parse character reference
- char charRef = 0;
+ // the code point may be above U+FFFF (a supplementary character)
so use an int
+ int charRef = 0;
ch = more();
if (ch == 'x') {
// encoded in hex
while (true) {
ch = more();
if (ch >= '0' && ch <= '9') {
- charRef = (char) (charRef * 16 + (ch - '0'));
+ charRef = hexDigit(charRef, ch - '0');
} else if (ch >= 'a' && ch <= 'f') {
- charRef = (char) (charRef * 16 + (ch - ('a' - 10)));
+ charRef = hexDigit(charRef, ch - ('a' - 10));
} else if (ch >= 'A' && ch <= 'F') {
- charRef = (char) (charRef * 16 + (ch - ('A' - 10)));
+ charRef = hexDigit(charRef, ch - ('A' - 10));
} else if (ch == ';') {
break;
} else {
@@ -2133,7 +2144,7 @@ public class MXParser implements XmlPullParser {
// encoded in decimal
while (true) {
if (ch >= '0' && ch <= '9') {
- charRef = (char) (charRef * 10 + (ch - '0'));
+ charRef = Math.min(charRef * 10 + (ch - '0'),
Character.MAX_CODE_POINT + 1);
} else if (ch == ';') {
break;
} else {
@@ -2144,11 +2155,21 @@ public class MXParser implements XmlPullParser {
}
}
posEnd = pos - 1;
- charRefOneCharBuf[0] = charRef;
+ if (!Character.isValidCodePoint(charRef)) {
+ throw new XmlPullParserException(
+ "character reference is not a valid character: " +
charRef, this, null);
+ }
+ final char[] chars;
+ if (Character.isBmpCodePoint(charRef)) {
+ charRefOneCharBuf[0] = (char) charRef;
+ chars = charRefOneCharBuf;
+ } else {
+ chars = Character.toChars(charRef);
+ }
if (tokenize) {
- text = newString(charRefOneCharBuf, 0, 1);
+ text = newString(chars, 0, chars.length);
}
- return charRefOneCharBuf;
+ return chars;
} else {
// [68] EntityRef ::= '&' Name ';'
// scan name until ;
diff --git
a/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/MXParserEdgeCasesTest.java
b/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/MXParserEdgeCasesTest.java
new file mode 100644
index 000000000000..9f7c9e961616
--- /dev/null
+++
b/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/MXParserEdgeCasesTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.xml.in;
+
+import java.io.StringReader;
+
+import org.apache.camel.xml.io.MXParser;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MXParserEdgeCasesTest {
+
+ private static String textOf(String xml) throws Exception {
+ MXParser parser = new BaseParser(new StringReader(xml)).parser;
+ assertThat(parser.next()).isEqualTo(MXParser.START_TAG);
+ assertThat(parser.next()).isEqualTo(MXParser.TEXT);
+ return parser.getText();
+ }
+
+ @Test
+ public void testTwoCDataFollowedByText() throws Exception {
+
assertThat(textOf("<a><![CDATA[x]]><![CDATA[y]]>z</a>")).isEqualTo("xyz");
+ // the idiom to have ]]> in cdata, and a new line before the end tag
+
assertThat(textOf("<a><![CDATA[a]]]]><![CDATA[>b]]>\n</a>")).isEqualTo("a]]>b\n");
+
assertThat(textOf("<a><![CDATA[x]]><![CDATA[y]]>&z</a>")).isEqualTo("xy&z");
+ assertThat(textOf("<a><![CDATA[x]]><![CDATA[y]]><!-- c
-->z</a>")).isEqualTo("xyz");
+ }
+
+ @Test
+ public void testCharacterReferenceAboveBmp() throws Exception {
+ assertThat(textOf("<a>😀</a>")).isEqualTo("😀");
+ assertThat(textOf("<a>😀</a>")).isEqualTo("😀");
+
+ MXParser parser = new BaseParser(new StringReader("<a
b=\"😀\"/>")).parser;
+ assertThat(parser.next()).isEqualTo(MXParser.START_TAG);
+ assertThat(parser.getAttributeValue(0)).isEqualTo("😀");
+ }
+}
diff --git
a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
index b7e3bbad885d..7fa0b935b0f7 100644
---
a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
+++
b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java
@@ -335,46 +335,38 @@ public class JaxbModelToXMLDumper implements
ModelToXMLDumper {
}
private void doWriteBeanFactoryDefinition(BeanFactoryDefinition<?> b) {
+ // the values are escaped as they can have characters such as &
and quotes (such as urls)
+ buffer.write(" <bean");
+ writeAttribute("name", b.getName());
String type = b.getType();
- if (type.startsWith("#class:")) {
+ if (type != null && type.startsWith("#class:")) {
type = type.substring(7);
}
- buffer.write(String.format(" <bean name=\"%s\" type=\"%s\"",
b.getName(), type));
- if (b.getFactoryBean() != null) {
- buffer.write(String.format(" factoryBean=\"%s\"",
b.getFactoryBean()));
- }
- if (b.getFactoryMethod() != null) {
- buffer.write(String.format(" factoryMethod=\"%s\"",
b.getFactoryMethod()));
- }
- if (b.getBuilderClass() != null) {
- buffer.write(String.format(" builderClass=\"%s\"",
b.getBuilderClass()));
- }
- if (b.getBuilderMethod() != null) {
- buffer.write(String.format(" builderMethod=\"%s\"",
b.getBuilderMethod()));
- }
- if (b.getInitMethod() != null) {
- buffer.write(String.format(" initMethod=\"%s\"",
b.getInitMethod()));
- }
- if (b.getDestroyMethod() != null) {
- buffer.write(String.format(" destroyMethod=\"%s\"",
b.getDestroyMethod()));
- }
- if (b.getScriptLanguage() != null) {
- buffer.write(String.format(" scriptLanguage=\"%s\"",
b.getScriptLanguage()));
- }
+ writeAttribute("type", type);
+ writeAttribute("factoryBean", b.getFactoryBean());
+ writeAttribute("factoryMethod", b.getFactoryMethod());
+ writeAttribute("builderClass", b.getBuilderClass());
+ writeAttribute("builderMethod", b.getBuilderMethod());
+ writeAttribute("initMethod", b.getInitMethod());
+ writeAttribute("destroyMethod", b.getDestroyMethod());
+ writeAttribute("scriptLanguage", b.getScriptLanguage());
+ buffer.write(">\n");
if (b.getScript() != null) {
+ // the script is an element (and not an attribute)
buffer.write(String.format(" <script>%n"));
- buffer.write(b.getScript());
+ buffer.write(StringHelper.xmlEncode(b.getScript()));
buffer.write("\n");
buffer.write(String.format(" </script>%n"));
}
- buffer.write(">\n");
if (b.getConstructors() != null && !b.getConstructors().isEmpty())
{
buffer.write(String.format(" <constructors>%n"));
b.getConstructors().forEach((idx, value) -> {
if (idx != null) {
- buffer.write(String.format(" <constructor
index=\"%d\" value=\"%s\"/>%n", idx, value));
+ buffer.write(String.format(" <constructor
index=\"%d\" value=\"%s\"/>%n", idx,
+
StringHelper.xmlEncode(String.valueOf(value))));
} else {
- buffer.write(String.format(" <constructor
value=\"%s\"/>%n", value));
+ buffer.write(String.format(" <constructor
value=\"%s\"/>%n",
+
StringHelper.xmlEncode(String.valueOf(value))));
}
});
buffer.write(String.format(" </constructors>%n"));
@@ -382,12 +374,19 @@ public class JaxbModelToXMLDumper implements
ModelToXMLDumper {
if (b.getProperties() != null && !b.getProperties().isEmpty()) {
buffer.write(String.format(" <properties>%n"));
b.getProperties().forEach((key, value) -> {
- buffer.write(String.format(" <property
key=\"%s\" value=\"%s\"/>%n", key, value));
+ buffer.write(String.format(" <property
key=\"%s\" value=\"%s\"/>%n",
+ StringHelper.xmlEncode(key),
StringHelper.xmlEncode(String.valueOf(value))));
});
buffer.write(String.format(" </properties>%n"));
}
buffer.write(String.format(" </bean>%n"));
}
+
+ private void writeAttribute(String name, String value) {
+ if (value != null) {
+ buffer.write(String.format(" %s=\"%s\"", name,
StringHelper.xmlEncode(value)));
+ }
+ }
}
private static class DataFormatModelWriter implements CamelContextAware {
diff --git
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
index 589c62e2713d..2a3ea94848be 100644
---
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
+++
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
@@ -112,6 +112,7 @@ public class LwModelToYAMLDumper implements
ModelToYAMLDumper {
doWriteAttribute(jo, "id", def.getId(), null);
}
doWriteAttribute(jo, "description", def.getDescription(),
null);
+ doWriteAttribute(jo, "note", def.getNote(), null);
if (sourceLocation || context.isDebugging()) {
String loc = (def instanceof RouteDefinition rd1 ?
rd1.getInput() : def).getLocation();
int line = (def instanceof RouteDefinition rd2 ?
rd2.getInput() : def).getLineNumber();