This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch fix/CAMEL-25258
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 6c585814420fc4c136fa449863f7447f235da57c
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Oct 2 09:42:54 2026 +0200

    CAMEL-25258: camel-jbang-mcp - camel_transform_route converts with the 
route DSL converter
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |  10 +
 .../modules/ROOT/pages/camel-jbang-mcp.adoc        |   5 +-
 .../dsl/jbang/core/commands/RouteDslConverter.java |  13 +-
 .../jbang/core/commands/RouteDslConverterTest.java |   5 +-
 dsl/camel-jbang/camel-jbang-mcp/pom.xml            |   9 -
 .../jbang/core/commands/mcp/TransformTools.java    | 214 ++++-----------------
 .../core/commands/mcp/TransformToolsTest.java      |  77 ++++++--
 7 files changed, 124 insertions(+), 209 deletions(-)

diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index c15293a15c68..fb0711352596 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -4213,3 +4213,13 @@ as Java, the error handler of an XML or YAML route is 
now `.errorHandler(...)` o
 
 The `timeout(long)` of the Resequencer EIP in Java keeps the millis as given 
(`2000`), instead of a duration
 (`2s0ms`).
+
+=== camel-jbang-mcp - camel_transform_route
+
+The `camel_transform_route` tool now converts with the same route DSL 
converter as `camel transform route
+--format=java`. It reads the routes without running them, so a Java route is 
no longer compiled. Instead it is read
+by the Java DSL parser, and a route the parser cannot read (such as a 
processor lambda) is refused with the reason.
+Property placeholders are kept as written instead of being resolved.
+
+In return, Java is also a target format, and rests, route templates, route 
configurations and beans are converted
+instead of only routes. A new `notes` field of the result lists what differs 
or is not carried over.
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc
index e4f19d052b4c..e95cae788727 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc
@@ -574,7 +574,10 @@ The advisories are also browseable as MCP resources: 
`camel://security/advisorie
 | Tool | Description
 
 | `camel_transform_route`
-| Assists with route DSL format transformation between YAML and XML.
+| Converts routes between the YAML, XML and Java DSLs, as `camel transform 
route` does, without running them:
+  routes, rests, route templates, route configurations and beans. The result 
is read back and compared with the
+  source, and what differs or is not carried over is returned in `notes`. A 
route that cannot be converted without
+  running it (such as a processor lambda) is refused with the reason.
 
 | `camel_configuration_validate`
 | Validate Camel configuration property lines (e.g., from 
`application.properties`). Detects misspelled option
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RouteDslConverter.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RouteDslConverter.java
index b5fa941e030a..e10491a9a2e9 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RouteDslConverter.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RouteDslConverter.java
@@ -351,6 +351,9 @@ public final class RouteDslConverter {
             DefaultCamelContext context, String fileName, String content, 
Map<String, Supplier<String>> javaSources,
             Resource resource, List<String> notes)
             throws Exception {
+        if (JAVA_SEMANTIC.matcher(content).find()) {
+            return SEMANTIC_REFUSED;
+        }
         CamelCatalog catalog = new DefaultCamelCatalog();
         JavaParseResult r = ProjectRoutes.parseJava(content, javaSources, 
catalog);
         for (JavaParseResult.Unresolved u : r.unresolved()) {
@@ -430,12 +433,16 @@ public final class RouteDslConverter {
     }
 
     private static final Pattern YAML_SEMANTIC = 
Pattern.compile("(?m)^-\\s+semantic\\s*:");
+    private static final Pattern JAVA_SEMANTIC = 
Pattern.compile("\\bsemanticQuestions\\s*\\(");
+
+    // they live outside the route model the writers export: converting would 
lose them without a word
+    private static final String SEMANTIC_REFUSED
+            = "semantic declarations cannot be converted with the routes: keep 
them in a separate declaration resource"
+              + " and convert only the routes";
 
     private static String loadYaml(DefaultCamelContext context, String 
content, Resource resource) throws Exception {
         if (YAML_SEMANTIC.matcher(content).find()) {
-            // they live outside the route model the writers export: 
converting would lose them without a word
-            return "semantic declarations cannot be converted with the routes: 
keep them in a separate declaration"
-                   + " resource and convert only the routes";
+            return SEMANTIC_REFUSED;
         }
         // the beans are taken out and read as definitions: the YAML DSL would 
create them, running code of the project
         StringBuilder routes = new StringBuilder();
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RouteDslConverterTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RouteDslConverterTest.java
index c23a8877ba8c..bc952e5cd541 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RouteDslConverterTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RouteDslConverterTest.java
@@ -172,9 +172,8 @@ class RouteDslConverterTest {
                     }
                 }
                 """;
-        // the parser cannot read the declaration: refused at its line, not 
dropped
-        assertThat(convert("SemanticRoute.java", java, 
"yaml").refused()).contains("SemanticRoute.java:5",
-                "cannot be converted without running it");
+        // refused for the same reason as in YAML, not dropped
+        assertThat(convert("SemanticRoute.java", java, 
"yaml").refused()).contains("semantic declarations");
     }
 
     @Test
diff --git a/dsl/camel-jbang/camel-jbang-mcp/pom.xml 
b/dsl/camel-jbang/camel-jbang-mcp/pom.xml
index 40786dbc0ab9..602d5c4dd3ce 100644
--- a/dsl/camel-jbang/camel-jbang-mcp/pom.xml
+++ b/dsl/camel-jbang/camel-jbang-mcp/pom.xml
@@ -111,10 +111,6 @@
             <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>
@@ -147,11 +143,6 @@
         </dependency>
 
         <!-- test dependencies -->
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-semantic</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-xml-io-dsl</artifactId>
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 d068f2403245..e7c64364d8e8 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
@@ -16,11 +16,9 @@
  */
 package org.apache.camel.dsl.jbang.core.commands.mcp;
 
-import java.io.ByteArrayInputStream;
-import java.io.StringWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -29,22 +27,11 @@ import jakarta.enterprise.context.ApplicationScoped;
 import io.quarkiverse.mcp.server.Tool;
 import io.quarkiverse.mcp.server.ToolArg;
 import io.quarkiverse.mcp.server.ToolCallException;
-import org.apache.camel.impl.DefaultCamelContext;
-import org.apache.camel.model.ExpressionNode;
-import org.apache.camel.model.ProcessorDefinitionHelper;
-import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.model.RoutesDefinition;
-import org.apache.camel.spi.Resource;
-import org.apache.camel.support.PluginHelper;
-import org.apache.camel.support.ResourceHelper;
-import org.apache.camel.util.ObjectHelper;
-import org.apache.camel.util.json.JsonObject;
-import org.apache.camel.xml.in.ModelParser;
-import org.apache.camel.yaml.out.YamlModelWriter;
+import org.apache.camel.dsl.jbang.core.commands.RouteDslConverter;
 
 /**
- * MCP tool transforming Camel routes between DSL formats using Quarkus MCP 
Server. Validation is the shared
- * {@code camel_validate_source} tool.
+ * MCP tool transforming Camel routes between DSL formats with the route DSL 
converter of camel-jbang, which reads the
+ * routes without running them. Validation is the shared {@code 
camel_validate_source} tool.
  */
 @McpSecured
 @ApplicationScoped
@@ -56,13 +43,16 @@ public class TransformTools {
      * Tool to transform routes between DSL formats.
      */
     @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."
-                        + " Java DSL can only be used as source format, not as 
target format.")
+          description = "Transform Camel routes between the YAML, XML and Java 
DSLs, without running them."
+                        + " Routes, rests, route templates, route 
configurations and beans are converted."
+                        + " The result is read back and compared with the 
source: what differs, or is not carried"
+                        + " over (such as comments, or the beans when the 
target is Java), is listed in notes."
+                        + " What cannot be converted without running it (a 
processor lambda) is refused with the reason.")
     public TransformResult camel_transform_route(
-            @ToolArg(description = "Route definition to transform") String 
route,
+            @ToolArg(description = "Route definition to transform: a YAML or 
XML routes file, a Java RouteBuilder class,"
+                                   + " or Java route statements such as 
from(\"timer:tick\").to(\"log:out\");") String route,
             @ToolArg(description = "Source format (yaml, xml, java)") String 
fromFormat,
-            @ToolArg(description = "Target format (yaml, xml)") String 
toFormat) {
+            @ToolArg(description = "Target format (yaml, xml, java)") String 
toFormat) {
 
         if (route == null || fromFormat == null || toFormat == null) {
             throw new ToolCallException("route, fromFormat, and toFormat are 
required", null);
@@ -72,175 +62,40 @@ public class TransformTools {
         result.fromFormat = fromFormat;
         result.toFormat = toFormat;
 
-        String from = fromFormat.toLowerCase();
-        String to = toFormat.toLowerCase();
+        String from = fromFormat.toLowerCase(Locale.ROOT);
+        String to = toFormat.toLowerCase(Locale.ROOT);
 
         if (from.equals(to)) {
             result.supported = true;
             result.result = route;
             return result;
         }
-
-        try {
-            if ("xml".equals(from) && "yaml".equals(to)) {
-                result.result = transformXmlToYaml(route);
-                result.supported = true;
-            } 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;
-            }
-        } catch (Throwable e) {
-            Throwable cause = ObjectHelper.createExceptionIterator(e).next();
-            String message = e.getMessage();
-            if (cause != e) {
-                message += ": " + cause.getMessage();
-            }
-            throw new ToolCallException(
-                    "Failed to transform route (" + e.getClass().getName() + 
"): " + message, null);
-        }
-
-        return result;
-    }
-
-    /**
-     * Transform an XML route definition to YAML format.
-     */
-    private String transformXmlToYaml(String xml) throws Exception {
-        // Try Spring namespace first (most common), then fall back to no 
namespace
-        RoutesDefinition routes = null;
-        try (ByteArrayInputStream is = new 
ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
-            routes = new ModelParser(is, 
"http://camel.apache.org/schema/spring";)
-                    .parseRoutesDefinition().orElse(null);
-        }
-        if (routes == null) {
-            try (ByteArrayInputStream is = new 
ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
-                routes = new ModelParser(is)
-                        .parseRoutesDefinition().orElse(null);
-            }
-        }
-        if (routes == null) {
-            throw new IllegalArgumentException(
-                    "Could not parse XML route. Ensure it contains a valid 
<routes> or <route> element.");
-        }
-
-        YamlModelWriter writer = new YamlModelWriter();
-        List<JsonObject> roots = new ArrayList<>();
-        for (RouteDefinition route : routes.getRoutes()) {
-            roots.add(writer.writeRouteDefinition(route));
-        }
-        return writer.printAsYaml(roots);
-    }
-
-    /**
-     * Transform a YAML route definition to XML format.
-     */
-    private String transformYamlToXml(String yaml) throws Exception {
-        DefaultCamelContext ctx = new DefaultCamelContext();
-        try {
-            ctx.build();
-
-            Resource resource = ResourceHelper.fromString("route.yaml", yaml);
-            PluginHelper.getRoutesLoader(ctx).loadRoutes(resource);
-
-            List<RouteDefinition> routeDefs = ctx.getRouteDefinitions();
-            if (routeDefs == null || routeDefs.isEmpty()) {
-                throw new IllegalArgumentException(
-                        "Could not parse YAML route. Ensure it contains a 
valid route definition.");
-            }
-
-            RoutesDefinition rd = new RoutesDefinition();
-            rd.setRoutes(routeDefs);
-            requireSeparateDeclarations(ctx);
-
-            StringWriter sw = new StringWriter();
-            new 
org.apache.camel.xml.out.ModelWriter(sw).writeRoutesDefinition(rd);
-            return sw.toString();
-        } finally {
-            ctx.stop();
+        if (!RouteDslConverter.FORMATS.contains(from) || 
!RouteDslConverter.FORMATS.contains(to)) {
+            result.supported = false;
+            result.note = "Unsupported transformation: " + fromFormat + " to " 
+ toFormat;
+            return result;
         }
-    }
 
-    private static void requireSeparateDeclarations(DefaultCamelContext 
context) throws ReflectiveOperationException {
-        // Semantic declarations are optional and live outside the model 
exported by this converter.
-        Class<?> type = 
context.getClassResolver().resolveClass("org.apache.camel.semantic.SemanticQuestions");
-        if (type == null) {
-            return;
+        RouteDslConverter.Result r = RouteDslConverter.convert(fileName(route, 
from), route, to, Map.of());
+        if (!r.converted()) {
+            throw new ToolCallException("Cannot transform route: " + 
r.refused(), null);
         }
-        Object questions = 
context.getCamelContextExtension().getContextPlugin(type);
-        if (questions != null && !(boolean) 
type.getMethod("isEmpty").invoke(questions)) {
-            throw new IllegalArgumentException(
-                    "Semantic declarations cannot be exported by the generic 
route converter. "
-                                               + "Keep them in a separate 
declaration resource and convert only the routes.");
-        }
-    }
-
-    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.");
-            }
-
-            // Java expression clauses are normally materialized when 
processors are created.
-            routeDefs.forEach(route -> 
ProcessorDefinitionHelper.filterTypeInOutputs(route.getOutputs(), 
ExpressionNode.class)
-                    .forEach(ExpressionNode::preCreateProcessor));
-
-            if ("yaml".equals(targetFormat)) {
-                YamlModelWriter writer = new YamlModelWriter();
-                List<JsonObject> roots = new ArrayList<>();
-                requireSeparateDeclarations(ctx);
-                for (RouteDefinition route : routeDefs) {
-                    roots.add(writer.writeRouteDefinition(route));
-                }
-                return writer.printAsYaml(roots);
-            } else {
-                RoutesDefinition rd = new RoutesDefinition();
-                rd.setRoutes(routeDefs);
-                requireSeparateDeclarations(ctx);
-
-                StringWriter sw = new StringWriter();
-                new 
org.apache.camel.xml.out.ModelWriter(sw).writeRoutesDefinition(rd);
-                return sw.toString();
-            }
-        } finally {
-            ctx.stop();
+        result.supported = true;
+        result.result = r.content();
+        result.notes = r.notes();
+        if (!r.notes().isEmpty()) {
+            result.note = String.join("; ", r.notes());
         }
+        return result;
     }
 
-    private static String wrapSnippetIfNeeded(String source) {
-        if (CLASS_NAME_PATTERN.matcher(source).find()) {
-            return source;
+    /** A file name for the route as the converter tells the DSLs apart: Java 
by its class. */
+    private static String fileName(String route, String format) {
+        if ("java".equals(format)) {
+            Matcher m = CLASS_NAME_PATTERN.matcher(route);
+            return (m.find() ? m.group(1) : "Route") + ".java";
         }
-        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";
+        return "route.camel." + format;
     }
 
     // Result class for Jackson serialization
@@ -249,6 +104,7 @@ public class TransformTools {
         public String fromFormat;
         public String toFormat;
         public String note;
+        public List<String> notes = List.of();
         public boolean supported;
         public String result;
     }
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
index a5dc8ed53fb3..fcee87765f55 100644
--- 
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
@@ -66,12 +66,12 @@ class TransformToolsTest {
     @CsvSource({ "yaml,xml", "java,xml", "java,yaml" })
     void genericConversionDoesNotSilentlyLoseSemanticDeclarations(String 
source, String target) {
         assertThatThrownBy(() -> 
createTools().camel_transform_route(semanticRoute(source, "0.8"), source, 
target))
-                
.isInstanceOf(ToolCallException.class).hasMessageContaining("Keep them in a 
separate declaration resource");
+                
.isInstanceOf(ToolCallException.class).hasMessageContaining("keep them in a 
separate declaration resource");
     }
 
     @ParameterizedTest
     @ValueSource(strings = { "xml", "yaml" })
-    void emptySemanticRegistryDoesNotPreventConversion(String target) {
+    void anEmptySemanticDeclarationIsRefusedToo(String target) {
         String route = """
                 import org.apache.camel.builder.RouteBuilder;
                 import static 
org.apache.camel.semantic.SemanticQuestionsBuilder.semanticQuestions;
@@ -82,20 +82,23 @@ class TransformToolsTest {
                     }
                 }
                 """;
-        var result = createTools().camel_transform_route(route, "java", 
target);
-
-        assertThat(result.supported).isTrue();
-        
assertThat(result.result).contains("direct:input").doesNotContain("semantic");
+        // read without running it, so whether it declares anything is not 
known: refused, not dropped
+        assertThatThrownBy(() -> createTools().camel_transform_route(route, 
"java", target))
+                
.isInstanceOf(ToolCallException.class).hasMessageContaining("semantic 
declarations");
     }
 
-    @ParameterizedTest
-    @CsvSource({ "yaml,xml", "java,xml", "java,yaml" })
-    void semanticConversionReportsMissingNumericProperty(String source, String 
target) {
-        String route = semanticRoute(source, 
"{{semantic.export.missing.threshold}}");
-
-        assertThatThrownBy(() -> createTools().camel_transform_route(route, 
source, target))
-                .isInstanceOf(ToolCallException.class)
-                .hasMessageContaining("Property with key 
[semantic.export.missing.threshold] not found");
+    @Test
+    void placeholdersAreNotResolved() {
+        // the routes are read, not run: a property that is not there is no 
error, the placeholder is kept
+        var result = createTools().camel_transform_route("""
+                - route:
+                    from:
+                      uri: "timer:{{my.timer.name}}"
+                      steps:
+                        - log: "{{my.message}}"
+                """, "yaml", "xml");
+        assertThat(result.supported).isTrue();
+        assertThat(result.result).contains("timer:{{my.timer.name}}", 
"{{my.message}}");
     }
 
     private static String semanticRoute(String source, String threshold) {
@@ -251,6 +254,52 @@ class TransformToolsTest {
         assertThat(result.result).contains("log:foo");
     }
 
+    @Test
+    void transformXmlToJava() {
+        String xml = """
+                <routes xmlns="http://camel.apache.org/schema/xml-io";>
+                    <!-- greetings -->
+                    <route id="hello">
+                        <from uri="timer:tick"/>
+                        <log message="Hello ${body}" loggingLevel="WARN"/>
+                    </route>
+                </routes>
+                """;
+        TransformTools.TransformResult result = 
createTools().camel_transform_route(xml, "xml", "java");
+        assertThat(result.supported).isTrue();
+        assertThat(result.result).contains("public class Route extends 
RouteBuilder", "from(\"timer:tick\")",
+                ".routeId(\"hello\")", ".log(LoggingLevel.WARN, \"Hello 
${body}\")");
+        // what is not carried over is said
+        assertThat(result.notes).anyMatch(n -> n.contains("comments"));
+        assertThat(result.note).contains("comments");
+    }
+
+    @Test
+    void restsAreCarriedOver() {
+        String xml = """
+                <rests xmlns="http://camel.apache.org/schema/xml-io";>
+                    <rest path="/api">
+                        <get path="/orders">
+                            <to uri="direct:orders"/>
+                        </get>
+                    </rest>
+                </rests>
+                """;
+        TransformTools.TransformResult result = 
createTools().camel_transform_route(xml, "xml", "yaml");
+        assertThat(result.supported).isTrue();
+        assertThat(result.result).contains("- rest:", "path: /api", "get:", 
"path: /orders", "direct:orders");
+        assertThat(result.notes).isEmpty();
+    }
+
+    @Test
+    void whatOnlyRunsIsRefusedWithTheReason() {
+        String java = """
+                from("timer:tick").process(e -> 
e.getIn().setBody("x")).to("log:out");
+                """;
+        assertThatThrownBy(() -> createTools().camel_transform_route(java, 
"java", "yaml"))
+                
.isInstanceOf(ToolCallException.class).hasMessageContaining("cannot be 
converted without running it");
+    }
+
     @Test
     void sameFormatReturnsInput() {
         TransformTools tools = createTools();

Reply via email to