orpiske commented on code in PR #11225:
URL: https://github.com/apache/camel/pull/11225#discussion_r1309934391


##########
core/camel-base/src/main/java/org/apache/camel/impl/converter/TypeResolverHelper.java:
##########
@@ -0,0 +1,192 @@
+/*
+ * 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.impl.converter;
+
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.camel.TypeConverter;
+import org.apache.camel.converter.TypeConvertible;
+
+/**
+ * Helper methods for resolving the type conversions. This is an internal API 
and not meant for public usages.
+ *
+ * In a broader sense: the methods of this code help with traversing the class 
hierarchy of the types involved in a
+ * conversion, so that the correct TypeConverter can be used. This is a helper 
class to CoreTypeConverterRegistry.
+ *
+ * In the CoreTypeConverterRegistry class, the registry of types if maintained 
in a ConcurrentMap that associates a type
+ * pair with the resolver for it (i.e.: it associates pair representing a 
conversion from String to Integer to a type
+ * converter - such as CamelBaseBulkConverterLoader).
+ *
+ * NOTE 1: a lot of this code is in the hot path of the core engine, so change 
with extreme caution to prevent
+ * performance issues on the core code.
+ *
+ * NOTE 2: also, a lot of this code runs rather slow operations, so calling 
these methods should be avoided as much as
+ * possible
+ *
+ */
+final class TypeResolverHelper {
+    private TypeResolverHelper() {
+
+    }
+
+    /**
+     * Lookup the type converter in the registry (given a type to convert to 
and a type to convert from, along with a
+     * mapping of all known converters)
+     *
+     * @param  toType     the type to convert to
+     * @param  fromType   the type to convert from
+     * @param  converters the map of all known converters
+     * @return            the type converter or null if unknown
+     */
+    static TypeConverter doLookup(
+            Class<?> toType, Class<?> fromType, Map<TypeConvertible<?, ?>, 
TypeConverter> converters) {
+        return doLookup(new TypeConvertible<>(fromType, toType), converters);
+    }
+
+    private static TypeConverter doLookup(
+            TypeConvertible<?, ?> typeConvertible, Map<TypeConvertible<?, ?>, 
TypeConverter> converters) {
+
+        // try with base converters first
+        final TypeConverter typeConverter = converters.get(typeConvertible);
+        if (typeConverter != null) {
+            return typeConverter;
+        }
+
+        final TypeConverter superConverterTc = tryMatch(typeConvertible, 
converters);
+        if (superConverterTc != null) {
+            return superConverterTc;
+        }
+
+        final TypeConverter arrayConverterTc = 
tryObjectArrayConverters(typeConvertible, converters);
+        if (arrayConverterTc != null) {
+            return arrayConverterTc;
+        }
+
+        final TypeConverter primitiveAwareConverter = 
tryPrimitive(typeConvertible, converters);
+        if (primitiveAwareConverter != null) {
+            return primitiveAwareConverter;
+        }
+
+        // only do these tests as fallback and only on the target type
+        if (!typeConvertible.getFrom().equals(Object.class)) {
+
+            final TypeConverter assignableConverter
+                    = tryAssignableFrom(typeConvertible, converters);
+            if (assignableConverter != null) {
+                return assignableConverter;
+            }
+
+            final TypeConverter objConverter = converters.get(new 
TypeConvertible<>(Object.class, typeConvertible.getTo()));
+            if (objConverter != null) {
+                return objConverter;
+            }
+        }
+
+        // none found
+        return null;
+    }
+
+    /**
+     * Try the base converters. That is, those matching a direct conversion 
(i.e.: when the from and to types requested
+     * do exist on the converters' map OR when the from and to types requested 
match for a _primitive type).
+     *
+     * For instance: From String.class, To: int.class (would match a method 
such as myConverter(String, Integer) or
+     * myConverter(String, int).
+     *
+     * @param  typeConvertible the type converter pair
+     * @param  converters      the map of all known converters
+     * @return                 the type converter or null if unknown
+     */
+    static TypeConverter tryAssignableFrom(
+            TypeConvertible<?, ?> typeConvertible, Map<TypeConvertible<?, ?>, 
TypeConverter> converters) {
+
+        /*
+         Let's try classes derived from this toType: basically it traverses 
the entries looking for assignable types
+         matching both the "from type" and the "to type" which are NOT Object 
(we usually try this later).
+         */
+        final Optional<Map.Entry<TypeConvertible<?, ?>, TypeConverter>> first 
= converters.entrySet().stream()
+                .filter(v -> v.getKey().isAssignableMatch(typeConvertible))
+                .findFirst();
+
+        return first.map(Map.Entry::getValue).orElse(null);
+    }
+
+    /**
+     * Try to resolve a TypeConverter by looking at Array matches for a given 
"from" type. This also includes evaluating
+     * candidates matching a receiver of Object[] type.
+     *
+     * @param  typeConvertible the type converter pair
+     * @param  converters      the map of all known converters
+     * @return                 the type converter or null if unknown
+     */
+    static TypeConverter tryObjectArrayConverters(
+            TypeConvertible<?, ?> typeConvertible, Map<TypeConvertible<?, ?>, 
TypeConverter> converters) {
+
+        return tryObjectArrayConverters(typeConvertible.getFrom(), 
typeConvertible.getTo(), converters);
+    }
+
+    private static TypeConverter tryObjectArrayConverters(
+            Class<?> fromType, Class<?> toType, Map<TypeConvertible<?, ?>, 
TypeConverter> converters) {
+        // Let the fallback converters handle the primitive arrays
+        if (fromType.isArray() && !fromType.getComponentType().isPrimitive()) {
+            /* We usually define our converters are receiving an object array 
(Object[]), however, this won't easily match:
+             * because an object array is not an interface or a super class of 
other array types (i.e.: not a super class
+             * of String[]). So, we take the direct road here and try check 
for an object array converter right away.
+             */
+            return converters.get(new TypeConvertible<>(Object[].class, 
toType));
+        }
+
+        return null;
+    }
+
+    /**
+     * Try to resolve the TypeConverter by forcing a costly and slow recursive 
check.
+     *
+     * @param  typeConvertible the type converter pair
+     * @param  converters      the map of all known converters
+     * @return                 the type converter or null if unknown
+     */
+    static TypeConverter tryMatch(
+            TypeConvertible<?, ?> typeConvertible, Map<TypeConvertible<?, ?>, 
TypeConverter> converters) {

Review Comment:
   There's indications that the plain loop is better as it creates less objects 
and all that. So, I changed to a loop as you suggested.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@camel.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to