INT-3327: Add IntegrationConverter Annotation
JIRA: https://jira.spring.io/browse/INT-3327 INT-3327: Addressing PR comments Polishing
This commit is contained in:
committed by
Gary Russell
parent
d74b4dba73
commit
969310b453
@@ -27,8 +27,10 @@ import java.lang.annotation.Target;
|
||||
* annotation will be applied as global channel interceptors
|
||||
* using the provided {@code patterns} to match channel names.
|
||||
* <p>
|
||||
* The annotation can be used at the {@code class} level for {@link org.springframework.stereotype.Component} beans
|
||||
* This annotation can be used at the {@code class} level for {@link org.springframework.stereotype.Component} beans
|
||||
* and on methods with {@link org.springframework.context.annotation.Bean}.
|
||||
* <p>
|
||||
* This annotation is an analogue of {@code <int:channel-interceptor/>}.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @since 4.0
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A marker annotation (an analogue of {@code <int:converter/>}) to register
|
||||
* {@link org.springframework.core.convert.converter.Converter},
|
||||
* {@link org.springframework.core.convert.converter.GenericConverter} or
|
||||
* {@link org.springframework.core.convert.converter.ConverterFactory} beans for the {@code integrationConversionService}.
|
||||
* <p>
|
||||
* This annotation can be used at the {@code class} level for {@link org.springframework.stereotype.Component} beans
|
||||
* and on methods with {@link org.springframework.context.annotation.Bean}.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @since 4.0
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface IntegrationConverter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @since 4.0
|
||||
*/
|
||||
public class IntegrationConverterInitializer implements IntegrationConfigurationInitializer {
|
||||
|
||||
private static final String CONTEXT_PACKAGE = "org.springframework.integration.context.";
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
|
||||
for (String beanName : registry.getBeanDefinitionNames()) {
|
||||
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
|
||||
if (beanDefinition instanceof AnnotatedBeanDefinition) {
|
||||
AnnotationMetadata metadata = ((AnnotatedBeanDefinition) beanDefinition).getMetadata();
|
||||
boolean hasIntegrationConverter = metadata.hasAnnotation(IntegrationConverter.class.getName());
|
||||
|
||||
if (!hasIntegrationConverter && beanDefinition.getSource() instanceof MethodMetadata) {
|
||||
MethodMetadata beanMethod = (MethodMetadata) beanDefinition.getSource();
|
||||
hasIntegrationConverter = beanMethod.isAnnotated(IntegrationConverter.class.getName());
|
||||
}
|
||||
|
||||
if (hasIntegrationConverter) {
|
||||
this.registerConverter(registry, new RuntimeBeanReference(beanName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void registerConverter(BeanDefinitionRegistry registry, BeanMetadataElement converterBeanDefinition) {
|
||||
Set<BeanMetadataElement> converters = new ManagedSet<BeanMetadataElement>();
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME)) {
|
||||
BeanDefinitionBuilder converterRegistrarBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
CONTEXT_PACKAGE + "ConverterRegistrar").addConstructorArgValue(converters);
|
||||
registry.registerBeanDefinition(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME,
|
||||
converterRegistrarBuilder.getBeanDefinition());
|
||||
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME)) {
|
||||
registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME,
|
||||
new RootBeanDefinition(CONTEXT_PACKAGE + "CustomConversionServiceFactoryBean"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
BeanDefinition converterRegistrarBeanDefinition = registry
|
||||
.getBeanDefinition(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME);
|
||||
converters = (Set<BeanMetadataElement>) converterRegistrarBeanDefinition
|
||||
.getConstructorArgumentValues()
|
||||
.getIndexedArgumentValues()
|
||||
.values()
|
||||
.iterator()
|
||||
.next()
|
||||
.getValue();
|
||||
}
|
||||
|
||||
converters.add(converterBeanDefinition);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -21,56 +21,37 @@ import org.w3c.dom.Element;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
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.ManagedSet;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.IntegrationConverterInitializer;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Mark Fisher
|
||||
* @author Artem Bilan
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ConverterParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
private final ManagedSet<Object> converters = new ManagedSet<Object>();
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
private final static IntegrationConverterInitializer INTEGRATION_CONVERTER_INITIALIZER = new IntegrationConverterInitializer();
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
this.initializeConversionServiceInfrastructureIfNecessary(parserContext);
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
BeanComponentDefinition converterDefinition = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element, parserContext);
|
||||
if (converterDefinition != null) {
|
||||
this.converters.add(converterDefinition);
|
||||
INTEGRATION_CONVERTER_INITIALIZER.registerConverter(registry, converterDefinition);
|
||||
}
|
||||
else {
|
||||
String beanName = element.getAttribute("ref");
|
||||
Assert.isTrue(StringUtils.hasText(beanName),
|
||||
"Either a 'ref' attribute pointing to a Converter or a <bean> sub-element defining a Converter is required.");
|
||||
this.converters.add(new RuntimeBeanReference(beanName));
|
||||
INTEGRATION_CONVERTER_INITIALIZER.registerConverter(registry, new RuntimeBeanReference(beanName));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void initializeConversionServiceInfrastructureIfNecessary(ParserContext parserContext) {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (!this.initialized) {
|
||||
String contextPackage = "org.springframework.integration.context.";
|
||||
BeanDefinitionBuilder creatorBuilder = BeanDefinitionBuilder.rootBeanDefinition(contextPackage + "ConversionServiceCreator");
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(creatorBuilder.getBeanDefinition(), parserContext.getRegistry());
|
||||
BeanDefinitionBuilder conversionServiceBuilder = BeanDefinitionBuilder.rootBeanDefinition(contextPackage + "ConverterRegistrar");
|
||||
conversionServiceBuilder.addConstructorArgValue(converters);
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(conversionServiceBuilder.getBeanDefinition(), parserContext.getRegistry());
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.context;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
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.support.GenericConversionService;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
class ConversionServiceCreator implements BeanFactoryPostProcessor {
|
||||
|
||||
private final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
if (!beanFactory.containsBean(IntegrationContextUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME)) {
|
||||
if (beanFactory instanceof BeanDefinitionRegistry) {
|
||||
BeanDefinitionBuilder conversionServiceBuilder = BeanDefinitionBuilder.rootBeanDefinition(CustomConversionServiceFactoryBean.class);
|
||||
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(
|
||||
conversionServiceBuilder.getBeanDefinition(), IntegrationContextUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(beanDefinitionHolder, (BeanDefinitionRegistry) beanFactory);
|
||||
}
|
||||
else if (logger.isWarnEnabled()) {
|
||||
logger.warn("BeanFactory is not a BeanDefinitionRegistry implementation. Cannot register a default ConversionService.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is a workaround until we depend on Spring 3.1 and specifically when SPR-8818 is resolved.
|
||||
* See INT-2259 and INT-1893 for more detail.
|
||||
*/
|
||||
static class CustomConversionServiceFactoryBean extends ConversionServiceFactoryBean {
|
||||
|
||||
@Override
|
||||
public ConversionService getObject() {
|
||||
ConversionService service = super.getObject();
|
||||
if (service instanceof GenericConversionService) {
|
||||
((GenericConversionService) service).removeConvertible(Object.class, Object.class);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
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;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -30,19 +29,19 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Utility class that keeps track of a set of Converters in order to register
|
||||
* them with the "integrationConversionService" upon initialization.
|
||||
*
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
class ConverterRegistrar implements InitializingBean, BeanFactoryAware {
|
||||
|
||||
private final Set<Converter<?, ?>> converters;
|
||||
private final Set<?> converters;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
public ConverterRegistrar(Set<Converter<?, ?>> converters) {
|
||||
public ConverterRegistrar(Set<?> converters) {
|
||||
this.converters = converters;
|
||||
}
|
||||
|
||||
@@ -55,7 +54,7 @@ class ConverterRegistrar implements InitializingBean, BeanFactoryAware {
|
||||
Assert.notNull(beanFactory, "BeanFactory is required");
|
||||
ConversionService conversionService = IntegrationContextUtils.getConversionService(beanFactory);
|
||||
if (conversionService instanceof GenericConversionService) {
|
||||
ConversionServiceFactory.registerConverters(converters, (GenericConversionService) conversionService);
|
||||
ConversionServiceFactory.registerConverters(converters, (GenericConversionService) conversionService);
|
||||
}
|
||||
else {
|
||||
Assert.notNull(conversionService, "Failed to locate '" + IntegrationContextUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME + "'");
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2014 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.context;
|
||||
|
||||
import org.springframework.context.support.ConversionServiceFactoryBean;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
|
||||
/**
|
||||
* This is a workaround until SPR-8818 will be resolved.
|
||||
* See INT-2259 and INT-1893 for more detail.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
class CustomConversionServiceFactoryBean extends ConversionServiceFactoryBean {
|
||||
|
||||
@Override
|
||||
public ConversionService getObject() {
|
||||
ConversionService service = super.getObject();
|
||||
if (service instanceof GenericConversionService) {
|
||||
((GenericConversionService) service).removeConvertible(Object.class, Object.class);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -52,6 +52,8 @@ public abstract class IntegrationContextUtils {
|
||||
|
||||
public static final String METADATA_STORE_BEAN_NAME = "metadataStore";
|
||||
|
||||
public static final String CONVERTER_REGISTRAR_BEAN_NAME = "converterRegistrar";
|
||||
|
||||
public static final String INTEGRATION_CONVERSION_SERVICE_BEAN_NAME = "integrationConversionService";
|
||||
|
||||
public static final String INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME = "integrationEvaluationContext";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.integration.config.boot.IntegrationAutoConfiguration
|
||||
org.springframework.integration.config.IntegrationConfigurationInitializer=\
|
||||
org.springframework.integration.config.GlobalChannelInterceptorInitializer
|
||||
org.springframework.integration.config.GlobalChannelInterceptorInitializer,\
|
||||
org.springframework.integration.config.IntegrationConverterInitializer
|
||||
|
||||
@@ -42,6 +42,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.serializer.support.SerializingConverter;
|
||||
import org.springframework.integration.annotation.Gateway;
|
||||
import org.springframework.integration.annotation.GatewayHeader;
|
||||
import org.springframework.integration.annotation.IntegrationComponentScan;
|
||||
@@ -53,6 +55,7 @@ import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.annotation.Transformer;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.FixedSubscriberChannel;
|
||||
import org.springframework.integration.channel.NullChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.channel.interceptor.WireTap;
|
||||
@@ -60,8 +63,10 @@ import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.config.EnableMessageHistory;
|
||||
import org.springframework.integration.config.EnablePublisher;
|
||||
import org.springframework.integration.config.GlobalChannelInterceptor;
|
||||
import org.springframework.integration.config.IntegrationConverter;
|
||||
import org.springframework.integration.history.MessageHistory;
|
||||
import org.springframework.integration.history.MessageHistoryConfigurer;
|
||||
import org.springframework.integration.message.MutableMessage;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -69,6 +74,7 @@ import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
import org.springframework.messaging.support.ChannelInterceptorAdapter;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
@@ -110,6 +116,15 @@ public class EnableIntegrationTests {
|
||||
@Autowired
|
||||
private AtomicInteger fbInterceptorCounter;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel numberChannel;
|
||||
|
||||
@Autowired
|
||||
private TestConverter testConverter;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel bytesChannel;
|
||||
|
||||
@Test
|
||||
public void testAnnotatedServiceActivator() {
|
||||
this.input.send(MessageBuilder.withPayload("Foo").build());
|
||||
@@ -192,6 +207,17 @@ public class EnableIntegrationTests {
|
||||
child.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegrationConverter() {
|
||||
this.numberChannel.send(new GenericMessage<Integer>(10));
|
||||
this.numberChannel.send(new GenericMessage<Boolean>(true));
|
||||
assertThat(this.testConverter.getInvoked(), Matchers.greaterThan(0));
|
||||
|
||||
assertTrue(this.bytesChannel.send(new GenericMessage<byte[]>("foo".getBytes())));
|
||||
assertTrue(this.bytesChannel.send(new GenericMessage<Message<?>>(new MutableMessage<Object>(""))));
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@IntegrationComponentScan
|
||||
@@ -271,6 +297,23 @@ public class EnableIntegrationTests {
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
@IntegrationConverter
|
||||
public static class TestConverter implements Converter<Boolean, Number> {
|
||||
|
||||
private final AtomicInteger invoked = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public Number convert(Boolean source) {
|
||||
this.invoked.incrementAndGet();
|
||||
return source ? 1 : 0;
|
||||
}
|
||||
|
||||
public Integer getInvoked() {
|
||||
return invoked.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
@ImportResource("classpath:org/springframework/integration/configuration/EnableIntegrationTests-context.xml")
|
||||
@@ -293,6 +336,26 @@ public class EnableIntegrationTests {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public QueueChannel numberChannel() {
|
||||
QueueChannel channel = new QueueChannel();
|
||||
channel.setDatatypes(Number.class);
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public QueueChannel bytesChannel() {
|
||||
QueueChannel channel = new QueueChannel();
|
||||
channel.setDatatypes(byte[].class);
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@IntegrationConverter
|
||||
public SerializingConverter serializingConverter() {
|
||||
return new SerializingConverter();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -16,29 +16,25 @@
|
||||
|
||||
package org.springframework.integration.transformer;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
|
||||
/**
|
||||
@@ -123,22 +119,8 @@ public class MapToObjectTransformerTests {
|
||||
|
||||
private BeanFactory getBeanFactory() {
|
||||
GenericApplicationContext ctx = TestUtils.createTestApplicationContext();
|
||||
Constructor<?> constructorToUse = null;
|
||||
try {
|
||||
// Add the integrationConversionService (reflection needed because of package protection)
|
||||
final Class<?> conversionServiceCreatorClass = ClassUtils.forName("org.springframework.integration.context.ConversionServiceCreator",
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
|
||||
public Constructor<?> run() throws Exception {
|
||||
return conversionServiceCreatorClass.getDeclaredConstructor((Class[]) null);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Unexpected Privilege Exception: ", e);
|
||||
}
|
||||
|
||||
ctx.addBeanFactoryPostProcessor((BeanFactoryPostProcessor) BeanUtils.instantiateClass(constructorToUse));
|
||||
ctx.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME,
|
||||
new RootBeanDefinition("org.springframework.integration.context.CustomConversionServiceFactoryBean"));
|
||||
ctx.refresh();
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -588,10 +588,12 @@ any transaction configuration essentially allowing you to enhance the behavior o
|
||||
In this scenario we need to perform type conversion. Spring Integration provides a convenient way for registering type
|
||||
converters (using the Spring 3.x ConversionService) within its own instance of a conversion service bean named
|
||||
<emphasis>integrationConversionService</emphasis>.
|
||||
That bean is automatically created as soon as the first converter is defined using the Spring Integration namespace support.
|
||||
That bean is automatically created as soon as the first converter is defined using the Spring Integration infrastructure.
|
||||
|
||||
To register a Converter all you need is to implement
|
||||
<interfacename>org.springframework.core.convert.converter.Converter</interfacename> and define it via
|
||||
<interfacename>org.springframework.core.convert.converter.Converter</interfacename>,
|
||||
<interfacename>org.springframework.core.convert.converter.GenericConverter</interfacename> or
|
||||
<interfacename>org.springframework.core.convert.converter.ConverterFactory</interfacename> and define it via
|
||||
convenient namespace support:
|
||||
<programlisting language="xml"><![CDATA[<int:converter ref="sampleConverter"/>
|
||||
|
||||
@@ -602,6 +604,31 @@ any transaction configuration essentially allowing you to enhance the behavior o
|
||||
<bean class="o.s.i.config.xml.ConverterParserTests$TestConverter3"/>
|
||||
</int:converter>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Starting with <emphasis>Spring Integration 4.0</emphasis>, the above configuration is available using annotations:
|
||||
<programlisting language="java"><![CDATA[@Component
|
||||
@IntegrationConverter
|
||||
public class TestConverter implements Converter<Boolean, Number> {
|
||||
|
||||
public Number convert(Boolean source) {
|
||||
return source ? 1 : 0;
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
|
||||
or as a <code>@Configuration</code> part:
|
||||
<programlisting language="java"><![CDATA[@Configuration
|
||||
@EnableIntegration
|
||||
public class ContextConfiguration {
|
||||
|
||||
@Bean
|
||||
@IntegrationConverter
|
||||
public SerializingConverter serializingConverter() {
|
||||
return new SerializingConverter();
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
</para>
|
||||
<important>
|
||||
<para>
|
||||
When configuring an <emphasis>Application Context</emphasis>, the
|
||||
|
||||
@@ -368,6 +368,15 @@
|
||||
on <classname>@Bean</classname> methods within <classname>@Configuration</classname> classes. In either case,
|
||||
the bean <emphasis role="bold">must</emphasis> be a <interfacename>ChannelInterceptor</interfacename>.
|
||||
</para>
|
||||
<para>
|
||||
The <classname>@IntegrationConverter</classname> annotation has been introduced to
|
||||
mark <interfacename>Converter</interfacename>, <interfacename>GenericConverter</interfacename> or
|
||||
<interfacename>ConverterFactory</interfacename> beans as candidate converters for <code>integrationConversionService</code>.
|
||||
This annotation is an analogue of the <code><int:converter></code> xml element
|
||||
(see <xref linkend="payload-type-conversion"/>). <code>@IntegrationConverter</code> annotations
|
||||
can be placed at the class level (with a <classname>@Component</classname> stereotype annotation), or
|
||||
on <classname>@Bean</classname> methods within <classname>@Configuration</classname> classes.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<title>@MessagingGateway</title>
|
||||
<para>
|
||||
Messaging gateway interfaces can now be configured with the <code>@MessagingGateway</code> annotation.
|
||||
It is an analogue of the <code><gateway/></code> xml element.
|
||||
It is an analogue of the <code><int:gateway/></code> xml element.
|
||||
For more information, see <xref linkend="messaging-gateway-annotation"/>.
|
||||
</para>
|
||||
</section>
|
||||
@@ -68,7 +68,7 @@
|
||||
Spring Integration infrastructure beans to be configured using Spring Boot's
|
||||
<code>@EnableAutoConfiguration</code>.
|
||||
For more information see
|
||||
<ulink url="http://projects.spring.io/spring-boot/docs/spring-boot-autoconfigure/README.html"
|
||||
<ulink url="http://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html"
|
||||
>Spring Boot - AutoConfigure</ulink>.
|
||||
</para>
|
||||
</section>
|
||||
@@ -80,6 +80,14 @@
|
||||
For more information, see <xref linkend="enable-integration"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="4.0-integration-converter">
|
||||
<title>@IntegrationConverter</title>
|
||||
<para>
|
||||
The <code>@IntegrationConverter</code> annotation has bean introduced,
|
||||
as an analogue of <code><int:converter/></code> component.
|
||||
For more information, see <xref linkend="enable-integration"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="4.0-enable-publisher">
|
||||
<title>@EnablePublisher</title>
|
||||
<para>
|
||||
|
||||
Reference in New Issue
Block a user