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 806835b6cf60 CAMEL-24410: Fix camel-jbang export redeliveryDelay 
Duration parsing (4.22.x backport)
806835b6cf60 is described below

commit 806835b6cf60aa78979917fee66f272fdae6d0c6
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Aug 25 13:19:53 2026 +0200

    CAMEL-24410: Fix camel-jbang export redeliveryDelay Duration parsing 
(4.22.x backport)
    
    Backport of #25635 to the camel-4.22.x maintenance branch.
    
    camel export failed when YAML routes use Duration-typed options (e.g. quoted
    redeliveryDelay: "500"), while camel run worked. During export, 
ExportTypeConverter
    is registered with TypeConverterExists.Override and replaced the default
    String-to-Duration converter but did not handle Duration, causing
    NoTypeConversionAvailableException. This adds Duration parsing via 
TimeUtils.toDuration.
    
    Cherry-picked cleanly from main (62c0150).
    
    Closes #25661
    
    Co-authored-by: Omar Atie <[email protected]>
    Co-authored-by: Cursor <[email protected]>
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 .../camel/dsl/jbang/core/commands/ExportTest.java  | 16 ++++
 .../route-configuration-redelivery-delay.yaml      | 34 ++++++++
 .../camel/main/download/ExportTypeConverter.java   |  5 ++
 .../main/download/ExportTypeConverterTest.java     | 96 ++++++++++++++++++++++
 4 files changed, 151 insertions(+)

diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java
index 5cd3ba749d61..d26c54931dff 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ExportTest.java
@@ -102,6 +102,22 @@ class ExportTest {
         
Assertions.assertNotNull(model.getProperties().getProperty("project.build.outputTimestamp"));
     }
 
+    @ParameterizedTest
+    @MethodSource("runtimeProvider")
+    void shouldExportRouteConfigurationWithStringRedeliveryDelay(RuntimeType 
rt) throws Exception {
+        LOG.info("shouldExportRouteConfigurationWithStringRedeliveryDelay {}", 
rt);
+        Export command = createCommand(rt,
+                new String[] { 
"src/test/resources/route-configuration-redelivery-delay.yaml" },
+                "--gav=examples:route:1.0.0", "--dir=" + workingDir, 
"--quiet");
+        int exit = command.doCall();
+
+        assertThat(exit).isZero();
+        Model model = readMavenModel();
+        assertThat(model.getGroupId()).isEqualTo("examples");
+        assertThat(model.getArtifactId()).isEqualTo("route");
+        assertThat(model.getVersion()).isEqualTo("1.0.0");
+    }
+
     @ParameterizedTest
     @MethodSource("runtimeProvider")
     public void shouldExportDifferentVersion(RuntimeType rt) throws Exception {
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/route-configuration-redelivery-delay.yaml
 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/route-configuration-redelivery-delay.yaml
new file mode 100644
index 000000000000..811a9809b897
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/route-configuration-redelivery-delay.yaml
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+- routeConfiguration:
+    errorHandler:
+      id: errorHandlerf23c
+      deadLetterChannel:
+        id: deadLetterChannelda61
+        deadLetterUri: direct:defaultDLQ
+        redeliveryPolicy:
+          id: redeliveryPolicybe2a
+          maximumRedeliveries: 0
+          redeliveryDelay: "500"
+- route:
+    id: testRoute
+    from:
+      uri: direct:start
+      steps:
+        - to:
+            uri: mock:result
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ExportTypeConverter.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ExportTypeConverter.java
index 1ec5c51cff7e..ae086b797b3b 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ExportTypeConverter.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ExportTypeConverter.java
@@ -16,11 +16,14 @@
  */
 package org.apache.camel.main.download;
 
+import java.time.Duration;
+
 import org.apache.camel.Exchange;
 import org.apache.camel.TypeConversionException;
 import org.apache.camel.converter.ObjectConverter;
 import org.apache.camel.support.TypeConverterSupport;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.TimeUtils;
 
 /**
  * During export then we can be more flexible and allow missing property 
placeholders to resolve to a hardcoded value,
@@ -47,6 +50,8 @@ public class ExportTypeConverter extends TypeConverterSupport 
{
             return (T) ObjectConverter.toByte(s);
         } else if (type == String.class) {
             return (T) s;
+        } else if (type == Duration.class) {
+            return (T) TimeUtils.toDuration(s);
         }
         return null;
     }
diff --git 
a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/ExportTypeConverterTest.java
 
b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/ExportTypeConverterTest.java
new file mode 100644
index 000000000000..c4d061846ecb
--- /dev/null
+++ 
b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/ExportTypeConverterTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.main.download;
+
+import java.time.Duration;
+
+import org.apache.camel.NoTypeConversionAvailableException;
+import org.apache.camel.TypeConverterExists;
+import org.apache.camel.impl.engine.SimpleCamelContext;
+import org.apache.camel.spi.TypeConverterRegistry;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class ExportTypeConverterTest {
+
+    private SimpleCamelContext context;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        context = new SimpleCamelContext();
+        TypeConverterRegistry registry = context.getTypeConverterRegistry();
+        registry.setTypeConverterExists(TypeConverterExists.Override);
+        registry.addTypeConverter(Duration.class, String.class, new 
ExportTypeConverter());
+        context.start();
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        if (context != null) {
+            context.stop();
+        }
+    }
+
+    @Test
+    void shouldConvertStringToDurationWhenExportConverterOverridesDefault() 
throws Exception {
+        Duration duration = 
context.getTypeConverter().mandatoryConvertTo(Duration.class, "500");
+
+        assertEquals(Duration.ofMillis(500), duration);
+    }
+
+    @Test
+    void 
shouldConvertDurationTextWithUnitWhenExportConverterOverridesDefault() throws 
Exception {
+        Duration duration = 
context.getTypeConverter().mandatoryConvertTo(Duration.class, "2s");
+
+        assertEquals(Duration.ofSeconds(2), duration);
+    }
+
+    @Test
+    void shouldFailMandatoryConversionWithoutDurationSupport() {
+        TypeConverterRegistry registry = context.getTypeConverterRegistry();
+        registry.addTypeConverter(Duration.class, String.class, new 
ExportTypeConverterWithoutDuration());
+
+        assertThrows(NoTypeConversionAvailableException.class,
+                () -> 
context.getTypeConverter().mandatoryConvertTo(Duration.class, "500"));
+    }
+
+    @Test
+    void shouldConvertViaExportTypeConverterDirectly() {
+        ExportTypeConverter converter = new ExportTypeConverter();
+
+        Duration duration = converter.convertTo(Duration.class, null, "500ms");
+
+        assertEquals(Duration.ofMillis(500), duration);
+    }
+
+    /**
+     * Mimics ExportTypeConverter before Duration support was added.
+     */
+    private static final class ExportTypeConverterWithoutDuration extends 
ExportTypeConverter {
+        @Override
+        public <T> T convertTo(Class<T> type, org.apache.camel.Exchange 
exchange, Object value) {
+            if (type == Duration.class) {
+                return null;
+            }
+            return super.convertTo(type, exchange, value);
+        }
+    }
+}

Reply via email to