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 765df73eee94 CAMEL-23756: camel-jbang-mcp - Support Java DSL as source
format in route transform tool
765df73eee94 is described below
commit 765df73eee94a6082cf650012e11bd362ecd8a07
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Jun 15 14:41:32 2026 +0200
CAMEL-23756: camel-jbang-mcp - Support Java DSL as source format in route
transform tool
The MCP camel_transform_route tool previously rejected Java as a source
format. This adds Java-to-YAML and Java-to-XML transformation by loading
Java source through the CamelContext routes loader (camel-java-joor-dsl).
Both full RouteBuilder classes and bare DSL snippets (e.g.
from("x").to("y"))
are supported via automatic wrapping.
Closes #24029
---
dsl/camel-jbang/camel-jbang-mcp/pom.xml | 4 +
.../jbang/core/commands/mcp/TransformTools.java | 74 ++++++++-
.../core/commands/mcp/TransformToolsTest.java | 168 +++++++++++++++++++++
3 files changed, 238 insertions(+), 8 deletions(-)
diff --git a/dsl/camel-jbang/camel-jbang-mcp/pom.xml
b/dsl/camel-jbang/camel-jbang-mcp/pom.xml
index ccf1351464ca..9bab3f333f9c 100644
--- a/dsl/camel-jbang/camel-jbang-mcp/pom.xml
+++ b/dsl/camel-jbang/camel-jbang-mcp/pom.xml
@@ -111,6 +111,10 @@
<groupId>org.apache.camel</groupId>
<artifactId>camel-yaml-dsl</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-java-joor-dsl</artifactId>
+ </dependency>
<!-- Swagger/OpenAPI parser for contract-first OpenAPI tools -->
<dependency>
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformTools.java
index 8b19c5e21ceb..604f7339b7da 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformTools.java
@@ -25,6 +25,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@@ -52,6 +54,8 @@ import org.apache.camel.yaml.out.YamlModelWriter;
@ApplicationScoped
public class TransformTools {
+ private static final Pattern CLASS_NAME_PATTERN =
Pattern.compile("(?:public\\s+)?class\\s+(\\w+)");
+
@Inject
CatalogService catalogService;
@@ -158,7 +162,8 @@ public class TransformTools {
*/
@Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint
= false, openWorldHint = false),
description = "Transform a Camel route between different DSL formats
(YAML, XML). " +
- "Note: Java to YAML/XML transformation has
limitations.")
+ "Note: Java to YAML/XML transformation has
limitations."
+ + " Java DSL can only be used as source format, not as
target format.")
public TransformResult camel_transform_route(
@ToolArg(description = "Route definition to transform") String
route,
@ToolArg(description = "Source format (yaml, xml, java)") String
fromFormat,
@@ -181,13 +186,6 @@ public class TransformTools {
return result;
}
- if ("java".equals(from)) {
- result.supported = false;
- result.note = "Java DSL to " + toFormat + " transformation is not
supported. "
- + "There is no lightweight Java DSL parser
available.";
- return result;
- }
-
try {
if ("xml".equals(from) && "yaml".equals(to)) {
result.result = transformXmlToYaml(route);
@@ -195,6 +193,12 @@ public class TransformTools {
} else if ("yaml".equals(from) && "xml".equals(to)) {
result.result = transformYamlToXml(route);
result.supported = true;
+ } else if ("java".equals(from) && "yaml".equals(to)) {
+ result.result = transformJavaToFormat(route, "yaml");
+ result.supported = true;
+ } else if ("java".equals(from) && "xml".equals(to)) {
+ result.result = transformJavaToFormat(route, "xml");
+ result.supported = true;
} else {
result.supported = false;
result.note = "Unsupported transformation: " + fromFormat + "
to " + toFormat;
@@ -264,6 +268,60 @@ public class TransformTools {
}
}
+ private String transformJavaToFormat(String java, String targetFormat)
throws Exception {
+ DefaultCamelContext ctx = new DefaultCamelContext();
+ try {
+ ctx.build();
+
+ String source = wrapSnippetIfNeeded(java);
+ String className = extractClassName(source);
+ Resource resource = ResourceHelper.fromString(className + ".java",
source);
+ PluginHelper.getRoutesLoader(ctx).loadRoutes(resource);
+
+ List<RouteDefinition> routeDefs = ctx.getRouteDefinitions();
+ if (routeDefs == null || routeDefs.isEmpty()) {
+ throw new IllegalArgumentException(
+ "Could not parse Java route. Ensure it contains a
valid route definition.");
+ }
+
+ if ("yaml".equals(targetFormat)) {
+ YamlModelWriter writer = new YamlModelWriter();
+ List<JsonObject> roots = new ArrayList<>();
+ for (RouteDefinition route : routeDefs) {
+ roots.add(writer.writeRouteDefinition(route));
+ }
+ return writer.printAsYaml(roots);
+ } else {
+ RoutesDefinition rd = new RoutesDefinition();
+ rd.setRoutes(routeDefs);
+
+ StringWriter sw = new StringWriter();
+ new
org.apache.camel.xml.out.ModelWriter(sw).writeRoutesDefinition(rd);
+ return sw.toString();
+ }
+ } finally {
+ ctx.stop();
+ }
+ }
+
+ private static String wrapSnippetIfNeeded(String source) {
+ if (CLASS_NAME_PATTERN.matcher(source).find()) {
+ return source;
+ }
+ return "import org.apache.camel.builder.RouteBuilder;\n\n"
+ + "public class SnippetRoute extends RouteBuilder {\n"
+ + " @Override\n"
+ + " public void configure() {\n"
+ + " " + source + "\n"
+ + " }\n"
+ + "}\n";
+ }
+
+ private static String extractClassName(String source) {
+ Matcher m = CLASS_NAME_PATTERN.matcher(source);
+ return m.find() ? m.group(1) : "Route";
+ }
+
/**
* Tool to validate a YAML DSL route definition against the Camel YAML DSL
JSON schema.
*/
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformToolsTest.java
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformToolsTest.java
new file mode 100644
index 000000000000..3d7644f97fd3
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/TransformToolsTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.dsl.jbang.core.commands.mcp;
+
+import java.util.Optional;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class TransformToolsTest {
+
+ private TransformTools createTools() {
+ CatalogService catalogService = new CatalogService();
+ catalogService.catalogRepos = Optional.empty();
+
+ TransformTools tools = new TransformTools();
+ tools.catalogService = catalogService;
+ return tools;
+ }
+
+ @Test
+ void transformXmlToYaml() {
+ TransformTools tools = createTools();
+ String xml = """
+ <routes xmlns="http://camel.apache.org/schema/spring">
+ <route>
+ <from uri="timer:hello"/>
+ <log message="Hello World"/>
+ </route>
+ </routes>
+ """;
+
+ TransformTools.TransformResult result =
tools.camel_transform_route(xml, "xml", "yaml");
+
+ assertThat(result.supported).isTrue();
+ assertThat(result.result).contains("timer");
+ assertThat(result.result).contains("log");
+ }
+
+ @Test
+ void transformYamlToXml() {
+ TransformTools tools = createTools();
+ String yaml = """
+ - route:
+ from:
+ uri: timer:hello
+ steps:
+ - log:
+ message: Hello World
+ """;
+
+ TransformTools.TransformResult result =
tools.camel_transform_route(yaml, "yaml", "xml");
+
+ assertThat(result.supported).isTrue();
+ assertThat(result.result).contains("timer:hello");
+ assertThat(result.result).contains("<log");
+ }
+
+ @Test
+ void transformJavaToYaml() {
+ TransformTools tools = createTools();
+ String java = """
+ import org.apache.camel.builder.RouteBuilder;
+
+ public class MyRoute extends RouteBuilder {
+ @Override
+ public void configure() {
+ from("timer:hello")
+ .log("Hello World");
+ }
+ }
+ """;
+
+ TransformTools.TransformResult result =
tools.camel_transform_route(java, "java", "yaml");
+
+ assertThat(result.supported).isTrue();
+ assertThat(result.result).contains("timer");
+ assertThat(result.result).contains("log");
+ }
+
+ @Test
+ void transformJavaToXml() {
+ TransformTools tools = createTools();
+ String java = """
+ import org.apache.camel.builder.RouteBuilder;
+
+ public class MyRoute extends RouteBuilder {
+ @Override
+ public void configure() {
+ from("timer:hello")
+ .log("Hello World");
+ }
+ }
+ """;
+
+ TransformTools.TransformResult result =
tools.camel_transform_route(java, "java", "xml");
+
+ assertThat(result.supported).isTrue();
+ assertThat(result.result).contains("timer:hello");
+ assertThat(result.result).contains("<log");
+ }
+
+ @Test
+ void transformJavaSnippetToYaml() {
+ TransformTools tools = createTools();
+ String snippet = """
+ from("timer:hello")
+ .log("Hello World");
+ """;
+
+ TransformTools.TransformResult result =
tools.camel_transform_route(snippet, "java", "yaml");
+
+ assertThat(result.supported).isTrue();
+ assertThat(result.result).contains("timer");
+ assertThat(result.result).contains("log");
+ }
+
+ @Test
+ void transformJavaSnippetToXml() {
+ TransformTools tools = createTools();
+ String snippet = """
+ from("timer:hello")
+ .to("log:foo");
+ """;
+
+ TransformTools.TransformResult result =
tools.camel_transform_route(snippet, "java", "xml");
+
+ assertThat(result.supported).isTrue();
+ assertThat(result.result).contains("timer:hello");
+ assertThat(result.result).contains("log:foo");
+ }
+
+ @Test
+ void sameFormatReturnsInput() {
+ TransformTools tools = createTools();
+ String yaml = "- route:\n from:\n uri: timer:hello\n";
+
+ TransformTools.TransformResult result =
tools.camel_transform_route(yaml, "yaml", "yaml");
+
+ assertThat(result.supported).isTrue();
+ assertThat(result.result).isEqualTo(yaml);
+ }
+
+ @Test
+ void unsupportedFormatReturnsNotSupported() {
+ TransformTools tools = createTools();
+
+ TransformTools.TransformResult result =
tools.camel_transform_route("some route", "groovy", "yaml");
+
+ assertThat(result.supported).isFalse();
+ assertThat(result.note).contains("Unsupported");
+ }
+}