From 281d8d5bf6d3963c82da28773d86ae00bcc02b9d Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 17 Feb 2021 13:36:16 -0500 Subject: [PATCH] Deprecate Properties as bean for int global props Having a bean as a `java.util.Properties` is not confusing and may lead to some conflicts in the real application. Plus it is not so easy to configure: need to know all the possible integration properties - bad end-user experience * Make an `IntegrationProperties` as a public POJO for easy configuration of global properties * Deprecate a presence of the `java.util.Properties` * Leave framework-created `integrationGlobalProperties` as a `Properties` instance for backward compatibility * Fix tests to expose an `IntegrationProperties` bean instead of deprecated `Properties` * Fix docs according the change and current recommendations --- ...ltConfiguringBeanFactoryPostProcessor.java | 15 +- .../context/IntegrationContextUtils.java | 44 ++- .../context/IntegrationObjectSupport.java | 6 +- .../context/IntegrationProperties.java | 262 ++++++++++++++++-- ...ubscribersOverrideDefaultTests-context.xml | 16 +- .../context/IntegrationContextTests.java | 12 +- .../gateway/GatewayInterfaceTests.java | 28 +- ...ctToJsonTransformerParserTests-context.xml | 10 +- src/reference/asciidoc/configuration.adoc | 5 +- src/reference/asciidoc/whats-new.adoc | 1 + 10 files changed, 314 insertions(+), 85 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java index c9edd4367a..72af6bb5bd 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java @@ -19,10 +19,7 @@ package org.springframework.integration.config; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.Arrays; import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; import java.util.Properties; import java.util.Set; import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy; @@ -328,17 +325,15 @@ class DefaultConfiguringBeanFactoryPostProcessor if (!this.beanFactory.containsBean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME)) { ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(this.classLoader); try { - Resource[] defaultResources = - resourceResolver.getResources("classpath*:META-INF/spring.integration.default.properties"); - Resource[] userResources = + Resource[] resources = resourceResolver.getResources("classpath*:META-INF/spring.integration.properties"); - List resources = new LinkedList<>(Arrays.asList(defaultResources)); - resources.addAll(Arrays.asList(userResources)); - + // TODO Revise in favor of 'IntegrationProperties' instance in the next 6.0 version BeanDefinitionBuilder integrationPropertiesBuilder = BeanDefinitionBuilder .genericBeanDefinition(PropertiesFactoryBean.class) - .addPropertyValue("locations", resources); + .addPropertyValue("properties", IntegrationProperties.defaults()) + .addPropertyValue("locations", resources) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); this.registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME, integrationPropertiesBuilder.getBeanDefinition()); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java index 29f2c9380e..c65fa8e691 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java @@ -18,7 +18,12 @@ package org.springframework.integration.context; import java.util.Properties; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jetbrains.annotations.Nullable; + import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanNotOfRequiredTypeException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -110,6 +115,8 @@ public abstract class IntegrationContextUtils { public static final String LIST_MESSAGE_HANDLER_FACTORY_BEAN_NAME = "integrationListMessageHandlerMethodFactory"; + private static final Log LOGGER = LogFactory.getLog(IntegrationContextUtils.class); + /** * @param beanFactory BeanFactory for lookup, must not be null. * @return The {@link MetadataStore} bean whose name is "metadataStore". @@ -173,15 +180,15 @@ public abstract class IntegrationContextUtils { return beanFactory.getBean(beanName, type); } + // TODO Revise in favor of 'IntegrationProperties' instance in the next 6.0 version /** * @param beanFactory The bean factory. * @return the global {@link IntegrationContextUtils#INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME} * bean from provided {@code #beanFactory}, which represents the merged - * properties values from all 'META-INF/spring.integration.default.properties' - * and 'META-INF/spring.integration.properties'. - * Or user-defined {@link Properties} bean. + * properties values from all 'META-INF/spring.integration.properties'. + * Or user-defined {@link IntegrationProperties} bean. * May return only {@link IntegrationProperties#defaults()} if there is no - * {@link IntegrationContextUtils#INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME} bean within + * {@link IntegrationContextUtils#INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME} bean in the * provided {@code #beanFactory} or provided {@code #beanFactory} is null. */ public static Properties getIntegrationProperties(BeanFactory beanFactory) { @@ -191,8 +198,7 @@ public abstract class IntegrationContextUtils { if (properties == null) { Properties propertiesToRegister = new Properties(); propertiesToRegister.putAll(IntegrationProperties.defaults()); - Properties userProperties = - getBeanOfType(beanFactory, INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME, Properties.class); + Properties userProperties = obtainUserProperties(beanFactory); if (userProperties != null) { propertiesToRegister.putAll(userProperties); } @@ -215,6 +221,32 @@ public abstract class IntegrationContextUtils { return properties; } + @Nullable + private static Properties obtainUserProperties(BeanFactory beanFactory) { + Object userProperties = getBeanOfType(beanFactory, INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME, Object.class); + if (userProperties instanceof Properties) { + if (BeanDefinition.ROLE_INFRASTRUCTURE != + ((BeanDefinitionRegistry) beanFactory) + .getBeanDefinition(INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME) + .getRole()) { + + LOGGER.warn("The 'integrationGlobalProperties' bean must be declared as an instance of " + + "'org.springframework.integration.context.IntegrationProperties'. " + + "A 'java.util.Properties' support as a bean is deprecated for " + + "'integrationGlobalProperties' since version 5.5."); + } + return (Properties) userProperties; + } + else if (userProperties instanceof IntegrationProperties) { + return ((IntegrationProperties) userProperties).toProperties(); + } + else if (userProperties != null) { + throw new BeanNotOfRequiredTypeException(INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME, + IntegrationProperties.class, userProperties.getClass()); + } + return null; + } + /** * Return a {@link BeanDefinition} with the given name, * obtained from the given {@link BeanFactory} or one of its parents. diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java index c17b27eab8..a34e0dcab6 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 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. @@ -294,12 +294,14 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo /** * @see IntegrationContextUtils#getIntegrationProperties(BeanFactory) * @return The global integration properties. + * @deprecated since version 5.5 in favor of {@link #getIntegrationProperty(String, Class)}; + * will be replaced with {@link IntegrationProperties} variant in the next major version. */ + @Deprecated protected Properties getIntegrationProperties() { return this.integrationProperties; } - protected MessageBuilderFactory getMessageBuilderFactory() { if (this.messageBuilderFactory == null) { this.messageBuilderFactory = new DefaultMessageBuilderFactory(); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java index 815d971295..522f7f2e28 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java @@ -16,17 +16,27 @@ package org.springframework.integration.context; -import java.io.IOException; import java.util.Properties; -import org.springframework.beans.factory.config.PropertiesFactoryBean; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.integration.util.JavaUtils; +import org.springframework.util.StringUtils; /** - * Utility class to encapsulate infrastructure Integration properties constants and - * their default values from resources 'META-INF/spring.integration.default.properties'. + * Utility class to encapsulate infrastructure Integration properties constants and their default values. + * The default values can be overridden by the {@code META-INF/spring.integration.properties} with this entries + * (includes their default values): + *

+ *

* * @author Artem Bilan * @@ -98,26 +108,228 @@ public final class IntegrationProperties { private static final Properties DEFAULTS; - static { - String resourcePattern = "classpath*:META-INF/spring.integration.default.properties"; - try { - ResourcePatternResolver resourceResolver = - new PathMatchingResourcePatternResolver(IntegrationProperties.class.getClassLoader()); - Resource[] defaultResources = resourceResolver.getResources(resourcePattern); + private boolean channelsAutoCreate = true; - PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); - propertiesFactoryBean.setLocations(defaultResources); - propertiesFactoryBean.afterPropertiesSet(); - DEFAULTS = propertiesFactoryBean.getObject(); - } - catch (IOException e) { - throw new IllegalStateException("Can't load '" + resourcePattern + "' resources.", e); - } + private int channelsMaxUnicastSubscribers = Integer.MAX_VALUE; + + private int channelsMaxBroadcastSubscribers = Integer.MAX_VALUE; + + private boolean errorChannelRequireSubscribers = true; + + private boolean errorChannelIgnoreFailures = true; + + private int taskSchedulerPoolSize = 10; + + private boolean messagingTemplateThrowExceptionOnLateReply = false; + + private String[] readOnlyHeaders = { }; + + private String[] noAutoStartupEndpoints = { }; + + static { + DEFAULTS = new IntegrationProperties().toProperties(); } /** - * @return {@link Properties} with default values for Integration properties - * from resources 'META-INF/spring.integration.default.properties'. + * Configure a value for {@link #CHANNELS_AUTOCREATE} option. + * @param channelsAutoCreate the value for {@link #CHANNELS_AUTOCREATE} option. + */ + public void setChannelsAutoCreate(boolean channelsAutoCreate) { + this.channelsAutoCreate = channelsAutoCreate; + } + + /** + * Return the value of {@link #CHANNELS_AUTOCREATE} option. + * @return the value of {@link #CHANNELS_AUTOCREATE} option. + */ + public boolean isChannelsAutoCreate() { + return this.channelsAutoCreate; + } + + /** + * Configure a value for {@link #CHANNELS_MAX_UNICAST_SUBSCRIBERS} option. + * @param channelsMaxUnicastSubscribers the value for {@link #CHANNELS_MAX_UNICAST_SUBSCRIBERS} option. + */ + public void setChannelsMaxUnicastSubscribers(int channelsMaxUnicastSubscribers) { + this.channelsMaxUnicastSubscribers = channelsMaxUnicastSubscribers; + } + + /** + * Return the value of {@link #CHANNELS_MAX_UNICAST_SUBSCRIBERS} option. + * @return the value of {@link #CHANNELS_MAX_UNICAST_SUBSCRIBERS} option. + */ + public int getChannelsMaxUnicastSubscribers() { + return this.channelsMaxUnicastSubscribers; + } + + /** + * Configure a value for {@link #CHANNELS_MAX_BROADCAST_SUBSCRIBERS} option. + * @param channelsMaxBroadcastSubscribers the value for {@link #CHANNELS_MAX_BROADCAST_SUBSCRIBERS} option. + */ + public void setChannelsMaxBroadcastSubscribers(int channelsMaxBroadcastSubscribers) { + this.channelsMaxBroadcastSubscribers = channelsMaxBroadcastSubscribers; + } + + /** + * Return the value of {@link #CHANNELS_MAX_BROADCAST_SUBSCRIBERS} option. + * @return the value of {@link #CHANNELS_MAX_BROADCAST_SUBSCRIBERS} option. + */ + public int getChannelsMaxBroadcastSubscribers() { + return this.channelsMaxBroadcastSubscribers; + } + + /** + * Configure a value for {@link #ERROR_CHANNEL_REQUIRE_SUBSCRIBERS} option. + * @param errorChannelRequireSubscribers the value for {@link #ERROR_CHANNEL_REQUIRE_SUBSCRIBERS} option. + */ + public void setErrorChannelRequireSubscribers(boolean errorChannelRequireSubscribers) { + this.errorChannelRequireSubscribers = errorChannelRequireSubscribers; + } + + /** + * Return the value of {@link #ERROR_CHANNEL_REQUIRE_SUBSCRIBERS} option. + * @return the value of {@link #ERROR_CHANNEL_REQUIRE_SUBSCRIBERS} option. + */ + public boolean isErrorChannelRequireSubscribers() { + return this.errorChannelRequireSubscribers; + } + + /** + * Configure a value for {@link #ERROR_CHANNEL_IGNORE_FAILURES} option. + * @param errorChannelIgnoreFailures the value for {@link #ERROR_CHANNEL_IGNORE_FAILURES} option. + */ + public void setErrorChannelIgnoreFailures(boolean errorChannelIgnoreFailures) { + this.errorChannelIgnoreFailures = errorChannelIgnoreFailures; + } + + /** + * Return the value of {@link #ERROR_CHANNEL_IGNORE_FAILURES} option. + * @return the value of {@link #ERROR_CHANNEL_IGNORE_FAILURES} option. + */ + public boolean isErrorChannelIgnoreFailures() { + return this.errorChannelIgnoreFailures; + } + + /** + * Configure a value for {@link #TASK_SCHEDULER_POOL_SIZE} option. + * @param taskSchedulerPoolSize the value for {@link #TASK_SCHEDULER_POOL_SIZE} option. + */ + public void setTaskSchedulerPoolSize(int taskSchedulerPoolSize) { + this.taskSchedulerPoolSize = taskSchedulerPoolSize; + } + + /** + * Return the value of {@link #TASK_SCHEDULER_POOL_SIZE} option. + * @return the value of {@link #TASK_SCHEDULER_POOL_SIZE} option. + */ + public int getTaskSchedulerPoolSize() { + return this.taskSchedulerPoolSize; + } + + /** + * Configure a value for {@link #THROW_EXCEPTION_ON_LATE_REPLY} option. + * @param messagingTemplateThrowExceptionOnLateReply the value for {@link #THROW_EXCEPTION_ON_LATE_REPLY} option. + */ + public void setMessagingTemplateThrowExceptionOnLateReply(boolean messagingTemplateThrowExceptionOnLateReply) { + this.messagingTemplateThrowExceptionOnLateReply = messagingTemplateThrowExceptionOnLateReply; + } + + /** + * Return the value of {@link #THROW_EXCEPTION_ON_LATE_REPLY} option. + * @return the value of {@link #THROW_EXCEPTION_ON_LATE_REPLY} option. + */ + public boolean isMessagingTemplateThrowExceptionOnLateReply() { + return this.messagingTemplateThrowExceptionOnLateReply; + } + + /** + * Configure a value for {@link #READ_ONLY_HEADERS} option. + * @param readOnlyHeaders the value for {@link #READ_ONLY_HEADERS} option. + */ + public void setReadOnlyHeaders(String... readOnlyHeaders) { + this.readOnlyHeaders = readOnlyHeaders; + } + + /** + * Return the value of {@link #READ_ONLY_HEADERS} option. + * @return the value of {@link #READ_ONLY_HEADERS} option. + */ + public String[] getReadOnlyHeaders() { + return this.readOnlyHeaders; + } + + /** + * Configure a value for {@link #ENDPOINTS_NO_AUTO_STARTUP} option. + * @param noAutoStartupEndpoints the value for {@link #ENDPOINTS_NO_AUTO_STARTUP} option. + */ + public void setNoAutoStartupEndpoints(String... noAutoStartupEndpoints) { + this.noAutoStartupEndpoints = noAutoStartupEndpoints; + } + + /** + * Return the value of {@link #ENDPOINTS_NO_AUTO_STARTUP} option. + * @return the value of {@link #ENDPOINTS_NO_AUTO_STARTUP} option. + */ + public String[] getNoAutoStartupEndpoints() { + return this.noAutoStartupEndpoints; + } + + /** + * Represent the current instance as a {@link Properties}. + * @return the {@link Properties} representation. + * @since 5.5 + */ + public Properties toProperties() { + Properties properties = new Properties(); + + properties.setProperty(CHANNELS_AUTOCREATE, "" + this.channelsAutoCreate); + properties.setProperty(CHANNELS_MAX_UNICAST_SUBSCRIBERS, "" + this.channelsMaxUnicastSubscribers); + properties.setProperty(CHANNELS_MAX_BROADCAST_SUBSCRIBERS, "" + this.channelsMaxBroadcastSubscribers); + properties.setProperty(ERROR_CHANNEL_REQUIRE_SUBSCRIBERS, "" + this.errorChannelRequireSubscribers); + properties.setProperty(ERROR_CHANNEL_IGNORE_FAILURES, "" + this.errorChannelIgnoreFailures); + properties.setProperty(TASK_SCHEDULER_POOL_SIZE, "" + this.taskSchedulerPoolSize); + properties.setProperty(THROW_EXCEPTION_ON_LATE_REPLY, "" + this.messagingTemplateThrowExceptionOnLateReply); + properties.setProperty(READ_ONLY_HEADERS, StringUtils.arrayToCommaDelimitedString(this.readOnlyHeaders)); + properties.setProperty(ENDPOINTS_NO_AUTO_STARTUP, + StringUtils.arrayToCommaDelimitedString(this.noAutoStartupEndpoints)); + + return properties; + } + + /** + * Parse a provided {@link Properties} and build an {@link IntegrationProperties} instance. + * @return {@link IntegrationProperties} based on the provided {@link Properties}. + * @since 5.5 + */ + public static IntegrationProperties parse(Properties properties) { + IntegrationProperties integrationProperties = new IntegrationProperties(); + JavaUtils.INSTANCE + .acceptIfHasText(properties.getProperty(CHANNELS_AUTOCREATE), + (value) -> integrationProperties.setChannelsAutoCreate(Boolean.parseBoolean(value))) + .acceptIfHasText(properties.getProperty(CHANNELS_MAX_UNICAST_SUBSCRIBERS), + (value) -> integrationProperties.setChannelsMaxUnicastSubscribers(Integer.parseInt(value))) + .acceptIfHasText(properties.getProperty(CHANNELS_MAX_BROADCAST_SUBSCRIBERS), + (value) -> integrationProperties.setChannelsMaxBroadcastSubscribers(Integer.parseInt(value))) + .acceptIfHasText(properties.getProperty(ERROR_CHANNEL_REQUIRE_SUBSCRIBERS), + (value) -> integrationProperties.setErrorChannelRequireSubscribers(Boolean.parseBoolean(value))) + .acceptIfHasText(properties.getProperty(ERROR_CHANNEL_IGNORE_FAILURES), + (value) -> integrationProperties.setErrorChannelIgnoreFailures(Boolean.parseBoolean(value))) + .acceptIfHasText(properties.getProperty(TASK_SCHEDULER_POOL_SIZE), + (value) -> integrationProperties.setTaskSchedulerPoolSize(Integer.parseInt(value))) + .acceptIfHasText(properties.getProperty(THROW_EXCEPTION_ON_LATE_REPLY), + (value) -> integrationProperties.setMessagingTemplateThrowExceptionOnLateReply( + Boolean.parseBoolean(value))) + .acceptIfHasText(properties.getProperty(READ_ONLY_HEADERS), + (value) -> integrationProperties.setReadOnlyHeaders( + StringUtils.commaDelimitedListToStringArray(value))) + .acceptIfHasText(properties.getProperty(ENDPOINTS_NO_AUTO_STARTUP), + (value) -> integrationProperties.setNoAutoStartupEndpoints( + StringUtils.commaDelimitedListToStringArray(value))); + return integrationProperties; + } + + /** + * @return {@link Properties} with default values for Integration properties. */ public static Properties defaults() { return DEFAULTS; @@ -126,7 +338,6 @@ public final class IntegrationProperties { /** * Build the bean property definition expression to resolve the value * from Integration properties within the bean building phase. - * * @param key the Integration property key. * @return the bean property definition expression. * @throws IllegalArgumentException if provided {@code key} isn't an Integration property. @@ -142,7 +353,4 @@ public final class IntegrationProperties { } } - private IntegrationProperties() { - } - } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DispatcherMaxSubscribersOverrideDefaultTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DispatcherMaxSubscribersOverrideDefaultTests-context.xml index 5221b52b5a..c9ed80a757 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DispatcherMaxSubscribersOverrideDefaultTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DispatcherMaxSubscribersOverrideDefaultTests-context.xml @@ -2,20 +2,18 @@ + http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - - 456 - 789 - + + + + - + - + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests.java b/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests.java index 9a1a7aee63..0cb8befea3 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2019 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. @@ -20,24 +20,21 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Properties; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.integration.endpoint.AbstractEndpoint; import org.springframework.integration.test.util.TestUtils; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; /** * @author Artem Bilan * * @since 3.0 */ -@ContextConfiguration -@RunWith(SpringJUnit4ClassRunner.class) +@SpringJUnitConfig public class IntegrationContextTests { @Autowired @@ -56,6 +53,7 @@ public class IntegrationContextTests { private ThreadPoolTaskScheduler taskScheduler; @Test + @SuppressWarnings("deprecation") public void testIntegrationContextComponents() { assertThat(this.integrationProperties.get(IntegrationProperties.THROW_EXCEPTION_ON_LATE_REPLY)) .isEqualTo("true"); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java index 48ebdac559..258e97dba7 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java @@ -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. @@ -17,6 +17,7 @@ package org.springframework.integration.gateway; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -29,15 +30,13 @@ import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.Map; -import java.util.Properties; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -86,8 +85,7 @@ import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Component; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import org.springframework.util.concurrent.ListenableFuture; import org.springframework.util.concurrent.ListenableFutureCallback; @@ -97,8 +95,7 @@ import org.springframework.util.concurrent.ListenableFutureCallback; * @author Gary Russell * @author Artem Bilan */ -@ContextConfiguration(classes = GatewayInterfaceTests.TestConfig.class) -@RunWith(SpringJUnit4ClassRunner.class) +@SpringJUnitConfig(classes = GatewayInterfaceTests.TestConfig.class) @DirtiesContext @ActiveProfiles("gatewayTest") public class GatewayInterfaceTests { @@ -236,7 +233,7 @@ public class GatewayInterfaceTests { } @Test - public void testWithServiceUnAnnotatedMethodGlobalHeaderDoesntOverride() throws Exception { + public void testWithServiceUnAnnotatedMethodGlobalHeaderDoesNotOverride() throws Exception { ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass()); DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class); @@ -344,9 +341,9 @@ public class GatewayInterfaceTests { ac.close(); } - @Test(expected = IllegalArgumentException.class) + @Test public void testWithServiceAsNotAnInterface() { - new GatewayProxyFactoryBean(NotAnInterface.class); + assertThatIllegalArgumentException().isThrownBy(() -> new GatewayProxyFactoryBean(NotAnInterface.class)); } @Test @@ -420,7 +417,7 @@ public class GatewayInterfaceTests { ListenableFuture result2 = this.execGateway.test2(Thread.currentThread()); final CountDownLatch latch = new CountDownLatch(1); final AtomicReference thread = new AtomicReference<>(); - result2.addCallback(new ListenableFutureCallback() { + result2.addCallback(new ListenableFutureCallback<>() { @Override public void onSuccess(Thread result) { @@ -431,6 +428,7 @@ public class GatewayInterfaceTests { @Override public void onFailure(Throwable t) { } + }); assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); assertThat(result2.get().getName()).startsWith("exec-"); @@ -594,9 +592,9 @@ public class GatewayInterfaceTests { public static class TestConfig { @Bean(name = IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME) - public static Properties integrationProperties() { - Properties properties = new Properties(); - properties.setProperty(IntegrationProperties.READ_ONLY_HEADERS, IGNORE_HEADER); + public static IntegrationProperties integrationProperties() { + IntegrationProperties properties = new IntegrationProperties(); + properties.setReadOnlyHeaders(IGNORE_HEADER); return properties; } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/json/ObjectToJsonTransformerParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/json/ObjectToJsonTransformerParserTests-context.xml index 8c1209b1ef..da47bf92d4 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/json/ObjectToJsonTransformerParserTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/json/ObjectToJsonTransformerParserTests-context.xml @@ -2,14 +2,12 @@ + http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd"> - - contentType,foo - + + + diff --git a/src/reference/asciidoc/configuration.adoc b/src/reference/asciidoc/configuration.adoc index 02d4dec76b..85de3e5ee8 100644 --- a/src/reference/asciidoc/configuration.adoc +++ b/src/reference/asciidoc/configuration.adoc @@ -154,8 +154,7 @@ The next section describes what happens if exceptions occur within the asynchron Certain global framework properties can be overridden by providing a properties file on the classpath. -The default properties can be found in `/META-INF/spring.integration.default.properties` in the `spring-integration-core` jar. -You can see them on GitHub https://github.com/spring-projects/spring-integration/blob/master/spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties[here]. +The default properties can be found in `org.springframework.integration.context.IntegrationProperties` class. The following listing shows the default values: ==== @@ -205,7 +204,7 @@ See <<./error-handling.adoc#error-handling,Error Handling>> for more information Since version 5.5. ==== -These properties can be overridden by adding a `/META-INF/spring.integration.properties` file to the classpath. +These properties can be overridden by adding a `/META-INF/spring.integration.properties` file to the classpath or an `IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME` bean for the `org.springframework.integration.context.IntegrationProperties` instance. You need not provide all the properties -- only those that you want to override. Starting with version 5.1, all the merged global properties are printed in the logs after application context startup when a `DEBUG` logic level is turned on for the `org.springframework.integration` category. diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index 500c478860..4f5bb8c828 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -21,6 +21,7 @@ If you are interested in more details, see the Issue Tracker tickets that were r All the persistent `MessageGroupStore` implementation provide a `streamMessagesForGroup(Object groupId)` contract based on the target database streaming API. See <<./message-store.adoc#message-store,Message Store>> for more information. +The `integrationGlobalProperties` bean (if declared) must be now an instance of `org.springframework.integration.context.IntegrationProperties` instead of `java.util.Properties`, which support is deprecated for backward compatibility. The `spring.integration.channels.error.requireSubscribers=true` global property is added to indicate that the global default `errorChannel` must be configured with the `requireSubscribers` option (or not). The `spring.integration.channels.error.ignoreFailures=true` global property is added to indicate that the global default `errorChannel` must ignore (or not) dispatching errors and pass the message to the next handler. See <<./configuration.adoc#global-properties,Global Properties>> for more information.