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 2026/08/05 14:20:33 UTC
(camel) 01/01: CAMEL-23530: Move DataWeave parser to camel-dataweave component for reuse
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch feature/CAMEL-23530-dataweave-component
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 908a6dd8cfe46b02fe10d363abb2f85e5d384911
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Aug 5 16:19:10 2026 +0200
CAMEL-23530: Move DataWeave parser to camel-dataweave component for reuse
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
bom/camel-bom/pom.xml | 5 ++
catalog/camel-allcomponents/pom.xml | 5 ++
.../org/apache/camel/catalog/others.properties | 1 +
.../org/apache/camel/catalog/others/dataweave.json | 15 ++++
components/camel-dataweave/pom.xml | 54 +++++++++++++++
.../services/org/apache/camel/other.properties | 7 ++
.../src/generated/resources/dataweave.json | 15 ++++
.../camel/component/dataweave}/DataWeaveAst.java | 2 +-
.../component/dataweave}/DataWeaveConverter.java | 20 +++---
.../camel/component/dataweave}/DataWeaveLexer.java | 2 +-
.../component/dataweave}/DataWeaveParser.java | 16 ++---
.../dataweave}/DataWeaveConverterTest.java | 45 ++++++------
.../component/dataweave}/DataWeaveLexerTest.java | 21 +-----
.../component/dataweave}/DataWeaveParserTest.java | 80 +++++++++-------------
.../test/resources/dataweave/collection-map.dwl | 0
.../src/test/resources/dataweave/event-message.dwl | 0
.../src/test/resources/dataweave/null-handling.dwl | 0
.../src/test/resources/dataweave/simple-rename.dwl | 0
.../src/test/resources/dataweave/string-ops.dwl | 0
.../src/test/resources/dataweave/type-coercion.dwl | 0
components/pom.xml | 1 +
.../modules/others/examples/json/dataweave.json | 1 +
dsl/camel-jbang/camel-jbang-core/pom.xml | 4 ++
.../jbang/core/commands/TransformDataWeave.java | 2 +-
parent/pom.xml | 5 ++
25 files changed, 190 insertions(+), 111 deletions(-)
diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index ea5383026c76..f6f06b4f00b6 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -707,6 +707,11 @@
<artifactId>camel-datasonnet</artifactId>
<version>4.22.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-dataweave</artifactId>
+ <version>4.22.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-debezium-common</artifactId>
diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml
index 9ff95f7750ff..0afdc8f168ad 100644
--- a/catalog/camel-allcomponents/pom.xml
+++ b/catalog/camel-allcomponents/pom.xml
@@ -597,6 +597,11 @@
<artifactId>camel-datasonnet</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-dataweave</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-debezium-common</artifactId>
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
index e1c80fb21928..20197d007d61 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
@@ -7,6 +7,7 @@ cluster
componentdsl
console
csimple-joor
+dataweave
debug
diagram
dsl-modeline
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/dataweave.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/dataweave.json
new file mode 100644
index 000000000000..c41beea0ddf9
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/dataweave.json
@@ -0,0 +1,15 @@
+{
+ "other": {
+ "kind": "other",
+ "name": "dataweave",
+ "title": "Dataweave",
+ "description": "Camel DataWeave support",
+ "deprecated": false,
+ "firstVersion": "4.22.0",
+ "label": "transformation",
+ "supportLevel": "Preview",
+ "groupId": "org.apache.camel",
+ "artifactId": "camel-dataweave",
+ "version": "4.22.0-SNAPSHOT"
+ }
+}
diff --git a/components/camel-dataweave/pom.xml b/components/camel-dataweave/pom.xml
new file mode 100644
index 000000000000..492acf2f43ce
--- /dev/null
+++ b/components/camel-dataweave/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>components</artifactId>
+ <version>4.22.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>camel-dataweave</artifactId>
+ <packaging>jar</packaging>
+
+ <name>Camel :: DataWeave</name>
+ <description>Camel DataWeave support</description>
+
+ <properties>
+ <firstVersion>4.22.0</firstVersion>
+ <label>transformation</label>
+ </properties>
+
+ <dependencies>
+ <!-- test dependencies -->
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/components/camel-dataweave/src/generated/resources/META-INF/services/org/apache/camel/other.properties b/components/camel-dataweave/src/generated/resources/META-INF/services/org/apache/camel/other.properties
new file mode 100644
index 000000000000..40bc48ca1d26
--- /dev/null
+++ b/components/camel-dataweave/src/generated/resources/META-INF/services/org/apache/camel/other.properties
@@ -0,0 +1,7 @@
+# Generated by camel build tools - do NOT edit this file!
+name=dataweave
+groupId=org.apache.camel
+artifactId=camel-dataweave
+version=4.22.0-SNAPSHOT
+projectName=Camel :: DataWeave
+projectDescription=Camel DataWeave support
diff --git a/components/camel-dataweave/src/generated/resources/dataweave.json b/components/camel-dataweave/src/generated/resources/dataweave.json
new file mode 100644
index 000000000000..c41beea0ddf9
--- /dev/null
+++ b/components/camel-dataweave/src/generated/resources/dataweave.json
@@ -0,0 +1,15 @@
+{
+ "other": {
+ "kind": "other",
+ "name": "dataweave",
+ "title": "Dataweave",
+ "description": "Camel DataWeave support",
+ "deprecated": false,
+ "firstVersion": "4.22.0",
+ "label": "transformation",
+ "supportLevel": "Preview",
+ "groupId": "org.apache.camel",
+ "artifactId": "camel-dataweave",
+ "version": "4.22.0-SNAPSHOT"
+ }
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveAst.java b/components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveAst.java
similarity index 98%
rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveAst.java
rename to components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveAst.java
index 4b75a0569aff..f1ef34b9b40b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveAst.java
+++ b/components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveAst.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.dsl.jbang.core.commands.transform;
+package org.apache.camel.component.dataweave;
import java.util.List;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveConverter.java b/components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveConverter.java
similarity index 96%
rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveConverter.java
rename to components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveConverter.java
index 3842f29b2c5e..6bc12820c8ea 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveConverter.java
+++ b/components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveConverter.java
@@ -14,13 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.dsl.jbang.core.commands.transform;
+package org.apache.camel.component.dataweave;
import java.util.ArrayList;
import java.util.List;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.*;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveLexer.Token;
+import org.apache.camel.component.dataweave.DataWeaveAst.*;
+import org.apache.camel.component.dataweave.DataWeaveLexer.Token;
/**
* Converts DataWeave 2.0 scripts to DataSonnet. Parses the DataWeave input, walks the AST, and emits equivalent
@@ -84,7 +84,7 @@ public class DataWeaveConverter {
return emitNode(ast);
}
- // ── Emission ──
+ // -- Emission --
private String emit(DataWeaveAst node) {
if (node instanceof Script script) {
@@ -352,7 +352,7 @@ public class DataWeaveConverter {
case "Boolean" -> "cml.toBoolean(" + expr + ")";
default -> {
todoCount++;
- yield expr + (includeComments ? " // TODO: manual conversion needed — as " + tc.type() : "");
+ yield expr + (includeComments ? " // TODO: manual conversion needed -- as " + tc.type() : "");
}
};
}
@@ -410,9 +410,9 @@ public class DataWeaveConverter {
yield "c.max(" + argStr + ")";
}
case "read" -> "std.parseJson(" + argStr + ")"
- + (includeComments ? " // NOTE: assumes JSON input — DW read() supports multiple formats" : "");
+ + (includeComments ? " // NOTE: assumes JSON input -- DW read() supports multiple formats" : "");
case "write" -> "std.manifestJsonEx(" + argStr + ", \" \")"
- + (includeComments ? " // NOTE: outputs JSON — DW write() supports multiple formats" : "");
+ + (includeComments ? " // NOTE: outputs JSON -- DW write() supports multiple formats" : "");
default -> fc.name() + "(" + argStr + ")";
};
}
@@ -436,7 +436,7 @@ public class DataWeaveConverter {
List<String> paramNames = lambdaParamNames(lam);
String body = emitNode(lam.body());
if (paramNames.size() == 2) {
- // DW: map ((item, index) -> body) — DS: std.mapWithIndex(function(index, item) body, collection)
+ // DW: map ((item, index) -> body) -- DS: std.mapWithIndex(function(index, item) body, collection)
// Parameter order is swapped: DW is (item, index), DS is (index, item)
return "std.mapWithIndex(function(" + paramNames.get(1) + ", " + paramNames.get(0)
+ ") " + body + ", " + collection + ")";
@@ -498,7 +498,7 @@ public class DataWeaveConverter {
if (dbe.lambda() instanceof Lambda lam) {
List<String> paramNames = lambdaParamNames(lam);
String body = emitNode(lam.body());
- // distinctBy keeps first occurrence per key — use distinctBy helper
+ // distinctBy keeps first occurrence per key -- use distinctBy helper
return "c.distinctBy(" + collection + ", function(" + paramNames.get(0) + ") " + body + ")";
}
return "c.distinct(" + collection + ")";
@@ -593,7 +593,7 @@ public class DataWeaveConverter {
todoCount++;
convertedCount--;
return includeComments
- ? "// TODO: manual conversion needed — " + u.reason() + ": " + u.originalText() + "\nnull"
+ ? "// TODO: manual conversion needed -- " + u.reason() + ": " + u.originalText() + "\nnull"
: "null";
}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveLexer.java b/components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveLexer.java
similarity index 99%
rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveLexer.java
rename to components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveLexer.java
index 1d74d45d7382..703424acaeb6 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveLexer.java
+++ b/components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveLexer.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.dsl.jbang.core.commands.transform;
+package org.apache.camel.component.dataweave;
import java.util.ArrayList;
import java.util.List;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveParser.java b/components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveParser.java
similarity index 98%
rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveParser.java
rename to components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveParser.java
index 8c2f62c29dfb..e91187d23f17 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveParser.java
+++ b/components/camel-dataweave/src/main/java/org/apache/camel/component/dataweave/DataWeaveParser.java
@@ -14,13 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.dsl.jbang.core.commands.transform;
+package org.apache.camel.component.dataweave;
import java.util.ArrayList;
import java.util.List;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveLexer.Token;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveLexer.TokenType;
+import org.apache.camel.component.dataweave.DataWeaveLexer.Token;
+import org.apache.camel.component.dataweave.DataWeaveLexer.TokenType;
/**
* Recursive descent parser for DataWeave 2.0 scripts producing {@link DataWeaveAst} nodes.
@@ -45,7 +45,7 @@ public class DataWeaveParser {
return parseExpression();
}
- // ── Header parsing ──
+ // -- Header parsing --
private DataWeaveAst.Header parseHeader() {
String version = "2.0";
@@ -57,7 +57,7 @@ public class DataWeaveParser {
|| checkIdentifier("output") || checkIdentifier("input");
if (!hasHeader) {
- // No header section — skip directly to body
+ // No header section -- skip directly to body
return new DataWeaveAst.Header(version, null, inputs);
}
@@ -118,7 +118,7 @@ public class DataWeaveParser {
return sb.toString();
}
- // ── Expression parsing (precedence climbing) ──
+ // -- Expression parsing (precedence climbing) --
private DataWeaveAst parseExpression() {
// Handle var/fun declarations at expression level
@@ -442,7 +442,7 @@ public class DataWeaveParser {
expr = new DataWeaveAst.ReplaceExpr(expr, target, replacement);
} else if (checkIdentifier("match")) {
advance(); // match
- // Capture the match block as unsupported — skip braces
+ // Capture the match block as unsupported -- skip braces
StringBuilder matchText = new StringBuilder("match ");
if (check(TokenType.LBRACE)) {
int depth = 1;
@@ -717,7 +717,7 @@ public class DataWeaveParser {
return new DataWeaveAst.ArrayLit(elements);
}
- // ── Token helpers ──
+ // -- Token helpers --
private Token current() {
return pos < tokens.size() ? tokens.get(pos) : tokens.get(tokens.size() - 1);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveConverterTest.java b/components/camel-dataweave/src/test/java/org/apache/camel/component/dataweave/DataWeaveConverterTest.java
similarity index 93%
rename from dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveConverterTest.java
rename to components/camel-dataweave/src/test/java/org/apache/camel/component/dataweave/DataWeaveConverterTest.java
index c2424bd1e66a..e435af0e483f 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveConverterTest.java
+++ b/components/camel-dataweave/src/test/java/org/apache/camel/component/dataweave/DataWeaveConverterTest.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.dsl.jbang.core.commands.transform;
+package org.apache.camel.component.dataweave;
import java.io.IOException;
import java.io.InputStream;
@@ -34,7 +34,7 @@ class DataWeaveConverterTest {
converter = new DataWeaveConverter();
}
- // ── Header conversion ──
+ // -- Header conversion --
@Test
void testHeaderConversion() {
@@ -51,7 +51,7 @@ class DataWeaveConverterTest {
assertTrue(result.contains("*/"));
}
- // ── Field access ──
+ // -- Field access --
@Test
void testPayloadToBody() {
@@ -83,7 +83,7 @@ class DataWeaveConverterTest {
assertEquals("cml.header('page')", result);
}
- // ── Operators ──
+ // -- Operators --
@Test
void testStringConcat() {
@@ -109,7 +109,7 @@ class DataWeaveConverterTest {
assertEquals("body.active && body.verified", result);
}
- // ── Default operator ──
+ // -- Default operator --
@Test
void testDefault() {
@@ -117,7 +117,7 @@ class DataWeaveConverterTest {
assertEquals("cml.defaultVal(body.currency, \"USD\")", result);
}
- // ── Type coercion ──
+ // -- Type coercion --
@Test
void testAsNumber() {
@@ -143,7 +143,7 @@ class DataWeaveConverterTest {
assertEquals("cml.toBoolean(body.active)", result);
}
- // ── Built-in functions ──
+ // -- Built-in functions --
@Test
void testSizeOf() {
@@ -194,7 +194,7 @@ class DataWeaveConverterTest {
assertTrue(converter.needsCamelLib());
}
- // ── String operations ──
+ // -- String operations --
@Test
void testContains() {
@@ -221,7 +221,7 @@ class DataWeaveConverterTest {
assertEquals("std.strReplace(body.text, \"old\", \"new\")", result);
}
- // ── Collection operations ──
+ // -- Collection operations --
@Test
void testMap() {
@@ -250,10 +250,8 @@ class DataWeaveConverterTest {
@Test
void testReduceParamSwap() {
- // Verify that acc and item params are swapped for std.foldl
String result = converter.convertExpression(
"payload.items reduce ((item, acc = 0) -> acc + item.price)");
- // In std.foldl, it should be function(acc, item) not function(item, acc)
assertTrue(result.contains("function(acc, item)"));
}
@@ -265,7 +263,7 @@ class DataWeaveConverterTest {
assertTrue(result.contains("item.tags"));
}
- // ── If/else ──
+ // -- If/else --
@Test
void testIfElse() {
@@ -274,7 +272,7 @@ class DataWeaveConverterTest {
assertEquals("if body.age >= 18 then \"adult\" else \"minor\"", result);
}
- // ── Object and array literals ──
+ // -- Object and array literals --
@Test
void testObjectLiteral() {
@@ -289,7 +287,7 @@ class DataWeaveConverterTest {
assertEquals("[1, 2, 3]", result);
}
- // ── Full script tests ──
+ // -- Full script tests --
@Test
void testSimpleRenameScript() throws IOException {
@@ -382,7 +380,7 @@ class DataWeaveConverterTest {
assertTrue(result.contains("name: body.name"));
}
- // ── startsWith / endsWith ──
+ // -- startsWith / endsWith --
@Test
void testStartsWith() {
@@ -398,7 +396,7 @@ class DataWeaveConverterTest {
assertTrue(converter.needsCamelLib());
}
- // ── Math functions ──
+ // -- Math functions --
@Test
void testAbs() {
@@ -427,17 +425,16 @@ class DataWeaveConverterTest {
assertTrue(converter.needsCamelLib());
}
- // ── mapWithIndex parameter order ──
+ // -- mapWithIndex parameter order --
@Test
void testMapWithIndex() {
String result = converter.convertExpression(
"payload.items map ((item, idx) -> { index: idx, name: item.name })");
- // DataSonnet std.mapWithIndex uses function(index, item), so params must be swapped
assertTrue(result.contains("std.mapWithIndex(function(idx, item)"));
}
- // ── distinctBy ──
+ // -- distinctBy --
@Test
void testDistinctBy() {
@@ -448,7 +445,7 @@ class DataWeaveConverterTest {
assertTrue(converter.needsCamelLib());
}
- // ── Lambda shorthand ──
+ // -- Lambda shorthand --
@Test
void testLambdaShorthand() {
@@ -456,7 +453,7 @@ class DataWeaveConverterTest {
assertTrue(result.contains("function(x) x.name"));
}
- // ── match expression ──
+ // -- match expression --
@Test
void testMatchExpressionUnsupported() {
@@ -466,7 +463,7 @@ class DataWeaveConverterTest {
assertTrue(converter.getTodoCount() > 0);
}
- // ── Multi-value selector ──
+ // -- Multi-value selector --
@Test
void testMultiValueSelector() {
@@ -475,7 +472,7 @@ class DataWeaveConverterTest {
assertEquals(0, converter.getTodoCount());
}
- // ── Escape handling ──
+ // -- Escape handling --
@Test
void testStringEscapesPreserved() {
@@ -483,7 +480,7 @@ class DataWeaveConverterTest {
assertTrue(result.contains("\"\\n\""), "Newline escape should be preserved, got: " + result);
}
- // ── Helpers ──
+ // -- Helpers --
private String loadResource(String path) throws IOException {
try (InputStream is = getClass().getClassLoader().getResourceAsStream(path)) {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveLexerTest.java b/components/camel-dataweave/src/test/java/org/apache/camel/component/dataweave/DataWeaveLexerTest.java
similarity index 79%
rename from dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveLexerTest.java
rename to components/camel-dataweave/src/test/java/org/apache/camel/component/dataweave/DataWeaveLexerTest.java
index 9395ac07424c..76a66320039a 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveLexerTest.java
+++ b/components/camel-dataweave/src/test/java/org/apache/camel/component/dataweave/DataWeaveLexerTest.java
@@ -14,23 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.dsl.jbang.core.commands.transform;
+package org.apache.camel.component.dataweave;
import java.util.List;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveLexer.Token;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveLexer.TokenType;
+import org.apache.camel.component.dataweave.DataWeaveLexer.Token;
+import org.apache.camel.component.dataweave.DataWeaveLexer.TokenType;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
-/**
- * Unit tests for {@link DataWeaveLexer}.
- *
- * These assert the concrete token stream (types, values and positions) for representative inputs, focusing on the
- * tricky, ambiguous cases where a tokenizer typically goes wrong: multi-character operators, negative numbers vs the
- * minus operator, the {@code ---} header separator, and comment skipping.
- */
class DataWeaveLexerTest {
private static List<Token> tokenize(String input) {
@@ -50,7 +43,6 @@ class DataWeaveLexerTest {
@Test
void shouldClassifyKeywordsAndIdentifiers() {
- // true/false -> BOOLEAN, null -> NULL_LIT, and/or/not -> logical ops, everything else -> IDENTIFIER
assertEquals(
List.of(TokenType.BOOLEAN, TokenType.BOOLEAN, TokenType.NULL_LIT,
TokenType.AND, TokenType.OR, TokenType.NOT,
@@ -65,7 +57,6 @@ class DataWeaveLexerTest {
assertEquals("hello", tokens.get(0).value());
assertEquals(TokenType.STRING, tokens.get(1).type());
assertEquals("world", tokens.get(1).value());
- // the escaped quote is preserved verbatim inside the string value
assertEquals("a\\\"b", tokens.get(2).value());
}
@@ -78,7 +69,6 @@ class DataWeaveLexerTest {
@Test
void shouldTreatLeadingMinusAsNegativeNumberWhenNotAfterValue() {
- // at the start of input the minus binds to the number
List<Token> tokens = tokenize("-5");
assertEquals(TokenType.NUMBER, tokens.get(0).type());
assertEquals("-5", tokens.get(0).value());
@@ -86,7 +76,6 @@ class DataWeaveLexerTest {
@Test
void shouldTreatMinusBetweenValuesAsOperator() {
- // "5 - 3": the minus follows a value, so it is the subtraction operator, not a sign
assertEquals(
List.of(TokenType.NUMBER, TokenType.MINUS, TokenType.NUMBER, TokenType.EOF),
types("5 - 3"));
@@ -94,7 +83,6 @@ class DataWeaveLexerTest {
@Test
void shouldTreatMinusAfterOpeningParenAsNegativeNumber() {
- // "(-3)": previous char is '(', not value-like, so the minus binds to the number
assertEquals(
List.of(TokenType.LPAREN, TokenType.NUMBER, TokenType.RPAREN, TokenType.EOF),
types("(-3)"));
@@ -112,7 +100,6 @@ class DataWeaveLexerTest {
@Test
void shouldRecognizeHeaderSeparatorAtLineStart() {
- // the --- on its own line is a header separator, while the negative number afterwards stays a number
List<TokenType> ts = types("%dw 2.0\n---\n-5");
assertEquals(
List.of(TokenType.PERCENT, TokenType.IDENTIFIER, TokenType.NUMBER,
@@ -133,7 +120,6 @@ class DataWeaveLexerTest {
@Test
void shouldTrackLineAndColumnPositions() {
- // "ab\n cd": first token at 1:1, second at line 2 after two spaces -> 2:3
List<Token> tokens = tokenize("ab\n cd");
assertEquals(1, tokens.get(0).line());
assertEquals(1, tokens.get(0).col());
@@ -145,7 +131,6 @@ class DataWeaveLexerTest {
@Test
void shouldSkipUnknownCharactersInsteadOfFailing() {
- // '@' is not a recognized token; the lexer drops it and keeps going
assertEquals(
List.of(TokenType.IDENTIFIER, TokenType.IDENTIFIER, TokenType.EOF),
types("a @ b"));
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveParserTest.java b/components/camel-dataweave/src/test/java/org/apache/camel/component/dataweave/DataWeaveParserTest.java
similarity index 74%
rename from dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveParserTest.java
rename to components/camel-dataweave/src/test/java/org/apache/camel/component/dataweave/DataWeaveParserTest.java
index 8802531c2932..dd8688ed8cb3 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/transform/DataWeaveParserTest.java
+++ b/components/camel-dataweave/src/test/java/org/apache/camel/component/dataweave/DataWeaveParserTest.java
@@ -14,31 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.dsl.jbang.core.commands.transform;
+package org.apache.camel.component.dataweave;
import java.util.List;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.ArrayLit;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.BinaryOp;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.DefaultExpr;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.FieldAccess;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.FunctionCall;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.Identifier;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.IfElse;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.IndexAccess;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.Lambda;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.LambdaShorthand;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.MapExpr;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.NumberLit;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.ObjectLit;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.Parens;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.Script;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.StringLit;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.TypeCoercion;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.UnaryOp;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.Unsupported;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveAst.VarDecl;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveLexer.Token;
+import org.apache.camel.component.dataweave.DataWeaveAst.ArrayLit;
+import org.apache.camel.component.dataweave.DataWeaveAst.BinaryOp;
+import org.apache.camel.component.dataweave.DataWeaveAst.DefaultExpr;
+import org.apache.camel.component.dataweave.DataWeaveAst.FieldAccess;
+import org.apache.camel.component.dataweave.DataWeaveAst.FunctionCall;
+import org.apache.camel.component.dataweave.DataWeaveAst.Identifier;
+import org.apache.camel.component.dataweave.DataWeaveAst.IfElse;
+import org.apache.camel.component.dataweave.DataWeaveAst.IndexAccess;
+import org.apache.camel.component.dataweave.DataWeaveAst.Lambda;
+import org.apache.camel.component.dataweave.DataWeaveAst.LambdaShorthand;
+import org.apache.camel.component.dataweave.DataWeaveAst.MapExpr;
+import org.apache.camel.component.dataweave.DataWeaveAst.NumberLit;
+import org.apache.camel.component.dataweave.DataWeaveAst.ObjectLit;
+import org.apache.camel.component.dataweave.DataWeaveAst.Parens;
+import org.apache.camel.component.dataweave.DataWeaveAst.Script;
+import org.apache.camel.component.dataweave.DataWeaveAst.StringLit;
+import org.apache.camel.component.dataweave.DataWeaveAst.TypeCoercion;
+import org.apache.camel.component.dataweave.DataWeaveAst.UnaryOp;
+import org.apache.camel.component.dataweave.DataWeaveAst.Unsupported;
+import org.apache.camel.component.dataweave.DataWeaveAst.VarDecl;
+import org.apache.camel.component.dataweave.DataWeaveLexer.Token;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -47,14 +47,6 @@ import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
-/**
- * Unit tests for {@link DataWeaveParser}.
- *
- * The parser is recursive descent and best-effort (it never throws on malformed input). These tests assert the shape of
- * the produced {@link DataWeaveAst} for representative scripts, with emphasis on operator precedence, postfix
- * collection operations, header parsing, and graceful handling of unsupported constructs. The AST records are exercised
- * transitively here rather than in a separate test, since they carry no logic of their own.
- */
class DataWeaveParserTest {
private static DataWeaveAst parseExpr(String src) {
@@ -67,7 +59,7 @@ class DataWeaveParserTest {
return new DataWeaveParser(tokens).parse();
}
- // ── Header ──
+ // -- Header --
@Test
void shouldParseHeaderVersionAndOutputType() {
@@ -102,14 +94,13 @@ class DataWeaveParserTest {
@Test
void shouldDefaultVersionWhenNoHeaderPresent() {
- // an expression with no %dw header still yields a Script with the default 2.0 version
Script script = assertInstanceOf(Script.class, parseScript("payload"));
assertEquals("2.0", script.header().version());
assertNull(script.header().outputType());
assertInstanceOf(Identifier.class, script.body());
}
- // ── Literals and field access ──
+ // -- Literals and field access --
@Test
void shouldParseLiterals() {
@@ -121,7 +112,6 @@ class DataWeaveParserTest {
@Test
void shouldParseFieldAccessAndIndexAccessChain() {
- // payload.items[0] -> IndexAccess(FieldAccess(Identifier(payload), items), NumberLit(0))
IndexAccess idx = assertInstanceOf(IndexAccess.class, parseExpr("payload.items[0]"));
assertEquals("0", assertInstanceOf(NumberLit.class, idx.index()).value());
FieldAccess fa = assertInstanceOf(FieldAccess.class, idx.object());
@@ -129,11 +119,10 @@ class DataWeaveParserTest {
assertEquals("payload", assertInstanceOf(Identifier.class, fa.object()).name());
}
- // ── Precedence ──
+ // -- Precedence --
@Test
void shouldGiveMultiplicationHigherPrecedenceThanAddition() {
- // 1 + 2 * 3 -> BinaryOp(+, 1, BinaryOp(*, 2, 3))
BinaryOp add = assertInstanceOf(BinaryOp.class, parseExpr("1 + 2 * 3"));
assertEquals("+", add.op());
assertEquals("1", assertInstanceOf(NumberLit.class, add.left()).value());
@@ -145,7 +134,6 @@ class DataWeaveParserTest {
@Test
void shouldGiveAndHigherPrecedenceThanOr() {
- // a and b or c -> BinaryOp(or, BinaryOp(and, a, b), c)
BinaryOp or = assertInstanceOf(BinaryOp.class, parseExpr("a and b or c"));
assertEquals("or", or.op());
assertEquals("c", assertInstanceOf(Identifier.class, or.right()).name());
@@ -165,16 +153,14 @@ class DataWeaveParserTest {
assertEquals("+", assertInstanceOf(BinaryOp.class, parens.expr()).op());
}
- // ── Object / array literals ──
+ // -- Object / array literals --
@Test
void shouldParseObjectLiteralWithStaticAndDynamicKeys() {
ObjectLit obj = assertInstanceOf(ObjectLit.class, parseExpr("{ name: payload.x, (k): v }"));
assertEquals(2, obj.entries().size());
- // static key
assertEquals("name", assertInstanceOf(Identifier.class, obj.entries().get(0).key()).name());
assertFalse(obj.entries().get(0).dynamic());
- // dynamic key parsed from a parenthesized expression
assertTrue(obj.entries().get(1).dynamic());
assertEquals("k", assertInstanceOf(Identifier.class, obj.entries().get(1).key()).name());
}
@@ -186,7 +172,7 @@ class DataWeaveParserTest {
assertEquals("2", assertInstanceOf(NumberLit.class, arr.elements().get(1)).value());
}
- // ── Collection operations / lambdas ──
+ // -- Collection operations / lambdas --
@Test
void shouldParseMapWithExplicitLambda() {
@@ -205,7 +191,7 @@ class DataWeaveParserTest {
assertEquals(List.of("name"), sh.fields());
}
- // ── Function calls ──
+ // -- Function calls --
@Test
void shouldParseBuiltinFunctionCall() {
@@ -215,7 +201,7 @@ class DataWeaveParserTest {
assertEquals("payload", assertInstanceOf(Identifier.class, call.args().get(0)).name());
}
- // ── Type coercion ──
+ // -- Type coercion --
@Test
void shouldParseTypeCoercionWithoutFormat() {
@@ -231,7 +217,7 @@ class DataWeaveParserTest {
assertEquals("yyyy-MM-dd", tc.format());
}
- // ── Control flow ──
+ // -- Control flow --
@Test
void shouldParseIfElse() {
@@ -250,14 +236,13 @@ class DataWeaveParserTest {
@Test
void shouldParseVarDeclarationWithTrailingBody() {
- // "var x = 1 x" -> VarDecl(x, NumberLit(1), body=Identifier(x))
VarDecl var = assertInstanceOf(VarDecl.class, parseExpr("var x = 1 x"));
assertEquals("x", var.name());
assertEquals("1", assertInstanceOf(NumberLit.class, var.value()).value());
assertEquals("x", assertInstanceOf(Identifier.class, var.body()).name());
}
- // ── Unary ──
+ // -- Unary --
@Test
void shouldParseLogicalNot() {
@@ -266,7 +251,7 @@ class DataWeaveParserTest {
assertEquals("a", assertInstanceOf(Identifier.class, not.operand()).name());
}
- // ── Graceful degradation ──
+ // -- Graceful degradation --
@Test
void shouldRepresentMatchExpressionAsUnsupported() {
@@ -278,7 +263,6 @@ class DataWeaveParserTest {
@Test
void shouldNotThrowOnUnbalancedInput() {
- // expect() silently skips a missing RPAREN, so a best-effort AST is still produced
List<Token> tokens = new DataWeaveLexer("(a + b").tokenize();
assertEquals(DataWeaveLexer.TokenType.EOF, tokens.get(tokens.size() - 1).type());
assertInstanceOf(Parens.class, parseExpr("(a + b"));
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/collection-map.dwl b/components/camel-dataweave/src/test/resources/dataweave/collection-map.dwl
similarity index 100%
rename from dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/collection-map.dwl
rename to components/camel-dataweave/src/test/resources/dataweave/collection-map.dwl
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/event-message.dwl b/components/camel-dataweave/src/test/resources/dataweave/event-message.dwl
similarity index 100%
rename from dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/event-message.dwl
rename to components/camel-dataweave/src/test/resources/dataweave/event-message.dwl
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/null-handling.dwl b/components/camel-dataweave/src/test/resources/dataweave/null-handling.dwl
similarity index 100%
rename from dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/null-handling.dwl
rename to components/camel-dataweave/src/test/resources/dataweave/null-handling.dwl
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/simple-rename.dwl b/components/camel-dataweave/src/test/resources/dataweave/simple-rename.dwl
similarity index 100%
rename from dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/simple-rename.dwl
rename to components/camel-dataweave/src/test/resources/dataweave/simple-rename.dwl
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/string-ops.dwl b/components/camel-dataweave/src/test/resources/dataweave/string-ops.dwl
similarity index 100%
rename from dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/string-ops.dwl
rename to components/camel-dataweave/src/test/resources/dataweave/string-ops.dwl
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/type-coercion.dwl b/components/camel-dataweave/src/test/resources/dataweave/type-coercion.dwl
similarity index 100%
rename from dsl/camel-jbang/camel-jbang-core/src/test/resources/dataweave/type-coercion.dwl
rename to components/camel-dataweave/src/test/resources/dataweave/type-coercion.dwl
diff --git a/components/pom.xml b/components/pom.xml
index e09d87cfe482..5c9fca05136b 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -120,6 +120,7 @@
<module>camel-cyberark-vault</module>
<module>camel-dapr</module>
<module>camel-datasonnet</module>
+ <module>camel-dataweave</module>
<module>camel-debug</module>
<module>camel-diagram</module>
<module>camel-debezium</module>
diff --git a/docs/components/modules/others/examples/json/dataweave.json b/docs/components/modules/others/examples/json/dataweave.json
new file mode 120000
index 000000000000..d2175aae6006
--- /dev/null
+++ b/docs/components/modules/others/examples/json/dataweave.json
@@ -0,0 +1 @@
+../../../../../../components/camel-dataweave/src/generated/resources/dataweave.json
\ No newline at end of file
diff --git a/dsl/camel-jbang/camel-jbang-core/pom.xml b/dsl/camel-jbang/camel-jbang-core/pom.xml
index d369b09415b0..d3066b4c5e6f 100644
--- a/dsl/camel-jbang/camel-jbang-core/pom.xml
+++ b/dsl/camel-jbang/camel-jbang-core/pom.xml
@@ -45,6 +45,10 @@
<dependencies>
<!-- camel -->
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-dataweave</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-diagram</artifactId>
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformDataWeave.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformDataWeave.java
index bc3ff95df84d..e08ed966680f 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformDataWeave.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformDataWeave.java
@@ -23,7 +23,7 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
-import org.apache.camel.dsl.jbang.core.commands.transform.DataWeaveConverter;
+import org.apache.camel.component.dataweave.DataWeaveConverter;
import picocli.CommandLine;
import picocli.CommandLine.Command;
diff --git a/parent/pom.xml b/parent/pom.xml
index d10f812f6c4d..1030dea51ba4 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -1247,6 +1247,11 @@
<artifactId>camel-datasonnet</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-dataweave</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-debezium-common</artifactId>