CAMEL-11379: Optimise - core type converters to be invoked faster
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/4a72341e Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/4a72341e Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/4a72341e Branch: refs/heads/master Commit: 4a72341ebffc9177be2d2897fdcfbc15a6c65c41 Parents: 79a1ae9 Author: Claus Ibsen <davscl...@apache.org> Authored: Sat Jun 24 11:10:19 2017 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Sat Jun 24 13:55:42 2017 +0200 ---------------------------------------------------------------------- .../org/apache/camel/impl/DefaultExchange.java | 4 +- .../converter/BaseTypeConverterRegistry.java | 10 +- .../impl/converter/OptimisedTypeConverter.java | 98 ++++++++++++++++++++ .../apache/camel/builder/SimpleBuilderTest.java | 2 +- .../apache/camel/converter/ConverterTest.java | 2 +- 5 files changed, 111 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/4a72341e/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java index 9888972..2ae2f5b 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java @@ -185,7 +185,7 @@ public final class DefaultExchange implements Exchange { Object value = getProperty(name); if (value == null) { // lets avoid NullPointerException when converting to boolean for null values - if (boolean.class == type || Boolean.class == type) { + if (boolean.class == type) { return (T) Boolean.FALSE; } return null; @@ -205,7 +205,7 @@ public final class DefaultExchange implements Exchange { Object value = getProperty(name, defaultValue); if (value == null) { // lets avoid NullPointerException when converting to boolean for null values - if (boolean.class == type || Boolean.class == type) { + if (boolean.class == type) { return (T) Boolean.FALSE; } return null; http://git-wip-us.apache.org/repos/asf/camel/blob/4a72341e/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java ---------------------------------------------------------------------- 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 28d9caf1..21e437a 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 @@ -64,6 +64,7 @@ import org.slf4j.LoggerFactory; */ 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<TypeMapping, TypeConverter>(); // for misses use a soft reference cache map, as the classes may be un-deployed at runtime protected final LRUSoftCache<TypeMapping, TypeMapping> misses = new LRUSoftCache<TypeMapping, TypeMapping>(1000); @@ -256,7 +257,7 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement noopCounter.increment(); } // lets avoid NullPointerException when converting to boolean for null values - if (boolean.class == type || Boolean.class == type) { + if (boolean.class == type) { return Boolean.FALSE; } return null; @@ -292,6 +293,13 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement attemptCounter.increment(); } + // use the optimised core converter first + Object result = optimisedTypeConverter.convertTo(type, exchange, value); + if (result != null) { + log.trace("Using optimised converter to convert: {} -> {}", type, value.getClass()); + 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)) { http://git-wip-us.apache.org/repos/asf/camel/blob/4a72341e/camel-core/src/main/java/org/apache/camel/impl/converter/OptimisedTypeConverter.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..45cc390 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/impl/converter/OptimisedTypeConverter.java @@ -0,0 +1,98 @@ +/** + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.Iterator; + +import org.apache.camel.Exchange; +import org.apache.camel.converter.ObjectConverter; +import org.apache.camel.converter.TimePatternConverter; +import org.apache.camel.util.ObjectHelper; + +/** + * Optimised type converter for performing the most common conversions using the type converters + * from camel-core. + */ +public class OptimisedTypeConverter { + + /** + * Attempts to convert the value to the given type + * + * @param type the type to convert to + * @param exchange the exchange, may be null + * @param value the value + * @return the converted value, or null if no core type converter exists to convert + */ + public Object convertTo(final Class<?> type, final Exchange exchange, final Object value) { + // 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(); + } + } + + // 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()); + } + } + + 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; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/4a72341e/camel-core/src/test/java/org/apache/camel/builder/SimpleBuilderTest.java ---------------------------------------------------------------------- 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 915ae53..c7cf355 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 @@ -66,7 +66,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().getCause()); + assertIsInstanceOf(NumberFormatException.class, e.getCause()); } assertEquals(true, SimpleBuilder.simple("${header.cool}", boolean.class).evaluate(exchange, Object.class)); http://git-wip-us.apache.org/repos/asf/camel/blob/4a72341e/camel-core/src/test/java/org/apache/camel/converter/ConverterTest.java ---------------------------------------------------------------------- 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 0f2fab5..8bafbfb 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 @@ -242,7 +242,7 @@ public class ConverterTest extends TestCase { converter.mandatoryConvertTo(char.class, "ABC"); fail("Should have thrown an exception"); } catch (TypeConversionException e) { - assertEquals("java.lang.IllegalArgumentException: String must have exactly a length of 1: ABC", e.getCause().getMessage()); + assertEquals("String must have exactly a length of 1: ABC", e.getCause().getMessage()); } }