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/10/01 10:28:46 UTC
(camel) branch fix/CAMEL-25222 created (now 873d723fd811)
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a change to branch fix/CAMEL-25222
in repository https://gitbox.apache.org/repos/asf/camel.git
at 873d723fd811 CAMEL-25222: Route dump - keep the list dash of a YAML item whose source location comes first, and dump the exception of throwException
This branch includes the following new commits:
new 873d723fd811 CAMEL-25222: Route dump - keep the list dash of a YAML item whose source location comes first, and dump the exception of throwException
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(camel) 01/01: CAMEL-25222: Route dump - keep the list dash of a YAML item whose source location comes first, and dump the exception of throwException
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch fix/CAMEL-25222
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 873d723fd8116b399dc19b76455a46491033d0ae
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Oct 1 12:28:33 2026 +0200
CAMEL-25222: Route dump - keep the list dash of a YAML item whose source location comes first, and dump the exception of throwException
The route-dump console drops the sourceLineNumber and sourceLocation lines of a YAML dump. When they started a list
item, such as a when of a choice, the dash went with them and the item became a map. The dash and the line number
now go to the next line.
An exception given to throwException as a class or an instance was dumped empty in YAML and XML; the dumpers now
write its exceptionType and message.
Co-Authored-By: Claude Opus 5.5 (1M context) <no...@anthropic.com>
Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
.../camel/impl/console/RouteDumpDevConsole.java | 42 ++++++++++----
.../impl/console/RouteDumpDevConsoleTest.java | 44 ++++++++++++++
.../util/DumpModelThrowExceptionInstanceTest.java | 67 ++++++++++++++++++++++
.../org/apache/camel/xml/LwModelToXMLDumper.java | 20 +++++++
.../org/apache/camel/yaml/LwModelToYAMLDumper.java | 18 ++++++
5 files changed, 181 insertions(+), 10 deletions(-)
diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDumpDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDumpDevConsole.java
index 30e6fc79a37e..7e4d707d2b4e 100644
--- a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDumpDevConsole.java
+++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDumpDevConsole.java
@@ -231,8 +231,11 @@ public class RouteDumpDevConsole extends AbstractDevConsole {
return code.isEmpty() ? null : code;
}
- private static List<CodeLine> javaOrYamlLoadSourceAsJson(Reader reader) {
+ static List<CodeLine> javaOrYamlLoadSourceAsJson(Reader reader) {
List<CodeLine> code = new ArrayList<>();
+ // a dropped source location line that started a YAML list item: its dash and line number go to the next line
+ int dashIndent = -1;
+ int dashLine = -1;
try {
LineNumberReader lnr = new LineNumberReader(reader);
String t;
@@ -240,21 +243,40 @@ public class RouteDumpDevConsole extends AbstractDevConsole {
t = lnr.readLine();
if (t != null) {
// extra source location from code line
- if (t.contains("sourceLocation: ")) {
- // skip this line
- } else if (t.contains("sourceLineNumber: ")) {
- String idx = StringHelper.after(t, "sourceLineNumber: ").trim();
- if (!code.isEmpty()) {
- // assign line number to previous code line
- CodeLine prev = code.get(code.size() - 1);
+ boolean location = t.contains("sourceLocation: ");
+ boolean lineNumber = !location && t.contains("sourceLineNumber: ");
+ if (location || lineNumber) {
+ int idx = -1;
+ if (lineNumber) {
try {
- code.set(code.size() - 1, new CodeLine(Integer.parseInt(idx), prev.code()));
+ idx = Integer.parseInt(StringHelper.after(t, "sourceLineNumber: ").trim());
} catch (NumberFormatException e) {
// ignore
}
}
+ int indent = t.length() - t.stripLeading().length();
+ if (t.stripLeading().startsWith("- ")) {
+ // the first key of a list item (such as a when of a choice): the next line takes the dash
+ dashIndent = indent;
+ dashLine = idx;
+ } else if (dashIndent >= 0) {
+ if (idx != -1) {
+ dashLine = idx;
+ }
+ } else if (idx != -1 && !code.isEmpty()) {
+ // assign line number to previous code line
+ CodeLine prev = code.get(code.size() - 1);
+ code.set(code.size() - 1, new CodeLine(idx, prev.code()));
+ }
} else {
- code.add(new CodeLine(-1, Jsoner.escape(t)));
+ if (dashIndent >= 0 && t.length() > dashIndent + 2 && t.startsWith(" ".repeat(dashIndent + 2))) {
+ t = " ".repeat(dashIndent) + "- " + t.substring(dashIndent + 2);
+ code.add(new CodeLine(dashLine, Jsoner.escape(t)));
+ } else {
+ code.add(new CodeLine(-1, Jsoner.escape(t)));
+ }
+ dashIndent = -1;
+ dashLine = -1;
}
}
} while (t != null);
diff --git a/core/camel-console/src/test/java/org/apache/camel/impl/console/RouteDumpDevConsoleTest.java b/core/camel-console/src/test/java/org/apache/camel/impl/console/RouteDumpDevConsoleTest.java
index 0b4013cdd491..06ff94760b68 100644
--- a/core/camel-console/src/test/java/org/apache/camel/impl/console/RouteDumpDevConsoleTest.java
+++ b/core/camel-console/src/test/java/org/apache/camel/impl/console/RouteDumpDevConsoleTest.java
@@ -16,12 +16,16 @@
*/
package org.apache.camel.impl.console;
+import java.io.StringReader;
+import java.util.List;
+
import org.apache.camel.ContextTestSupport;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.console.DevConsole;
import org.apache.camel.support.PluginHelper;
import org.apache.camel.util.json.JsonArray;
import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -63,4 +67,44 @@ public class RouteDumpDevConsoleTest extends ContextTestSupport {
JsonArray routes = out.getCollection("routes");
Assertions.assertNotNull(routes);
}
+
+ @Test
+ public void testYamlSourceLocationOfAListItem() {
+ // the source location of a when comes first in its list item: dropping it must keep the dash
+ String yaml = """
+ - route:
+ from:
+ sourceLineNumber: 7
+ sourceLocation: OrderRoute.java
+ uri: timer:orders
+ steps:
+ - choice:
+ sourceLineNumber: 13
+ sourceLocation: OrderRoute.java
+ when:
+ - sourceLineNumber: 14
+ sourceLocation: OrderRoute.java
+ expression:
+ simple:
+ expression: "${body} == 9"
+ steps:
+ - throwException:
+ sourceLineNumber: 15
+ sourceLocation: OrderRoute.java
+ """;
+ List<RouteDumpDevConsole.CodeLine> code = RouteDumpDevConsole.javaOrYamlLoadSourceAsJson(new StringReader(yaml));
+ List<String> lines = code.stream().map(c -> c.line() + " " + Jsoner.unescape(c.code())).toList();
+ Assertions.assertEquals(List.of(
+ "-1 - route:",
+ "7 from:",
+ "-1 uri: timer:orders",
+ "-1 steps:",
+ "13 - choice:",
+ "-1 when:",
+ "14 - expression:",
+ "-1 simple:",
+ "-1 expression: \"${body} == 9\"",
+ "-1 steps:",
+ "15 - throwException:"), lines);
+ }
}
diff --git a/core/camel-core/src/test/java/org/apache/camel/util/DumpModelThrowExceptionInstanceTest.java b/core/camel-core/src/test/java/org/apache/camel/util/DumpModelThrowExceptionInstanceTest.java
new file mode 100644
index 000000000000..073f8d008c19
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/util/DumpModelThrowExceptionInstanceTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.util;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.support.PluginHelper;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * An exception given to throwException as an instance is dumped as its type and message.
+ */
+public class DumpModelThrowExceptionInstanceTest extends DumpModelAsYamlTestSupport {
+
+ @Test
+ public void testDumpModelAsYaml() throws Exception {
+ String out = PluginHelper.getModelToYAMLDumper(context).dumpModelAsYaml(context, context.getRouteDefinition("myRoute"));
+ assertThat(out).contains("- throwException:", """
+ message: Out of stock
+ exceptionType: java.lang.IllegalStateException
+ """);
+ String typed = PluginHelper.getModelToYAMLDumper(context).dumpModelAsYaml(context, context.getRouteDefinition("typed"));
+ assertThat(typed).contains("- throwException:", """
+ message: Sold out
+ exceptionType: java.lang.IllegalArgumentException
+ """);
+ }
+
+ @Test
+ public void testDumpModelAsXml() throws Exception {
+ String out = PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context, context.getRouteDefinition("myRoute"));
+ assertThat(out).contains(
+ "message=\"Out of stock\" exceptionType=\"java.lang.IllegalStateException\"/>");
+ String typed = PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context, context.getRouteDefinition("typed"));
+ assertThat(typed).contains(
+ "message=\"Sold out\" exceptionType=\"java.lang.IllegalArgumentException\"/>");
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:start").routeId("myRoute")
+ .throwException(new IllegalStateException("Out of stock"));
+
+ from("direct:typed").routeId("typed")
+ .throwException(IllegalArgumentException.class, "Sold out");
+ }
+ };
+ }
+}
diff --git a/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java b/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
index 9ebc1f233868..347f983d8e0f 100644
--- a/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
+++ b/core/camel-xml-io/src/main/java/org/apache/camel/xml/LwModelToXMLDumper.java
@@ -45,6 +45,7 @@ import org.apache.camel.model.RouteTemplatesDefinition;
import org.apache.camel.model.RoutesDefinition;
import org.apache.camel.model.SendDefinition;
import org.apache.camel.model.SwitchDefinition;
+import org.apache.camel.model.ThrowExceptionDefinition;
import org.apache.camel.model.ToDynamicDefinition;
import org.apache.camel.model.dataformat.DataFormatsDefinition;
import org.apache.camel.model.language.ExpressionDefinition;
@@ -138,6 +139,25 @@ public class LwModelToXMLDumper implements ModelToXMLDumper {
}
}
+ @Override
+ protected void doWriteThrowExceptionDefinition(String name, ThrowExceptionDefinition def) throws IOException {
+ Exception e = def.getException();
+ String type = def.getExceptionClass() != null
+ ? def.getExceptionClass().getName() : e != null ? e.getClass().getName() : null;
+ if (type == null || def.getExceptionType() != null || def.getRef() != null) {
+ super.doWriteThrowExceptionDefinition(name, def);
+ return;
+ }
+ // an exception given as a class or an instance, as in throwException(new Exception("...")), is
+ // written as its type and message, as the class or instance itself cannot be
+ startElement(name);
+ doWriteProcessorDefinitionAttributes(def);
+ String message = def.getMessage() != null ? def.getMessage() : e != null ? e.getMessage() : null;
+ doWriteAttribute("message", message, null);
+ doWriteAttribute("exceptionType", type, null);
+ endElement(name);
+ }
+
@Override
protected void doWriteValue(String value) throws IOException {
if (value != null && !value.isEmpty()) {
diff --git a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
index 318e20db2cf9..657928a75aee 100644
--- a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
+++ b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
@@ -46,6 +46,7 @@ import org.apache.camel.model.RouteTemplatesDefinition;
import org.apache.camel.model.RoutesDefinition;
import org.apache.camel.model.SendDefinition;
import org.apache.camel.model.SwitchDefinition;
+import org.apache.camel.model.ThrowExceptionDefinition;
import org.apache.camel.model.ToDynamicDefinition;
import org.apache.camel.model.dataformat.DataFormatsDefinition;
import org.apache.camel.model.language.ExpressionDefinition;
@@ -137,6 +138,23 @@ public class LwModelToYAMLDumper implements ModelToYAMLDumper {
super.doWriteAttribute(jo, key, value, defaultValue);
}
+ @Override
+ protected JsonObject doWriteThrowExceptionDefinition(ThrowExceptionDefinition def) {
+ JsonObject jo = super.doWriteThrowExceptionDefinition(def);
+ Exception e = def.getException();
+ String type = def.getExceptionClass() != null
+ ? def.getExceptionClass().getName() : e != null ? e.getClass().getName() : null;
+ if (type != null && def.getExceptionType() == null && def.getRef() == null) {
+ // an exception given as a class or an instance, as in throwException(new Exception("...")), is
+ // written as its type and message, as the class or instance itself cannot be
+ if (def.getMessage() == null && e != null) {
+ doWriteAttribute(jo, "message", e.getMessage(), null);
+ }
+ doWriteAttribute(jo, "exceptionType", type, null);
+ }
+ return jo;
+ }
+
@Override
protected void doWriteValue(JsonObject jo, String value) {
if (resolvePlaceholders && value != null) {