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

gnodet pushed a commit to branch sandbox/camel-3.x
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 9a3de64451939b021e550a6e82fdd365c8988d68
Author: Guillaume Nodet <gno...@gmail.com>
AuthorDate: Mon Oct 29 22:33:02 2018 +0100

    Use statically generated type converter for core converters and optimize 
the converter registry
    
    Before
    ------
    Benchmark                                           Mode  Cnt    Score    
Error  Units
    ConverterBenchmark.benchmarkConversionIntToLong          avgt    5   17,861 
±  1,333  us/op
    ConverterBenchmark.benchmarkConversionListToStringArray  avgt    5   90,854 
± 21,918  us/op
    ConverterBenchmark.benchmarkConversionStringToChar       avgt    5   27,644 
±  1,563  us/op
    ConverterBenchmark.benchmarkConversionStringToURI        avgt    5  157,240 
± 11,084  us/op
    ConverterBenchmark.benchmarkConversionTimeEnum           avgt    5   73,541 
± 10,457  us/op
    ConverterBenchmark.benchmarkLoadTime                     avgt    5  586,724 
± 73,011  us/op
    
    After
    -----
    Benchmark                                           Mode  Cnt    Score    
Error  Units
    ConverterBenchmark.benchmarkConversionIntToLong          avgt    5   13,242 
±  0,041  us/op
    ConverterBenchmark.benchmarkConversionListToStringArray  avgt    5   50,731 
±  2,220  us/op
    ConverterBenchmark.benchmarkConversionStringToChar       avgt    5   24,443 
±  1,268  us/op
    ConverterBenchmark.benchmarkConversionStringToURI        avgt    5   98,887 
±  6,203  us/op
    ConverterBenchmark.benchmarkConversionTimeEnum           avgt    5   35,148 
±  1,820  us/op
    ConverterBenchmark.benchmarkLoadTime                     avgt    5  551,463 
± 12,174  us/op
---
 .../main/java/org/apache/camel/TypeConverter.java  |   2 +
 camel-core/pom.xml                                 |  12 +
 .../apache/camel/component/bean/BeanConverter.java |   4 +-
 .../camel/converter/IOConverterOptimised.java      | 172 -------
 .../camel/converter/NIOConverterOptimised.java     |  82 ----
 .../apache/camel/converter/ObjectConverter.java    | 165 +++----
 .../camel/converter/ObjectConverterOptimised.java  |  84 ----
 .../converter/TimePatternConverterOptimised.java   |  42 --
 .../impl/converter/BaseTypeConverterRegistry.java  | 529 +++++++++++----------
 .../converter/CorePackageScanClassResolver.java    | 125 -----
 .../impl/converter/CoreTypeConverterLoader.java    |  39 --
 .../camel/impl/converter/EnumTypeConverter.java    |   6 +-
 .../camel/impl/converter/FutureTypeConverter.java  |   4 +-
 .../impl/converter/OptimisedTypeConverter.java     |  77 ---
 .../impl/converter/ToStringTypeConverter.java      |   8 +-
 .../apache/camel/builder/SimpleBuilderTest.java    |   2 +-
 .../apache/camel/builder/xml/XPathFeatureTest.java |   6 +-
 .../apache/camel/converter/ConverterBenchmark.java | 160 +++++++
 .../org/apache/camel/converter/ConverterTest.java  |  20 +
 .../camel/converter/DurationConverterTest.java     |   2 +-
 .../camel/converter/ObjectConverterTest.java       |  24 +-
 .../java/org/apache/camel/util/ObjectHelper.java   |  10 +-
 .../component/cxf/converter/CxfConverter.java      |   6 +-
 .../cxf/converter/CxfPayloadConverter.java         |  12 +-
 .../camel/component/exec/ExecResultConverter.java  |   4 +-
 .../camel/component/jetty/JettyConverter.java      |   4 +-
 .../apache/camel/tools/apt/ConverterProcessor.java | 159 +++++--
 27 files changed, 712 insertions(+), 1048 deletions(-)

diff --git a/camel-api/src/main/java/org/apache/camel/TypeConverter.java 
b/camel-api/src/main/java/org/apache/camel/TypeConverter.java
index 1f1fe5b..1222d0e 100644
--- a/camel-api/src/main/java/org/apache/camel/TypeConverter.java
+++ b/camel-api/src/main/java/org/apache/camel/TypeConverter.java
@@ -25,6 +25,8 @@ package org.apache.camel;
  */
 public interface TypeConverter {
 
+    Object MISS_VALUE = Void.TYPE;
+
     /**
      * Whether the type converter allows returning null as a valid response.
      * <p/>
diff --git a/camel-core/pom.xml b/camel-core/pom.xml
index 4bda334..51c6e83 100644
--- a/camel-core/pom.xml
+++ b/camel-core/pom.xml
@@ -203,6 +203,18 @@
       </exclusions>
     </dependency>
     <dependency>
+      <groupId>org.openjdk.jmh</groupId>
+      <artifactId>jmh-core</artifactId>
+      <version>1.21</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.openjdk.jmh</groupId>
+      <artifactId>jmh-generator-annprocess</artifactId>
+      <version>1.21</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.hamcrest</groupId>
       <artifactId>java-hamcrest</artifactId>
       <version>${hamcrest-version}</version>
diff --git 
a/camel-core/src/main/java/org/apache/camel/component/bean/BeanConverter.java 
b/camel-core/src/main/java/org/apache/camel/component/bean/BeanConverter.java
index 6ca7403..fc85841 100644
--- 
a/camel-core/src/main/java/org/apache/camel/component/bean/BeanConverter.java
+++ 
b/camel-core/src/main/java/org/apache/camel/component/bean/BeanConverter.java
@@ -22,6 +22,8 @@ import org.apache.camel.FallbackConverter;
 import org.apache.camel.TypeConverter;
 import org.apache.camel.spi.TypeConverterRegistry;
 
+import static org.apache.camel.TypeConverter.MISS_VALUE;
+
 /**
  * A set of converter methods for working with beans
  */
@@ -40,7 +42,7 @@ public final class BeanConverter {
             BeanInvocation bi = (BeanInvocation) value;
             if (bi.getArgs() == null || bi.getArgs().length != 1) {
                 // not possible to convert at this time as we try to convert 
the data passed in at first argument
-                return Void.TYPE;
+                return MISS_VALUE;
             }
 
             Class<?> from = bi.getArgs()[0].getClass();
diff --git 
a/camel-core/src/main/java/org/apache/camel/converter/IOConverterOptimised.java 
b/camel-core/src/main/java/org/apache/camel/converter/IOConverterOptimised.java
deleted file mode 100644
index cddbb03..0000000
--- 
a/camel-core/src/main/java/org/apache/camel/converter/IOConverterOptimised.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * 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.converter;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.InputStream;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-import java.net.URL;
-import java.util.Properties;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.StreamCache;
-
-/**
- * Optimised {@link IOConverter}
- */
-public final class IOConverterOptimised {
-
-    private IOConverterOptimised() {
-    }
-
-    // CHECKSTYLE:OFF
-    public static Object convertTo(final Class<?> type, final Exchange 
exchange, final Object value) throws Exception {
-        Class fromType = value.getClass();
-
-        // if the value is StreamCache then ensure its readable before doing 
conversions
-        // by resetting it (this is also what StreamCachingAdvice does)
-        if (value instanceof StreamCache) {
-            ((StreamCache) value).reset();
-        }
-
-        if (type == InputStream.class) {
-            if (fromType == String.class) {
-                return IOConverter.toInputStream((String) value, exchange);
-            } else if (fromType == URL.class) {
-                return IOConverter.toInputStream((URL) value);
-            } else if (fromType == File.class) {
-                return IOConverter.toInputStream((File) value);
-            } else if (fromType == byte[].class) {
-                return IOConverter.toInputStream((byte[]) value);
-            } else if (fromType == ByteArrayOutputStream.class) {
-                return IOConverter.toInputStream((ByteArrayOutputStream) 
value);
-            } else if (fromType == BufferedReader.class) {
-                return IOConverter.toInputStream((BufferedReader) value, 
exchange);
-            } else if (fromType == StringBuilder.class) {
-                return IOConverter.toInputStream((StringBuilder) value, 
exchange);
-            }
-            return null;
-        }
-
-        if (type == Reader.class) {
-            if (fromType == File.class) {
-                return IOConverter.toReader((File) value, exchange);
-            } else if (fromType == String.class) {
-                return IOConverter.toReader((String) value);
-            } else if (InputStream.class.isAssignableFrom(fromType)) {
-                return IOConverter.toReader((InputStream) value, exchange);
-            }
-            return null;
-        }
-
-        if (type == File.class) {
-            if (fromType == String.class) {
-                return IOConverter.toFile((String) value);
-            }
-            return null;
-        }
-
-        if (type == OutputStream.class) {
-            if (fromType == File.class) {
-                return IOConverter.toOutputStream((File) value);
-            }
-            return null;
-        }
-
-        if (type == Writer.class) {
-            if (fromType == File.class) {
-                return IOConverter.toWriter((File) value, exchange);
-            } else if (OutputStream.class.isAssignableFrom(fromType)) {
-                return IOConverter.toWriter((OutputStream) value, exchange);
-            }
-            return null;
-        }
-
-        if (type == String.class) {
-            if (fromType == byte[].class) {
-                return IOConverter.toString((byte[]) value, exchange);
-            } else if (fromType == File.class) {
-                return IOConverter.toString((File) value, exchange);
-            } else if (fromType == URL.class) {
-                return IOConverter.toString((URL) value, exchange);
-            } else if (fromType == BufferedReader.class) {
-                return IOConverter.toString((BufferedReader) value);
-            } else if (Reader.class.isAssignableFrom(fromType)) {
-                return IOConverter.toString((Reader) value);
-            } else if (InputStream.class.isAssignableFrom(fromType)) {
-                return IOConverter.toString((InputStream) value, exchange);
-            } else if (fromType == ByteArrayOutputStream.class) {
-                return IOConverter.toString((ByteArrayOutputStream) value, 
exchange);
-            }
-            return null;
-        }
-
-        if (type == byte[].class) {
-            if (fromType == BufferedReader.class) {
-                return IOConverter.toByteArray((BufferedReader) value, 
exchange);
-            } else if (Reader.class.isAssignableFrom(fromType)) {
-                return IOConverter.toByteArray((Reader) value, exchange);
-            } else if (fromType == File.class) {
-                return IOConverter.toByteArray((File) value);
-            } else if (fromType == String.class) {
-                return IOConverter.toByteArray((String) value, exchange);
-            } else if (fromType == ByteArrayOutputStream.class) {
-                return IOConverter.toByteArray((ByteArrayOutputStream) value);
-            } else if (InputStream.class.isAssignableFrom(fromType)) {
-                return IOConverter.toBytes((InputStream) value);
-            }
-            return null;
-        }
-
-        if (type == ObjectInput.class) {
-            if (fromType == InputStream.class || fromType == 
BufferedInputStream.class) {
-                return IOConverter.toObjectInput((InputStream) value, 
exchange);
-            }
-            return null;
-        }
-
-        if (type == ObjectOutput.class) {
-            if (fromType == OutputStream.class) {
-                return IOConverter.toObjectOutput((OutputStream) value);
-            }
-            return null;
-        }
-
-        if (type == Properties.class) {
-            if (fromType == File.class) {
-                return IOConverter.toProperties((File) value);
-            } else if (fromType == InputStream.class) {
-                return IOConverter.toProperties((InputStream) value);
-            } else if (fromType == Reader.class) {
-                return IOConverter.toProperties((Reader) value);
-            }
-            return null;
-        }
-
-        // no optimised type converter found
-        return null;
-    }
-    // CHECKSTYLE:ON
-
-}
diff --git 
a/camel-core/src/main/java/org/apache/camel/converter/NIOConverterOptimised.java
 
b/camel-core/src/main/java/org/apache/camel/converter/NIOConverterOptimised.java
deleted file mode 100644
index cbef7a9..0000000
--- 
a/camel-core/src/main/java/org/apache/camel/converter/NIOConverterOptimised.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * 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.converter;
-
-import java.io.File;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
-import org.apache.camel.Exchange;
-
-/**
- * Optimised {@link NIOConverter}
- */
-public final class NIOConverterOptimised {
-
-    private NIOConverterOptimised() {
-    }
-
-    public static Object convertTo(final Class<?> type, final Exchange 
exchange, final Object value) throws Exception {
-        Class fromType = value.getClass();
-
-        if (type == String.class) {
-            if (fromType == ByteBuffer.class) {
-                return NIOConverter.toString((ByteBuffer) value, exchange);
-            }
-            return null;
-        }
-
-        if (type == byte[].class) {
-            if (fromType == ByteBuffer.class) {
-                return NIOConverter.toByteArray((ByteBuffer) value);
-            }
-            return null;
-        }
-
-        if (type == InputStream.class) {
-            if (fromType == ByteBuffer.class) {
-                return NIOConverter.toInputStream((ByteBuffer) value);
-            }
-            return null;
-        }
-
-        if (type == ByteBuffer.class) {
-            if (fromType == byte[].class) {
-                return NIOConverter.toByteBuffer((byte[]) value);
-            } else if (fromType == File.class) {
-                return NIOConverter.toByteBuffer((File) value);
-            } else if (fromType == String.class) {
-                return NIOConverter.toByteBuffer((String) value, exchange);
-            } else if (fromType == short.class || fromType == Short.class) {
-                return NIOConverter.toByteBuffer((Short) value);
-            } else if (fromType == int.class || fromType == Integer.class) {
-                return NIOConverter.toByteBuffer((Integer) value);
-            } else if (fromType == long.class || fromType == Long.class) {
-                return NIOConverter.toByteBuffer((Long) value);
-            } else if (fromType == float.class || fromType == Float.class) {
-                return NIOConverter.toByteBuffer((Float) value);
-            } else if (fromType == double.class || fromType == Double.class) {
-                return NIOConverter.toByteBuffer((Double) value);
-            }
-            return null;
-        }
-
-        // no optimised type converter found
-        return null;
-    }
-
-}
diff --git 
a/camel-core/src/main/java/org/apache/camel/converter/ObjectConverter.java 
b/camel-core/src/main/java/org/apache/camel/converter/ObjectConverter.java
index 75f0131..3e326d7 100644
--- a/camel-core/src/main/java/org/apache/camel/converter/ObjectConverter.java
+++ b/camel-core/src/main/java/org/apache/camel/converter/ObjectConverter.java
@@ -76,18 +76,17 @@ public final class ObjectConverter {
     /**
      * Returns the converted value, or null if the value is null
      */
-    @Converter
-    public static Byte toByte(Object value) {
-        if (value instanceof Byte) {
-            return (Byte) value;
-        } else if (value instanceof Number) {
-            Number number = (Number) value;
-            return number.byteValue();
-        } else if (value instanceof String) {
-            return Byte.valueOf((String) value);
-        } else {
+    @Converter(allowNull = true)
+    public static Byte toByte(Number value) {
+        if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
             return null;
         }
+        return value.byteValue();
+    }
+
+    @Converter
+    public static Byte toByte(String value) {
+        return Byte.valueOf(value);
     }
 
     @Converter
@@ -118,85 +117,77 @@ public final class ObjectConverter {
      * Returns the converted value, or null if the value is null
      */
     @Converter
-    public static Class<?> toClass(Object value, Exchange exchange) {
-        if (value instanceof Class) {
-            return (Class<?>) value;
-        } else if (value instanceof String) {
-            // prefer to use class resolver API
-            if (exchange != null) {
-                return 
exchange.getContext().getClassResolver().resolveClass((String) value);
-            } else {
-                return org.apache.camel.util.ObjectHelper.loadClass((String) 
value);
-            }
+    public static Class<?> toClass(String value, Exchange exchange) {
+        // prefer to use class resolver API
+        if (exchange != null) {
+            return 
exchange.getContext().getClassResolver().resolveClass((String) value);
         } else {
-            return null;
+            return org.apache.camel.util.ObjectHelper.loadClass((String) 
value);
         }
     }
 
     /**
      * Returns the converted value, or null if the value is null
      */
-    @Converter
-    public static Short toShort(Object value) {
-        if (value instanceof Short) {
-            return (Short) value;
-        } else if (value instanceof Number) {
-            Number number = (Number) value;
-            return number.shortValue();
-        } else if (value instanceof String) {
-            return Short.valueOf((String) value);
-        } else {
+    @Converter(allowNull = true)
+    public static Short toShort(Number value) {
+        if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
             return null;
         }
+        return value.shortValue();
+    }
+
+    @Converter
+    public static Short toShort(String value) {
+        return Short.valueOf(value);
     }
 
     /**
      * Returns the converted value, or null if the value is null
      */
-    @Converter
-    public static Integer toInteger(Object value) {
-        if (value instanceof Integer) {
-            return (Integer) value;
-        } else if (value instanceof Number) {
-            Number number = (Number) value;
-            return number.intValue();
-        } else if (value instanceof String) {
-            return Integer.valueOf((String) value);
-        } else {
+    @Converter(allowNull = true)
+    public static Integer toInteger(Number value) {
+        if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
             return null;
         }
+        return value.intValue();
+    }
+
+    @Converter
+    public static Integer toInteger(String value) {
+        return Integer.valueOf(value);
     }
 
     /**
      * Returns the converted value, or null if the value is null
      */
-    @Converter
-    public static Long toLong(Object value) {
-        if (value instanceof Long) {
-            return (Long) value;
-        } else if (value instanceof Number) {
-            Number number = (Number) value;
-            return number.longValue();
-        } else if (value instanceof String) {
-            return Long.valueOf((String) value);
-        } else {
+    @Converter(allowNull = true)
+    public static Long toLong(Number value) {
+        if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
             return null;
         }
+        return value.longValue();
+    }
+
+    @Converter
+    public static Long toLong(String value) {
+        return Long.valueOf(value);
     }
 
     /**
      * Returns the converted value, or null if the value is null
      */
-    @Converter
+    @Converter(allowNull = true)
     public static BigInteger toBigInteger(Object value) {
+        if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
+            return null;
+        }
         if (value instanceof String) {
             return new BigInteger((String) value);
         }
 
         Long num = null;
-        if (value instanceof Long) {
-            num = (Long) value;
-        } else if (value instanceof Number) {
+        if (value instanceof Number) {
             Number number = (Number) value;
             num = number.longValue();
         }
@@ -211,40 +202,32 @@ public final class ObjectConverter {
      * Returns the converted value, or null if the value is null
      */
     @Converter
-    public static Float toFloat(Object value) {
-        if (value instanceof Float) {
-            return (Float) value;
-        } else if (value instanceof Number) {
-            if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
-                return Float.NaN;
-            }
-            Number number = (Number) value;
-            return number.floatValue();
-        } else if (value instanceof String) {
-            return Float.valueOf((String) value);
-        } else {
-            return null;
+    public static Float toFloat(Number value) {
+        if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
+            return Float.NaN;
         }
+        return value.floatValue();
+    }
+
+    @Converter
+    public static Float toFloat(String value) {
+        return Float.valueOf(value);
     }
 
     /**
      * Returns the converted value, or null if the value is null
      */
     @Converter
-    public static Double toDouble(Object value) {
-        if (value instanceof Double) {
-            return (Double) value;
-        } else if (value instanceof Number) {
-            if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
-                return Double.NaN;
-            }
-            Number number = (Number) value;
-            return number.doubleValue();
-        } else if (value instanceof String) {
-            return Double.valueOf((String) value);
-        } else {
-            return null;
+    public static Double toDouble(Number value) {
+        if (org.apache.camel.util.ObjectHelper.isNaN(value)) {
+            return Double.NaN;
         }
+        return value.doubleValue();
+    }
+
+    @Converter
+    public static Double toDouble(String value) {
+        return Double.valueOf(value);
     }
 
     // add fast type converters from most common used
@@ -275,26 +258,6 @@ public final class ObjectConverter {
     }
 
     @Converter
-    public static Integer toInteger(String value) {
-        return Integer.valueOf(value);
-    }
-
-    @Converter
-    public static Long toLong(String value) {
-        return Long.valueOf(value);
-    }
-
-    @Converter
-    public static Float toFloat(String value) {
-        return Float.valueOf(value);
-    }
-
-    @Converter
-    public static Double toDouble(String value) {
-        return Double.valueOf(value);
-    }
-
-    @Converter
     public static Boolean toBoolean(String value) {
         return Boolean.parseBoolean(value);
     }
diff --git 
a/camel-core/src/main/java/org/apache/camel/converter/ObjectConverterOptimised.java
 
b/camel-core/src/main/java/org/apache/camel/converter/ObjectConverterOptimised.java
deleted file mode 100644
index c6391ed..0000000
--- 
a/camel-core/src/main/java/org/apache/camel/converter/ObjectConverterOptimised.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * 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.converter;
-
-import java.util.Iterator;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.support.ObjectHelper;
-
-/**
- * Optimised {@link ObjectConverter}
- */
-public final class ObjectConverterOptimised {
-
-    private ObjectConverterOptimised() {
-    }
-
-    public static Object convertTo(final Class<?> type, final Exchange 
exchange, final Object value) throws Exception {
-        // converting to a String is very common
-        if (type == String.class) {
-            Class fromType = value.getClass();
-            if (fromType == boolean.class || fromType == Boolean.class) {
-                return value.toString();
-            } else if (fromType == int.class || fromType == Integer.class) {
-                return value.toString();
-            } else if (fromType == long.class || fromType == Long.class) {
-                return value.toString();
-            } else if (fromType == char[].class) {
-                return ObjectConverter.fromCharArray((char[]) value);
-            } else if (fromType == StringBuffer.class || fromType == 
StringBuilder.class) {
-                return value.toString();
-            }
-            return null;
-        }
-
-        if (type == boolean.class || type == Boolean.class) {
-            return ObjectConverter.toBoolean(value);
-        } else if (type == int.class || type == Integer.class) {
-            return ObjectConverter.toInteger(value);
-        } else if (type == long.class || type == Long.class) {
-            return ObjectConverter.toLong(value);
-        } else if (type == byte.class || type == Byte.class) {
-            return ObjectConverter.toByte(value);
-        } else if (type == double.class || type == Double.class) {
-            return ObjectConverter.toDouble(value);
-        } else if (type == float.class || type == Float.class) {
-            return ObjectConverter.toFloat(value);
-        } else if (type == short.class || type == Short.class) {
-            return ObjectConverter.toShort(value);
-        } else if ((type == char.class || type == Character.class) && 
value.getClass() == String.class) {
-            return ObjectConverter.toCharacter((String) value);
-        } else if ((type == char[].class || type == Character[].class) && 
value.getClass() == String.class) {
-            return ObjectConverter.toCharArray((String) value);
-        }
-
-        if (type == Iterator.class) {
-            return ObjectHelper.createIterator(value);
-        } else if (type == Iterable.class) {
-            return ObjectHelper.createIterable(value);
-        }
-
-        if (type == Class.class) {
-            return ObjectConverter.toClass(value, exchange);
-        }
-
-        // no optimised type converter found
-        return null;
-    }
-
-}
diff --git 
a/camel-core/src/main/java/org/apache/camel/converter/TimePatternConverterOptimised.java
 
b/camel-core/src/main/java/org/apache/camel/converter/TimePatternConverterOptimised.java
deleted file mode 100644
index bb45a40..0000000
--- 
a/camel-core/src/main/java/org/apache/camel/converter/TimePatternConverterOptimised.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * 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.converter;
-
-import org.apache.camel.Exchange;
-
-/**
- * Optimised {@link TimePatternConverter}
- */
-public final class TimePatternConverterOptimised {
-
-    private TimePatternConverterOptimised() {
-    }
-
-    public static Object convertTo(final Class<?> type, final Exchange 
exchange, final Object value) throws Exception {
-        // special for String -> long where we support time patterns
-        if (type == long.class || type == Long.class) {
-            Class fromType = value.getClass();
-            if (fromType == String.class) {
-                return TimePatternConverter.toMilliSeconds(value.toString());
-            }
-        }
-
-        // no optimised type converter found
-        return null;
-    }
-
-}
diff --git 
a/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
 
b/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
index 27d90dc..a728621 100644
--- 
a/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
+++ 
b/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
@@ -18,16 +18,13 @@ package org.apache.camel.impl.converter;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.LongAdder;
+import java.util.concurrent.locks.StampedLock;
+import java.util.function.Predicate;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
@@ -43,31 +40,33 @@ import org.apache.camel.TypeConverterExists;
 import org.apache.camel.TypeConverterExistsException;
 import org.apache.camel.TypeConverterLoaderException;
 import org.apache.camel.TypeConverters;
+import org.apache.camel.spi.CamelLogger;
 import org.apache.camel.spi.FactoryFinder;
 import org.apache.camel.spi.Injector;
 import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.TypeConverterAware;
 import org.apache.camel.spi.TypeConverterLoader;
 import org.apache.camel.spi.TypeConverterRegistry;
-import org.apache.camel.spi.CamelLogger;
-import org.apache.camel.support.LRUCacheFactory;
 import org.apache.camel.support.MessageHelper;
 import org.apache.camel.support.ServiceSupport;
+import org.apache.camel.support.TypeConverterSupport;
 import org.apache.camel.util.ObjectHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.camel.util.function.TriConsumer;
 
 /**
  * Base implementation of a type converter registry used for
  * <a href="http://camel.apache.org/type-converter.html";>type converters</a> 
in Camel.
  */
 public abstract class BaseTypeConverterRegistry extends ServiceSupport 
implements TypeConverter, TypeConverterRegistry, CamelContextAware {
-    protected final Logger log = LoggerFactory.getLogger(getClass());
-    protected final OptimisedTypeConverter optimisedTypeConverter = new 
OptimisedTypeConverter();
-    protected final ConcurrentMap<TypeMapping, TypeConverter> typeMappings = 
new ConcurrentHashMap<>();
-    // for misses use a soft reference cache map, as the classes may be 
un-deployed at runtime
-    @SuppressWarnings("unchecked")
-    protected final Map<TypeMapping, TypeMapping> misses = 
LRUCacheFactory.newLRUSoftCache(1000);
+
+    protected static final TypeConverter MISS_CONVERTER = new 
TypeConverterSupport() {
+        @Override
+        public <T> T convertTo(Class<T> type, Exchange exchange, Object value) 
throws TypeConversionException {
+            return (T) MISS_VALUE;
+        }
+    };
+
+    protected final DoubleMap<Class<?>, Class<?>, TypeConverter> typeMappings 
= new DoubleMap<>(200);
     protected final List<TypeConverterLoader> typeConverterLoaders = new 
ArrayList<>();
     protected final List<FallbackTypeConverter> fallbackConverters = new 
CopyOnWriteArrayList<>();
     protected final PackageScanClassResolver resolver;
@@ -130,44 +129,7 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
     @SuppressWarnings("unchecked")
     @Override
     public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
-        if (!isRunAllowed()) {
-            throw new IllegalStateException(this + " is not started");
-        }
-
-        Object answer;
-        try {
-            answer = doConvertTo(type, exchange, value, false);
-        } catch (Exception e) {
-            if (statistics.isStatisticsEnabled()) {
-                failedCounter.increment();
-            }
-            // if its a ExecutionException then we have rethrow it as its not 
due to failed conversion
-            // this is special for FutureTypeConverter
-            boolean execution = 
ObjectHelper.getException(ExecutionException.class, e) != null
-                    || 
ObjectHelper.getException(CamelExecutionException.class, e) != null;
-            if (execution) {
-                throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
-            }
-
-            // error occurred during type conversion
-            if (e instanceof TypeConversionException) {
-                throw (TypeConversionException) e;
-            } else {
-                throw createTypeConversionException(exchange, type, value, e);
-            }
-        }
-        if (answer == Void.TYPE) {
-            if (statistics.isStatisticsEnabled()) {
-                missCounter.increment();
-            }
-            // Could not find suitable conversion
-            return null;
-        } else {
-            if (statistics.isStatisticsEnabled()) {
-                hitCounter.increment();
-            }
-            return (T) answer;
-        }
+        return (T) doConvertTo(type, exchange, value, false, false);
     }
 
     @Override
@@ -178,36 +140,12 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
     @SuppressWarnings("unchecked")
     @Override
     public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object 
value) throws NoTypeConversionAvailableException {
-        if (!isRunAllowed()) {
-            throw new IllegalStateException(this + " is not started");
-        }
-
-        Object answer;
-        try {
-            answer = doConvertTo(type, exchange, value, false);
-        } catch (Exception e) {
-            if (statistics.isStatisticsEnabled()) {
-                failedCounter.increment();
-            }
-            // error occurred during type conversion
-            if (e instanceof TypeConversionException) {
-                throw (TypeConversionException) e;
-            } else {
-                throw createTypeConversionException(exchange, type, value, e);
-            }
-        }
-        if (answer == Void.TYPE || value == null) {
-            if (statistics.isStatisticsEnabled()) {
-                missCounter.increment();
-            }
+        Object answer = doConvertTo(type, exchange, value, true, false);
+        if (answer == null) {
             // Could not find suitable conversion
             throw new NoTypeConversionAvailableException(value, type);
-        } else {
-            if (statistics.isStatisticsEnabled()) {
-                hitCounter.increment();
-            }
-            return (T) answer;
         }
+        return (T) answer;
     }
 
     @Override
@@ -218,20 +156,32 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
     @SuppressWarnings("unchecked")
     @Override
     public <T> T tryConvertTo(Class<T> type, Exchange exchange, Object value) {
-        if (!isRunAllowed()) {
-            return null;
-        }
+        return (T) doConvertTo(type, exchange, value, false, true);
+    }
 
+    protected Object doConvertTo(final Class<?> type, final Exchange exchange, 
final Object value, final boolean mandatory, final boolean tryConvert) {
         Object answer;
         try {
-            answer = doConvertTo(type, exchange, value, true);
+            answer = doConvertTo(type, exchange, value, tryConvert);
         } catch (Exception e) {
             if (statistics.isStatisticsEnabled()) {
                 failedCounter.increment();
             }
-            return null;
+            if (tryConvert) {
+                return null;
+            }
+
+            // if its a ExecutionException then we have rethrow it as its not 
due to failed conversion
+            // this is special for FutureTypeConverter
+            boolean execution = 
ObjectHelper.getException(ExecutionException.class, e) != null
+                    || 
ObjectHelper.getException(CamelExecutionException.class, e) != null;
+            if (execution) {
+                throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
+            }
+            // error occurred during type conversion
+            throw createTypeConversionException(exchange, type, value, e);
         }
-        if (answer == Void.TYPE) {
+        if (answer == MISS_VALUE) {
             // Could not find suitable conversion
             if (statistics.isStatisticsEnabled()) {
                 missCounter.increment();
@@ -241,25 +191,52 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
             if (statistics.isStatisticsEnabled()) {
                 hitCounter.increment();
             }
-            return (T) answer;
+            return answer;
         }
     }
 
     protected Object doConvertTo(final Class<?> type, final Exchange exchange, 
final Object value, final boolean tryConvert) throws Exception {
-        if (log.isTraceEnabled()) {
+        boolean trace = log.isTraceEnabled();
+        boolean statisticsEnabled = statistics.isStatisticsEnabled();
+
+        if (trace) {
             log.trace("Finding type converter to convert {} -> {} with value: 
{}",
-                    new Object[]{value == null ? "null" : 
value.getClass().getCanonicalName(), 
-                        type.getCanonicalName(), value});
+                    value == null ? "null" : 
value.getClass().getCanonicalName(),
+                    type.getCanonicalName(), value);
         }
 
+
         if (value == null) {
             // no type conversion was needed
-            if (statistics.isStatisticsEnabled()) {
+            if (statisticsEnabled) {
                 noopCounter.increment();
             }
-            // lets avoid NullPointerException when converting to boolean for 
null values
-            if (boolean.class == type) {
-                return Boolean.FALSE;
+            // lets avoid NullPointerException when converting to primitives 
for null values
+            if (type.isPrimitive()) {
+                if (boolean.class == type) {
+                    return Boolean.FALSE;
+                }
+                if (int.class == type) {
+                    return 0;
+                }
+                if (long.class == type) {
+                    return 0L;
+                }
+                if (byte.class == type) {
+                    return (byte) 0;
+                }
+                if (short.class == type) {
+                    return (short) 0;
+                }
+                if (double.class == type) {
+                    return 0.0;
+                }
+                if (float.class == type) {
+                    return 0.0f;
+                }
+                if (char.class == type) {
+                    return '\0';
+                }
             }
             return null;
         }
@@ -267,66 +244,33 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
         // same instance type
         if (type.isInstance(value)) {
             // no type conversion was needed
-            if (statistics.isStatisticsEnabled()) {
+            if (statisticsEnabled) {
                 noopCounter.increment();
             }
             return value;
         }
 
-        // special for NaN numbers, which we can only convert for floating 
numbers
-        if ((value instanceof Float && value.equals(Float.NaN)) || (value 
instanceof Double && value.equals(Double.NaN))) {
-            // no type conversion was needed
-            if (statistics.isStatisticsEnabled()) {
-                noopCounter.increment();
-            }
-            if (Float.class.isAssignableFrom(type)) {
-                return Float.NaN;
-            } else if (Double.class.isAssignableFrom(type)) {
-                return Double.NaN;
-            } else {
-                // we cannot convert the NaN
-                return Void.TYPE;
-            }
-        }
-
         // okay we need to attempt to convert
-        if (statistics.isStatisticsEnabled()) {
+        if (statisticsEnabled) {
             attemptCounter.increment();
         }
 
-        // use the optimised core converter first
-        Object result = optimisedTypeConverter.convertTo(type, exchange, 
value);
-        if (result != null) {
-            if (statistics.isStatisticsEnabled()) {
-                baseHitCounter.increment();
-            }
-            if (log.isTraceEnabled()) {
-                log.trace("Using optimised core converter to convert: {} -> 
{}", type, value.getClass().getCanonicalName());
-            }
-            return result;
-        }
-
-        // check if we have tried it before and if its a miss
-        TypeMapping key = new TypeMapping(type, value.getClass());
-        if (misses.containsKey(key)) {
-            // we have tried before but we cannot convert this one
-            return Void.TYPE;
-        }
-        
         // try to find a suitable type converter
-        TypeConverter converter = getOrFindTypeConverter(key);
+        TypeConverter converter = getOrFindTypeConverter(type, 
value.getClass());
         if (converter != null) {
-            log.trace("Using converter: {} to convert {}", converter, key);
+            if (trace) {
+                log.trace("Using converter: {} to convert [{}=>{}]", 
converter, value.getClass(), type);
+            }
             Object rc;
             if (tryConvert) {
                 rc = converter.tryConvertTo(type, exchange, value);
             } else {
                 rc = converter.convertTo(type, exchange, value);
             }
-            if (rc == null && converter.allowNull()) {
-                return null;
-            } else if (rc != null) {
+            if (rc != null) {
                 return rc;
+            } else if (converter.allowNull()) {
+                return null;
             }
         }
 
@@ -335,7 +279,7 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
             Class<?> primitiveType = 
ObjectHelper.convertPrimitiveTypeToWrapperType(type);
             if (primitiveType != type) {
                 Class<?> fromType = value.getClass();
-                TypeConverter tc = getOrFindTypeConverter(new 
TypeMapping(primitiveType, fromType));
+                TypeConverter tc = getOrFindTypeConverter(primitiveType, 
fromType);
                 if (tc != null) {
                     // add the type as a known type converter as we can 
convert from primitive to object converter
                     addTypeConverter(type, fromType, tc);
@@ -367,9 +311,9 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
                 return null;
             }
 
-            if (Void.TYPE.equals(rc)) {
+            if (rc == MISS_VALUE) {
                 // it cannot be converted so give up
-                return Void.TYPE;
+                return MISS_VALUE;
             }
 
             if (rc != null) {
@@ -378,15 +322,14 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
                     // add it as a known type converter since we found a 
fallback that could do it
                     if (log.isDebugEnabled()) {
                         log.debug("Promoting fallback type converter as a 
known type converter to convert from: {} to: {} for the fallback converter: {}",
-                                new Object[]{type.getCanonicalName(), 
value.getClass().getCanonicalName(), fallback.getFallbackTypeConverter()});
+                                type.getCanonicalName(), 
value.getClass().getCanonicalName(), fallback.getFallbackTypeConverter());
                     }
                     addTypeConverter(type, value.getClass(), 
fallback.getFallbackTypeConverter());
                 }
 
                 if (log.isTraceEnabled()) {
                     log.trace("Fallback type converter {} converted type from: 
{} to: {}",
-                            new Object[]{fallback.getFallbackTypeConverter(),
-                                type.getCanonicalName(), 
value.getClass().getCanonicalName()});
+                            fallback.getFallbackTypeConverter(), 
type.getCanonicalName(), value.getClass().getCanonicalName());
                 }
 
                 // return converted value
@@ -397,18 +340,17 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
         if (!tryConvert) {
             // Could not find suitable conversion, so remember it
             // do not register misses for try conversions
-            misses.put(key, key);
+            typeMappings.put(type, value.getClass(), MISS_CONVERTER);
         }
 
         // Could not find suitable conversion, so return Void to indicate not 
found
-        return Void.TYPE;
+        return MISS_VALUE;
     }
 
     @Override
     public void addTypeConverter(Class<?> toType, Class<?> fromType, 
TypeConverter typeConverter) {
         log.trace("Adding type converter: {}", typeConverter);
-        TypeMapping key = new TypeMapping(toType, fromType);
-        TypeConverter converter = typeMappings.get(key);
+        TypeConverter converter = typeMappings.get(toType, fromType);
         // only override it if its different
         // as race conditions can lead to many threads trying to promote the 
same fallback converter
 
@@ -433,9 +375,7 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
             }
 
             if (add) {
-                typeMappings.put(key, typeConverter);
-                // remove any previous misses, as we added the new type 
converter
-                misses.remove(key);
+                typeMappings.put(toType, fromType, typeConverter);
             }
         }
     }
@@ -455,13 +395,7 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
     @Override
     public boolean removeTypeConverter(Class<?> toType, Class<?> fromType) {
         log.trace("Removing type converter from: {} to: {}", fromType, toType);
-        TypeMapping key = new TypeMapping(toType, fromType);
-        TypeConverter converter = typeMappings.remove(key);
-        if (converter != null) {
-            typeMappings.remove(key);
-            misses.remove(key);
-        }
-        return converter != null;
+        return typeMappings.remove(toType, fromType);
     }
 
     @Override
@@ -502,8 +436,7 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
     }
 
     public TypeConverter getTypeConverter(Class<?> toType, Class<?> fromType) {
-        TypeMapping key = new TypeMapping(toType, fromType);
-        return typeMappings.get(key);
+        return typeMappings.get(toType, fromType);
     }
 
     @Override
@@ -516,36 +449,13 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
         this.injector = injector;
     }
 
-    public Set<Class<?>> getFromClassMappings() {
-        Set<Class<?>> answer = new HashSet<>();
-        for (TypeMapping mapping : typeMappings.keySet()) {
-            answer.add(mapping.getFromType());
-        }
-        return answer;
-    }
-
-    public Map<Class<?>, TypeConverter> getToClassMappings(Class<?> fromClass) 
{
-        Map<Class<?>, TypeConverter> answer = new HashMap<>();
-        for (Map.Entry<TypeMapping, TypeConverter> entry : 
typeMappings.entrySet()) {
-            TypeMapping mapping = entry.getKey();
-            if (mapping.isApplicable(fromClass)) {
-                answer.put(mapping.getToType(), entry.getValue());
-            }
-        }
-        return answer;
-    }
-
-    public Map<TypeMapping, TypeConverter> getTypeMappings() {
-        return typeMappings;
-    }
-
-    protected <T> TypeConverter getOrFindTypeConverter(TypeMapping key) {
-        TypeConverter converter = typeMappings.get(key);
+    protected <T> TypeConverter getOrFindTypeConverter(Class<?> toType, 
Class<?> fromType) {
+        TypeConverter converter = typeMappings.get(toType, fromType);
         if (converter == null) {
             // converter not found, try to lookup then
-            converter = lookup(key.getToType(), key.getFromType());
+            converter = lookup(toType, fromType);
             if (converter != null) {
-                typeMappings.putIfAbsent(key, converter);
+                typeMappings.put(toType, fromType, converter);
             }
         }
         return converter;
@@ -588,21 +498,16 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
             if (fromType != null && !fromType.equals(Object.class)) {
 
                 // lets try classes derived from this toType
-                Set<Map.Entry<TypeMapping, TypeConverter>> entries = 
typeMappings.entrySet();
-                for (Map.Entry<TypeMapping, TypeConverter> entry : entries) {
-                    TypeMapping key = entry.getKey();
-                    Class<?> aToType = key.getToType();
-                    if (toType.isAssignableFrom(aToType)) {
-                        Class<?> aFromType = key.getFromType();
+                TypeConverter converter = typeMappings.getFirst(
+                        to -> toType.isAssignableFrom(to),
                         // skip Object based we do them last
-                        if (!aFromType.equals(Object.class) && 
aFromType.isAssignableFrom(fromType)) {
-                            return entry.getValue();
-                        }
-                    }
+                        from -> !from.equals(Object.class) && 
from.isAssignableFrom(fromType));
+                if (converter != null) {
+                    return converter;
                 }
 
                 // lets test for Object based converters as last resort
-                TypeConverter converter = getTypeConverter(toType, 
Object.class);
+                converter = getTypeConverter(toType, Object.class);
                 if (converter != null) {
                     return converter;
                 }
@@ -614,10 +519,8 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
     }
 
     public List<Class<?>[]> listAllTypeConvertersFromTo() {
-        List<Class<?>[]> answer = new ArrayList<>(typeMappings.size());
-        for (TypeMapping mapping : typeMappings.keySet()) {
-            answer.add(new Class<?>[]{mapping.getFromType(), 
mapping.getToType()});
-        }
+        List<Class<?>[]> answer = new ArrayList<>();
+        typeMappings.forEach((k1, k2, v) -> answer.add(new Class<?>[]{k2, 
k1}));
         return answer;
     }
 
@@ -626,7 +529,7 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
      */
     public void loadCoreTypeConverters() throws Exception {
         // load all the type converters from camel-core
-        CoreTypeConverterLoader core = new CoreTypeConverterLoader();
+        CoreStaticTypeConverterLoader core = new 
CoreStaticTypeConverterLoader();
         core.load(this);
     }
 
@@ -654,6 +557,11 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
     }
 
     protected TypeConversionException createTypeConversionException(Exchange 
exchange, Class<?> type, Object value, Throwable cause) {
+        if (cause instanceof TypeConversionException) {
+            if (((TypeConversionException) cause).getToType() == type) {
+                return (TypeConversionException) cause;
+            }
+        }
         Object body;
         // extract the body for logging which allows to limit the message body 
in the exception/stacktrace
         // and also can be used to turn off logging sensitive message data
@@ -701,12 +609,17 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
         // log utilization statistics when stopping, including mappings
         if (statistics.isStatisticsEnabled()) {
             String info = statistics.toString();
-            info += String.format(" mappings[total=%s, misses=%s]", 
typeMappings.size(), misses.size());
+            AtomicInteger misses = new AtomicInteger();
+            typeMappings.forEach((k1, k2, v) -> {
+                if (v == MISS_CONVERTER) {
+                    misses.incrementAndGet();
+                }
+            });
+            info += String.format(" mappings[total=%s, misses=%s]", 
typeMappings.size(), misses);
             log.info(info);
         }
 
         typeMappings.clear();
-        misses.clear();
         statistics.reset();
     }
 
@@ -775,75 +688,193 @@ public abstract class BaseTypeConverterRegistry extends 
ServiceSupport implement
     }
 
     /**
-     * Represents a mapping from one type (which can be null) to another
+     * Represents a fallback type converter
      */
-    protected static final class TypeMapping {
-        private final Class<?> toType;
-        private final Class<?> fromType;
-        private final int hashCode;
+    protected static class FallbackTypeConverter {
+        private final boolean canPromote;
+        private final TypeConverter fallbackTypeConverter;
 
-        TypeMapping(Class<?> toType, Class<?> fromType) {
-            this.toType = toType;
-            this.fromType = fromType;
+        FallbackTypeConverter(TypeConverter fallbackTypeConverter, boolean 
canPromote) {
+            this.canPromote = canPromote;
+            this.fallbackTypeConverter = fallbackTypeConverter;
+        }
 
-            // pre calculate hashcode
-            int hash = toType.hashCode();
-            if (fromType != null) {
-                hash *= 37 + fromType.hashCode();
-            }
-            hashCode = hash;
+        public boolean isCanPromote() {
+            return canPromote;
         }
 
-        public Class<?> getFromType() {
-            return fromType;
+        public TypeConverter getFallbackTypeConverter() {
+            return fallbackTypeConverter;
         }
+    }
 
-        public Class<?> getToType() {
-            return toType;
+    @SuppressWarnings("unchecked")
+    protected static class DoubleMap<K1, K2, V> {
+
+        static class Entry {
+            Object k1;
+            Object k2;
+            Object v;
+            Entry next;
         }
 
-        @Override
-        public boolean equals(Object object) {
-            if (object instanceof TypeMapping) {
-                TypeMapping that = (TypeMapping) object;
-                return this.fromType == that.fromType && this.toType == 
that.toType;
+        private Entry[] table;
+        private int mask;
+
+        public DoubleMap(int size) {
+            table = new Entry[closedTableSize(size)];
+            mask = table.length - 1;
+        }
+
+        public V get(K1 k1, K2 k2) {
+            Entry[] table = this.table;
+            int mask = this.mask;
+            int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
+            for (Entry entry = table[index]; entry != null; entry = 
entry.next) {
+                if (k1 == entry.k1 && k2 == entry.k2) {
+                    return (V) entry.v;
+                }
+            }
+            return null;
+        }
+
+        public void forEach(TriConsumer<K1, K2, V> consumer) {
+            Entry[] table = this.table;
+            for (Entry entry : table) {
+                while (entry != null) {
+                    consumer.accept((K1) entry.k1, (K2) entry.k2, (V) entry.v);
+                    entry = entry.next;
+                }
+            }
+        }
+
+        public boolean containsKey(K1 k1, K2 k2) {
+            Entry[] table = this.table;
+            int mask = this.mask;
+            int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
+            for (Entry entry = table[index]; entry != null; entry = 
entry.next) {
+                if (k1 == entry.k1 && k2 == entry.k2) {
+                    return true;
+                }
             }
             return false;
         }
 
-        @Override
-        public int hashCode() {
-            return hashCode;
+        public synchronized void put(K1 k1, K2 k2, V v) {
+            Entry[] table = this.table;
+            int size = size() + 1;
+            int realSize = closedTableSize(size);
+            if (realSize <= table.length) {
+                realSize = table.length;
+                int index = smear(k1.hashCode() * 31 + k2.hashCode()) & 
(realSize - 1);
+                for (Entry oldEntry = table[index]; oldEntry != null; oldEntry 
= oldEntry.next) {
+                    if (oldEntry.k1 == k1 && oldEntry.k2 == k2) {
+                        oldEntry.v = v;
+                        return;
+                    }
+                }
+                Entry entry = new Entry();
+                entry.k1 = k1;
+                entry.k2 = k2;
+                entry.v = v;
+                entry.next = table[index];
+                table[index] = entry;
+            } else {
+                Entry[] newT = new Entry[realSize];
+                int index = smear(k1.hashCode() * 31 + k2.hashCode()) & 
(realSize - 1);
+                Entry entry = new Entry();
+                newT[index] = entry;
+                entry.k1 = k1;
+                entry.k2 = k2;
+                entry.v = v;
+                for (Entry oldEntry : table) {
+                    while (oldEntry != null) {
+                        if (k1 != oldEntry.k1 || k2 != oldEntry.k2) {
+                            index = smear(oldEntry.k1.hashCode() * 31 + 
oldEntry.k2.hashCode()) & (realSize - 1);
+                            Entry newEntry = new Entry();
+                            newEntry.k1 = oldEntry.k1;
+                            newEntry.k2 = oldEntry.k2;
+                            newEntry.v = oldEntry.v;
+                            newEntry.next = newT[index];
+                            newT[index] = newEntry;
+                        }
+                        oldEntry = oldEntry.next;
+                    }
+                }
+                this.table = newT;
+                this.mask = realSize - 1;
+            }
         }
 
-        @Override
-        public String toString() {
-            return "[" + fromType + "=>" + toType + "]";
+        public synchronized boolean remove(K1 k1, K2 k2) {
+            Entry[] table = this.table;
+            int mask = this.mask;
+            int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
+            Entry prevEntry = null;
+            for (Entry oldEntry = table[index]; oldEntry != null; prevEntry = 
oldEntry, oldEntry = oldEntry.next) {
+                if (oldEntry.k1 == k1 && oldEntry.k2 == k2) {
+                    if (prevEntry == null) {
+                        table[index] = oldEntry.next;
+                    } else {
+                        prevEntry.next = oldEntry.next;
+                    }
+                    return true;
+                }
+            }
+            return false;
         }
 
-        public boolean isApplicable(Class<?> fromClass) {
-            return fromType.isAssignableFrom(fromClass);
+        public V getFirst(Predicate<K1> p1, Predicate<K2> p2) {
+            for (Entry entry : table) {
+                while (entry != null) {
+                    if (p1.test((K1) entry.k1) && p2.test((K2) entry.k2)) {
+                        return (V) entry.v;
+                    }
+                    entry = entry.next;
+                }
+            }
+            return null;
         }
-    }
 
-    /**
-     * Represents a fallback type converter
-     */
-    protected static class FallbackTypeConverter {
-        private final boolean canPromote;
-        private final TypeConverter fallbackTypeConverter;
+        public int size() {
+            Entry[] table = this.table;
+            int n = 0;
+            if (table != null) {
+                for (Entry e : table) {
+                    for (Entry c = e; c != null; c = c.next) {
+                        n++;
+                    }
+                }
+            }
+            return n;
+        }
 
-        FallbackTypeConverter(TypeConverter fallbackTypeConverter, boolean 
canPromote) {
-            this.canPromote = canPromote;
-            this.fallbackTypeConverter = fallbackTypeConverter;
+        public synchronized void clear() {
+            this.table = new Entry[table.length];
         }
 
-        public boolean isCanPromote() {
-            return canPromote;
+        private static final double MAX_LOAD_FACTOR = 1.2;
+        private static final int MAX_TABLE_SIZE = 32768;
+        private static final int C1 = 0xcc9e2d51;
+        private static final int C2 = 0x1b873593;
+
+        static int smear(int hashCode) {
+            return C2 * Integer.rotateLeft(hashCode * C1, 15);
         }
 
-        public TypeConverter getFallbackTypeConverter() {
-            return fallbackTypeConverter;
+        static int closedTableSize(int expectedEntries) {
+            // Get the recommended table size.
+            // Round down to the nearest power of 2.
+            expectedEntries = Math.max(expectedEntries, 2);
+            int tableSize = Integer.highestOneBit(expectedEntries);
+            // Check to make sure that we will not exceed the maximum load 
factor.
+            if (expectedEntries > (int) (MAX_LOAD_FACTOR * tableSize)) {
+                tableSize <<= 1;
+                return (tableSize > 0) ? tableSize : MAX_TABLE_SIZE;
+            }
+            return tableSize;
         }
+
     }
+
 }
diff --git 
a/camel-core/src/main/java/org/apache/camel/impl/converter/CorePackageScanClassResolver.java
 
b/camel-core/src/main/java/org/apache/camel/impl/converter/CorePackageScanClassResolver.java
deleted file mode 100644
index 0ceb81d..0000000
--- 
a/camel-core/src/main/java/org/apache/camel/impl/converter/CorePackageScanClassResolver.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * 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.lang.annotation.Annotation;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import org.apache.camel.component.bean.BeanConverter;
-import org.apache.camel.component.file.GenericFileConverter;
-import org.apache.camel.converter.AttachmentConverter;
-import org.apache.camel.converter.CamelConverter;
-import org.apache.camel.converter.CollectionConverter;
-import org.apache.camel.converter.DateTimeConverter;
-import org.apache.camel.converter.DurationConverter;
-import org.apache.camel.converter.IOConverter;
-import org.apache.camel.converter.NIOConverter;
-import org.apache.camel.converter.ObjectConverter;
-import org.apache.camel.converter.SQLConverter;
-import org.apache.camel.converter.TimePatternConverter;
-import org.apache.camel.converter.jaxp.DomConverter;
-import org.apache.camel.converter.jaxp.StaxConverter;
-import org.apache.camel.converter.jaxp.StreamSourceConverter;
-import org.apache.camel.converter.jaxp.XmlConverter;
-import org.apache.camel.converter.stream.StreamCacheConverter;
-import org.apache.camel.spi.PackageScanClassResolver;
-import org.apache.camel.spi.PackageScanFilter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A {@link org.apache.camel.spi.ClassResolver} which loads type converters
- * from a hardcoded list of classes.
- * <p/>
- * <b>Important:</b> Whenever a new type converter class is added to camel-core
- * then the class should be added to the list in this class.
- *
- * @see CoreTypeConverterLoader
- */
-public class CorePackageScanClassResolver implements PackageScanClassResolver {
-
-    protected final Logger log = LoggerFactory.getLogger(getClass());
-    private final Set<ClassLoader> classLoaders = new LinkedHashSet<>();
-    private final Set<Class<?>> converters = new LinkedHashSet<>();
-
-    public CorePackageScanClassResolver() {
-        converters.add(ObjectConverter.class);
-        converters.add(CollectionConverter.class);
-        converters.add(DateTimeConverter.class);
-        converters.add(SQLConverter.class);
-        converters.add(IOConverter.class);
-        converters.add(NIOConverter.class);
-        converters.add(StaxConverter.class);
-        converters.add(DomConverter.class);
-        converters.add(StreamSourceConverter.class);
-        converters.add(XmlConverter.class);
-        converters.add(CamelConverter.class);
-        converters.add(StreamCacheConverter.class);
-        converters.add(TimePatternConverter.class);
-        converters.add(FutureTypeConverter.class);
-        converters.add(BeanConverter.class);
-        converters.add(GenericFileConverter.class);
-        converters.add(DurationConverter.class);
-        converters.add(AttachmentConverter.class);
-        converters.add(UriTypeConverter.class);
-    }
-
-    @Override
-    public Set<ClassLoader> getClassLoaders() {
-        // return a new set to avoid any concurrency issues in other runtimes 
such as OSGi
-        return Collections.unmodifiableSet(new LinkedHashSet<>(classLoaders));
-    }
-
-    @Override
-    public void addClassLoader(ClassLoader classLoader) {
-        classLoaders.add(classLoader);
-    }
-
-    @Override
-    public Set<Class<?>> findAnnotated(Class<? extends Annotation> annotation, 
String... packageNames) {
-        return converters;
-    }
-
-    @Override
-    public Set<Class<?>> findAnnotated(Set<Class<? extends Annotation>> 
annotations, String... packageNames) {
-        return converters;
-    }
-
-    @Override
-    public Set<Class<?>> findImplementations(Class<?> parent, String... 
packageNames) {
-        // noop
-        return null;
-    }
-
-    @Override
-    public Set<Class<?>> findByFilter(PackageScanFilter filter, String... 
packageNames) {
-        // noop
-        return null;
-    }
-
-    @Override
-    public void addFilter(PackageScanFilter filter) {
-        // noop
-    }
-
-    @Override
-    public void removeFilter(PackageScanFilter filter) {
-        // noop
-    }
-}
diff --git 
a/camel-core/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterLoader.java
 
b/camel-core/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterLoader.java
deleted file mode 100644
index 06b7353..0000000
--- 
a/camel-core/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterLoader.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * 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.io.IOException;
-
-/**
- * Will load all type converters from camel-core without classpath scanning, 
which makes
- * it much faster.
- * <p/>
- * The {@link CorePackageScanClassResolver} contains a hardcoded list of the 
type converter classes to load.
- */
-public class CoreTypeConverterLoader extends AnnotationTypeConverterLoader {
-
-    public CoreTypeConverterLoader() {
-        super(new CorePackageScanClassResolver());
-    }
-
-    @Override
-    protected String[] findPackageNames() throws IOException {
-        // this method doesn't change the behavior of the 
CorePackageScanClassResolver
-        return new String[]{"org.apache.camel.converter", 
"org.apache.camel.component.bean", "org.apache.camel.component.file"};
-    }
-
-}
diff --git 
a/camel-core/src/main/java/org/apache/camel/impl/converter/EnumTypeConverter.java
 
b/camel-core/src/main/java/org/apache/camel/impl/converter/EnumTypeConverter.java
index 095bef8..bdcaaa6 100644
--- 
a/camel-core/src/main/java/org/apache/camel/impl/converter/EnumTypeConverter.java
+++ 
b/camel-core/src/main/java/org/apache/camel/impl/converter/EnumTypeConverter.java
@@ -28,8 +28,12 @@ import org.apache.camel.support.TypeConverterSupport;
  */
 public class EnumTypeConverter extends TypeConverterSupport {
 
-    @SuppressWarnings("unchecked")
     public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
+        return EnumTypeConverter.doConvertTo(type, exchange, value);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T doConvertTo(Class<T> type, Exchange exchange, Object 
value) {
         if (type.isEnum()) {
             String text = value.toString();
             Class<Enum> enumClass = (Class<Enum>) type;
diff --git 
a/camel-core/src/main/java/org/apache/camel/impl/converter/FutureTypeConverter.java
 
b/camel-core/src/main/java/org/apache/camel/impl/converter/FutureTypeConverter.java
index 38032c9..b2f2004 100644
--- 
a/camel-core/src/main/java/org/apache/camel/impl/converter/FutureTypeConverter.java
+++ 
b/camel-core/src/main/java/org/apache/camel/impl/converter/FutureTypeConverter.java
@@ -64,7 +64,7 @@ public final class FutureTypeConverter extends 
TypeConverterSupport {
 
             if (future.isCancelled()) {
                 // return void to indicate its not possible to convert at this 
time
-                return (T) Void.TYPE;
+                return (T) MISS_VALUE;
             }
 
             // do some trace logging as the get is blocking until the response 
is ready
@@ -75,7 +75,7 @@ public final class FutureTypeConverter extends 
TypeConverterSupport {
 
             if (body == null) {
                 // return void to indicate its not possible to convert at this 
time
-                return (T) Void.TYPE;
+                return (T) MISS_VALUE;
             }
 
             // maybe from is already the type we want
diff --git 
a/camel-core/src/main/java/org/apache/camel/impl/converter/OptimisedTypeConverter.java
 
b/camel-core/src/main/java/org/apache/camel/impl/converter/OptimisedTypeConverter.java
deleted file mode 100644
index df774f8..0000000
--- 
a/camel-core/src/main/java/org/apache/camel/impl/converter/OptimisedTypeConverter.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * 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 org.apache.camel.Exchange;
-import org.apache.camel.converter.IOConverterOptimised;
-import org.apache.camel.converter.NIOConverterOptimised;
-import org.apache.camel.converter.ObjectConverterOptimised;
-import org.apache.camel.converter.TimePatternConverterOptimised;
-
-/**
- * Optimised type converter for performing the most common conversions using 
the type converters
- * from camel-core.
- * <p/>
- * The most commonly used type converters has been optimised to be invoked in 
a faster by
- * using direct method calls instead of a calling via a reflection method call 
via
- * {@link InstanceMethodTypeConverter} or {@link StaticMethodTypeConverter}.
- * In addition the performance is faster because the type converter is not 
looked up
- * via a key in the type converter {@link Map}; which requires creating a new 
object
- * as they key and perform the map lookup. The caveat is that for any new type 
converter
- * to be included it must be manually added by adding the nessasary source 
code to the
- * optimised classes such as {@link ObjectConverterOptimised}.
- */
-public class OptimisedTypeConverter {
-
-    private final EnumTypeConverter enumTypeConverter = new 
EnumTypeConverter();
-
-    /**
-     * Attempts to convert the value to the given type
-     *
-     * @param type     the type to convert to
-     * @param exchange the exchange, may be <tt>null</tt>
-     * @param value    the value
-     * @return the converted value, or <tt>null</tt> if no optimised core type 
converter exists to convert
-     */
-    public Object convertTo(final Class<?> type, final Exchange exchange, 
final Object value) throws Exception {
-        Object answer;
-
-        // use the optimised type converters and use them in the most commonly 
used order
-
-        // we need time pattern first as it can do a special String -> long 
conversion which should happen first
-        answer = TimePatternConverterOptimised.convertTo(type, exchange, 
value);
-        if (answer == null) {
-            answer = ObjectConverterOptimised.convertTo(type, exchange, value);
-        }
-        if (answer == null) {
-            answer = IOConverterOptimised.convertTo(type, exchange, value);
-        }
-        if (answer == null) {
-            answer = NIOConverterOptimised.convertTo(type, exchange, value);
-        }
-
-        // specially optimised for enums
-        if (answer == null && type.isEnum()) {
-            answer = enumTypeConverter.convertTo(type, exchange, value);
-        }
-
-        return answer;
-    }
-
-}
diff --git 
a/camel-core/src/main/java/org/apache/camel/impl/converter/ToStringTypeConverter.java
 
b/camel-core/src/main/java/org/apache/camel/impl/converter/ToStringTypeConverter.java
index 2fa600d..c15f52f 100644
--- 
a/camel-core/src/main/java/org/apache/camel/impl/converter/ToStringTypeConverter.java
+++ 
b/camel-core/src/main/java/org/apache/camel/impl/converter/ToStringTypeConverter.java
@@ -36,22 +36,22 @@ public class ToStringTypeConverter extends 
TypeConverterSupport {
 
         // should not try to convert Message
         if (Message.class.isAssignableFrom(value.getClass())) {
-            return (T) Void.TYPE;
+            return (T) MISS_VALUE;
         }
 
         // should not try to convert future
         if (Future.class.isAssignableFrom(value.getClass())) {
-            return (T) Void.TYPE;
+            return (T) MISS_VALUE;
         }
 
         // should not try to convert bean invocations
         if (BeanInvocation.class.isAssignableFrom(value.getClass())) {
-            return (T) Void.TYPE;
+            return (T) MISS_VALUE;
         }
 
         // should not try to convert files
         if (WrappedFile.class.isAssignableFrom(value.getClass())) {
-            return (T) Void.TYPE;
+            return (T) MISS_VALUE;
         }
 
         if (toType.equals(String.class)) {
diff --git 
a/camel-core/src/test/java/org/apache/camel/builder/SimpleBuilderTest.java 
b/camel-core/src/test/java/org/apache/camel/builder/SimpleBuilderTest.java
index 7e7d4de..7b29975 100644
--- a/camel-core/src/test/java/org/apache/camel/builder/SimpleBuilderTest.java
+++ b/camel-core/src/test/java/org/apache/camel/builder/SimpleBuilderTest.java
@@ -69,7 +69,7 @@ public class SimpleBuilderTest extends TestSupport {
             SimpleBuilder.simple("${body}", int.class).evaluate(exchange, 
Object.class);
             fail("Should have thrown exception");
         } catch (TypeConversionException e) {
-            assertIsInstanceOf(NumberFormatException.class, e.getCause());
+            assertIsInstanceOf(NumberFormatException.class, 
e.getCause().getCause());
         }
 
         assertEquals(true, SimpleBuilder.simple("${header.cool}", 
boolean.class).evaluate(exchange, Object.class));
diff --git 
a/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFeatureTest.java 
b/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFeatureTest.java
index d745d8e..50ff16b 100644
--- 
a/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFeatureTest.java
+++ 
b/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFeatureTest.java
@@ -58,8 +58,7 @@ public class XPathFeatureTest extends ContextTestSupport {
             xpath("/").stringResult().evaluate(createExchange(XML_DATA));
             fail("Expect an Exception here");
         } catch (TypeConversionException ex) {
-            assertTrue("Get a wrong exception cause.", ex.getCause() 
instanceof RuntimeCamelException);
-            assertTrue("Get a wrong exception cause.", 
ex.getCause().getCause() instanceof FileNotFoundException);
+            assertTrue("Get a wrong exception cause.", ex.getCause() 
instanceof FileNotFoundException);
         } finally {
             System.clearProperty(DOM_BUILDER_FACTORY_FEATURE + ":"
                 + "http://xml.org/sax/features/external-general-entities";);
@@ -83,8 +82,7 @@ public class XPathFeatureTest extends ContextTestSupport {
             
xpath("/").stringResult().evaluate(createExchange(XML_DATA_INVALID));
             fail("Expect an Exception here");
         } catch (TypeConversionException ex) {
-            assertTrue("Get a wrong exception cause.", ex.getCause() 
instanceof RuntimeCamelException);
-            assertTrue("Get a wrong exception cause.", 
ex.getCause().getCause() instanceof SAXParseException);
+            assertTrue("Get a wrong exception cause.", ex.getCause() 
instanceof SAXParseException);
         }
     }
 
diff --git 
a/camel-core/src/test/java/org/apache/camel/converter/ConverterBenchmark.java 
b/camel-core/src/test/java/org/apache/camel/converter/ConverterBenchmark.java
new file mode 100644
index 0000000..3967a9c
--- /dev/null
+++ 
b/camel-core/src/test/java/org/apache/camel/converter/ConverterBenchmark.java
@@ -0,0 +1,160 @@
+/**
+ * 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.converter;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.impl.DefaultClassResolver;
+import org.apache.camel.impl.DefaultFactoryFinderResolver;
+import org.apache.camel.impl.DefaultPackageScanClassResolver;
+import org.apache.camel.impl.converter.DefaultTypeConverter;
+import org.apache.camel.spi.FactoryFinder;
+import org.apache.camel.spi.Injector;
+import org.apache.camel.util.ReflectionInjector;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.TimeValue;
+
+public class ConverterBenchmark {
+
+    @Ignore
+    @Test
+    public void launchBenchmark() throws Exception {
+
+        Options opt = new OptionsBuilder()
+                // Specify which benchmarks to run.
+                // You can be more specific if you'd like to run only one 
benchmark per test.
+                .include(this.getClass().getName() + ".*")
+                // Set the following options as needed
+                .mode (Mode.AverageTime)
+                .timeUnit(TimeUnit.MICROSECONDS)
+                .warmupTime(TimeValue.seconds(2))
+                .warmupIterations(5)
+                .measurementTime(TimeValue.seconds(1))
+                .measurementIterations(5)
+                .threads(2)
+                .forks(1)
+                .shouldFailOnError(true)
+                .shouldDoGC(true)
+                //.jvmArgs("-XX:+UnlockDiagnosticVMOptions", 
"-XX:+PrintInlining")
+                //.addProfiler(WinPerfAsmProfiler.class)
+                .build();
+
+        new Runner(opt).run();
+    }
+
+    // The JMH samples are the best documentation for how to use it
+    // 
http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/
+    @State (Scope.Thread)
+    public static class BenchmarkState
+    {
+        DefaultPackageScanClassResolver packageScanClassResolver;
+        Injector injector;
+        FactoryFinder factoryFinder;
+        DefaultTypeConverter converter;
+
+        @Setup (Level.Trial)
+        public void initialize() throws Exception {
+            packageScanClassResolver = new DefaultPackageScanClassResolver();
+            injector = new ReflectionInjector();
+            factoryFinder = new 
DefaultFactoryFinderResolver().resolveDefaultFactoryFinder(new 
DefaultClassResolver());
+            converter = new DefaultTypeConverter(packageScanClassResolver, 
injector, factoryFinder, true);
+            converter.start();
+        }
+    }
+
+    @Benchmark
+    public void benchmarkLoadTime(BenchmarkState state, Blackhole bh) throws 
Exception {
+
+        DefaultPackageScanClassResolver packageScanClassResolver = 
state.packageScanClassResolver;
+        Injector injector = state.injector;
+        FactoryFinder factoryFinder = state.factoryFinder;
+
+        DefaultTypeConverter converter = new 
DefaultTypeConverter(packageScanClassResolver, injector, factoryFinder, true);
+        converter.start();
+        bh.consume(converter);
+    }
+
+    @Benchmark
+    public void benchmarkConversionTimeEnum(BenchmarkState state, Blackhole 
bh) {
+        DefaultTypeConverter converter = state.converter;
+
+        for (int i = 0; i < 1000; i++)
+            bh.consume(converter.convertTo(LoggingLevel.class, "DEBUG"));
+    }
+
+    @Benchmark
+    public void benchmarkConversionIntToLong(BenchmarkState state, Blackhole 
bh) {
+        DefaultTypeConverter converter = state.converter;
+
+        for (int i = 0; i < 1000; i++)
+            bh.consume(converter.convertTo(Long.class, 3));
+    }
+
+    @Benchmark
+    public void benchmarkConversionStringToChar(BenchmarkState state, 
Blackhole bh) {
+        DefaultTypeConverter converter = state.converter;
+
+        for (int i = 0; i < 1000; i++)
+            bh.consume(converter.convertTo(char[].class, "Hello world"));
+    }
+
+    @Benchmark
+    public void benchmarkConversionStringToURI(BenchmarkState state, Blackhole 
bh) {
+        DefaultTypeConverter converter = state.converter;
+
+        for (int i = 0; i < 1000; i++)
+            bh.consume(converter.convertTo(URI.class, "uri:foo"));
+    }
+
+    @Benchmark
+    public void benchmarkConversionListToStringArray(BenchmarkState state, 
Blackhole bh) {
+        DefaultTypeConverter converter = state.converter;
+
+        for (int i = 0; i < 1000; i++)
+            bh.consume(converter.convertTo(String[].class, 
Arrays.asList("DEBUG")));
+    }
+
+    @Ignore
+    @Test
+    public void testConvertEnumPerfs() throws Exception {
+        Blackhole bh = new Blackhole("Today's password is swordfish. I 
understand instantiating Blackholes directly is dangerous.");
+        BenchmarkState state = new BenchmarkState();
+        state.initialize();
+        doTest(bh, state);
+    }
+
+    private void doTest(Blackhole bh, BenchmarkState state) {
+        DefaultTypeConverter converter = state.converter;
+        for (int i = 0; i < 1000000; i++) {
+            bh.consume(converter.convertTo(Long.class, 3));
+        }
+    }
+}
diff --git 
a/camel-core/src/test/java/org/apache/camel/converter/ConverterTest.java 
b/camel-core/src/test/java/org/apache/camel/converter/ConverterTest.java
index 18f48e8..d43b545 100644
--- a/camel-core/src/test/java/org/apache/camel/converter/ConverterTest.java
+++ b/camel-core/src/test/java/org/apache/camel/converter/ConverterTest.java
@@ -43,11 +43,14 @@ import org.apache.camel.support.ServiceHelper;
 import org.apache.camel.util.ReflectionInjector;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class ConverterTest extends Assert {
+
     private static final Logger LOG = 
LoggerFactory.getLogger(ConverterTest.class);
 
     protected TypeConverter converter = new DefaultTypeConverter(new 
DefaultPackageScanClassResolver(),
@@ -262,4 +265,21 @@ public class ConverterTest extends Assert {
         }
     }
 
+    @Test
+    public void testNullToBoolean() throws Exception {
+        boolean b = converter.convertTo(boolean.class, null);
+        assertFalse(b);
+    }
+
+    @Test
+    public void testNullToInt() throws Exception {
+        int i = converter.convertTo(int.class, null);
+        assertEquals(0, i);
+    }
+
+    @Test
+    public void testToInt() throws Exception {
+        int i = converter.convertTo(int.class, "0");
+        assertEquals(0, i);
+    }
 }
diff --git 
a/camel-core/src/test/java/org/apache/camel/converter/DurationConverterTest.java
 
b/camel-core/src/test/java/org/apache/camel/converter/DurationConverterTest.java
index 86ad5f0..193a512 100644
--- 
a/camel-core/src/test/java/org/apache/camel/converter/DurationConverterTest.java
+++ 
b/camel-core/src/test/java/org/apache/camel/converter/DurationConverterTest.java
@@ -42,7 +42,7 @@ public class DurationConverterTest extends ContextTestSupport 
{
             context.getTypeConverter().convertTo(long.class, duration);
             fail("Should throw exception");
         } catch (TypeConversionException e) {
-            assertIsInstanceOf(ArithmeticException.class, 
e.getCause().getCause());
+            assertIsInstanceOf(ArithmeticException.class, e.getCause());
         }
     }
 
diff --git 
a/camel-core/src/test/java/org/apache/camel/converter/ObjectConverterTest.java 
b/camel-core/src/test/java/org/apache/camel/converter/ObjectConverterTest.java
index be5e00f..f7c3275 100644
--- 
a/camel-core/src/test/java/org/apache/camel/converter/ObjectConverterTest.java
+++ 
b/camel-core/src/test/java/org/apache/camel/converter/ObjectConverterTest.java
@@ -53,14 +53,11 @@ public class ObjectConverterTest extends Assert {
         assertEquals(Byte.valueOf("4"), 
ObjectConverter.toByte(Byte.valueOf("4")));
         assertEquals(Byte.valueOf("4"), 
ObjectConverter.toByte(Integer.valueOf("4")));
         assertEquals(Byte.valueOf("4"), ObjectConverter.toByte("4"));
-        assertEquals(null, ObjectConverter.toByte(new Date()));
     }
     
     @Test
     public void testToClass() {
-        assertEquals(String.class, ObjectConverter.toClass(String.class, 
null));
         assertEquals(String.class, ObjectConverter.toClass("java.lang.String", 
null));
-        assertEquals(null, ObjectConverter.toClass(new Integer(4), null));
         assertEquals(null, ObjectConverter.toClass("foo.Bar", null));
     }
 
@@ -69,9 +66,8 @@ public class ObjectConverterTest extends Assert {
         assertEquals(Short.valueOf("4"), 
ObjectConverter.toShort(Short.valueOf("4")));
         assertEquals(Short.valueOf("4"), 
ObjectConverter.toShort(Integer.valueOf("4")));
         assertEquals(Short.valueOf("4"), ObjectConverter.toShort("4"));
-        assertEquals(null, ObjectConverter.toShort(new Date()));
-        assertEquals(Short.valueOf("0"), ObjectConverter.toShort(Double.NaN));
-        assertEquals(Short.valueOf("0"), ObjectConverter.toShort(Float.NaN));
+        assertEquals(null, ObjectConverter.toShort(Double.NaN));
+        assertEquals(null, ObjectConverter.toShort(Float.NaN));
         assertEquals(Short.valueOf("4"), 
ObjectConverter.toShort(Short.valueOf("4")));
     }
 
@@ -80,9 +76,8 @@ public class ObjectConverterTest extends Assert {
         assertEquals(Integer.valueOf("4"), 
ObjectConverter.toInteger(Integer.valueOf("4")));
         assertEquals(Integer.valueOf("4"), 
ObjectConverter.toInteger(Long.valueOf("4")));
         assertEquals(Integer.valueOf("4"), ObjectConverter.toInteger("4"));
-        assertEquals(null, ObjectConverter.toInteger(new Date()));
-        assertEquals(Integer.valueOf("0"), 
ObjectConverter.toInteger(Double.NaN));
-        assertEquals(Integer.valueOf("0"), 
ObjectConverter.toInteger(Float.NaN));
+        assertEquals(null, ObjectConverter.toInteger(Double.NaN));
+        assertEquals(null, ObjectConverter.toInteger(Float.NaN));
         assertEquals(Integer.valueOf("4"), 
ObjectConverter.toInteger(Integer.valueOf("4")));
     }
 
@@ -91,9 +86,8 @@ public class ObjectConverterTest extends Assert {
         assertEquals(Long.valueOf("4"), 
ObjectConverter.toLong(Long.valueOf("4")));
         assertEquals(Long.valueOf("4"), 
ObjectConverter.toLong(Integer.valueOf("4")));
         assertEquals(Long.valueOf("4"), ObjectConverter.toLong("4"));
-        assertEquals(null, ObjectConverter.toLong(new Date()));
-        assertEquals(Long.valueOf("0"), ObjectConverter.toLong(Double.NaN));
-        assertEquals(Long.valueOf("0"), ObjectConverter.toLong(Float.NaN));
+        assertEquals(null, ObjectConverter.toLong(Double.NaN));
+        assertEquals(null, ObjectConverter.toLong(Float.NaN));
         assertEquals(Long.valueOf("4"), 
ObjectConverter.toLong(Long.valueOf("4")));
     }
 
@@ -102,7 +96,6 @@ public class ObjectConverterTest extends Assert {
         assertEquals(Float.valueOf("4"), 
ObjectConverter.toFloat(Float.valueOf("4")));
         assertEquals(Float.valueOf("4"), 
ObjectConverter.toFloat(Integer.valueOf("4")));
         assertEquals(Float.valueOf("4"), ObjectConverter.toFloat("4"));
-        assertEquals(null, ObjectConverter.toFloat(new Date()));
         assertEquals((Float) Float.NaN, ObjectConverter.toFloat(Double.NaN));
         assertEquals((Float) Float.NaN, ObjectConverter.toFloat(Float.NaN));
         assertEquals(Float.valueOf("4"), 
ObjectConverter.toFloat(Float.valueOf("4")));
@@ -113,7 +106,6 @@ public class ObjectConverterTest extends Assert {
         assertEquals(Double.valueOf("4"), 
ObjectConverter.toDouble(Double.valueOf("4")));
         assertEquals(Double.valueOf("4"), 
ObjectConverter.toDouble(Integer.valueOf("4")));
         assertEquals(Double.valueOf("4"), ObjectConverter.toDouble("4"));
-        assertEquals(null, ObjectConverter.toDouble(new Date()));
         assertEquals((Double) Double.NaN, 
ObjectConverter.toDouble(Double.NaN));
         assertEquals((Double) Double.NaN, ObjectConverter.toDouble(Float.NaN));
         assertEquals(Double.valueOf("4"), 
ObjectConverter.toDouble(Double.valueOf("4")));
@@ -126,8 +118,8 @@ public class ObjectConverterTest extends Assert {
         assertEquals(BigInteger.valueOf(4), ObjectConverter.toBigInteger("4"));
         assertEquals(BigInteger.valueOf(123456789L), 
ObjectConverter.toBigInteger("123456789"));
         assertEquals(null, ObjectConverter.toBigInteger(new Date()));
-        assertEquals(BigInteger.valueOf(0), 
ObjectConverter.toBigInteger(Double.NaN));
-        assertEquals(BigInteger.valueOf(0), 
ObjectConverter.toBigInteger(Float.NaN));
+        assertEquals(null, ObjectConverter.toBigInteger(Double.NaN));
+        assertEquals(null, ObjectConverter.toBigInteger(Float.NaN));
         assertEquals(BigInteger.valueOf(4), 
ObjectConverter.toBigInteger(Long.valueOf("4")));
         assertEquals(new BigInteger("14350442579497085228"), 
ObjectConverter.toBigInteger("14350442579497085228"));
     }
diff --git a/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java 
b/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java
index c4ee55b..f9acd94 100644
--- a/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java
+++ b/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java
@@ -1080,6 +1080,9 @@ public final class ObjectHelper {
         return null;
     }
 
+    private static final Float FLOAT_NAN = Float.NaN;
+    private static final Double DOUBLE_NAN = Double.NaN;
+
     /**
      * Is the given value a numeric NaN type
      * 
@@ -1087,11 +1090,8 @@ public final class ObjectHelper {
      * @return <tt>true</tt> if its a {@link Float#NaN} or {@link Double#NaN}.
      */
     public static boolean isNaN(Object value) {
-        if (value == null || !(value instanceof Number)) {
-            return false;
-        }
-        // value must be a number
-        return value.equals(Float.NaN) || value.equals(Double.NaN);
+        return (value instanceof Number)
+                && (FLOAT_NAN.equals(value) || DOUBLE_NAN.equals(value));
     }
 
 }
diff --git 
a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfConverter.java
 
b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfConverter.java
index 4b33df0..323e028 100644
--- 
a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfConverter.java
+++ 
b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfConverter.java
@@ -36,6 +36,8 @@ import org.apache.camel.spi.TypeConverterRegistry;
 import org.apache.camel.support.ExchangeHelper;
 import org.apache.cxf.message.MessageContentsList;
 
+import static org.apache.camel.TypeConverter.MISS_VALUE;
+
 /**
  * The <a href="http://camel.apache.org/type-converter.html";>Type 
Converters</a>
  * for CXF related types' converting .
@@ -160,7 +162,7 @@ public final class CxfConverter {
                 }
             }
             // return void to indicate its not possible to convert at this time
-            return (T) Void.TYPE;
+            return (T) MISS_VALUE;
         }
 
         // CXF-RS Response class
@@ -174,7 +176,7 @@ public final class CxfConverter {
             }
 
             // return void to indicate its not possible to convert at this time
-            return (T) Void.TYPE;
+            return (T) MISS_VALUE;
         }
         
         return null;
diff --git 
a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfPayloadConverter.java
 
b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfPayloadConverter.java
index 2e4da69..9bc96d7 100644
--- 
a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfPayloadConverter.java
+++ 
b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfPayloadConverter.java
@@ -46,6 +46,8 @@ import org.apache.camel.spi.TypeConverterRegistry;
 import org.apache.cxf.staxutils.StaxSource;
 import org.apache.cxf.staxutils.StaxUtils;
 
+import static org.apache.camel.TypeConverter.MISS_VALUE;
+
 @Converter
 public final class CxfPayloadConverter {
     private static XmlConverter xml = new XmlConverter();
@@ -179,10 +181,10 @@ public final class CxfPayloadConverter {
                 }
             } catch (RuntimeCamelException e) {
                 // the internal conversion to XML can throw an exception if 
the content is not XML
-                // ignore this and return Void.TYPE to indicate that we cannot 
convert this
+                // ignore this and return MISS_VALUE to indicate that we 
cannot convert this
             }
             // no we could not do it currently
-            return (T) Void.TYPE;
+            return (T) MISS_VALUE;
         }
         // Convert a CxfPayload into something else
         if (CxfPayload.class.isAssignableFrom(value.getClass())) {
@@ -234,7 +236,7 @@ public final class CxfPayloadConverter {
                 Object result = tc.convertTo(type, exchange, 
cxfPayloadToNodeList((CxfPayload<?>) value, exchange));
                 if (result == null) {
                     // no we could not do it currently, and we just abort the 
convert here
-                    return (T) Void.TYPE;
+                    return (T) MISS_VALUE;
                 } else {
                     return (T) result;
                 }
@@ -249,12 +251,12 @@ public final class CxfPayloadConverter {
                     return tc.convertTo(type, exchange, nodeList.item(0));
                 } else {
                     // no we could not do it currently
-                    return (T) Void.TYPE;
+                    return (T) MISS_VALUE;
                 }
             } else {
                 if (size == 0) {
                     // empty size so we cannot convert
-                    return (T) Void.TYPE;
+                    return (T) MISS_VALUE;
                 }
             }
         }
diff --git 
a/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResultConverter.java
 
b/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResultConverter.java
index c49dceb..ca9723f 100644
--- 
a/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResultConverter.java
+++ 
b/components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecResultConverter.java
@@ -30,6 +30,8 @@ import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.camel.TypeConverter.MISS_VALUE;
+
 /**
  * Default converters for {@link ExecResult}. For details how to extend the
  * converters check out <a
@@ -96,7 +98,7 @@ public final class ExecResultConverter {
         } else {
             // use Void to indicate we cannot convert it
             // (prevents Camel from using a fallback converter which may 
convert a String from the instance name)  
-            return (T) Void.TYPE;
+            return (T) MISS_VALUE;
         }
     }
 
diff --git 
a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyConverter.java
 
b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyConverter.java
index 112db0a..e382ab8 100644
--- 
a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyConverter.java
+++ 
b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyConverter.java
@@ -23,6 +23,8 @@ import org.apache.camel.spi.TypeConverterRegistry;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Response;
 
+import static org.apache.camel.TypeConverter.MISS_VALUE;
+
 @Converter
 public final class JettyConverter {
 
@@ -41,7 +43,7 @@ public final class JettyConverter {
         if (value != null) {
             // should not try to convert Request as its not possible
             if (Request.class.isAssignableFrom(value.getClass())) {
-                return (T) Void.TYPE;
+                return (T) MISS_VALUE;
             }
         }
 
diff --git 
a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java 
b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java
index 43232a0..1757f21 100644
--- 
a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java
+++ 
b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConverterProcessor.java
@@ -21,9 +21,12 @@ import java.io.FileOutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.io.Writer;
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -33,6 +36,8 @@ import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.annotation.processing.SupportedSourceVersion;
 import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
@@ -50,20 +55,25 @@ public class ConverterProcessor extends AbstractProcessor {
     @Override
     public boolean process(Set<? extends TypeElement> annotations, 
RoundEnvironment roundEnv) {
         try {
-            if 
(this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.impl.converter.CoreFallbackConverter")
 != null) {
+            if (roundEnv.processingOver()) {
                 return false;
             }
 
-            if (roundEnv.processingOver()) {
+            if 
(this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.impl.converter.CoreStaticTypeConverterLoader")
 != null) {
+                return false;
+            }
+
+            // We're in tests, do not generate anything
+            if 
(this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.converter.ObjectConverter")
 == null) {
                 return false;
             }
 
             Comparator<TypeMirror> comparator = (o1, o2) -> 
processingEnv.getTypeUtils().isAssignable(o1, o2)
                     ? -1 : processingEnv.getTypeUtils().isAssignable(o2, o1) ? 
+1 : o1.toString().compareTo(o2.toString());
 
-            Map<String, Map<TypeMirror, ExecutableElement>> converters = new 
HashMap<>();
-            TypeElement annotationType = 
this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.Converter");
-            for (Element element : 
roundEnv.getElementsAnnotatedWith(annotationType)) {
+            Map<String, Map<TypeMirror, ExecutableElement>> converters = new 
TreeMap<>();
+            TypeElement converterAnnotationType = 
this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.Converter");
+            for (Element element : 
roundEnv.getElementsAnnotatedWith(converterAnnotationType)) {
                 if (element.getKind() == ElementKind.METHOD) {
                     ExecutableElement ee = (ExecutableElement) element;
                     TypeMirror to = ee.getReturnType();
@@ -81,57 +91,127 @@ public class ConverterProcessor extends AbstractProcessor {
                     converters.computeIfAbsent(toString(to), c -> new 
TreeMap<>(comparator)).put(from, ee);
                 }
             }
-
-            // We're in tests, do not generate anything
-            if 
(this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.converter.ObjectConverter")
 == null) {
-                return false;
+            TypeElement fallbackAnnotationType = 
this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.FallbackConverter");
+            List<ExecutableElement> fallbackConverters = new ArrayList<>();
+            for (Element element : 
roundEnv.getElementsAnnotatedWith(fallbackAnnotationType)) {
+                if (element.getKind() == ElementKind.METHOD) {
+                    ExecutableElement ee = (ExecutableElement) element;
+                    fallbackConverters.add(ee);
+                }
             }
 
             String p = "org.apache.camel.impl.converter";
-            String c = "CoreFallbackConverter";
+            String c = "CoreStaticTypeConverterLoader";
             JavaFileObject jfo = processingEnv.getFiler().createSourceFile(p + 
"." + c);
             Set<String> converterClasses = new LinkedHashSet<>();
             try (Writer writer = jfo.openWriter()) {
 
                 writer.append("package ").append(p).append(";\n");
                 writer.append("\n");
-                writer.append("import 
org.apache.camel.support.TypeConverterSupport;\n");
                 writer.append("import org.apache.camel.Exchange;\n");
                 writer.append("import 
org.apache.camel.TypeConversionException;\n");
+                writer.append("import 
org.apache.camel.TypeConverterLoaderException;\n");
+                writer.append("import 
org.apache.camel.spi.TypeConverterLoader;\n");
+                writer.append("import 
org.apache.camel.spi.TypeConverterRegistry;\n");
+                writer.append("import 
org.apache.camel.support.TypeConverterSupport;\n");
                 writer.append("\n");
                 writer.append("@SuppressWarnings(\"unchecked\")\n");
-                writer.append("public class ").append(c).append(" extends 
TypeConverterSupport {\n");
+                writer.append("public class ").append(c).append(" implements 
TypeConverterLoader {\n");
+                writer.append("\n");
+                writer.append("    static abstract class SimpleTypeConverter 
extends TypeConverterSupport {\n");
+                writer.append("        private final boolean allowNull;\n");
                 writer.append("\n");
-                writer.append("    public <T> T convertTo(Class<T> type, 
Exchange exchange, Object value) throws TypeConversionException {\n");
-                writer.append("        try {\n");
-                writer.append("            return (T) doConvert(type, 
exchange, value);\n");
-                writer.append("        } catch (TypeConversionException e) 
{\n");
-                writer.append("            throw e;\n");
-                writer.append("        } catch (Exception e) {\n");
-                writer.append("            throw new 
TypeConversionException(value, type, e);\n");
+                writer.append("        public SimpleTypeConverter(boolean 
allowNull) {\n");
+                writer.append("            this.allowNull = allowNull;\n");
                 writer.append("        }\n");
-                writer.append("    }\n");
                 writer.append("\n");
-                writer.append("    private Object doConvert(Class<?> type, 
Exchange exchange, Object value) throws Exception {\n");
-                writer.append("        switch (type.getName()) {\n");
+                writer.append("        @Override\n");
+                writer.append("        public boolean allowNull() {\n");
+                writer.append("            return allowNull;\n");
+                writer.append("        }\n");
+                writer.append("\n");
+                writer.append("        @Override\n");
+                writer.append("        public <T> T convertTo(Class<T> type, 
Exchange exchange, Object value) throws TypeConversionException {\n");
+                writer.append("            try {\n");
+                writer.append("                return (T) doConvert(exchange, 
value);\n");
+                writer.append("            } catch (TypeConversionException e) 
{\n");
+                writer.append("                throw e;\n");
+                writer.append("            } catch (Exception e) {\n");
+                writer.append("                throw new 
TypeConversionException(value, type, e);\n");
+                writer.append("            }\n");
+                writer.append("        }\n");
+                writer.append("        protected abstract Object 
doConvert(Exchange exchange, Object value) throws Exception;\n");
+                writer.append("    };\n");
+                writer.append("\n");
+                writer.append("    @Override\n");
+                writer.append("    public void load(TypeConverterRegistry 
registry) throws TypeConverterLoaderException {\n");
+
                 for (Map.Entry<String, Map<TypeMirror, ExecutableElement>> to 
: converters.entrySet()) {
-                    writer.append("            case 
\"").append(to.getKey()).append("\": {\n");
                     for (Map.Entry<TypeMirror, ExecutableElement> from : 
to.getValue().entrySet()) {
-                        String name = toString(from.getKey());
-                        if ("java.lang.Object".equals(name)) {
-                            writer.append("                if (value != null) 
{\n");
-                        } else {
-                            writer.append("                if (value 
instanceof ").append(name).append(") {\n");
+                        boolean allowNull = false;
+                        for (AnnotationMirror ann : 
from.getValue().getAnnotationMirrors()) {
+                            if (ann.getAnnotationType().asElement() == 
converterAnnotationType) {
+                                for (Map.Entry<? extends ExecutableElement, ? 
extends AnnotationValue> entry : ann.getElementValues().entrySet()) {
+                                    switch 
(entry.getKey().getSimpleName().toString()) {
+                                        case "allowNull":
+                                            allowNull = (Boolean) 
entry.getValue().getValue();
+                                            break;
+                                        default:
+                                            throw new IllegalStateException();
+                                    }
+                                }
+                            }
+                        }
+                        writer.append("        
registry.addTypeConverter(").append(to.getKey()).append(".class").append(", ")
+                                
.append(toString(from.getKey())).append(".class, new SimpleTypeConverter(")
+                                .append(Boolean.toString(allowNull)).append(") 
{\n");
+                        writer.append("            @Override\n");
+                        writer.append("            public Object 
doConvert(Exchange exchange, Object value) throws Exception {\n");
+                        writer.append("                return 
").append(toJava(from.getValue(), converterClasses)).append(";\n");
+                        writer.append("            }\n");
+                        writer.append("        });\n");
+                    }
+                }
+
+                for (ExecutableElement ee : fallbackConverters) {
+                    boolean allowNull = false;
+                    boolean canPromote = false;
+                    for (AnnotationMirror ann : ee.getAnnotationMirrors()) {
+                        if (ann.getAnnotationType().asElement() == 
fallbackAnnotationType) {
+                            for (Map.Entry<? extends ExecutableElement, ? 
extends AnnotationValue> entry : ann.getElementValues().entrySet()) {
+                                switch 
(entry.getKey().getSimpleName().toString()) {
+                                    case "allowNull":
+                                        allowNull = (Boolean) 
entry.getValue().getValue();
+                                        break;
+                                    case "canPromote":
+                                        canPromote = (Boolean) 
entry.getValue().getValue();
+                                        break;
+                                    default:
+                                        throw new IllegalStateException();
+                                }
+                            }
                         }
-                        writer.append("                    return 
").append(toJava(from.getValue(), converterClasses)).append(";\n");
-                        writer.append("                }\n");
                     }
-                    writer.append("                break;\n");
+                    writer.append("        
registry.addFallbackTypeConverter(new TypeConverterSupport() {\n");
+                    writer.append("            @Override\n");
+                    writer.append("            public boolean allowNull() 
{\n");
+                    writer.append("                return 
").append(Boolean.toString(allowNull)).append(";\n");
                     writer.append("            }\n");
+                    writer.append("            @Override\n");
+                    writer.append("            public <T> T convertTo(Class<T> 
type, Exchange exchange, Object value) throws TypeConversionException {\n");
+                    writer.append("                try {\n");
+                    writer.append("                    return (T) 
").append(toJavaFallback(ee, converterClasses)).append(";\n");
+                    writer.append("                } catch 
(TypeConversionException e) {\n");
+                    writer.append("                    throw e;\n");
+                    writer.append("                } catch (Exception e) {\n");
+                    writer.append("                    throw new 
TypeConversionException(value, type, e);\n");
+                    writer.append("                }\n");
+                    writer.append("            }\n");
+                    writer.append("        }, 
").append(Boolean.toString(canPromote)).append(");\n");
                 }
-                writer.append("        }\n");
-                writer.append("        return null;\n");
+                writer.append("\n");
                 writer.append("    }\n");
+                writer.append("\n");
 
                 for (String f : converterClasses) {
                     String s = f.substring(f.lastIndexOf('.') + 1);
@@ -177,6 +257,19 @@ public class ConverterProcessor extends AbstractProcessor {
         return pfx + "(" + cast + "value" + (converter.getParameters().size() 
== 2 ? ", exchange" : "") + ")";
     }
 
+    private String toJavaFallback(ExecutableElement converter, Set<String> 
converterClasses) {
+        String pfx;
+        if (converter.getModifiers().contains(Modifier.STATIC)) {
+            pfx = converter.getEnclosingElement().toString() + "." + 
converter.getSimpleName();
+        } else {
+            converterClasses.add(converter.getEnclosingElement().toString());
+            pfx = "get" + converter.getEnclosingElement().getSimpleName() + 
"()." + converter.getSimpleName();
+        }
+        String type = 
toString(converter.getParameters().get(converter.getParameters().size() - 
2).asType());
+        String cast = type.equals("java.lang.Object") ? "" : "(" + type + ") ";
+        return pfx + "(type, " + (converter.getParameters().size() == 4 ? 
"exchange, " : "") + cast + "value" + ", registry)";
+    }
+
     public static void dumpExceptionToErrorFile(String fileName, String 
message, Throwable e) {
         File file = new File(fileName);
         try {

Reply via email to