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

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


The following commit(s) were added to refs/heads/camel-4.22.x by this push:
     new 5075e244f797 [camel-4.22.x] CAMEL-25222: Route dump - keep the YAML 
list dash with source locations, and dump the exception of throwException
5075e244f797 is described below

commit 5075e244f797f6a5489fc70e41fbec99ac465945
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Oct 1 15:30:38 2026 +0200

    [camel-4.22.x] CAMEL-25222: Route dump - keep the YAML list dash with 
source locations, and dump the exception of throwException
    
    Backport of #27198. When a route is dumped as YAML with source locations, 
the
    list dash of an element (such as a choice when) was dropped together with 
the
    source-location lines, so the dumped YAML was wrong. The dash is now 
carried to
    the first content line. throwException given an exception instance was 
dumped
    empty; the XML and YAML dumpers now write its type and message.
    
    4.22.x has no typed CodeLine records in the route-dump console, so that 
change
    is ported to the JsonObject form used there, with the same logic.
    
    Closes #27199
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../camel/impl/console/RouteDumpDevConsole.java    | 42 +++++++++---
 .../impl/console/RouteDumpDevConsoleTest.java      | 74 ++++++++++++++++++++++
 .../util/DumpModelThrowExceptionInstanceTest.java  | 67 ++++++++++++++++++++
 .../org/apache/camel/xml/LwModelToXMLDumper.java   | 20 ++++++
 .../org/apache/camel/yaml/LwModelToYAMLDumper.java | 18 ++++++
 5 files changed, 211 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 fb42ea5e9ea7..6a4523298822 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
@@ -226,8 +226,11 @@ public class RouteDumpDevConsole extends 
AbstractDevConsole {
         return code.isEmpty() ? null : code;
     }
 
-    private static JsonArray javaOrYamlLoadSourceAsJson(Reader reader) {
+    static JsonArray javaOrYamlLoadSourceAsJson(Reader reader) {
         JsonArray code = new JsonArray();
+        // 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;
@@ -235,23 +238,42 @@ 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
-                            JsonObject c = (JsonObject) 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 {
-                                c.put("line", Integer.parseInt(idx));
+                                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
+                            JsonObject c = (JsonObject) code.get(code.size() - 
1);
+                            c.put("line", idx);
+                        }
                     } else {
+                        int line = -1;
+                        if (dashIndent >= 0 && t.length() > dashIndent + 2 && 
t.startsWith(" ".repeat(dashIndent + 2))) {
+                            t = " ".repeat(dashIndent) + "- " + 
t.substring(dashIndent + 2);
+                            line = dashLine;
+                        }
+                        dashIndent = -1;
+                        dashLine = -1;
                         JsonObject c = new JsonObject();
                         c.put("code", Jsoner.escape(t));
-                        c.put("line", -1);
+                        c.put("line", line);
                         code.add(c);
                     }
                 }
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
new file mode 100644
index 000000000000..91fac44c1dbb
--- /dev/null
+++ 
b/core/camel-console/src/test/java/org/apache/camel/impl/console/RouteDumpDevConsoleTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.impl.console;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+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;
+
+public class RouteDumpDevConsoleTest {
+
+    @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
+                """;
+        JsonArray code = RouteDumpDevConsole.javaOrYamlLoadSourceAsJson(new 
StringReader(yaml));
+        List<String> lines = new ArrayList<>();
+        for (Object o : code) {
+            JsonObject c = (JsonObject) o;
+            lines.add(c.getInteger("line") + " " + 
Jsoner.unescape(c.getString("code")));
+        }
+        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 11f8aa7cb7a7..de7668158351 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
@@ -44,6 +44,7 @@ import org.apache.camel.model.RouteTemplateDefinition;
 import org.apache.camel.model.RouteTemplatesDefinition;
 import org.apache.camel.model.RoutesDefinition;
 import org.apache.camel.model.SendDefinition;
+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;
@@ -132,6 +133,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 serialized
+                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 589c62e2713d..12fd0707bda0 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
@@ -45,6 +45,7 @@ import org.apache.camel.model.RouteTemplateDefinition;
 import org.apache.camel.model.RouteTemplatesDefinition;
 import org.apache.camel.model.RoutesDefinition;
 import org.apache.camel.model.SendDefinition;
+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;
@@ -134,6 +135,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 serialized
+                    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) {

Reply via email to