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 4f1c8337a09 CAMEL-19898: camel-core - Optimize StreamCaching strategy 
to skip con… (#18191)
4f1c8337a09 is described below

commit 4f1c8337a096fbb7f5d032cff273bda68d8b15bd
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Tue May 27 14:54:30 2025 +0200

    CAMEL-19898: camel-core - Optimize StreamCaching strategy to skip con… 
(#18191)
    
    * CAMEL-19898: camel-core - Optimize StreamCaching strategy to skip 
conversion for well known types and do fast lookup of dedicated StreamCache 
converters, to bypass regular type converter.
---
 .../apache/camel/spi/TypeConverterRegistry.java    | 13 +++--
 .../impl/engine/DefaultStreamCachingStrategy.java  | 60 +++++++++++++++++-----
 .../impl/converter/CoreTypeConverterRegistry.java  | 13 +++++
 ...TypeConverterRegistryStatisticsEnabledTest.java |  4 +-
 .../ManagedTypeConverterRegistryTest.java          |  4 +-
 .../ROOT/pages/camel-4x-upgrade-guide-4_13.adoc    |  5 ++
 6 files changed, 80 insertions(+), 19 deletions(-)

diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/TypeConverterRegistry.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/TypeConverterRegistry.java
index 979a37acfe3..58667314a9a 100644
--- 
a/core/camel-api/src/main/java/org/apache/camel/spi/TypeConverterRegistry.java
+++ 
b/core/camel-api/src/main/java/org/apache/camel/spi/TypeConverterRegistry.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.spi;
 
+import java.util.Map;
 import java.util.function.LongConsumer;
 import java.util.function.LongSupplier;
 
@@ -125,6 +126,14 @@ public interface TypeConverterRegistry extends 
StaticService, CamelContextAware
      */
     TypeConverter lookup(Class<?> toType, Class<?> fromType);
 
+    /**
+     * Lookup the type converters that can convert to a given type
+     *
+     * @param  toType the type to convert to
+     * @return        the type converters that can convert from
+     */
+    Map<Class<?>, TypeConverter> lookup(Class<?> toType);
+
     /**
      * Sets the injector to be used for creating new instances during type 
conversions.
      *
@@ -189,8 +198,6 @@ public interface TypeConverterRegistry extends 
StaticService, CamelContextAware
      * @param typeConvertible A type convertible pair
      * @param typeConverter   The type converter to associate with the type 
convertible pair
      */
-    default void addConverter(TypeConvertible<?, ?> typeConvertible, 
TypeConverter typeConverter) {
-
-    }
+    void addConverter(TypeConvertible<?, ?> typeConvertible, TypeConverter 
typeConverter);
 
 }
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultStreamCachingStrategy.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultStreamCachingStrategy.java
index d22e9aa0712..c335a76eb5e 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultStreamCachingStrategy.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultStreamCachingStrategy.java
@@ -33,6 +33,7 @@ import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.StreamCache;
+import org.apache.camel.TypeConverter;
 import org.apache.camel.spi.StreamCachingStrategy;
 import org.apache.camel.support.TempDirHelper;
 import org.apache.camel.support.service.ServiceSupport;
@@ -46,12 +47,17 @@ import org.slf4j.LoggerFactory;
  */
 public class DefaultStreamCachingStrategy extends ServiceSupport implements 
CamelContextAware, StreamCachingStrategy {
 
+    // stream cache type converters
+    private record CoreConverter(Class<?> from, TypeConverter converter) {
+    }
+
     private static final Logger LOG = 
LoggerFactory.getLogger(DefaultStreamCachingStrategy.class);
 
     private CamelContext camelContext;
     private boolean enabled;
     private String allowClassNames;
     private String denyClassNames;
+    private final Collection<CoreConverter> coreConverters = new ArrayList<>();
     private Collection<Class<?>> allowClasses;
     private Collection<Class<?>> denyClasses;
     private boolean spoolEnabled;
@@ -269,15 +275,33 @@ public class DefaultStreamCachingStrategy extends 
ServiceSupport implements Came
         StreamCache cache = null;
         // try convert to stream cache
         if (body != null) {
+            // fast skip some common types that should never be converted
+            if (body instanceof String) {
+                return null;
+            } else if (body instanceof byte[]) {
+                return null;
+            } else if (body instanceof Boolean) {
+                return null;
+            } else if (body instanceof Number) {
+                return null;
+            }
+            Class<?> type = body.getClass();
+            if (type.isPrimitive() || type.isEnum()) {
+                return null;
+            }
+
             boolean allowed = allowClasses == null && denyClasses == null;
             if (!allowed) {
-                allowed = checkAllowDenyList(body);
+                allowed = checkAllowDenyList(type);
             }
             if (allowed) {
-                if (exchange != null) {
-                    cache = 
camelContext.getTypeConverter().convertTo(StreamCache.class, exchange, body);
-                } else {
-                    cache = 
camelContext.getTypeConverter().convertTo(StreamCache.class, body);
+                TypeConverter tc = lookupTypeConverter(type);
+                if (tc != null) {
+                    if (exchange != null) {
+                        cache = tc.convertTo(StreamCache.class, exchange, 
body);
+                    } else {
+                        cache = tc.convertTo(StreamCache.class, body);
+                    }
                 }
             }
         }
@@ -292,22 +316,30 @@ public class DefaultStreamCachingStrategy extends 
ServiceSupport implements Came
         return cache;
     }
 
-    private boolean checkAllowDenyList(Object body) {
+    private TypeConverter lookupTypeConverter(Class<?> type) {
+        for (var tc : coreConverters) {
+            if (tc.from().isAssignableFrom(type)) {
+                return tc.converter();
+            }
+        }
+        return null;
+    }
+
+    private boolean checkAllowDenyList(Class<?> type) {
         boolean allowed;
-        Class<?> source = body.getClass();
         if (denyClasses != null && allowClasses != null) {
             // deny takes precedence
-            allowed = !isAssignableFrom(source, denyClasses);
+            allowed = !isAssignableFrom(type, denyClasses);
             if (allowed) {
-                allowed = isAssignableFrom(source, allowClasses);
+                allowed = isAssignableFrom(type, allowClasses);
             }
         } else if (denyClasses != null) {
-            allowed = !isAssignableFrom(source, denyClasses);
+            allowed = !isAssignableFrom(type, denyClasses);
         } else {
-            allowed = isAssignableFrom(source, allowClasses);
+            allowed = isAssignableFrom(type, allowClasses);
         }
         if (LOG.isTraceEnabled()) {
-            LOG.trace("Cache stream from class: {} is {}", source, allowed ? 
"allowed" : "denied");
+            LOG.trace("Cache stream from class: {} is {}", type, allowed ? 
"allowed" : "denied");
         }
         return allowed;
     }
@@ -340,6 +372,10 @@ public class DefaultStreamCachingStrategy extends 
ServiceSupport implements Came
             return;
         }
 
+        // find core type converters that can convert to StreamCache
+        var set = 
getCamelContext().getTypeConverterRegistry().lookup(StreamCache.class).entrySet();
+        set.forEach(e -> coreConverters.add(new CoreConverter(e.getKey(), 
e.getValue())));
+
         if (allowClassNames != null) {
             if (allowClasses == null) {
                 allowClasses = new ArrayList<>();
diff --git 
a/core/camel-base/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterRegistry.java
 
b/core/camel-base/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterRegistry.java
index e6cc5048980..47494e5efc3 100644
--- 
a/core/camel-base/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterRegistry.java
+++ 
b/core/camel-base/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterRegistry.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.impl.converter;
 
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -565,6 +566,18 @@ public abstract class CoreTypeConverterRegistry extends 
ServiceSupport implement
         return doLookup(toType, fromType);
     }
 
+    @Override
+    public Map<Class<?>, TypeConverter> lookup(Class<?> toType) {
+        Map<Class<?>, TypeConverter> answer = new LinkedHashMap<>();
+        for (var e : converters.entrySet()) {
+            Class<?> target = e.getKey().getTo();
+            if (target == toType) {
+                answer.put(e.getKey().getFrom(), e.getValue());
+            }
+        }
+        return answer;
+    }
+
     @Deprecated(since = "4.0.0")
     protected TypeConverter getOrFindTypeConverter(Class<?> toType, Class<?> 
fromType) {
         TypeConvertible<?, ?> typeConvertible = new 
TypeConvertible<>(fromType, toType);
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/impl/TypeConverterRegistryStatisticsEnabledTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/impl/TypeConverterRegistryStatisticsEnabledTest.java
index 0a9dec58add..25a71a1b1fa 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/impl/TypeConverterRegistryStatisticsEnabledTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/impl/TypeConverterRegistryStatisticsEnabledTest.java
@@ -48,7 +48,7 @@ public class TypeConverterRegistryStatisticsEnabledTest 
extends ContextTestSuppo
         long failed = reg.getStatistics().getFailedCounter();
         assertEquals(0, (int) failed);
         long miss = reg.getStatistics().getMissCounter();
-        assertEquals(4, (int) miss); // stream caching misses
+        assertEquals(0, (int) miss);
 
         assertThrows(Exception.class, () -> template.sendBody("direct:start", 
"foo"),
                 "Should have thrown exception");
@@ -57,7 +57,7 @@ public class TypeConverterRegistryStatisticsEnabledTest 
extends ContextTestSuppo
         failed = reg.getStatistics().getFailedCounter();
         assertEquals(1, (int) failed);
         miss = reg.getStatistics().getMissCounter();
-        assertEquals(5, (int) miss); // stream caching misses
+        assertEquals(0, (int) miss);
 
         // reset
         reg.getStatistics().reset();
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedTypeConverterRegistryTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedTypeConverterRegistryTest.java
index 5f91f325353..979cb676be0 100644
--- 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedTypeConverterRegistryTest.java
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedTypeConverterRegistryTest.java
@@ -80,7 +80,7 @@ public class ManagedTypeConverterRegistryTest extends 
ManagementTestSupport {
         Long failed = (Long) mbeanServer.getAttribute(name, "FailedCounter");
         assertEquals(0, failed.intValue());
         Long miss = (Long) mbeanServer.getAttribute(name, "MissCounter");
-        assertEquals(2, miss.intValue());  // stream caching misses
+        assertEquals(0, miss.intValue());
 
         // reset
         mbeanServer.invoke(name, "resetTypeConversionCounters", null, null);
@@ -96,7 +96,7 @@ public class ManagedTypeConverterRegistryTest extends 
ManagementTestSupport {
         failed = (Long) mbeanServer.getAttribute(name, "FailedCounter");
         assertEquals(1, failed.intValue());
         miss = (Long) mbeanServer.getAttribute(name, "MissCounter");
-        assertEquals(1, miss.intValue());  // stream caching misses
+        assertEquals(0, miss.intValue());
 
         // reset
         mbeanServer.invoke(name, "resetTypeConversionCounters", null, null);
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_13.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_13.adoc
index 0049ee16f5a..d417a21ba1e 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_13.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_13.adoc
@@ -6,6 +6,11 @@ from both 4.0 to 4.1 and 4.1 to 4.2.
 
 == Upgrading Camel 4.12 to 4.13
 
+=== camel-core
+
+Added a 2nd `lookup` method to `org.apache.camel.spi.TypeConverterRegistry` 
and changed the `addConverter` to no longer have
+an empty default noop implementation in the interface.
+
 === camel-http
 
 Renamed class 
`org.apache.camel.component.http.BasicAuthenticationHttpClientConfigurer` to 
`org.apache.camel.component.http.DefaultAuthenticationHttpClientConfigurer`.

Reply via email to