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 44e2fb14b7e CAMEL-22361: camel-groovy-xml - Add data format that uses groovy xml that is easy to use and no need for POJOs 44e2fb14b7e is described below commit 44e2fb14b7e122a50a9004990ba78ecb7ceb70ca Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri Aug 22 16:29:08 2025 +0200 CAMEL-22361: camel-groovy-xml - Add data format that uses groovy xml that is easy to use and no need for POJOs --- .../org/apache/camel/groovy/xml/groovyXml.json | 2 +- .../src/main/docs/groovyXml-dataformat.adoc | 2 +- .../camel/groovy/xml/GroovyXmlDataFormat.java | 21 ++++--- .../camel/groovy/xml/GroovyXmlDataFormatTest.java | 70 ++++++++++++++++++++++ 4 files changed, 85 insertions(+), 10 deletions(-) diff --git a/components/camel-groovy-xml/src/generated/resources/META-INF/org/apache/camel/groovy/xml/groovyXml.json b/components/camel-groovy-xml/src/generated/resources/META-INF/org/apache/camel/groovy/xml/groovyXml.json index af52a11b703..20da0954eab 100644 --- a/components/camel-groovy-xml/src/generated/resources/META-INF/org/apache/camel/groovy/xml/groovyXml.json +++ b/components/camel-groovy-xml/src/generated/resources/META-INF/org/apache/camel/groovy/xml/groovyXml.json @@ -3,7 +3,7 @@ "kind": "dataformat", "name": "groovyXml", "title": "Groovy XML", - "description": "Transform between XML and Java Map via Groovy", + "description": "Transform between XML and Groovy Node (Map structure) objects.", "deprecated": false, "firstVersion": "4.15.0", "label": "dataformat,transformation,xml", diff --git a/components/camel-groovy-xml/src/main/docs/groovyXml-dataformat.adoc b/components/camel-groovy-xml/src/main/docs/groovyXml-dataformat.adoc index 9a8a4e878b2..67ccc1e1eb0 100644 --- a/components/camel-groovy-xml/src/main/docs/groovyXml-dataformat.adoc +++ b/components/camel-groovy-xml/src/main/docs/groovyXml-dataformat.adoc @@ -2,7 +2,7 @@ :doctitle: Groovy XML :shortname: groovyXml :artifactid: camel-groovy-xml -:description: Transform between XML and Java Map via Groovy +:description: Transform between XML and Groovy Node (Map structure) objects. :since: 4.15 :supportlevel: Preview :tabs-sync-option: diff --git a/components/camel-groovy-xml/src/main/java/org/apache/camel/groovy/xml/GroovyXmlDataFormat.java b/components/camel-groovy-xml/src/main/java/org/apache/camel/groovy/xml/GroovyXmlDataFormat.java index c5d99b5a851..d29d19e4882 100644 --- a/components/camel-groovy-xml/src/main/java/org/apache/camel/groovy/xml/GroovyXmlDataFormat.java +++ b/components/camel-groovy-xml/src/main/java/org/apache/camel/groovy/xml/GroovyXmlDataFormat.java @@ -39,9 +39,9 @@ import org.apache.camel.util.StringHelper; @Dataformat("groovyXml") public class GroovyXmlDataFormat extends ServiceSupport implements DataFormat, DataFormatName { - int START_TAG = 1; - int VALUE = 2; - int END_TAG = 3; + private static final int START_TAG = 1; + private static final int VALUE = 2; + private static final int END_TAG = 3; @Override public void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception { @@ -122,6 +122,7 @@ public class GroovyXmlDataFormat extends ServiceSupport implements DataFormat, D } private void doSerialize(CamelContext context, Map<String, Object> map, List<Line> lines) { + boolean root = false; for (var e : map.entrySet()) { String key = e.getKey(); @@ -132,6 +133,7 @@ public class GroovyXmlDataFormat extends ServiceSupport implements DataFormat, D // root tag if (lines.isEmpty()) { + root = true; lines.add(new Line(key, null, START_TAG)); } @@ -140,7 +142,7 @@ public class GroovyXmlDataFormat extends ServiceSupport implements DataFormat, D if (e.getValue() instanceof Map cm) { doSerialize(context, cm, lines); } else if (e.getValue() instanceof List cl) { - doSerialize(context, cl, key, lines); + doSerialize(context, cl, key, lines, root); } else { String val = context.getTypeConverter().convertTo(String.class, e.getValue()); if (val != null) { @@ -154,14 +156,17 @@ public class GroovyXmlDataFormat extends ServiceSupport implements DataFormat, D } } - private void doSerialize(CamelContext context, List list, String key, List<Line> lines) { - // list of map or value entries + private void doSerialize(CamelContext context, List list, String key, List<Line> lines, boolean root) { for (var e : list) { - lines.add(new Line(key, null, START_TAG)); + if (!root) { + lines.add(new Line(key, null, START_TAG)); + } if (e instanceof Map map) { doSerialize(context, map, lines); } - lines.add(new Line(key, null, END_TAG)); + if (!root) { + lines.add(new Line(key, null, END_TAG)); + } } } diff --git a/components/camel-groovy-xml/src/test/java/org/apache/camel/groovy/xml/GroovyXmlDataFormatTest.java b/components/camel-groovy-xml/src/test/java/org/apache/camel/groovy/xml/GroovyXmlDataFormatTest.java index a82685ebee2..59ef9b44ba3 100644 --- a/components/camel-groovy-xml/src/test/java/org/apache/camel/groovy/xml/GroovyXmlDataFormatTest.java +++ b/components/camel-groovy-xml/src/test/java/org/apache/camel/groovy/xml/GroovyXmlDataFormatTest.java @@ -94,6 +94,40 @@ public class GroovyXmlDataFormatTest extends CamelTestSupport { } """; + private static final String COUNTRIES + = """ + <countries> + <country>Norway</country> + <country>Denmark</country> + <country>Sweden</country> + <country>Germany</country> + <country>Finland</country> + </countries> + """; + + private static final String COUNTRIES_JSON + = """ + { + "countries": [ + { + "country": "Norway" + }, + { + "country": "Denmark" + }, + { + "country": "Sweden" + }, + { + "country": "Germany" + }, + { + "country": "Finland" + } + ] + } + """; + @Test public void testUnmarshal() throws Exception { getMockEndpoint("mock:unmarshal").expectedMessageCount(1); @@ -198,6 +232,42 @@ public class GroovyXmlDataFormatTest extends CamelTestSupport { MockEndpoint.assertIsSatisfied(context); } + @Test + public void testUnmarshalArray() throws Exception { + getMockEndpoint("mock:unmarshal").expectedMessageCount(1); + + Object out = template.requestBody("direct:unmarshal", COUNTRIES); + Assertions.assertNotNull(out); + Assertions.assertInstanceOf(Node.class, out); + + Node n = (Node) out; + Assertions.assertEquals(5, n.children().size()); + Assertions.assertEquals("country[attributes={}; value=[Norway]]", n.children().get(0).toString()); + Assertions.assertEquals("country[attributes={}; value=[Denmark]]", n.children().get(1).toString()); + Assertions.assertEquals("country[attributes={}; value=[Sweden]]", n.children().get(2).toString()); + Assertions.assertEquals("country[attributes={}; value=[Germany]]", n.children().get(3).toString()); + Assertions.assertEquals("country[attributes={}; value=[Finland]]", n.children().get(4).toString()); + + MockEndpoint.assertIsSatisfied(context); + } + + @Test + public void testMarshalArrayJacksonJSon() throws Exception { + getMockEndpoint("mock:marshal").expectedMessageCount(1); + + ObjectMapper om = new JsonMapper(); + JsonNode root = om.readTree(COUNTRIES_JSON); + + Object out = template.requestBody("direct:marshal", root); + Assertions.assertNotNull(out); + Assertions.assertInstanceOf(byte[].class, out); + + String xml = context.getTypeConverter().convertTo(String.class, out); + Assertions.assertEquals(COUNTRIES, xml); + + MockEndpoint.assertIsSatisfied(context); + } + @Override protected RoutesBuilder createRouteBuilder() throws Exception { return new RouteBuilder() {