diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ConverterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ConverterParser.java index 5940db2924..d47272e1da 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ConverterParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ConverterParser.java @@ -21,10 +21,11 @@ import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; -import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedSet; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.context.support.ConversionServiceFactoryBean; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.integration.util.ConverterRegistrar; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.w3c.dom.Element; @@ -34,16 +35,15 @@ import org.w3c.dom.Element; * @since 2.0 */ public class ConverterParser extends AbstractBeanDefinitionParser { - private final ManagedList converters = new ManagedList(); - private final static String CONVERSION_SERVICE = "integrationConversionService"; - + private final ManagedSet converters = new ManagedSet(); + private String CONVERTER_REGISTRAR = "converterRegistrar"; /* (non-Javadoc) * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext) */ @Override protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { - if (!parserContext.getReaderContext().getRegistry().containsBeanDefinition(CONVERSION_SERVICE)){ - this.defineConversionSesrvice(parserContext); + if (!parserContext.getRegistry().containsBeanDefinition(CONVERTER_REGISTRAR)){ + this.defineConverterRegistrar(parserContext); } BeanComponentDefinition converterDefinition = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element, parserContext); if (converterDefinition == null){ @@ -58,10 +58,10 @@ public class ConverterParser extends AbstractBeanDefinitionParser { /* * */ - private void defineConversionSesrvice(ParserContext parserContext){ - BeanDefinitionBuilder conversionServiceBuilder = BeanDefinitionBuilder.rootBeanDefinition(ConversionServiceFactoryBean.class); - conversionServiceBuilder.addPropertyValue("converters", converters); - BeanDefinitionHolder bdHolder = new BeanDefinitionHolder(conversionServiceBuilder.getBeanDefinition(), CONVERSION_SERVICE); + private void defineConverterRegistrar(ParserContext parserContext){ + BeanDefinitionBuilder conversionServiceBuilder = BeanDefinitionBuilder.rootBeanDefinition(ConverterRegistrar.class); + conversionServiceBuilder.addConstructorArgValue(converters); + BeanDefinitionHolder bdHolder = new BeanDefinitionHolder(conversionServiceBuilder.getBeanDefinition(), CONVERTER_REGISTRAR); BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, parserContext.getRegistry()); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/ConverterRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/util/ConverterRegistrar.java new file mode 100644 index 0000000000..9cce815d07 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/util/ConverterRegistrar.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed 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.springframework.integration.util; + +import java.util.Set; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.support.ConversionServiceFactoryBean; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.support.ConversionServiceFactory; +import org.springframework.core.convert.support.GenericConversionService; + +/** + * @author Oleg Zhurakousky + * @since 2.0 + */ +public class ConverterRegistrar implements BeanFactoryPostProcessor { + private final Set> converters; + + public ConverterRegistrar(Set> converters){ + this.converters = converters; + } + /** + * This method will add converters to the SI's conversion service - {@link SI#CONVERSION_SERVICE} + * If SI's conversion service does not exist, then an instance of the {@link ConversionService} will + * be created and registered under the name {@link SI#CONVERSION_SERVICE} + */ + public void postProcessBeanFactory( + ConfigurableListableBeanFactory beanFactory) throws BeansException { + if (!beanFactory.containsBean(SI.CONVERSION_SERVICE)){ + BeanDefinitionBuilder conversionServiceBuilder = BeanDefinitionBuilder.rootBeanDefinition(ConversionServiceFactoryBean.class); + BeanDefinitionHolder csHolder = new BeanDefinitionHolder(conversionServiceBuilder.getBeanDefinition(), SI.CONVERSION_SERVICE); + BeanDefinitionReaderUtils.registerBeanDefinition(csHolder, (BeanDefinitionRegistry) beanFactory); + } + GenericConversionService conversionService = beanFactory.getBean(SI.CONVERSION_SERVICE, GenericConversionService.class); + ConversionServiceFactory.registerConverters(converters, conversionService); + } +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/SI.java b/spring-integration-core/src/main/java/org/springframework/integration/util/SI.java new file mode 100644 index 0000000000..4d6b66e668 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/util/SI.java @@ -0,0 +1,25 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed 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.springframework.integration.util; + +/** + * @author Oleg Zhurakousky + * @since 2.0 + */ +public interface SI { + + public String CONVERSION_SERVICE = "integrationConversionService"; +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ConverterParserWithExistingConversionServiceTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ConverterParserWithExistingConversionServiceTests-context.xml new file mode 100644 index 0000000000..712fcab694 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ConverterParserWithExistingConversionServiceTests-context.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ConverterParserWithExistingConversionServiceTests-parent.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ConverterParserWithExistingConversionServiceTests-parent.xml new file mode 100644 index 0000000000..2c7d00ed9b --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ConverterParserWithExistingConversionServiceTests-parent.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ConverterParserWithExistingConversionServiceTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ConverterParserWithExistingConversionServiceTests.java new file mode 100644 index 0000000000..d3e6127bcd --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ConverterParserWithExistingConversionServiceTests.java @@ -0,0 +1,122 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed 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.springframework.integration.config.xml; + +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.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.support.GenericConversionService; +import org.springframework.integration.util.SI; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.Assert; + + +/** + * @author Oleg Zhurakousky + * + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class ConverterParserWithExistingConversionServiceTests { + @Autowired + private ApplicationContext applicationContext; + + @Autowired + @Qualifier(SI.CONVERSION_SERVICE) + private ConversionService conversionService; + + @Test + public void testConversionServiceAvailability(){ + Assert.isTrue(applicationContext.getBean(SI.CONVERSION_SERVICE).equals(conversionService)); + Assert.isTrue(conversionService.canConvert(TestBean1.class, TestBean2.class)); + Assert.isTrue(conversionService.canConvert(TestBean1.class, TestBean3.class)); + } + @Test + public void testParentConversionServiceAvailability(){ + ApplicationContext parentContext = + new ClassPathXmlApplicationContext("ConverterParserWithExistingConversionServiceTests-parent.xml", ConverterParserWithExistingConversionServiceTests.class); + GenericApplicationContext childContext = new GenericApplicationContext(); + childContext.setParent(parentContext); + + GenericConversionService conversionServiceParent = parentContext.getBean(SI.CONVERSION_SERVICE,GenericConversionService.class); + GenericConversionService conversionServiceChild = childContext.getBean(SI.CONVERSION_SERVICE,GenericConversionService.class); + Assert.isTrue(conversionServiceParent == conversionServiceChild); // validating that they are pointing to the same object + conversionServiceChild.addConverter(new TestConverter()); + conversionServiceChild.addConverter(new TestConverter3()); + Assert.isTrue(conversionServiceChild.canConvert(TestBean1.class, TestBean2.class)); + Assert.isTrue(conversionServiceChild.canConvert(TestBean1.class, TestBean3.class)); + } + + + private static class TestBean1 { + + private String text; + + public TestBean1(String text) { + this.text = text; + } + } + + + private static class TestBean2 { + + private String text; + + public TestBean2(String text) { + this.text = text; + } + + // called by router for channel name + public String toString() { + return this.text.replace("-TEST", "_TARGET_CHANNEL"); + } + } + private static class TestBean3 { + + private String text; + + public TestBean3(String text) { + this.text = text; + } + + // called by router for channel name + public String toString() { + return this.text.replace("-TEST", "_TARGET_CHANNEL"); + } + } + + @SuppressWarnings("unused") + private static class TestConverter implements Converter { + + public TestBean2 convert(TestBean1 source) { + return new TestBean2(source.text.toUpperCase()); + } + } + @SuppressWarnings("unused") + private static class TestConverter3 implements Converter { + + public TestBean3 convert(TestBean1 source) { + return new TestBean3(source.text.toUpperCase()); + } + } +}