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

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

commit 8e997d0f51989af383556f597a1c3ef0de0b1c62
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Tue May 27 12:09:30 2025 +0200

    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  | 59 +++++++++++++++++-----
 .../impl/converter/CoreTypeConverterRegistry.java  | 13 +++++
 ...TypeConverterRegistryStatisticsEnabledTest.java |  4 +-
 .../ManagedTypeConverterRegistryTest.java          |  4 +-
 .../ROOT/pages/camel-4x-upgrade-guide-4_13.adoc    |  5 ++
 6 files changed, 79 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..a16f2a217c9 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
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Lock;
@@ -33,6 +34,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;
@@ -52,6 +54,7 @@ public class DefaultStreamCachingStrategy extends 
ServiceSupport implements Came
     private boolean enabled;
     private String allowClassNames;
     private String denyClassNames;
+    private Map<Class<?>, TypeConverter> coreConverters;
     private Collection<Class<?>> allowClasses;
     private Collection<Class<?>> denyClasses;
     private boolean spoolEnabled;
@@ -269,15 +272,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 +313,33 @@ public class DefaultStreamCachingStrategy extends 
ServiceSupport implements Came
         return cache;
     }
 
-    private boolean checkAllowDenyList(Object body) {
+    private TypeConverter lookupTypeConverter(Class<?> type) {
+        if (coreConverters != null) {
+            for (var tc : coreConverters.entrySet()) {
+                Class<?> clazz = tc.getKey();
+                if (clazz.isAssignableFrom(type)) {
+                    return tc.getValue();
+                }
+            }
+        }
+        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,9 @@ public class DefaultStreamCachingStrategy extends 
ServiceSupport implements Came
             return;
         }
 
+        // find core type converters that can convert to StreamCache
+        this.coreConverters = 
getCamelContext().getTypeConverterRegistry().lookup(StreamCache.class);
+
         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..375b314d6d2 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.HashMap;
 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 HashMap<>();
+        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 04865c0397c..797274e7990 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