GH-3502: More refactoring to avoid reflection (#3532)

* GH-3502: More refactoring to avoid reflection

Fixes https://github.com/spring-projects/spring-integration/issues/3502

* Move `ChannelInitializer` bean registration into an `AbstractIntegrationNamespaceHandler` -
it was never used for annotations and Java DSL...
* Rework `IntegrationFlows.fromSupplier()` to call a provided `Supplier` directly -
not via reflection in the `MethodInvokingMessageSource`
* Resolve new Sonar smells
* Rework `EndpointSpec` to accept an expected factory bean instance via ctor arg
instead of reflection
* Rework `Jackson2JsonObjectMapper` to use well-known module instances directly -
not via reflection from their class names

* * Revert `DefaultMethodInvokingMethodInterceptor.methodHandleCache` property definition wrap
This commit is contained in:
Artem Bilan
2021-04-06 10:06:07 -04:00
committed by GitHub
parent 27e1f3a636
commit 3f0c57894b
21 changed files with 372 additions and 308 deletions

View File

@@ -440,7 +440,15 @@ project('spring-integration-core') {
exclude group: 'org.springframework'
}
api 'io.projectreactor:reactor-core'
optionalApi 'com.fasterxml.jackson.core:jackson-databind'
optionalApi 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8'
optionalApi 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
optionalApi 'com.fasterxml.jackson.datatype:jackson-datatype-joda'
optionalApi ('com.fasterxml.jackson.module:jackson-module-kotlin') {
exclude group: 'org.jetbrains.kotlin'
}
optionalApi "com.jayway.jsonpath:json-path:$jsonpathVersion"
optionalApi "com.esotericsoftware:kryo-shaded:$kryoShadedVersion"
optionalApi "io.micrometer:micrometer-core:$micrometerVersion"
@@ -449,10 +457,6 @@ project('spring-integration-core') {
optionalApi 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
testImplementation "org.aspectj:aspectjweaver:$aspectjVersion"
testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
testRuntime ('com.fasterxml.jackson.module:jackson-module-kotlin') {
exclude group: 'org.jetbrains.kotlin'
}
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@@ -40,16 +40,20 @@ import org.springframework.util.Assert;
*
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
*
* @since 2.1.1
*/
final class ChannelInitializer implements BeanFactoryAware, InitializingBean {
public final class ChannelInitializer implements BeanFactoryAware, InitializingBean {
private final Log logger = LogFactory.getLog(this.getClass());
private static final Log LOGGER = LogFactory.getLog(ChannelInitializer.class);
private volatile BeanFactory beanFactory;
private volatile boolean autoCreate = true;
ChannelInitializer() {
}
public void setAutoCreate(boolean autoCreate) {
this.autoCreate = autoCreate;
@@ -68,17 +72,18 @@ final class ChannelInitializer implements BeanFactoryAware, InitializingBean {
}
else {
AutoCreateCandidatesCollector channelCandidatesCollector =
this.beanFactory.getBean(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME, AutoCreateCandidatesCollector.class);
Assert.notNull(channelCandidatesCollector, "Failed to locate '" + IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
this.beanFactory.getBean(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME,
AutoCreateCandidatesCollector.class);
// at this point channelNames are all resolved with placeholders and SpEL
Collection<String> channelNames = channelCandidatesCollector.getChannelNames();
if (channelNames != null) {
for (String channelName : channelNames) {
if (!this.beanFactory.containsBean(channelName)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Auto-creating channel '" + channelName + "' as DirectChannel");
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Auto-creating channel '" + channelName + "' as DirectChannel");
}
IntegrationConfigUtils.autoCreateDirectChannel(channelName, (BeanDefinitionRegistry) this.beanFactory);
IntegrationConfigUtils.autoCreateDirectChannel(channelName,
(BeanDefinitionRegistry) this.beanFactory);
}
}
}
@@ -88,7 +93,7 @@ final class ChannelInitializer implements BeanFactoryAware, InitializingBean {
/*
* Collects candidate channel names to be auto-created by ChannelInitializer
*/
static class AutoCreateCandidatesCollector {
public static class AutoCreateCandidatesCollector {
private final Collection<String> channelNames;

View File

@@ -32,7 +32,6 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
@@ -58,6 +57,7 @@ import org.springframework.integration.handler.support.CollectionArgumentResolve
import org.springframework.integration.handler.support.MapArgumentResolver;
import org.springframework.integration.handler.support.PayloadExpressionArgumentResolver;
import org.springframework.integration.handler.support.PayloadsArgumentResolver;
import org.springframework.integration.json.JsonNodeWrapperToJsonNodeConverter;
import org.springframework.integration.support.DefaultMessageBuilderFactory;
import org.springframework.integration.support.NullAwarePayloadArgumentResolver;
import org.springframework.integration.support.SmartLifecycleRoleController;
@@ -67,7 +67,6 @@ import org.springframework.integration.support.converter.ConfigurableCompositeMe
import org.springframework.integration.support.converter.DefaultDatatypeChannelMessageConverter;
import org.springframework.integration.support.json.JacksonPresent;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
@@ -75,6 +74,7 @@ import org.springframework.messaging.handler.invocation.HandlerMethodArgumentRes
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.ClassUtils;
import org.springframework.util.ErrorHandler;
import org.springframework.util.StringUtils;
/**
* A {@link BeanFactoryPostProcessor} implementation that registers bean definitions
@@ -100,12 +100,44 @@ class DefaultConfiguringBeanFactoryPostProcessor
private static final Set<Integer> REGISTRIES_PROCESSED = new HashSet<>();
private static final Class<?> XPATH_CLASS;
private static final Class<?> JSON_PATH_CLASS;
static {
Class<?> xpathClass = null;
try {
xpathClass = ClassUtils.forName(IntegrationConfigUtils.BASE_PACKAGE + ".xml.xpath.XPathUtils",
ClassUtils.getDefaultClassLoader());
}
catch (@SuppressWarnings("unused") ClassNotFoundException e) {
LOGGER.debug("SpEL function '#xpath' isn't registered: " +
"there is no spring-integration-xml.jar on the classpath.");
}
finally {
XPATH_CLASS = xpathClass;
}
Class<?> jsonPathClass = null;
try {
jsonPathClass = ClassUtils.forName(IntegrationConfigUtils.BASE_PACKAGE + ".json.JsonPathUtils",
ClassUtils.getDefaultClassLoader());
}
catch (@SuppressWarnings("unused") ClassNotFoundException e) {
LOGGER.debug("The '#jsonPath' SpEL function cannot be registered: " +
"there is no jayway json-path.jar on the classpath.");
}
finally {
JSON_PATH_CLASS = jsonPathClass;
}
}
private ClassLoader classLoader;
private ConfigurableListableBeanFactory beanFactory;
private BeanExpressionContext expressionContext;
private BeanDefinitionRegistry registry;
@Override
@@ -117,7 +149,6 @@ class DefaultConfiguringBeanFactoryPostProcessor
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof BeanDefinitionRegistry) {
this.beanFactory = beanFactory;
this.expressionContext = new BeanExpressionContext(beanFactory, null);
this.registry = (BeanDefinitionRegistry) beanFactory;
registerBeanFactoryChannelResolver();
@@ -242,16 +273,14 @@ class DefaultConfiguringBeanFactoryPostProcessor
}
private PublishSubscribeChannel createErrorChannel() {
String requireSubscribersExpression =
IntegrationProperties.getExpressionFor(IntegrationProperties.ERROR_CHANNEL_REQUIRE_SUBSCRIBERS);
Boolean requireSubscribers = resolveExpression(requireSubscribersExpression, Boolean.class);
Properties integrationProperties = IntegrationContextUtils.getIntegrationProperties(this.beanFactory);
String requireSubscribers =
integrationProperties.getProperty(IntegrationProperties.ERROR_CHANNEL_REQUIRE_SUBSCRIBERS);
PublishSubscribeChannel errorChannel = new PublishSubscribeChannel(Boolean.TRUE.equals(requireSubscribers));
PublishSubscribeChannel errorChannel = new PublishSubscribeChannel(Boolean.parseBoolean(requireSubscribers));
String ignoreFailuresExpression =
IntegrationProperties.getExpressionFor(IntegrationProperties.ERROR_CHANNEL_IGNORE_FAILURES);
Boolean ignoreFailures = resolveExpression(ignoreFailuresExpression, Boolean.class);
errorChannel.setIgnoreFailures(Boolean.TRUE.equals(ignoreFailures));
String ignoreFailures = integrationProperties.getProperty(IntegrationProperties.ERROR_CHANNEL_IGNORE_FAILURES);
errorChannel.setIgnoreFailures(Boolean.parseBoolean(ignoreFailures));
return errorChannel;
}
@@ -323,12 +352,9 @@ class DefaultConfiguringBeanFactoryPostProcessor
taskScheduler.setErrorHandler(
this.beanFactory.getBean(ChannelUtils.MESSAGE_PUBLISHING_ERROR_HANDLER_BEAN_NAME, ErrorHandler.class));
String poolSizeExpression =
IntegrationProperties.getExpressionFor(IntegrationProperties.TASK_SCHEDULER_POOL_SIZE);
Integer poolSize = resolveExpression(poolSizeExpression, Integer.class);
if (poolSize != null) {
taskScheduler.setPoolSize(poolSize);
}
Properties integrationProperties = IntegrationContextUtils.getIntegrationProperties(this.beanFactory);
String poolSize = integrationProperties.getProperty(IntegrationProperties.TASK_SCHEDULER_POOL_SIZE);
taskScheduler.setPoolSize(Integer.parseInt(poolSize));
return taskScheduler;
}
@@ -376,54 +402,21 @@ class DefaultConfiguringBeanFactoryPostProcessor
private void jsonPath(int registryId) throws LinkageError {
String jsonPathBeanName = "jsonPath";
if (!this.beanFactory.containsBean(jsonPathBeanName) && !REGISTRIES_PROCESSED.contains(registryId)) {
Class<?> jsonPathClass = null;
try {
jsonPathClass = ClassUtils.forName("com.jayway.jsonpath.JsonPath", this.classLoader);
}
catch (@SuppressWarnings("unused") ClassNotFoundException e) {
LOGGER.debug("The '#jsonPath' SpEL function cannot be registered: " +
"there is no jayway json-path.jar on the classpath.");
}
if (JSON_PATH_CLASS != null
&& !this.beanFactory.containsBean(jsonPathBeanName)
&& !REGISTRIES_PROCESSED.contains(registryId)) {
if (jsonPathClass != null) {
try {
ClassUtils.forName("com.jayway.jsonpath.Predicate", this.classLoader);
}
catch (ClassNotFoundException ex) {
jsonPathClass = null;
LOGGER.warn(ex, "The '#jsonPath' SpEL function cannot be registered. " +
"An old json-path.jar version is detected in the classpath." +
"At least 2.4.0 is required; see version information at: " +
"https://github.com/jayway/JsonPath/releases");
}
}
if (jsonPathClass != null) {
IntegrationConfigUtils.registerSpelFunctionBean(this.registry, jsonPathBeanName,
IntegrationConfigUtils.BASE_PACKAGE + ".json.JsonPathUtils", "evaluate");
}
IntegrationConfigUtils.registerSpelFunctionBean(this.registry, jsonPathBeanName, JSON_PATH_CLASS, "evaluate");
}
}
private void xpath(int registryId) throws LinkageError {
String xpathBeanName = "xpath";
if (!this.beanFactory.containsBean(xpathBeanName) && !REGISTRIES_PROCESSED.contains(registryId)) {
Class<?> xpathClass = null;
try {
xpathClass = ClassUtils.forName(IntegrationConfigUtils.BASE_PACKAGE + ".xml.xpath.XPathUtils",
this.classLoader);
}
catch (@SuppressWarnings("unused") ClassNotFoundException e) {
LOGGER.debug("SpEL function '#xpath' isn't registered: " +
"there is no spring-integration-xml.jar on the classpath.");
}
if (XPATH_CLASS != null
&& !this.beanFactory.containsBean(xpathBeanName)
&& !REGISTRIES_PROCESSED.contains(registryId)) {
if (xpathClass != null) {
IntegrationConfigUtils.registerSpelFunctionBean(this.registry, xpathBeanName,
IntegrationConfigUtils.BASE_PACKAGE + ".xml.xpath.XPathUtils", "evaluate");
}
IntegrationConfigUtils.registerSpelFunctionBean(this.registry, xpathBeanName, XPATH_CLASS, "evaluate");
}
}
@@ -434,9 +427,9 @@ class DefaultConfiguringBeanFactoryPostProcessor
this.registry.registerBeanDefinition(
IntegrationContextUtils.JSON_NODE_WRAPPER_TO_JSON_NODE_CONVERTER,
BeanDefinitionBuilder.genericBeanDefinition(IntegrationConfigUtils.BASE_PACKAGE +
".json.JsonNodeWrapperToJsonNodeConverter")
.getBeanDefinition());
new RootBeanDefinition(JsonNodeWrapperToJsonNodeConverter.class,
JsonNodeWrapperToJsonNodeConverter::new));
INTEGRATION_CONVERTER_INITIALIZER.registerConverter(this.registry,
new RuntimeBeanReference(IntegrationContextUtils.JSON_NODE_WRAPPER_TO_JSON_NODE_CONVERTER));
}
@@ -457,21 +450,19 @@ class DefaultConfiguringBeanFactoryPostProcessor
*/
private void registerMessageBuilderFactory() {
if (!this.beanFactory.containsBean(IntegrationUtils.INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME)) {
BeanDefinition mbfBean =
new RootBeanDefinition(DefaultMessageBuilderFactory.class,
() -> {
DefaultMessageBuilderFactory messageBuilderFactory = new DefaultMessageBuilderFactory();
String readOnlyHeadersExpression =
IntegrationProperties.getExpressionFor(IntegrationProperties.READ_ONLY_HEADERS);
String[] readOnlyHeaders = resolveExpression(readOnlyHeadersExpression, String[].class);
messageBuilderFactory.setReadOnlyHeaders(readOnlyHeaders);
return messageBuilderFactory;
});
this.registry.registerBeanDefinition(IntegrationUtils.INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME, mbfBean);
this.registry.registerBeanDefinition(IntegrationUtils.INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME,
new RootBeanDefinition(DefaultMessageBuilderFactory.class, this::createDefaultMessageBuilderFactory));
}
}
private DefaultMessageBuilderFactory createDefaultMessageBuilderFactory() {
DefaultMessageBuilderFactory messageBuilderFactory = new DefaultMessageBuilderFactory();
Properties integrationProperties = IntegrationContextUtils.getIntegrationProperties(this.beanFactory);
String readOnlyHeaders = integrationProperties.getProperty(IntegrationProperties.READ_ONLY_HEADERS);
messageBuilderFactory.setReadOnlyHeaders(StringUtils.commaDelimitedListToStringArray(readOnlyHeaders));
return messageBuilderFactory;
}
/**
* Register a {@link DefaultHeaderChannelRegistry} if necessary.
*/
@@ -585,10 +576,4 @@ class DefaultConfiguringBeanFactoryPostProcessor
return resolvers;
}
@Nullable
private <T> T resolveExpression(String expression, Class<T> expectedType) {
Object value = this.beanFactory.getBeanExpressionResolver().evaluate(expression, this.expressionContext);
return this.beanFactory.getTypeConverter().convertIfNecessary(value, expectedType);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2021 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,18 +16,22 @@
package org.springframework.integration.config;
import java.util.Arrays;
import java.util.Map;
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.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
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.beans.factory.support.RootBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.integration.channel.interceptor.GlobalChannelInterceptorWrapper;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.util.CollectionUtils;
/**
@@ -39,38 +43,72 @@ import org.springframework.util.CollectionUtils;
*
* @author Artem Bilan
* @author Gary Russell
*
* @since 4.0
*/
public class GlobalChannelInterceptorInitializer implements IntegrationConfigurationInitializer {
private ConfigurableListableBeanFactory beanFactory;
private BeanExpressionContext beanExpressionContext;
@Override
public void initialize(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
this.beanExpressionContext = new BeanExpressionContext(beanFactory, null);
for (String beanName : registry.getBeanDefinitionNames()) {
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
if (beanDefinition instanceof AnnotatedBeanDefinition) {
AnnotationMetadata metadata = ((AnnotatedBeanDefinition) beanDefinition).getMetadata();
Map<String, Object> annotationAttributes = metadata
.getAnnotationAttributes(GlobalChannelInterceptor.class.getName());
Map<String, Object> annotationAttributes =
metadata.getAnnotationAttributes(GlobalChannelInterceptor.class.getName());
if (CollectionUtils.isEmpty(annotationAttributes)
&& beanDefinition.getSource() instanceof MethodMetadata) {
MethodMetadata beanMethod = (MethodMetadata) beanDefinition.getSource();
annotationAttributes =
beanMethod.getAnnotationAttributes(GlobalChannelInterceptor.class.getName()); // NOSONAR not null
beanMethod.getAnnotationAttributes(GlobalChannelInterceptor.class.getName()); // NOSONAR not null
}
if (!CollectionUtils.isEmpty(annotationAttributes)) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(GlobalChannelInterceptorWrapper.class)
.addConstructorArgReference(beanName)
.addPropertyValue("patterns", annotationAttributes.get("patterns"))
.addPropertyValue("order", annotationAttributes.get("order"));
Map<String, Object> attributes = annotationAttributes;
RootBeanDefinition channelInterceptorWrapper =
new RootBeanDefinition(GlobalChannelInterceptorWrapper.class,
() -> createGlobalChannelInterceptorWrapper(beanName, attributes));
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), registry);
BeanDefinitionReaderUtils.registerWithGeneratedName(channelInterceptorWrapper, registry);
}
}
}
}
private GlobalChannelInterceptorWrapper createGlobalChannelInterceptorWrapper(String interceptorBeanName,
Map<String, Object> annotationAttributes) {
ChannelInterceptor interceptor = this.beanFactory.getBean(interceptorBeanName, ChannelInterceptor.class);
GlobalChannelInterceptorWrapper interceptorWrapper = new GlobalChannelInterceptorWrapper(interceptor);
String[] patterns =
Arrays.stream((String[]) annotationAttributes.get("patterns"))
.map(this::resolveEmbeddedValue)
.toArray(String[]::new);
interceptorWrapper.setPatterns(patterns);
interceptorWrapper.setOrder((Integer) annotationAttributes.get("order"));
return interceptorWrapper;
}
private String resolveEmbeddedValue(String value) {
String valueToReturn = this.beanFactory.resolveEmbeddedValue(value);
if (valueToReturn == null || !(valueToReturn.startsWith("#{") && value.endsWith("}"))) {
return valueToReturn;
}
BeanExpressionResolver beanExpressionResolver = this.beanFactory.getBeanExpressionResolver();
if (beanExpressionResolver != null) {
Object result = beanExpressionResolver.evaluate(valueToReturn, this.beanExpressionContext);
return result != null ? result.toString() : null;
}
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2021 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,10 +16,9 @@
package org.springframework.integration.config;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.integration.channel.DirectChannel;
/**
@@ -36,7 +35,7 @@ public final class IntegrationConfigUtils {
public static final String HANDLER_ALIAS_SUFFIX = ".handler";
public static void registerSpelFunctionBean(BeanDefinitionRegistry registry, String functionId, String className,
String methodSignature) {
String methodSignature) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SpelFunctionFactoryBean.class)
.addConstructorArgValue(className)
@@ -44,10 +43,23 @@ public final class IntegrationConfigUtils {
registry.registerBeanDefinition(functionId, builder.getBeanDefinition());
}
/**
* Register a {@link SpelFunctionFactoryBean} for the provided method signature
* @param registry the registry for bean to register
* @param functionId the bean name
* @param aClass the class for function
* @param methodSignature the function method to be called from SpEL
* @since 5.5
*/
public static void registerSpelFunctionBean(BeanDefinitionRegistry registry, String functionId, Class<?> aClass,
String methodSignature) {
registry.registerBeanDefinition(functionId, new RootBeanDefinition(SpelFunctionFactoryBean.class,
() -> new SpelFunctionFactoryBean(aClass, methodSignature)));
}
public static void autoCreateDirectChannel(String channelName, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder channelBuilder = BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class);
BeanDefinitionHolder holder = new BeanDefinitionHolder(channelBuilder.getBeanDefinition(), channelName);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
registry.registerBeanDefinition(channelName, new RootBeanDefinition(DirectChannel.class, DirectChannel::new));
}
private IntegrationConfigUtils() {

View File

@@ -17,18 +17,14 @@
package org.springframework.integration.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.NativeDetector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.context.IntegrationProperties;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
@@ -63,42 +59,10 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(@Nullable AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
registerImplicitChannelCreator(registry);
registerDefaultConfiguringBeanFactoryPostProcessor(registry);
registerIntegrationConfigurationBeanFactoryPostProcessor(registry);
if (importingClassMetadata != null) {
registerMessagingAnnotationPostProcessors(importingClassMetadata, registry);
}
}
/**
* This method will auto-register a ChannelInitializer which could also be overridden by the user
* by simply registering a ChannelInitializer {@code <bean>} with its {@code autoCreate} property
* set to false to suppress channel creation.
* It will also register a ChannelInitializer$AutoCreateCandidatesCollector
* which simply collects candidate channel names.
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s.
*/
private void registerImplicitChannelCreator(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(IntegrationContextUtils.CHANNEL_INITIALIZER_BEAN_NAME)) {
String channelsAutoCreateExpression =
IntegrationProperties.getExpressionFor(IntegrationProperties.CHANNELS_AUTOCREATE);
BeanDefinitionBuilder channelDef = BeanDefinitionBuilder.genericBeanDefinition(ChannelInitializer.class)
.addPropertyValue("autoCreate", channelsAutoCreateExpression);
BeanDefinitionHolder channelCreatorHolder = new BeanDefinitionHolder(channelDef.getBeanDefinition(),
IntegrationContextUtils.CHANNEL_INITIALIZER_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(channelCreatorHolder, registry);
}
if (!registry.containsBeanDefinition(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME)) {
BeanDefinitionBuilder channelRegistryBuilder = BeanDefinitionBuilder
.genericBeanDefinition(ChannelInitializer.AutoCreateCandidatesCollector.class);
channelRegistryBuilder.addConstructorArgValue(new ManagedSet<String>());
channelRegistryBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); //SPR-12761
BeanDefinitionHolder channelRegistryHolder =
new BeanDefinitionHolder(channelRegistryBuilder.getBeanDefinition(),
IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(channelRegistryHolder, registry);
registerMessagingAnnotationPostProcessors(registry);
}
}
@@ -108,13 +72,9 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar {
*/
private void registerDefaultConfiguringBeanFactoryPostProcessor(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME)) {
BeanDefinitionBuilder postProcessorBuilder =
BeanDefinitionBuilder.genericBeanDefinition(DefaultConfiguringBeanFactoryPostProcessor.class,
DefaultConfiguringBeanFactoryPostProcessor::new);
BeanDefinitionHolder postProcessorHolder = new BeanDefinitionHolder(
postProcessorBuilder.getBeanDefinition(),
IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(postProcessorHolder, registry);
registry.registerBeanDefinition(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME,
new RootBeanDefinition(DefaultConfiguringBeanFactoryPostProcessor.class,
DefaultConfiguringBeanFactoryPostProcessor::new));
}
}
@@ -123,13 +83,13 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar {
* to process the external Integration infrastructure.
*/
private void registerIntegrationConfigurationBeanFactoryPostProcessor(BeanDefinitionRegistry registry) {
if (!(NativeDetector.inNativeImage()) // Spring Native detects all the 'spring.factories'
&& !registry.containsBeanDefinition(
if (!registry.containsBeanDefinition(
IntegrationContextUtils.INTEGRATION_CONFIGURATION_POST_PROCESSOR_BEAN_NAME)) {
BeanDefinitionBuilder postProcessorBuilder = BeanDefinitionBuilder
.genericBeanDefinition(IntegrationConfigurationBeanFactoryPostProcessor.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
BeanDefinitionBuilder postProcessorBuilder =
BeanDefinitionBuilder.genericBeanDefinition(IntegrationConfigurationBeanFactoryPostProcessor.class,
IntegrationConfigurationBeanFactoryPostProcessor::new)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_CONFIGURATION_POST_PROCESSOR_BEAN_NAME,
postProcessorBuilder.getBeanDefinition());
}
@@ -140,10 +100,9 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar {
* {@link org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor},
* if necessary.
* Inject {@code defaultPublishedChannel} from provided {@link AnnotationMetadata}, if any.
* @param meta The {@link AnnotationMetadata} to get additional properties for {@link BeanDefinition}s.
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s.
*/
private void registerMessagingAnnotationPostProcessors(AnnotationMetadata meta, BeanDefinitionRegistry registry) {
private void registerMessagingAnnotationPostProcessors(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME)) {
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.genericBeanDefinition(MessagingAnnotationPostProcessor.class,
@@ -153,11 +112,6 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar {
registry.registerBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME,
builder.getBeanDefinition());
}
if (meta.getAnnotationAttributes(EnablePublisher.class.getName()) != null) {
new PublisherRegistrar().
registerBeanDefinitions(meta, registry);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2020 the original author or authors.
* Copyright 2014-2021 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,17 +21,18 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
@@ -49,50 +50,62 @@ public class PublisherRegistrar implements ImportBeanDefinitionRegistrar {
Map<String, Object> annotationAttributes =
importingClassMetadata.getAnnotationAttributes(EnablePublisher.class.getName());
String defaultChannel =
annotationAttributes == null
? (String) AnnotationUtils.getDefaultValue(EnablePublisher.class)
: (String) annotationAttributes.get("defaultChannel");
if (!registry.containsBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME)) {
ConfigurableBeanFactory beanFactory;
if (registry instanceof ConfigurableBeanFactory) {
beanFactory = (ConfigurableBeanFactory) registry;
}
else if (registry instanceof ConfigurableApplicationContext) {
beanFactory = ((ConfigurableApplicationContext) registry).getBeanFactory();
}
else {
beanFactory = null;
}
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.genericBeanDefinition(PublisherAnnotationBeanPostProcessor.class)
BeanDefinitionBuilder.genericBeanDefinition(PublisherAnnotationBeanPostProcessor.class,
() -> createPublisherAnnotationBeanPostProcessor(annotationAttributes, beanFactory))
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
if (StringUtils.hasText(defaultChannel)) {
builder.addPropertyValue("defaultChannelName", defaultChannel);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Setting '@Publisher' default-output-channel to '" + defaultChannel + "'.");
}
}
if (annotationAttributes != null) {
Object proxyTargetClass = annotationAttributes.get("proxyTargetClass");
builder.addPropertyValue("proxyTargetClass", proxyTargetClass);
Object order = annotationAttributes.get("order");
builder.addPropertyValue("order", order);
}
registry.registerBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME,
builder.getBeanDefinition());
}
else {
BeanDefinition beanDefinition =
registry.getBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME);
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
PropertyValue defaultChannelPropertyValue = propertyValues.getPropertyValue("defaultChannelName");
if (StringUtils.hasText(defaultChannel)) {
if (defaultChannelPropertyValue == null) {
propertyValues.addPropertyValue("defaultChannelName", defaultChannel);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Setting '@Publisher' default-output-channel to '" + defaultChannel + "'.");
}
}
else if (!defaultChannel.equals(defaultChannelPropertyValue.getValue())) {
throw new BeanDefinitionStoreException("When more than one enable publisher definition " +
"(@EnablePublisher or <annotation-config>) is found in the context, " +
"they all must have the same 'default-publisher-channel' attribute value.");
}
}
throw new BeanDefinitionStoreException("Only one enable publisher definition " +
"(@EnablePublisher or <annotation-config>) can be declared in the application context.");
}
}
private PublisherAnnotationBeanPostProcessor createPublisherAnnotationBeanPostProcessor(
@Nullable Map<String, Object> annotationAttributes, @Nullable ConfigurableBeanFactory beanFactory) {
PublisherAnnotationBeanPostProcessor postProcessor = new PublisherAnnotationBeanPostProcessor();
String defaultChannel =
annotationAttributes == null
? (String) AnnotationUtils.getDefaultValue(EnablePublisher.class)
: (String) annotationAttributes.get("defaultChannel");
if (StringUtils.hasText(defaultChannel)) {
if (beanFactory != null) {
defaultChannel = beanFactory.resolveEmbeddedValue(defaultChannel);
}
postProcessor.setDefaultChannelName(defaultChannel);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Setting '@Publisher' default-output-channel to '" + defaultChannel + "'.");
}
}
if (annotationAttributes != null) {
String proxyTargetClass = annotationAttributes.get("proxyTargetClass").toString();
if (beanFactory != null) {
proxyTargetClass = beanFactory.resolveEmbeddedValue(proxyTargetClass);
}
postProcessor.setProxyTargetClass(Boolean.parseBoolean(proxyTargetClass));
String order = annotationAttributes.get("order").toString();
if (beanFactory != null) {
order = beanFactory.resolveEmbeddedValue(order);
}
postProcessor.setOrder(Integer.parseInt(order));
}
return postProcessor;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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,9 +21,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.ChannelInitializer;
import org.springframework.integration.config.IntegrationRegistrar;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.context.IntegrationProperties;
/**
* Base class for NamespaceHandlers that registers a BeanFactoryPostProcessor
@@ -41,10 +49,42 @@ public abstract class AbstractIntegrationNamespaceHandler extends NamespaceHandl
@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
if (!this.initialized.getAndSet(true)) {
IntegrationRegistrar integrationRegistrar = new IntegrationRegistrar();
integrationRegistrar.registerBeanDefinitions(null, parserContext.getRegistry());
BeanDefinitionRegistry registry = parserContext.getRegistry();
new IntegrationRegistrar().registerBeanDefinitions(null, registry);
registerImplicitChannelCreator(registry);
}
return super.parse(element, parserContext);
}
/**
* This method will auto-register a ChannelInitializer which could also be overridden by the user
* by simply registering a ChannelInitializer {@code <bean>} with its {@code autoCreate} property
* set to false to suppress channel creation.
* It will also register a ChannelInitializer$AutoCreateCandidatesCollector
* which simply collects candidate channel names.
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s.
*/
private static void registerImplicitChannelCreator(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(IntegrationContextUtils.CHANNEL_INITIALIZER_BEAN_NAME)) {
String channelsAutoCreateExpression =
IntegrationProperties.getExpressionFor(IntegrationProperties.CHANNELS_AUTOCREATE);
BeanDefinitionBuilder channelDef = BeanDefinitionBuilder.genericBeanDefinition(ChannelInitializer.class)
.addPropertyValue("autoCreate", channelsAutoCreateExpression);
BeanDefinitionHolder channelCreatorHolder = new BeanDefinitionHolder(channelDef.getBeanDefinition(),
IntegrationContextUtils.CHANNEL_INITIALIZER_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(channelCreatorHolder, registry);
}
if (!registry.containsBeanDefinition(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME)) {
BeanDefinitionBuilder channelRegistryBuilder = BeanDefinitionBuilder
.genericBeanDefinition(ChannelInitializer.AutoCreateCandidatesCollector.class);
channelRegistryBuilder.addConstructorArgValue(new ManagedSet<String>());
channelRegistryBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
BeanDefinitionHolder channelRegistryHolder =
new BeanDefinitionHolder(channelRegistryBuilder.getBeanDefinition(),
IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(channelRegistryHolder, registry);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@@ -22,16 +22,20 @@ import java.util.Map;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.EnablePublisher;
import org.springframework.integration.config.IntegrationRegistrar;
import org.springframework.integration.config.PublisherRegistrar;
import org.springframework.integration.config.annotation.AnnotationMetadataAdapter;
import org.springframework.util.xml.DomUtils;
/**
* Parser for the &lt;annotation-config&gt; element of the integration namespace.
* Just delegate the real configuration to the {@link IntegrationRegistrar}.
* Parser for the {@code <annotation-config>} element of the integration namespace.
* Delegates the real configuration to the {@link IntegrationRegistrar}.
* If {@code <enable-publisher>} sub-element is present, the {@link PublisherRegistrar}
* is called, too.
*
* @author Mark Fisher
* @author Artem Bilan
@@ -40,9 +44,15 @@ import org.springframework.util.xml.DomUtils;
public class AnnotationConfigParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(final Element element, ParserContext parserContext) {
new IntegrationRegistrar().registerBeanDefinitions(new ExtendedAnnotationMetadata(element),
parserContext.getRegistry());
public BeanDefinition parse(Element element, ParserContext parserContext) {
ExtendedAnnotationMetadata importingClassMetadata = new ExtendedAnnotationMetadata(element);
BeanDefinitionRegistry registry = parserContext.getRegistry();
new IntegrationRegistrar()
.registerBeanDefinitions(importingClassMetadata, registry);
if (DomUtils.getChildElementByTagName(element, "enable-publisher") != null) {
new PublisherRegistrar()
.registerBeanDefinitions(importingClassMetadata, registry);
}
return null;
}

View File

@@ -3106,9 +3106,6 @@ public abstract class BaseIntegrationFlowDefinition<B extends BaseIntegrationFlo
public static final class ReplyProducerCleaner implements DestructionAwareBeanPostProcessor {
private ReplyProducerCleaner() {
}
@Override
public boolean requiresDestruction(Object bean) {
return bean instanceof MessageProducer &&

View File

@@ -63,7 +63,7 @@ public abstract class ConsumerEndpointSpec<S extends ConsumerEndpointSpec<S, H>,
protected final List<Advice> adviceChain = new LinkedList<>(); // NOSONAR final
protected ConsumerEndpointSpec(H messageHandler) {
super(messageHandler);
super(messageHandler, new ConsumerEndpointFactoryBean());
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2020 the original author or authors.
* Copyright 2016-2021 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.
@@ -20,10 +20,10 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.core.ResolvableType;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.scheduling.PollerMetadata;
import org.springframework.messaging.MessageChannel;
import org.springframework.util.Assert;
@@ -44,20 +44,18 @@ import reactor.util.function.Tuples;
*
* @since 5.0
*/
public abstract class EndpointSpec<S extends EndpointSpec<S, F, H>, F extends BeanNameAware, H>
public abstract class EndpointSpec<S extends EndpointSpec<S, F, H>, F extends BeanNameAware & FactoryBean<? extends AbstractEndpoint>, H>
extends IntegrationComponentSpec<S, Tuple2<F, H>>
implements ComponentsRegistration {
protected final Map<Object, String> componentsToRegister = new LinkedHashMap<>(); // NOSONAR final
protected H handler; // NOSONAR final
protected final F endpointFactoryBean; // NOSONAR final
protected F endpointFactoryBean; // NOSONAR final
protected H handler; // NOSONAR
@SuppressWarnings("unchecked")
protected EndpointSpec(H handler) {
Class<?> fClass = ResolvableType.forClass(this.getClass()).as(EndpointSpec.class).resolveGenerics()[1];
this.endpointFactoryBean = (F) BeanUtils.instantiateClass(fClass);
protected EndpointSpec(H handler, F endpointFactoryBean) {
this.endpointFactoryBean = endpointFactoryBean;
this.handler = handler;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2020 the original author or authors.
* Copyright 2016-2021 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.
@@ -26,8 +26,8 @@ import org.springframework.integration.channel.FluxMessageChannel;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.dsl.support.FixedSubscriberChannelPrototype;
import org.springframework.integration.dsl.support.MessageChannelReference;
import org.springframework.integration.endpoint.AbstractMessageSource;
import org.springframework.integration.endpoint.MessageProducerSupport;
import org.springframework.integration.endpoint.MethodInvokingMessageSource;
import org.springframework.integration.gateway.MessagingGatewaySupport;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
@@ -160,10 +160,19 @@ public final class IntegrationFlows {
Consumer<SourcePollingChannelAdapterSpec> endpointConfigurer) {
Assert.notNull(messageSource, "'messageSource' must not be null");
MethodInvokingMessageSource methodInvokingMessageSource = new MethodInvokingMessageSource();
methodInvokingMessageSource.setObject(messageSource);
methodInvokingMessageSource.setMethodName("get");
return from(methodInvokingMessageSource, endpointConfigurer);
return from(new AbstractMessageSource<Object>() {
@Override
protected Object doReceive() {
return messageSource.get();
}
@Override
public String getComponentType() {
return "inbound-channel-adapter";
}
}, endpointConfigurer);
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2020 the original author or authors.
* Copyright 2016-2021 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.
@@ -29,7 +29,7 @@ public class SourcePollingChannelAdapterSpec extends
EndpointSpec<SourcePollingChannelAdapterSpec, SourcePollingChannelAdapterFactoryBean, MessageSource<?>> {
protected SourcePollingChannelAdapterSpec(MessageSource<?> messageSource) {
super(messageSource);
super(messageSource, new SourcePollingChannelAdapterFactoryBean());
this.endpointFactoryBean.setSource(messageSource);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 the original author or authors.
* Copyright 2016-2021 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.
@@ -60,11 +60,13 @@ public class DslIntegrationConfigurationInitializer implements IntegrationConfig
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) configurableListableBeanFactory;
if (!registry.containsBeanDefinition(INTEGRATION_FLOW_BPP_BEAN_NAME)) {
registry.registerBeanDefinition(INTEGRATION_FLOW_BPP_BEAN_NAME,
new RootBeanDefinition(IntegrationFlowBeanPostProcessor.class));
new RootBeanDefinition(IntegrationFlowBeanPostProcessor.class,
IntegrationFlowBeanPostProcessor::new));
registry.registerBeanDefinition(INTEGRATION_FLOW_CONTEXT_BEAN_NAME,
new RootBeanDefinition(StandardIntegrationFlowContext.class));
new RootBeanDefinition(StandardIntegrationFlowContext.class, StandardIntegrationFlowContext::new));
registry.registerBeanDefinition(INTEGRATION_FLOW_REPLY_PRODUCER_CLEANER_BEAN_NAME,
new RootBeanDefinition(IntegrationFlowDefinition.ReplyProducerCleaner.class));
new RootBeanDefinition(IntegrationFlowDefinition.ReplyProducerCleaner.class,
IntegrationFlowDefinition.ReplyProducerCleaner::new));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 the original author or authors.
* Copyright 2015-2021 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.
@@ -34,7 +34,7 @@ import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
import org.springframework.util.ReflectionUtils;
/**
* Method interceptor to invoke default methods on the repository proxy.
* Method interceptor to invoke default methods on the gateway proxy.
*
* The copy of {@code DefaultMethodInvokingMethodInterceptor} from Spring Data Commons.
*

View File

@@ -37,7 +37,7 @@ import com.fasterxml.jackson.databind.JsonNode;
*
* @since 5.5
*/
class JsonNodeWrapperToJsonNodeConverter implements GenericConverter {
public class JsonNodeWrapperToJsonNodeConverter implements GenericConverter {
@Override
public Set<ConvertiblePair> getConvertibleTypes() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2020 the original author or authors.
* Copyright 2013-2021 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.
@@ -26,7 +26,6 @@ import java.net.URL;
import java.util.Collection;
import java.util.Map;
import org.springframework.beans.BeanUtils;
import org.springframework.integration.mapping.support.JsonHeaders;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -38,14 +37,13 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
/**
* Jackson 2 JSON-processor (@link https://github.com/FasterXML)
* {@linkplain JsonObjectMapper} implementation.
* Delegates <code>toJson</code> and <code>fromJson</code>
* Delegates {@link #toJson} and {@link #fromJson}
* to the {@linkplain com.fasterxml.jackson.databind.ObjectMapper}
* <p>
* It customizes Jackson's default properties with the following ones:
@@ -66,7 +64,20 @@ import com.fasterxml.jackson.databind.json.JsonMapper;
*/
public class Jackson2JsonObjectMapper extends AbstractJacksonJsonObjectMapper<JsonNode, JsonParser, JavaType> {
private static final String UNUSED = "unused";
private static final ClassLoader CLASS_LOADER = ClassUtils.getDefaultClassLoader();
private static final boolean JDK8_MODULE_PRESENT =
ClassUtils.isPresent("com.fasterxml.jackson.datatype.jdk8.Jdk8Module", CLASS_LOADER);
private static final boolean JAVA_TIME_MODULE_PRESENT =
ClassUtils.isPresent("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule", CLASS_LOADER);
private static final boolean JODA_MODULE_PRESENT =
ClassUtils.isPresent("com.fasterxml.jackson.datatype.joda.JodaModule", CLASS_LOADER);
private static final boolean KOTLIN_MODULE_PRESENT =
ClassUtils.isPresent("kotlin.Unit", CLASS_LOADER) &&
ClassUtils.isPresent("com.fasterxml.jackson.module.kotlin.KotlinModule", CLASS_LOADER);
private final ObjectMapper objectMapper;
@@ -185,58 +196,48 @@ public class Jackson2JsonObjectMapper extends AbstractJacksonJsonObjectMapper<Js
return this.objectMapper.constructType(type);
}
@SuppressWarnings("unchecked")
private void registerWellKnownModulesIfAvailable() {
try {
Class<? extends Module> jdk7Module = (Class<? extends Module>)
ClassUtils.forName("com.fasterxml.jackson.datatype.jdk7.Jdk7Module", getClassLoader());
this.objectMapper.registerModule(BeanUtils.instantiateClass(jdk7Module));
}
catch (@SuppressWarnings(UNUSED) ClassNotFoundException ex) {
// jackson-datatype-jdk7 not available
if (JDK8_MODULE_PRESENT) {
this.objectMapper.registerModule(Jdk8ModuleProvider.module);
}
try {
Class<? extends Module> jdk8Module = (Class<? extends Module>)
ClassUtils.forName("com.fasterxml.jackson.datatype.jdk8.Jdk8Module", getClassLoader());
this.objectMapper.registerModule(BeanUtils.instantiateClass(jdk8Module));
}
catch (@SuppressWarnings(UNUSED) ClassNotFoundException ex) {
// jackson-datatype-jdk8 not available
if (JAVA_TIME_MODULE_PRESENT) {
this.objectMapper.registerModule(JavaTimeModuleProvider.module);
}
try {
Class<? extends Module> javaTimeModule = (Class<? extends Module>)
ClassUtils.forName("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule", getClassLoader());
this.objectMapper.registerModule(BeanUtils.instantiateClass(javaTimeModule));
}
catch (@SuppressWarnings(UNUSED) ClassNotFoundException ex) {
// jackson-datatype-jsr310 not available
if (JODA_MODULE_PRESENT) {
this.objectMapper.registerModule(JodaModuleProvider.module);
}
// Joda-Time present?
if (ClassUtils.isPresent("org.joda.time.LocalDate", getClassLoader())) {
try {
Class<? extends Module> jodaModule = (Class<? extends Module>)
ClassUtils.forName("com.fasterxml.jackson.datatype.joda.JodaModule", getClassLoader());
this.objectMapper.registerModule(BeanUtils.instantiateClass(jodaModule));
}
catch (@SuppressWarnings(UNUSED) ClassNotFoundException ex) {
// jackson-datatype-joda not available
}
}
// Kotlin present?
if (ClassUtils.isPresent("kotlin.Unit", getClassLoader())) {
try {
Class<? extends Module> kotlinModule = (Class<? extends Module>)
ClassUtils.forName("com.fasterxml.jackson.module.kotlin.KotlinModule", getClassLoader());
this.objectMapper.registerModule(BeanUtils.instantiateClass(kotlinModule));
}
catch (@SuppressWarnings(UNUSED) ClassNotFoundException ex) {
//jackson-module-kotlin not available
}
if (KOTLIN_MODULE_PRESENT) {
this.objectMapper.registerModule(KotlinModuleProvider.module);
}
}
private static final class Jdk8ModuleProvider {
static final com.fasterxml.jackson.databind.Module module = new com.fasterxml.jackson.datatype.jdk8.Jdk8Module();
}
private static final class JavaTimeModuleProvider {
static final com.fasterxml.jackson.databind.Module module =
new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule();
}
private static final class JodaModuleProvider {
static final com.fasterxml.jackson.databind.Module module = new com.fasterxml.jackson.datatype.joda.JodaModule();
}
private static final class KotlinModuleProvider {
static final com.fasterxml.jackson.databind.Module module =
new com.fasterxml.jackson.module.kotlin.KotlinModule();
}
}

View File

@@ -14,10 +14,6 @@
<message-history tracked-components="publishedChannel,input,annotationTestService*"/>
<annotation-config>
<enable-publisher default-publisher-channel="publishedChannel" proxy-target-class="true" order="2147483646"/>
</annotation-config>
<channel-interceptor pattern="none">
<wire-tap channel="bar" />
</channel-interceptor>

View File

@@ -554,11 +554,11 @@ public class EnableIntegrationTests {
@Test
public void testIntegrationConverter() {
this.numberChannel.send(new GenericMessage<Integer>(10));
this.numberChannel.send(new GenericMessage<Boolean>(true));
this.numberChannel.send(new GenericMessage<>(10));
this.numberChannel.send(new GenericMessage<>(true));
assertThat(this.testConverter.getInvoked()).isGreaterThan(0);
assertThat(this.bytesChannel.send(new GenericMessage<byte[]>("foo".getBytes()))).isTrue();
assertThat(this.bytesChannel.send(new GenericMessage<>("foo".getBytes()))).isTrue();
assertThat(this.bytesChannel.send(new GenericMessage<>(MutableMessageBuilder.withPayload("").build())))
.isTrue();
@@ -1046,7 +1046,7 @@ public class EnableIntegrationTests {
@EnableIntegration
@ImportResource("classpath:org/springframework/integration/configuration/EnableIntegrationTests-context.xml")
@EnableMessageHistory("${message.history.tracked.components}")
@EnablePublisher(defaultChannel = "publishedChannel")
@EnablePublisher(defaultChannel = "publishedChannel", proxyTargetClass = true, order = 2147483646)
@EnableAsync
public static class ContextConfiguration2 {
@@ -1069,7 +1069,7 @@ public class EnableIntegrationTests {
@Bean
public AtomicReference<Thread> asyncAnnotationProcessThread() {
return new AtomicReference<Thread>();
return new AtomicReference<>();
}
@Bean

View File

@@ -25,7 +25,6 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.expression.Expression;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.integration.dsl.ComponentsRegistration;
import org.springframework.integration.dsl.MessageHandlerSpec;
import org.springframework.integration.expression.FunctionExpression;
@@ -312,9 +311,10 @@ public abstract class BaseHttpMessageHandlerSpec<S extends BaseHttpMessageHandle
}
/**
* The flag to extract a body of the {@link ResponseEntity} for reply message payload.
* Defaults to true.
* @param extractResponseBody produce a reply message with a whole {@link ResponseEntity} or just its body.
* The flag to extract a body of the {@link org.springframework.http.ResponseEntity}
* for reply message payload. Defaults to true.
* @param extractResponseBody produce a reply message with a whole
* {@link org.springframework.http.ResponseEntity} or just its body.
* @return the current Spec.
* @since 5.5
*/