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

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

commit 82e48cc5fb6462eb900a4a60738a4cb3e8f88bb9
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Sep 23 21:51:05 2026 +0200

    CAMEL-24976: type converter - fix smaller bugs in core converters
    
    - String to TimeUnit supports MICROSECONDS
    - String to ByteBuffer uses the charset from the exchange (header or
      property) like the other converters, instead of only the property
    - converting an array to a Set no longer returns a List
    - enum conversion prefers an exact match over a case-insensitive match
    - converting a Future restores the interrupted flag when interrupted
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../apache/camel/converter/DateTimeConverter.java  |  1 +
 .../org/apache/camel/converter/NIOConverter.java   | 23 ++--------------------
 .../camel/impl/converter/ArrayTypeConverter.java   |  8 +++++---
 .../camel/impl/converter/EnumTypeConverter.java    |  7 +++++++
 .../camel/impl/converter/FutureTypeConverter.java  |  3 +++
 .../camel/converter/DateTimeConverterTest.java     |  1 +
 .../apache/camel/converter/EnumConverterTest.java  | 10 ++++++++++
 .../camel/converter/FutureConverterTest.java       | 19 ++++++++++++++++++
 .../apache/camel/converter/NIOConverterTest.java   | 10 ++++++++++
 .../converter/CoreTypeConverterRegistryTest.java   | 13 ++++++++++++
 10 files changed, 71 insertions(+), 24 deletions(-)

diff --git 
a/core/camel-base/src/main/java/org/apache/camel/converter/DateTimeConverter.java
 
b/core/camel-base/src/main/java/org/apache/camel/converter/DateTimeConverter.java
index b1714a9d17a5..e81c133000c4 100644
--- 
a/core/camel-base/src/main/java/org/apache/camel/converter/DateTimeConverter.java
+++ 
b/core/camel-base/src/main/java/org/apache/camel/converter/DateTimeConverter.java
@@ -59,6 +59,7 @@ public final class DateTimeConverter {
             case "MINUTES" -> TimeUnit.MINUTES;
             case "SECONDS" -> TimeUnit.SECONDS;
             case "MILLISECONDS" -> TimeUnit.MILLISECONDS;
+            case "MICROSECONDS" -> TimeUnit.MICROSECONDS;
             case "NANOSECONDS" -> TimeUnit.NANOSECONDS;
             default -> throw new IllegalStateException("Unexpected value: " + 
unit);
         };
diff --git 
a/core/camel-base/src/main/java/org/apache/camel/converter/NIOConverter.java 
b/core/camel-base/src/main/java/org/apache/camel/converter/NIOConverter.java
index 55eb58eef253..5dd054764ecc 100644
--- a/core/camel-base/src/main/java/org/apache/camel/converter/NIOConverter.java
+++ b/core/camel-base/src/main/java/org/apache/camel/converter/NIOConverter.java
@@ -20,16 +20,13 @@ import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
 import java.nio.file.Files;
 import java.nio.file.Path;
 
 import org.apache.camel.Converter;
 import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePropertyKey;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.camel.support.ExchangeHelper;
 
 import static org.apache.camel.util.BufferCaster.cast;
 
@@ -39,8 +36,6 @@ import static org.apache.camel.util.BufferCaster.cast;
 @Converter(generateBulkLoader = true)
 public final class NIOConverter {
 
-    private static final Logger LOG = 
LoggerFactory.getLogger(NIOConverter.class);
-
     /**
      * Utility classes should not have a public constructor.
      */
@@ -88,21 +83,7 @@ public final class NIOConverter {
 
     @Converter(order = 7)
     public static ByteBuffer toByteBuffer(String value, Exchange exchange) {
-        byte[] bytes = null;
-        if (exchange != null) {
-            String charsetName = 
exchange.getProperty(ExchangePropertyKey.CHARSET_NAME, String.class);
-            if (charsetName != null) {
-                try {
-                    bytes = value.getBytes(charsetName);
-                } catch (UnsupportedEncodingException e) {
-                    LOG.warn("Cannot convert the byte to String with the 
charset {}", charsetName, e);
-                }
-            }
-        }
-        if (bytes == null) {
-            bytes = value.getBytes();
-        }
-        return ByteBuffer.wrap(bytes);
+        return 
ByteBuffer.wrap(value.getBytes(ExchangeHelper.getCharset(exchange)));
     }
 
     @Converter(order = 8)
diff --git 
a/core/camel-base/src/main/java/org/apache/camel/impl/converter/ArrayTypeConverter.java
 
b/core/camel-base/src/main/java/org/apache/camel/impl/converter/ArrayTypeConverter.java
index 4716d0c62e3d..b053bed4ff52 100644
--- 
a/core/camel-base/src/main/java/org/apache/camel/impl/converter/ArrayTypeConverter.java
+++ 
b/core/camel-base/src/main/java/org/apache/camel/impl/converter/ArrayTypeConverter.java
@@ -54,10 +54,12 @@ public class ArrayTypeConverter extends 
TypeConverterSupport {
                 }
                 return (T) answer;
             }
-        } else if (Collection.class.isAssignableFrom(type)) {
+        } else if (Collection.class.isAssignableFrom(type) && 
type.isAssignableFrom(ArrayList.class)) {
+            // only for collection types a list can be assigned to (such as 
not a Set)
             if (value != null) {
-                if (value instanceof Object[]) {
-                    return (T) Arrays.asList((Object[]) value);
+                if (value instanceof Object[] arr) {
+                    List<Object> list = Arrays.asList(arr);
+                    return (T) (type.isInstance(list) ? list : new 
ArrayList<>(list));
                 } else if (value.getClass().isArray()) {
                     int size = Array.getLength(value);
                     List<Object> answer = new ArrayList<>(size);
diff --git 
a/core/camel-base/src/main/java/org/apache/camel/impl/converter/EnumTypeConverter.java
 
b/core/camel-base/src/main/java/org/apache/camel/impl/converter/EnumTypeConverter.java
index 0be4f5ef0727..432f7f920fb0 100644
--- 
a/core/camel-base/src/main/java/org/apache/camel/impl/converter/EnumTypeConverter.java
+++ 
b/core/camel-base/src/main/java/org/apache/camel/impl/converter/EnumTypeConverter.java
@@ -72,6 +72,13 @@ public class EnumTypeConverter extends TypeConverterSupport 
implements CamelCont
             String text = value.toString().trim();
             Class<Enum<?>> enumClass = (Class<Enum<?>>) type;
 
+            // prefer an exact match
+            for (Enum<?> enumValue : enumClass.getEnumConstants()) {
+                if (enumValue.name().equals(text)) {
+                    return type.cast(enumValue);
+                }
+            }
+
             // we want to match case insensitive for enums
             for (Enum<?> enumValue : enumClass.getEnumConstants()) {
                 if (enumValue.name().equalsIgnoreCase(text)) {
diff --git 
a/core/camel-base/src/main/java/org/apache/camel/impl/converter/FutureTypeConverter.java
 
b/core/camel-base/src/main/java/org/apache/camel/impl/converter/FutureTypeConverter.java
index 9da2fc178c4b..26ca7c8ee0be 100644
--- 
a/core/camel-base/src/main/java/org/apache/camel/impl/converter/FutureTypeConverter.java
+++ 
b/core/camel-base/src/main/java/org/apache/camel/impl/converter/FutureTypeConverter.java
@@ -44,6 +44,9 @@ public final class FutureTypeConverter extends 
TypeConverterSupport {
     public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
         try {
             return doConvertTo(type, exchange, value);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new TypeConversionException(value, type, e);
         } catch (Exception e) {
             throw new TypeConversionException(value, type, e);
         }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/converter/DateTimeConverterTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/converter/DateTimeConverterTest.java
index acb2d1e784d2..8c6204d3836b 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/converter/DateTimeConverterTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/converter/DateTimeConverterTest.java
@@ -59,5 +59,6 @@ public class DateTimeConverterTest extends ContextTestSupport 
{
     public void testToTimeUnit() {
         assertEquals(TimeUnit.DAYS, 
context.getTypeConverter().convertTo(TimeUnit.class, "DAYS"));
         assertEquals(TimeUnit.MILLISECONDS, 
context.getTypeConverter().convertTo(TimeUnit.class, "MILLISECONDS"));
+        assertEquals(TimeUnit.MICROSECONDS, 
context.getTypeConverter().convertTo(TimeUnit.class, "MICROSECONDS"));
     }
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/converter/EnumConverterTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/converter/EnumConverterTest.java
index 9981c70f0f18..ccfaf995daeb 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/converter/EnumConverterTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/converter/EnumConverterTest.java
@@ -139,4 +139,14 @@ public class EnumConverterTest extends ContextTestSupport {
         GET_USERS_BY_TOPIC
     }
 
+    @Test
+    public void testEnumPreferExactMatch() {
+        assertSame(CaseEnum.a, 
context.getTypeConverter().convertTo(CaseEnum.class, "a"));
+        assertSame(CaseEnum.A, 
context.getTypeConverter().convertTo(CaseEnum.class, "A"));
+    }
+
+    public enum CaseEnum {
+        a,
+        A
+    }
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/converter/FutureConverterTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/converter/FutureConverterTest.java
index d93a04e19023..a059ea5cbdcc 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/converter/FutureConverterTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/converter/FutureConverterTest.java
@@ -17,11 +17,13 @@
 package org.apache.camel.converter;
 
 import java.sql.Timestamp;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
 
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.Exchange;
 import org.apache.camel.NoTypeConversionAvailableException;
+import org.apache.camel.TypeConversionException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.support.DefaultExchange;
 import org.junit.jupiter.api.Test;
@@ -30,6 +32,7 @@ import org.junit.jupiter.api.parallel.Isolated;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 @Isolated
 public class FutureConverterTest extends ContextTestSupport {
@@ -113,4 +116,20 @@ public class FutureConverterTest extends 
ContextTestSupport {
             }
         };
     }
+
+    @Test
+    public void testConvertInterruptedFuture() {
+        Future<String> future = new CompletableFuture<>() {
+            @Override
+            public String get() throws InterruptedException {
+                throw new InterruptedException("Interrupted");
+            }
+        };
+        Exchange exchange = new DefaultExchange(context);
+
+        assertThrows(TypeConversionException.class,
+                () -> context.getTypeConverter().convertTo(String.class, 
exchange, future));
+        // the interrupted flag should be restored (and interrupted() clears 
it again)
+        assertTrue(Thread.interrupted());
+    }
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/converter/NIOConverterTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/converter/NIOConverterTest.java
index a8bf1349b9de..2246d0e9a181 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/converter/NIOConverterTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/converter/NIOConverterTest.java
@@ -223,4 +223,14 @@ class NIOConverterTest extends ContextTestSupport {
         assertEquals("Hello", IOConverter.toString(is, null));
     }
 
+    @Test
+    public void testToByteBufferWithCharsetHeader() {
+        Exchange exchange = 
context.getEndpoint("direct:start").createExchange();
+        exchange.getIn().setHeader(Exchange.CHARSET_NAME, "UTF-16BE");
+
+        ByteBuffer bb = NIOConverter.toByteBuffer("A", exchange);
+        assertEquals(2, bb.remaining());
+        assertEquals(0, bb.get());
+        assertEquals('A', bb.get());
+    }
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/impl/converter/CoreTypeConverterRegistryTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/impl/converter/CoreTypeConverterRegistryTest.java
index 35d4144a4b6d..b8e2906c90c0 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/impl/converter/CoreTypeConverterRegistryTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/impl/converter/CoreTypeConverterRegistryTest.java
@@ -21,6 +21,7 @@ import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.Exchange;
@@ -244,4 +245,16 @@ public class CoreTypeConverterRegistryTest extends 
ContextTestSupport {
             return type.cast(new Foo(name));
         }
     }
+
+    @Test
+    public void testArrayToCollectionTypes() {
+        TypeConverter tc = context.getTypeConverter();
+
+        assertInstanceOf(List.class, tc.convertTo(List.class, new String[] { 
"a", "b" }));
+        assertInstanceOf(ArrayList.class, tc.convertTo(ArrayList.class, new 
String[] { "a", "b" }));
+        assertInstanceOf(List.class, tc.convertTo(List.class, new int[] { 1, 2 
}));
+        // a set is not a list
+        assertInstanceOf(Set.class, tc.convertTo(Set.class, new String[] { 
"a", "b" }));
+        assertNull(tc.convertTo(Set.class, new int[] { 1, 2 }));
+    }
 }

Reply via email to