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 6e5050a04175 CAMEL-25899: camel-jbang - AI tools: the reload output of 
a write keeps the hint of a failure, and a write of a script the routes load 
waits for the reload (#28209)
6e5050a04175 is described below

commit 6e5050a0417585b1d4fd94a122d5d562356ba7ba
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Oct 21 21:30:02 2026 +0200

    CAMEL-25899: camel-jbang - AI tools: the reload output of a write keeps the 
hint of a failure, and a write of a script the routes load waits for the reload 
(#28209)
    
    * CAMEL-25899: camel-jbang - AI tools: the reload output of a write keeps 
the hint of a failure, and a write of a script the routes load waits for the 
reload
    
    - The reload outcome of a write compacts a WARN or ERROR line: the message 
ids and attempt count of the error handler,
      the exchange dumps, the packages of exception classes and long bean dumps 
go, and such a line may be 800 characters.
      The hint at the end of an exception message (such as "unmarshal it 
first") was cut off at 400 characters.
    - A write of a script or template the routes load (.groovy, .js, .py, .ftl, 
.vm, .mustache, .jslt, .jsonata) waits for
      the dev-mode reload and reports what the routes then do, as a route write 
does; it answered at once before, and the
      agent read the errors before the reload.
    
    Claude-Session: https://claude.ai/code/session_01STT6whBgK1AqsSsUKrnE8m
    
    * CAMEL-25899: camel-jbang - AI tools: the failed reload of a script the 
routes load names its routes, as the reloaded one does
    
    * CAMEL-25899: Answer a template or script write at once when the 
integration does not watch it (address review)
    
    - An integration started with its own files (not --source-dir) watches only 
those: a write of a template or
      script beside them no longer waits RELOAD_WAIT_MILLIS for a reload that 
does not come, and says that
      camel_control restart picks up the change
    - The javadoc of ReloadOutcome.awaitOutput says that a WARN or ERROR line 
is compacted and cut at 800 characters
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/ai/AuthoringTools.java | 34 +++++++++++-
 .../core/commands/ai/IntegrationLauncher.java      | 21 +++++++
 .../dsl/jbang/core/commands/ai/ReloadOutcome.java  | 64 ++++++++++++++++++++--
 .../jbang/core/commands/ai/AuthoringToolsTest.java | 27 +++++++++
 .../core/commands/ai/IntegrationLauncherTest.java  | 17 ++++++
 .../jbang/core/commands/ai/ReloadOutcomeTest.java  | 47 ++++++++++++++++
 6 files changed, 202 insertions(+), 8 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java
index 551e175bb5c2..31174238a18a 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java
@@ -1633,7 +1633,7 @@ public final class AuthoringTools {
         String processName = null;
         String sinceKey = null;
         long watchPid = -1;
-        if (SourceValidator.isValidatableFile(file)) {
+        if (SourceValidator.isValidatableFile(file) || 
reloadsWithRoutes(file)) {
             if (ctx.hasProcess()) {
                 watchPid = ctx.pid();
                 RuntimeHelper.ProcessInfo p = 
RuntimeHelper.findProcess(Long.toString(ctx.pid()));
@@ -1648,6 +1648,14 @@ public final class AuthoringTools {
                 }
             }
         }
+        long notWatchedBy = -1;
+        if (watchPid >= 0 && !SourceValidator.isValidatableFile(file) && 
!IntegrationLauncher.watchesFile(watchPid, file)) {
+            // started with its own files, the template or script is not one 
it watches: waiting the whole
+            // RELOAD_WAIT_MILLIS would only end in "no reload seen" (route 
files keep the wait: application.properties
+            // is watched without being on the command line)
+            notWatchedBy = watchPid;
+            watchPid = -1;
+        }
         boolean watch = watchPid >= 0;
         if (watch) {
             sinceKey = 
ReloadOutcome.latestReloadKey(ReloadOutcome.records(watchPid, processName));
@@ -1701,13 +1709,19 @@ public final class AuthoringTools {
                           + (output.size() > 1 ? " (and " + (output.size() - 
1) + " more in reload.output)" : "");
             }
             final String loggedAfter = logged;
+            String reloadedWhat = SourceValidator.isValidatableFile(file) ? 
"the file" : "its routes, which load the file";
             result.put("message", switch (status) {
-                case "reloaded" -> "The running integration reloaded the 
file." + loggedAfter;
+                case "reloaded" -> "The running integration reloaded " + 
reloadedWhat + "." + loggedAfter;
                 case "properties" -> "The running integration reloaded the 
properties.";
-                case "failed" -> "The running integration FAILED to reload the 
file, the route is not running; fix the"
+                case "failed" ->
+                    "The running integration FAILED to reload " + reloadedWhat 
+ ", the route is not running; fix the"
                                  + " content and write again (see 
reload.message).";
                 default -> "Written; " + reload.getString("message");
             });
+        } else if (notWatchedBy >= 0) {
+            result.put("message", "The running integration (pid " + 
notWatchedBy + ") was started with its own files"
+                                  + " and does not reload when this file 
changes; camel_control restart picks up the"
+                                  + " change.");
         } else {
             result.put("message", "An integration running the file in dev mode 
reloads it now; otherwise restart the"
                                   + " integration for the change to take 
effect.");
@@ -1723,6 +1737,20 @@ public final class AuthoringTools {
         return result;
     }
 
+    /** The script and template files that routes load, such as 
resource:file:mapping.groovy. */
+    private static final List<String> ROUTE_RESOURCES
+            = List.of(".groovy", ".js", ".py", ".ftl", ".vm", ".mustache", 
".jslt", ".jsonata");
+
+    /**
+     * A file the routes load, such as the Groovy script of a setBody 
(resource:file:mapping.groovy) or a template: dev
+     * mode reloads the routes when it changes, so its write waits for that 
reload and reports what the routes then do,
+     * as the write of a route file does. Answered at once, an agent read the 
errors before the reload, and saw none.
+     */
+    static boolean reloadsWithRoutes(String fileName) {
+        String name = fileName == null ? "" : 
fileName.toLowerCase(Locale.ROOT);
+        return ROUTE_RESOURCES.stream().anyMatch(name::endsWith);
+    }
+
     /** The content of the last refused write of each file, and how many times 
in a row it was refused. */
     private record Refused(String content, int times) {
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncher.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncher.java
index 20c6f0733dd9..f38868a9e16f 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncher.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncher.java
@@ -457,6 +457,27 @@ public final class IntegrationLauncher {
                 : " It is not in dev mode: camel_control restart picks up a 
changed or added file.");
     }
 
+    /**
+     * Whether the integration reloads its routes when this file changes. One 
started with --source-dir watches its
+     * whole directory. One started with its own files watches only those: 
camel run puts a template or a script on the
+     * classpath, not in the reload pattern, so a write of it is not reloaded. 
True when the command line of the process
+     * cannot be read, as before.
+     */
+    static boolean watchesFile(long pid, String file) {
+        List<String> args = ProcessHandle.of(pid).flatMap(ph -> 
ph.info().arguments()).map(Arrays::asList).orElse(null);
+        return watchesFile(args, file);
+    }
+
+    static boolean watchesFile(List<String> args, String file) {
+        if (args == null || args.stream().anyMatch(a -> 
a.startsWith("--source-dir"))) {
+            return true;
+        }
+        String name = Path.of(file).getFileName().toString();
+        // the file itself on the command line (a Groovy route), or a wildcard 
that camel run expands
+        return args.stream().anyMatch(a -> a.contains("*") || a.equals(name) 
|| a.endsWith("/" + name)
+                || a.endsWith(":" + name));
+    }
+
     /**
      * The integration that runs in dev mode from the directory (its working 
directory, started with --dev), or null:
      * the one whose reload a write to the directory is answered with when no 
integration is selected (CAMEL-25513).
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ReloadOutcome.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ReloadOutcome.java
index cb4f1e38919e..13df72e1dfcb 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ReloadOutcome.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ReloadOutcome.java
@@ -21,6 +21,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.function.Supplier;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.camel.util.StopWatch;
@@ -180,13 +181,28 @@ public final class ReloadOutcome {
     private static final int OUTPUT_LINES = 5;
     private static final int OUTPUT_ERRORS = 3;
     private static final int OUTPUT_CHARS = 400;
+    /** A WARN or ERROR line may be longer: the hint of a failure comes late 
in the exception message. */
+    private static final int OUTPUT_ERROR_CHARS = 800;
+
+    // the text of the error handler around the exception, which says nothing 
the agent can act on
+    private static final Pattern FAILED_DELIVERY = Pattern.compile(
+            "^Failed delivery for \\(MessageId: \\S+ on ExchangeId: \\S+\\)(?: 
at (.+?))?\\."
+                                                                   + " 
Exhausted after delivery attempt: \\d+ caught: ");
+    private static final Pattern EXCEPTION_PACKAGE
+            = 
Pattern.compile("\\b(?:[a-z][a-z0-9_]*\\.)+([A-Z][\\w$]*(?:Exception|Error))\\b");
+    private static final Pattern ON_THE_EXCHANGE = Pattern.compile(" on the 
exchange: Exchange\\[[^\\]]*]");
+    // "Error processing exchange. Exchange[1028039098EFE4D-0000000000000009]. 
Caused by: [...]"
+    private static final Pattern EXCHANGE_ID = 
Pattern.compile("Exchange\\[[0-9A-Fa-f]+-[0-9A-Fa-f]+]\\. ");
+    private static final String ON_BEAN = " on bean: ";
+    private static final int MAX_BEAN = 80;
 
     /**
      * What the routes logged after the newest reload, waiting up to the 
timeout for the first of it: the records of the
-     * routes' log steps, and any WARN or ERROR, newest last, each cut to 400 
characters: the first five, the first
-     * three ERROR after them, and a line that says how many are left out. A 
write answered with the result of the
-     * change shows the agent at once what its route now does (CAMEL-25513): 
an agent left to call camel_get_log reads
-     * it before the reload ran, or not at all.
+     * routes' log steps, and any WARN or ERROR, newest last. A record of a 
log step is cut to 400 characters; a WARN or
+     * ERROR of Camel is compacted (no exchange dump, ids or exception 
packages) and cut to 800 characters, as the hint
+     * of a failure comes late in the message. The first five, the first three 
ERROR after them, and a line that says
+     * how many are left out. A write answered with the result of the change 
shows the agent at once what its route now
+     * does (CAMEL-25513): an agent left to call camel_get_log reads it before 
the reload ran, or not at all.
      */
     public static JsonArray awaitOutput(long pid, String name, long 
timeoutMillis) {
         StopWatch watch = new StopWatch();
@@ -203,6 +219,39 @@ public final class ReloadOutcome {
         return out;
     }
 
+    /**
+     * A WARN or ERROR line, as short as it can be without losing what the 
agent acts on: the message ids and the
+     * attempt count of the error handler, the dump of the exchange, the 
packages of the exception classes and the long
+     * dump of a bean go. The hint of a failure, which Camel adds at the end 
of the exception message (such as
+     * "unmarshal it first"), was cut off: the line of a failed exchange 
starts with some 250 characters of such text.
+     */
+    static String compact(String message) {
+        String m = message;
+        Matcher fd = FAILED_DELIVERY.matcher(m);
+        if (fd.find()) {
+            m = "Failed" + (fd.group(1) != null ? " at " + fd.group(1) : "") + 
": " + m.substring(fd.end());
+        }
+        m = ON_THE_EXCHANGE.matcher(m).replaceAll("");
+        m = EXCHANGE_ID.matcher(m).replaceAll("");
+        m = EXCEPTION_PACKAGE.matcher(m).replaceAll("$1");
+        // "not found on bean: [{orderId=ORD-1001, ...}, ...] of type: 
java.util.ArrayList": the start of the dump
+        StringBuilder sb = new StringBuilder();
+        int from = 0;
+        int at;
+        while ((at = m.indexOf(ON_BEAN, from)) >= 0) {
+            int start = at + ON_BEAN.length();
+            int end = m.indexOf(" of type: ", start);
+            if (end < 0) {
+                break;
+            }
+            sb.append(m, from, start);
+            sb.append(end - start > MAX_BEAN ? m.substring(start, start + 
MAX_BEAN) + "..." : m.substring(start, end));
+            from = end;
+        }
+        sb.append(m.substring(from));
+        return sb.toString();
+    }
+
     static JsonArray output(List<JsonObject> newestFirst) {
         List<String> lines = new ArrayList<>();
         for (JsonObject r : newestFirst) {
@@ -222,8 +271,13 @@ public final class ReloadOutcome {
                 // a multi-line body (an XML or JSON document) is part of what 
the route logged
                 m = m + "\n" + detail;
             }
+            int max = OUTPUT_CHARS;
+            if (!routeLog) {
+                m = compact(m);
+                max = OUTPUT_ERROR_CHARS;
+            }
             lines.add((routeLog ? "" : level.toUpperCase(Locale.ROOT) + " ")
-                      + (m.length() > OUTPUT_CHARS ? m.substring(0, 
OUTPUT_CHARS) + "..." : m));
+                      + (m.length() > max ? m.substring(0, max) + "..." : m));
         }
         // newest first in the log: the first lines the routes logged after 
the reload are at the end
         Collections.reverse(lines);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringToolsTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringToolsTest.java
index 2ca880ea05a0..e4bf42b3b783 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringToolsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringToolsTest.java
@@ -37,6 +37,7 @@ import org.junit.jupiter.api.io.TempDir;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -238,6 +239,32 @@ class AuthoringToolsTest {
         return (List<JsonObject>) (List<?>) errors.getCollection("errors");
     }
 
+    /** A script or template the routes load: dev mode reloads the routes when 
it changes, so its write waits. */
+    @Test
+    void aWriteOfAFileTheRoutesLoadWaitsForTheReload() {
+        
assertTrue(AuthoringTools.reloadsWithRoutes("shipment-mapping.groovy"));
+        assertTrue(AuthoringTools.reloadsWithRoutes("templates/letter.FTL"));
+        
assertFalse(AuthoringTools.reloadsWithRoutes("orders/order-1001.json"), "a data 
file is not loaded by a route");
+        assertFalse(AuthoringTools.reloadsWithRoutes("README.md"));
+    }
+
+    /**
+     * Started with its own files, an integration watches only those, not a 
template or script beside them: its write is
+     * answered at once, not after waiting for a reload that does not come.
+     */
+    @Test
+    void aWriteOfATemplateTheIntegrationDoesNotWatchIsAnsweredAtOnce(@TempDir 
Path dir) {
+        ToolContext ctx = new ToolContext();
+        // this JVM: its command line has no --source-dir and not the template
+        ctx.selectProcess(ProcessHandle.current().pid());
+        JsonObject written = call("camel_write_file", ctx,
+                Map.of("directory", dir.toString(), "file", "letter.ftl", 
"content", "Dear ${body}"));
+        assertEquals("created", written.getString("status"));
+        assertNull(written.get("reload"), written.toJson());
+        assertTrue(written.getString("message").contains("was started with its 
own files and does not reload"),
+                written.toJson());
+    }
+
     @Test
     void writeValidatesFirstAndRefusesInvalidContent(@TempDir Path dir) throws 
IOException {
         Files.writeString(dir.resolve("demo.camel.yaml"), "- route: {}\n");
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncherTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncherTest.java
index fcfbd42a33ac..023b96b7b55f 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncherTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/IntegrationLauncherTest.java
@@ -231,4 +231,21 @@ class IntegrationLauncherTest {
         assertThat(IntegrationLauncher.stoppedByRestart(other, 
null)).isFalse();
         assertThat(IntegrationLauncher.runName(other, null)).isNull();
     }
+
+    /**
+     * Started with --source-dir, the integration watches its directory; 
started with its own files, only those: camel
+     * run puts a template or a script on the classpath, not in the reload 
pattern.
+     */
+    @Test
+    void anIntegrationStartedWithItsOwnFilesWatchesOnlyThose() {
+        List<String> sourceDir = List.of("run", "--source-dir=.", "--dev");
+        assertThat(IntegrationLauncher.watchesFile(sourceDir, 
"templates/letter.ftl")).isTrue();
+        List<String> ownFiles = List.of("run", "order.camel.yaml", 
"routes/stock.groovy", "--dev");
+        assertThat(IntegrationLauncher.watchesFile(ownFiles, 
"letter.ftl")).isFalse();
+        assertThat(IntegrationLauncher.watchesFile(ownFiles, 
"mapping.groovy")).isFalse();
+        assertThat(IntegrationLauncher.watchesFile(ownFiles, 
"routes/stock.groovy")).isTrue();
+        assertThat(IntegrationLauncher.watchesFile(List.of("run", "*", 
"--dev"), "letter.ftl")).isTrue();
+        // the command line cannot be read: waited for, as before
+        assertThat(IntegrationLauncher.watchesFile(null, 
"letter.ftl")).isTrue();
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/ReloadOutcomeTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/ReloadOutcomeTest.java
index adb97d9222fa..befcec4ff7af 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/ReloadOutcomeTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/ReloadOutcomeTest.java
@@ -156,6 +156,53 @@ class ReloadOutcomeTest {
         assertEquals(7, output.size(), output.toJson());
     }
 
+    /**
+     * The line of a failed exchange starts with the message ids and the 
attempts of the error handler, and the hint of
+     * the failure comes late in the exception message: cut at 400 characters, 
the agent never saw it (enrich step 2 of
+     * the r20 runs). The line is compacted, and the hint fits.
+     */
+    @Test
+    void theHintOfAFailedExchangeFitsTheLine() {
+        List<String> failed = List.of(
+                "2026-10-21 00:30:00.000  INFO 42 --- [rReloadStrategy] 
org.apache.camel.support.RouteWatcherReloadStrategy : Routes reloaded summary 
(total:1 started:1)",
+                "2026-10-21 00:30:01.000 ERROR 42 --- [ - file://orders] 
or.errorhandler.DefaultErrorHandler : Failed delivery for"
+                                                                               
                                                                                
             + " (MessageId: 7188B2FCF80AE47-000000000000001B on ExchangeId: 
7188B2FCF80AE47-000000000000001B) at"
+                                                                               
                                                                                
             + " incoming-orders[log14] enrich-and-dedupe.camel.yaml:42. 
Exhausted after delivery attempt: 1 caught:"
+                                                                               
                                                                                
             + " org.apache.camel.language.bean.RuntimeBeanExpressionException: 
Failed to invoke method: [name] on"
+                                                                               
                                                                                
             + " org.apache.camel.component.file.GenericFile due to: 
java.lang.IndexOutOfBoundsException: Key: name"
+                                                                               
                                                                                
             + " not found in bean: GenericFile[C-482.json] of type: 
org.apache.camel.component.file.GenericFile"
+                                                                               
                                                                                
             + " using OGNL path [[name]] (the value is the file as read (a 
GenericFile), not its data: unmarshal it"
+                                                                               
                                                                                
             + " first, for example with json, then read the key; a variable is 
unmarshalled in place with"
+                                                                               
                                                                                
             + " variableSend and variableReceive set to its name, such as 
unmarshal: {json: {}, variableSend:"
+                                                                               
                                                                                
             + " customer, variableReceive: customer})");
+
+        JsonArray output = ReloadOutcome.output(records(BEFORE, failed));
+
+        assertEquals(1, output.size(), output.toJson());
+        String line = output.get(0).toString();
+        assertTrue(line.startsWith("ERROR Failed at incoming-orders[log14] 
enrich-and-dedupe.camel.yaml:42:"
+                                   + " RuntimeBeanExpressionException: Failed 
to invoke method: [name]"),
+                line);
+        // the whole hint, not cut
+        assertTrue(line.endsWith("variableSend: customer, variableReceive: 
customer})"), line);
+        assertTrue(!line.contains("MessageId") && !line.contains("Exhausted 
after"), line);
+    }
+
+    @Test
+    void theDumpOfAnExchangeAndOfALongBeanGo() {
+        String m = ReloadOutcome.compact("Method with name: orderId not found 
on bean: ["
+                                         + "{orderId=ORD-1001, 
customer=C-482}, ".repeat(5)
+                                         + "] of type: java.util.ArrayList on 
the exchange: Exchange[ABC-1]");
+        assertTrue(m.startsWith("Method with name: orderId not found on bean: 
[{orderId=ORD-1001, customer=C-482}"), m);
+        assertTrue(m.endsWith("... of type: java.util.ArrayList"), m);
+        assertEquals("Error processing exchange. Caused by: 
[NullPointerException - Cannot get property 'id' on null object]",
+                ReloadOutcome.compact("Error processing exchange. 
Exchange[1028039098EFE4D-0000000000000009]. Caused by:"
+                                      + " [java.lang.NullPointerException - 
Cannot get property 'id' on null object]"));
+        // a short dump stays
+        assertEquals("Key: name not found in bean: GenericFile[C-482.json] of 
type: x",
+                ReloadOutcome.compact("Key: name not found in bean: 
GenericFile[C-482.json] of type: x"));
+    }
+
     @Test
     void whatWasLoggedBeforeTheNewestReloadIsNotOutput() {
         assertEquals(List.of("Hello Camel"), 
List.copyOf(ReloadOutcome.output(records(BEFORE))));

Reply via email to