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 cf1b5e60592b CAMEL-25202: camel-jbang - camel transform route reads
Java routes without compiling them (#27150)
cf1b5e60592b is described below
commit cf1b5e60592bd6864c7ab5c878619882903c9494
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Oct 1 09:14:55 2026 +0200
CAMEL-25202: camel-jbang - camel transform route reads Java routes without
compiling them (#27150)
When all files are Java and every route can be read completely, the Java DSL
parser reads them into the model and the dump strategy of a running Camel
writes them, in a CamelContext that is never started: the same YAML or XML
as
compiling them, in milliseconds instead of seconds, and no code of the
project
runs. A route with a lambda or a value known only at runtime, or
--resolve-placeholders, compiles them as before; --compile forces it.
camel-jbang-core depends on camel-yaml-io for the YAML writer.
CAMEL-25202: the Java DSL parser design says camel transform route uses it
…es it
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
design/java-dsl-parser.adoc | 7 +-
.../ROOT/pages/camel-jbang-transforming.adoc | 17 +++
.../camel-jbang-transform-route.adoc | 1 +
dsl/camel-jbang/camel-jbang-core/pom.xml | 5 +
.../META-INF/camel-jbang-commands-metadata.json | 2 +-
.../jbang/core/commands/TransformJavaRoutes.java | 140 +++++++++++++++++
.../dsl/jbang/core/commands/TransformRoute.java | 25 +++-
.../core/commands/TransformJavaRoutesTest.java | 165 +++++++++++++++++++++
8 files changed, 356 insertions(+), 6 deletions(-)
diff --git a/design/java-dsl-parser.adoc b/design/java-dsl-parser.adoc
index 1a9c187194b9..80ee524bbfd2 100644
--- a/design/java-dsl-parser.adoc
+++ b/design/java-dsl-parser.adoc
@@ -102,6 +102,12 @@ camel-jbang reads Java routes with the parser only; the
pattern matching on stri
consume, with constants, formats and the endpoint DSL resolved;
* the jump links between routes in the TUI Source tab.
+=== Transforming Java routes
+
+`camel transform route` reads Java routes with the parser by default and
writes them with the dump strategy of a
+running Camel, in a CamelContext that is never started (CAMEL-25202); it
compiles the routes only when one cannot be
+read completely, or with `--compile`.
+
== Security
The parser reads sources nobody vetted: a cloned example opened in the TUI,
documentation, a project an AI agent
@@ -145,7 +151,6 @@ points a tool at. What it guarantees, and how each is
enforced:
== Future Work
* Checking the Java examples of the documentation in the build, as the YAML
and XML ones are.
-* `camel transform` reading Java without compiling by default, compiling when
a route is partial.
* Plain-language labels for the decision points of routes in the AI project
overview (CAMEL-25161).
* A Java DSL for Camel 5 designed with what the parser found hard (end()
scoping, expression clauses, a class or its
name for the same option, varargs options), with this replay as the bridge
from the current Java DSL: the findings
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-transforming.adoc
b/docs/user-manual/modules/ROOT/pages/camel-jbang-transforming.adoc
index fc46c1663b84..c136c90d73d8 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-transforming.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-transforming.adoc
@@ -495,3 +495,20 @@ Output:
----
TIP: When all input files share the same extension (e.g., `.yaml`), the target
format defaults to the other DSL (XML) and vice versa.
+
+=== Transforming Java routes
+
+Java DSL routes are transformed to YAML or XML the same way:
+
+[source,bash]
+----
+camel transform route --format=yaml src/main/java/com/acme/OrderRoute.java
+----
+
+The Java sources are read without compiling or running them: the routes are
read into the model by the Java DSL
+parser, with the constants of the other classes in the same folder,
`String.format` and the Endpoint DSL resolved, and
+written as a running Camel would dump them. This takes a fraction of a second,
and no code of the project runs.
+
+When a route cannot be read completely that way, for example a processor
written as a lambda or a value only known
+at runtime, the routes are compiled and started to dump them, which takes a
few seconds and may download dependencies.
+The same happens with `--resolve-placeholders`. Use `--compile` to always
compile and start the routes.
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-transform-route.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-transform-route.adoc
index 4db629cee52f..ff61e758b31c 100644
---
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-transform-route.adoc
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-transform-route.adoc
@@ -19,6 +19,7 @@ camel transform route [options]
[cols="2,5,1,2",options="header"]
|===
| Option | Description | Default | Type
+| `--compile` | Compile and run Java routes to transform them. By default Java
routes are read without compiling them, and compiled only when a route cannot
be read that way | false | boolean
| `--download` | Whether to allow automatic downloading JAR dependencies (over
the internet) | true | boolean
| `--format` | Output format (xml, yaml), if only yaml files are provided, the
format defaults to xml and vice versa | | String
| `--fresh` | Make sure we use fresh (i.e. non-cached) resources | false |
boolean
diff --git a/dsl/camel-jbang/camel-jbang-core/pom.xml
b/dsl/camel-jbang/camel-jbang-core/pom.xml
index a0156fec1c5c..29fc9e7c400f 100644
--- a/dsl/camel-jbang/camel-jbang-core/pom.xml
+++ b/dsl/camel-jbang/camel-jbang-core/pom.xml
@@ -74,6 +74,11 @@
<groupId>org.apache.camel</groupId>
<artifactId>camel-java-io</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <!-- camel transform route writes YAML from Java routes read
without compiling them -->
+ <artifactId>camel-yaml-io</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-xml-io-util</artifactId>
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
index d17551956db8..3fe53a77e6ec 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
+++
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
@@ -34,7 +34,7 @@
{ "name": "stop", "fullName": "stop", "description": "Shuts down running
Camel integrations", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.process.StopProcess", "options": [ {
"names": "--kill", "description": "To force killing the process (SIGKILL)",
"javaType": "boolean", "type": "boolean" }, { "names": "-h,--help",
"description": "Display the help and sub-commands", "javaType": "boolean",
"type": "boolean" } ] },
{ "name": "top", "fullName": "top", "description": "Top status of Camel
integrations", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.process.CamelTop", "options": [ {
"names": "--watch", "description": "Execute periodically and showing output
fullscreen", "javaType": "boolean", "type": "boolean" }, { "names":
"-h,--help", "description": "Display the help and sub-commands", "javaType":
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "context",
"fullName": "top [...]
{ "name": "trace", "fullName": "trace", "description": "Tail message
traces from running Camel integrations", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.action.CamelTraceAction", "options":
[ { "names": "--action", "description": "Action to start, stop, clear, list
status, or dump traces", "defaultValue": "status", "javaType":
"java.lang.String", "type": "string" }, { "names": "--ago", "description": "Use
ago instead of yyyy-MM-dd HH:mm:ss in timestamp.", "javaType": "b [...]
- { "name": "transform", "fullName": "transform", "description": "Transform
message or Camel routes", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.TransformCommand", "options": [ {
"names": "-h,--help", "description": "Display the help and sub-commands",
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name":
"dataweave", "fullName": "transform dataweave", "description": "Convert
DataWeave scripts to DataSonnet format", "sourceClass": "org.apache.camel.dsl.
[...]
+ { "name": "transform", "fullName": "transform", "description": "Transform
message or Camel routes", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.TransformCommand", "options": [ {
"names": "-h,--help", "description": "Display the help and sub-commands",
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name":
"dataweave", "fullName": "transform dataweave", "description": "Convert
DataWeave scripts to DataSonnet format", "sourceClass": "org.apache.camel.dsl.
[...]
{ "name": "update", "fullName": "update", "description": "Update Camel
project", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.update.UpdateCommand", "options": [ {
"names": "-h,--help", "description": "Display the help and sub-commands",
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name":
"list", "fullName": "update list", "description": "List available update
versions for Camel and its runtime variants", "sourceClass":
"org.apache.camel.dsl.jbang.cor [...]
{ "name": "version", "fullName": "version", "description": "Manage Camel
versions", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.version.VersionCommand", "options": [
{ "names": "-h,--help", "description": "Display the help and sub-commands",
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "get",
"fullName": "version get", "description": "Displays current Camel version",
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.version.VersionGet",
[...]
{ "name": "wrapper", "fullName": "wrapper", "description": "Install Camel
wrapper scripts for version pinning", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.WrapperCommand", "options": [ {
"names": "--camel-version", "description": "Camel version to pin (defaults to
current version)", "javaType": "java.lang.String", "type": "string" }, {
"names": "--command-name", "description": "The name of the command to use
(camel or camelw)", "defaultValue": "camel", "javaType": "java [...]
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformJavaRoutes.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformJavaRoutes.java
new file mode 100644
index 000000000000..1172cf28159d
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformJavaRoutes.java
@@ -0,0 +1,140 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.dsl.jbang.core.commands.ai.ProjectRoutes;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultDumpRoutesStrategy;
+import org.apache.camel.java.in.JavaParseResult;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.support.ResourceHelper;
+
+/**
+ * {@code camel transform route} for Java routes without compiling them
(CAMEL-25202): the sources are read into the
+ * model by the Java DSL parser of camel-java-io, and dumped as YAML or XML by
the same dump strategy a running Camel
+ * uses ({@code camel.main.dumpRoutes}), in a CamelContext that is never
started. Nothing of the project is compiled,
+ * loaded or run.
+ */
+final class TransformJavaRoutes {
+
+ /** Whether the routes were transformed, and why not: the first part the
parser could not read. */
+ record Result(boolean transformed, String reason) {
+ }
+
+ private TransformJavaRoutes() {
+ }
+
+ /** Whether the files are all Java sources, which the parser may read. */
+ static boolean applies(List<String> files) {
+ return !files.isEmpty()
+ && files.stream().allMatch(f -> f.endsWith(".java") &&
Files.isRegularFile(Path.of(f)));
+ }
+
+ /**
+ * Transforms the Java routes of the files when every route can be read
completely.
+ *
+ * @param format yaml or xml
+ * @param output the file or directory to write to
+ * @param uriAsParameters whether to expand URIs into key/value
parameters (YAML)
+ * @return whether they were transformed; else why not,
and nothing is written
+ */
+ static Result transform(List<String> files, String format, String output,
boolean uriAsParameters)
+ throws Exception {
+ CamelCatalog catalog = new DefaultCamelCatalog();
+ Map<String, Supplier<String>> sources = javaSources(files);
+ List<JavaParseResult> results = new ArrayList<>();
+ List<Resource> resources = new ArrayList<>();
+ for (String f : files) {
+ String content = Files.readString(Path.of(f),
StandardCharsets.UTF_8);
+ JavaParseResult result = ProjectRoutes.parseJava(content, sources,
catalog);
+ for (JavaParseResult.Unresolved u : result.unresolved()) {
+ if (!JavaParseResult.configuresTheContext(u)) {
+ return new Result(false, f + ":" + u.line() + " " +
u.text() + " (" + u.reason() + ")");
+ }
+ }
+ if (result.routes().getRoutes().isEmpty() &&
result.rests().getRests().isEmpty()
+ && result.routeTemplates().getRouteTemplates().isEmpty()
+ &&
result.routeConfigurations().getRouteConfigurations().isEmpty()) {
+ return new Result(false, f + " has no routes the parser can
read");
+ }
+ results.add(result);
+ // the source file, so each is dumped on its own and named after
it, as when the routes run
+ resources.add(ResourceHelper.fromString("file:" +
Path.of(f).getFileName(), content));
+ }
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ // never started: adding the definitions only registers them
+ for (int i = 0; i < results.size(); i++) {
+ JavaParseResult r = results.get(i);
+ Resource resource = resources.get(i);
+ r.routes().getRoutes().forEach(d -> d.setResource(resource));
+ r.rests().getRests().forEach(d -> d.setResource(resource));
+ r.routeTemplates().getRouteTemplates().forEach(d ->
d.setResource(resource));
+ r.routeConfigurations().getRouteConfigurations().forEach(d ->
d.setResource(resource));
+
context.addRouteConfigurations(r.routeConfigurations().getRouteConfigurations());
+ context.addRestDefinitions(r.rests().getRests(), false);
+
context.addRouteTemplateDefinitions(r.routeTemplates().getRouteTemplates());
+ context.addRouteDefinitions(r.routes().getRoutes());
+ }
+ DefaultDumpRoutesStrategy dumper = new DefaultDumpRoutesStrategy();
+ dumper.setCamelContext(context);
+
dumper.setInclude("routes,rests,routeConfigurations,beans,dataFormats");
+ dumper.setLog(false);
+ dumper.setResolvePlaceholders(false);
+ dumper.setUriAsParameters(uriAsParameters);
+ dumper.setOutput(output);
+ dumper.dumpRoutes(format);
+ }
+ return new Result(true, null);
+ }
+
+ /** The Java sources of the files' folders, for the constants a route
takes from another class. */
+ private static Map<String, Supplier<String>> javaSources(List<String>
files) throws IOException {
+ Map<String, Supplier<String>> answer = new LinkedHashMap<>();
+ for (String f : files) {
+ Path dir = Path.of(f).toAbsolutePath().getParent();
+ if (dir == null) {
+ continue;
+ }
+ try (Stream<Path> list = Files.list(dir)) {
+ list.filter(p -> p.getFileName().toString().endsWith(".java"))
+ .forEach(p -> answer.putIfAbsent(p.toString(), () ->
read(p)));
+ }
+ }
+ return answer;
+ }
+
+ private static String read(Path p) {
+ try {
+ return Files.readString(p, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
index 7a74d4924b3e..020f4d745822 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
@@ -82,6 +82,11 @@ public class TransformRoute extends CamelCommand {
description = "Whether to ignore route loading and
compilation errors (use this with care!)")
boolean ignoreLoadingError;
+ @CommandLine.Option(names = { "--compile" }, defaultValue = "false",
+ description = "Compile and run Java routes to
transform them. By default Java routes are read "
+ + "without compiling them, and compiled
only when a route cannot be read that way")
+ boolean compile;
+
@CommandLine.Mixin
MavenResolverMixin mavenResolver;
@@ -108,6 +113,15 @@ public class TransformRoute extends CamelCommand {
Files.deleteIfExists(Path.of(dump));
final String target = dump;
+ if (!compile && !resolvePlaceholders &&
TransformJavaRoutes.applies(files)) {
+ // Java routes read without compiling them: in milliseconds, and
no code of the project runs
+ TransformJavaRoutes.Result result =
TransformJavaRoutes.transform(files, format, target, uriAsParameters);
+ if (result.transformed()) {
+ return printDump(target);
+ }
+ // a route the parser cannot read completely (a lambda, a value
known only at runtime): compile them all
+ }
+
Run run = new Run(getMain()) {
@Override
protected void doAddInitialProperty(KameletMain main) {
@@ -135,9 +149,13 @@ public class TransformRoute extends CamelCommand {
return exit;
}
+ return printDump(target);
+ }
+
+ private Integer printDump(String target) {
if (output == null || "clipboard".equals(output)) {
// load target file and print to console
- dump = waitForDumpFile(Path.of(target));
+ String dump = waitForDumpFile(Path.of(target));
if (dump != null) {
if ("clipboard".equals(output)) {
Clipboard c =
Toolkit.getDefaultToolkit().getSystemClipboard();
@@ -155,14 +173,13 @@ public class TransformRoute extends CamelCommand {
StopWatch watch = new StopWatch();
while (watch.taken() < 5000) {
try {
- // give time for response to be ready
- Thread.sleep(100);
-
if (Files.exists(dumpFile)) {
try (InputStream is = Files.newInputStream(dumpFile)) {
return IOHelper.loadText(is);
}
}
+ // give time for response to be ready
+ Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/TransformJavaRoutesTest.java
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/TransformJavaRoutesTest.java
new file mode 100644
index 000000000000..02192249a836
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/TransformJavaRoutesTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * CAMEL-25202: camel transform route reads Java routes without compiling
them, and writes what the same routes compiled
+ * and dumped give.
+ */
+class TransformJavaRoutesTest {
+
+ private static final String ORDERS = """
+ import org.apache.camel.builder.RouteBuilder;
+
+ public class Orders extends RouteBuilder {
+ private static final String QUEUE = "orders";
+
+ @Override
+ public void configure() {
+ from("direct:orders").routeId("intake").description("Order
entry point")
+ .setHeader("source").constant("web")
+ .choice()
+ .when(simple("${header.vip} == true"))
+ .to("seda:" + QUEUE + "-vip")
+ .otherwise()
+ .to("seda:" + QUEUE)
+ .end()
+ .log("${body}");
+
+ from("direct:audit").routeId("audit")
+ .split(body().tokenize(","))
+ .to("mock:audit")
+ .end();
+ }
+ }
+ """;
+
+ /** What camel transform route wrote for these routes before, compiling
them (Camel 4.23). */
+ private static final String YAML = """
+ - route:
+ id: intake
+ description: Order entry point
+ from:
+ uri: direct
+ parameters:
+ name: orders
+ steps:
+ - setHeader:
+ name: source
+ expression:
+ constant:
+ expression: web
+ - choice:
+ when:
+ - expression:
+ simple:
+ expression: "${header.vip} == true"
+ steps:
+ - to:
+ uri: seda
+ parameters:
+ name: orders-vip
+ otherwise:
+ steps:
+ - to:
+ uri: seda
+ parameters:
+ name: orders
+ - log:
+ message: "${body}"
+ - route:
+ id: audit
+ from:
+ uri: direct
+ parameters:
+ name: audit
+ steps:
+ - split:
+ expression:
+ expressionDefinition:
+ expression: "tokenize(simple{${body}}, ,)"
+ steps:
+ - to:
+ uri: mock
+ parameters:
+ name: audit
+ """;
+
+ @TempDir
+ Path dir;
+
+ @Test
+ void writesWhatCompilingTheRoutesGives() throws Exception {
+ Path source = Files.writeString(dir.resolve("Orders.java"), ORDERS);
+ Path out = dir.resolve("out.yaml");
+ TransformJavaRoutes.Result result =
TransformJavaRoutes.transform(List.of(source.toString()), "yaml",
out.toString(),
+ true);
+ assertThat(result.transformed()).as(result.reason()).isTrue();
+ assertThat(Files.readString(out)).isEqualToIgnoringNewLines(YAML);
+
+ Path xml = dir.resolve("out.xml");
+ assertThat(TransformJavaRoutes.transform(List.of(source.toString()),
"xml", xml.toString(), true).transformed())
+ .isTrue();
+ assertThat(Files.readString(xml)).contains("<route id=\"intake\"
description=\"Order entry point\">",
+ "<constant>web</constant>", "<to uri=\"seda:orders-vip\"/>");
+ }
+
+ @Test
+ void aDirectoryGetsAFileNamedAfterEachSource() throws Exception {
+ Path source = Files.writeString(dir.resolve("Orders.java"), ORDERS);
+ Path out = dir.resolve("out");
+ assertThat(TransformJavaRoutes.transform(List.of(source.toString()),
"yaml", out.toString(), true).transformed())
+ .isTrue();
+ assertThat(out.resolve("Orders.yaml")).exists();
+ }
+
+ @Test
+ void aRouteThatCannotBeReadIsCompiled() throws Exception {
+ Path source = Files.writeString(dir.resolve("Hey.java"), """
+ public class Hey extends org.apache.camel.builder.RouteBuilder
{
+ @Override
+ public void configure() {
+ from("timer:java").process(e ->
e.getMessage().setBody("Hello")).log("${body}");
+ }
+ }
+ """);
+ Path out = dir.resolve("out.yaml");
+ TransformJavaRoutes.Result result =
TransformJavaRoutes.transform(List.of(source.toString()), "yaml",
out.toString(),
+ true);
+ assertThat(result.transformed()).isFalse();
+ assertThat(result.reason()).contains("Hey.java:4").contains("lambda");
+ assertThat(out).doesNotExist();
+ }
+
+ @Test
+ void onlyJavaSources() throws Exception {
+ Path java = Files.writeString(dir.resolve("Orders.java"), ORDERS);
+ Path yaml = Files.writeString(dir.resolve("r.camel.yaml"), "- route:
{}");
+
assertThat(TransformJavaRoutes.applies(List.of(java.toString()))).isTrue();
+ assertThat(TransformJavaRoutes.applies(List.of(java.toString(),
yaml.toString()))).isFalse();
+ assertThat(TransformJavaRoutes.applies(List.of())).isFalse();
+ }
+}