Repository: camel Updated Branches: refs/heads/camel-2.18.x 6cb200c09 -> 495cddd83
CAMEL-10548: Converter from List to String is not found when @EnableAutoConfiguration is used Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/65a67bc4 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/65a67bc4 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/65a67bc4 Branch: refs/heads/camel-2.18.x Commit: 65a67bc4a4a975017200e1ce46a1d27d4d552a76 Parents: 6cb200c Author: lburgazzoli <lburgazz...@gmail.com> Authored: Thu Dec 1 15:06:44 2016 +0100 Committer: lburgazzoli <lburgazz...@gmail.com> Committed: Thu Dec 1 16:32:03 2016 +0100 ---------------------------------------------------------------------- .../camel/spring/boot/SpringTypeConverter.java | 31 ++++- .../spring/boot/SpringTypeConverterTest.java | 129 +++++++++++++++++++ 2 files changed, 158 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/65a67bc4/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringTypeConverter.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringTypeConverter.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringTypeConverter.java index 5f4021a..204f13b 100644 --- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringTypeConverter.java +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringTypeConverter.java @@ -19,20 +19,26 @@ package org.apache.camel.spring.boot; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.camel.Exchange; import org.apache.camel.TypeConversionException; import org.apache.camel.support.TypeConverterSupport; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.convert.TypeDescriptor; public class SpringTypeConverter extends TypeConverterSupport { private final List<ConversionService> conversionServices; + private final ConcurrentHashMap<Class<?>, TypeDescriptor> types; @Autowired public SpringTypeConverter(List<ConversionService> conversionServices) { this.conversionServices = conversionServices; + this.types = new ConcurrentHashMap<>(); } @Override @@ -47,12 +53,33 @@ public class SpringTypeConverter extends TypeConverterSupport { return null; } + TypeDescriptor sourceType = types.computeIfAbsent(value.getClass(), TypeDescriptor::valueOf); + TypeDescriptor targetType = types.computeIfAbsent(type, TypeDescriptor::valueOf); + for (ConversionService conversionService : conversionServices) { - if (conversionService.canConvert(value.getClass(), type)) { - return conversionService.convert(value, type); + if (conversionService.canConvert(sourceType, targetType)) { + try { + return (T)conversionService.convert(value, sourceType, targetType); + } catch (ConversionFailedException e) { + // if value is a collection or an array the check ConversionService::canConvert + // may return true but then the conversion of specific objects may fail + // + // https://issues.apache.org/jira/browse/CAMEL-10548 + // https://jira.spring.io/browse/SPR-14971 + // + if (e.getCause() instanceof ConverterNotFoundException && isArrayOrCollection(value)) { + return null; + } else { + throw new TypeConversionException(value, type, e); + } + } } } + return null; } + private boolean isArrayOrCollection(Object value) { + return value instanceof Collection || value.getClass().isArray(); + } } http://git-wip-us.apache.org/repos/asf/camel/blob/65a67bc4/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/SpringTypeConverterTest.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/SpringTypeConverterTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/SpringTypeConverterTest.java new file mode 100644 index 0000000..3ccc367 --- /dev/null +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/SpringTypeConverterTest.java @@ -0,0 +1,129 @@ +/** + * 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.spring.boot; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringTypeConverterTest.SpringTypeConversionConfiguration.class) +public class SpringTypeConverterTest { + @Autowired + @Qualifier("camelSpringConversionService") + ConversionService conversionService; + + @Autowired + @Qualifier("camelSpringTypeConverter") + SpringTypeConverter converter; + + @Test + public void testConversionService() { + Collection<?> source = Arrays.asList(new Person("Name", 30)); + + Assert.assertFalse(conversionService.canConvert(Person.class, String.class)); + Assert.assertTrue(conversionService.canConvert(source.getClass(), String.class)); + + try { + conversionService.convert(source, String.class); + } catch (ConversionFailedException e) { + // Expected as Person can't be converted to a string according to + // Spring's FallbackObjectToStringConverter, see javadoc for: + // + // org.springframework.core.convert.support.FallbackObjectToStringConverter + // + Assert.assertTrue(e.getCause() instanceof ConverterNotFoundException); + } + + + Assert.assertNull(converter.convertTo(String.class, source)); + } + + public static class Person { + private String name; + private int age; + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } + } + + @Configuration + @EnableAutoConfiguration( + exclude = { + CamelAutoConfiguration.class, TypeConversionConfiguration.class, WebMvcAutoConfiguration.class + } + ) + public static class SpringTypeConversionConfiguration { + @Bean + ConversionService camelSpringConversionService(ApplicationContext applicationContext) { + DefaultConversionService service = new DefaultConversionService(); + for (Converter converter : applicationContext.getBeansOfType(Converter.class).values()) { + service.addConverter(converter); + } + + return service; + } + @Bean + SpringTypeConverter camelSpringTypeConverter(List<ConversionService> conversionServices) { + return new SpringTypeConverter(conversionServices); + } + } +} \ No newline at end of file