Skip to content

Commit f062c46

Browse files
committed
Merge branch '3.2.x' into 3.3.x
Closes gh-41521
2 parents 754e71d + 1cc7498 commit f062c46

File tree

5 files changed

+151
-37
lines changed

5 files changed

+151
-37
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -105,6 +105,9 @@ public static org.springframework.integration.context.IntegrationProperties inte
105105
map.from(properties.getError().isIgnoreFailures()).to(integrationProperties::setErrorChannelIgnoreFailures);
106106
map.from(properties.getEndpoint().isThrowExceptionOnLateReply())
107107
.to(integrationProperties::setMessagingTemplateThrowExceptionOnLateReply);
108+
map.from(properties.getEndpoint().getDefaultTimeout())
109+
.as(Duration::toMillis)
110+
.to(integrationProperties::setEndpointsDefaultTimeout);
108111
map.from(properties.getEndpoint().getReadOnlyHeaders())
109112
.as(StringUtils::toStringArray)
110113
.to(integrationProperties::setReadOnlyHeaders);

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationProperties.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -141,6 +141,11 @@ public static class Endpoint {
141141
*/
142142
private List<String> noAutoStartup = new ArrayList<>();
143143

144+
/**
145+
* Default timeout for blocking operations such as sending or receiving messages.
146+
*/
147+
private Duration defaultTimeout = Duration.ofSeconds(30);
148+
144149
public void setThrowExceptionOnLateReply(boolean throwExceptionOnLateReply) {
145150
this.throwExceptionOnLateReply = throwExceptionOnLateReply;
146151
}
@@ -165,6 +170,14 @@ public void setNoAutoStartup(List<String> noAutoStartup) {
165170
this.noAutoStartup = noAutoStartup;
166171
}
167172

173+
public Duration getDefaultTimeout() {
174+
return this.defaultTimeout;
175+
}
176+
177+
public void setDefaultTimeout(Duration defaultTimeout) {
178+
this.defaultTimeout = defaultTimeout;
179+
}
180+
168181
}
169182

170183
public static class Error {

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationPropertiesEnvironmentPostProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -85,6 +85,7 @@ private static final class IntegrationPropertiesPropertySource extends PropertyS
8585
IntegrationProperties.CHANNELS_MAX_BROADCAST_SUBSCRIBERS);
8686
mappings.put(PREFIX + "error.require-subscribers", IntegrationProperties.ERROR_CHANNEL_REQUIRE_SUBSCRIBERS);
8787
mappings.put(PREFIX + "error.ignore-failures", IntegrationProperties.ERROR_CHANNEL_IGNORE_FAILURES);
88+
mappings.put(PREFIX + "endpoint.default-timeout", IntegrationProperties.ENDPOINTS_DEFAULT_TIMEOUT);
8889
mappings.put(PREFIX + "endpoint.throw-exception-on-late-reply",
8990
IntegrationProperties.THROW_EXCEPTION_ON_LATE_REPLY);
9091
mappings.put(PREFIX + "endpoint.read-only-headers", IntegrationProperties.READ_ONLY_HEADERS);

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,10 +16,13 @@
1616

1717
package org.springframework.boot.autoconfigure.integration;
1818

19+
import java.beans.PropertyDescriptor;
1920
import java.time.Duration;
21+
import java.util.List;
2022
import java.util.concurrent.BlockingQueue;
2123
import java.util.concurrent.LinkedBlockingQueue;
2224
import java.util.concurrent.TimeUnit;
25+
import java.util.stream.Stream;
2326

2427
import javax.management.MBeanServer;
2528
import javax.sql.DataSource;
@@ -32,6 +35,7 @@
3235
import reactor.core.publisher.Mono;
3336

3437
import org.springframework.beans.DirectFieldAccessor;
38+
import org.springframework.beans.PropertyAccessorFactory;
3539
import org.springframework.boot.autoconfigure.AutoConfigurations;
3640
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
3741
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration.IntegrationComponentScanConfiguration;
@@ -82,6 +86,7 @@
8286
import org.springframework.scheduling.TaskScheduler;
8387
import org.springframework.scheduling.support.CronTrigger;
8488
import org.springframework.scheduling.support.PeriodicTrigger;
89+
import org.springframework.test.util.ReflectionTestUtils;
8590

8691
import static org.assertj.core.api.Assertions.assertThat;
8792
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -295,55 +300,63 @@ void taskSchedulerCanBeCustomized() {
295300

296301
@Test
297302
void integrationGlobalPropertiesAutoConfigured() {
298-
this.contextRunner.withPropertyValues("spring.integration.channel.auto-create=false",
303+
String[] propertyValues = { "spring.integration.channel.auto-create=false",
299304
"spring.integration.channel.max-unicast-subscribers=2",
300305
"spring.integration.channel.max-broadcast-subscribers=3",
301306
"spring.integration.error.require-subscribers=false", "spring.integration.error.ignore-failures=false",
307+
"spring.integration.endpoint.defaultTimeout=60s",
302308
"spring.integration.endpoint.throw-exception-on-late-reply=true",
303309
"spring.integration.endpoint.read-only-headers=ignoredHeader",
304-
"spring.integration.endpoint.no-auto-startup=notStartedEndpoint,_org.springframework.integration.errorLogger")
305-
.run((context) -> {
306-
assertThat(context).hasSingleBean(org.springframework.integration.context.IntegrationProperties.class);
307-
org.springframework.integration.context.IntegrationProperties integrationProperties = context
308-
.getBean(org.springframework.integration.context.IntegrationProperties.class);
309-
assertThat(integrationProperties.isChannelsAutoCreate()).isFalse();
310-
assertThat(integrationProperties.getChannelsMaxUnicastSubscribers()).isEqualTo(2);
311-
assertThat(integrationProperties.getChannelsMaxBroadcastSubscribers()).isEqualTo(3);
312-
assertThat(integrationProperties.isErrorChannelRequireSubscribers()).isFalse();
313-
assertThat(integrationProperties.isErrorChannelIgnoreFailures()).isFalse();
314-
assertThat(integrationProperties.isMessagingTemplateThrowExceptionOnLateReply()).isTrue();
315-
assertThat(integrationProperties.getReadOnlyHeaders()).containsOnly("ignoredHeader");
316-
assertThat(integrationProperties.getNoAutoStartupEndpoints()).containsOnly("notStartedEndpoint",
317-
"_org.springframework.integration.errorLogger");
318-
});
310+
"spring.integration.endpoint.no-auto-startup=notStartedEndpoint,_org.springframework.integration.errorLogger" };
311+
assertThat(propertyValues).hasSameSizeAs(globalIntegrationPropertyNames());
312+
this.contextRunner.withPropertyValues(propertyValues).run((context) -> {
313+
assertThat(context).hasSingleBean(org.springframework.integration.context.IntegrationProperties.class);
314+
org.springframework.integration.context.IntegrationProperties integrationProperties = context
315+
.getBean(org.springframework.integration.context.IntegrationProperties.class);
316+
assertThat(integrationProperties.isChannelsAutoCreate()).isFalse();
317+
assertThat(integrationProperties.getChannelsMaxUnicastSubscribers()).isEqualTo(2);
318+
assertThat(integrationProperties.getChannelsMaxBroadcastSubscribers()).isEqualTo(3);
319+
assertThat(integrationProperties.isErrorChannelRequireSubscribers()).isFalse();
320+
assertThat(integrationProperties.isErrorChannelIgnoreFailures()).isFalse();
321+
assertThat(integrationProperties.getEndpointsDefaultTimeout()).isEqualTo(60000);
322+
assertThat(integrationProperties.isMessagingTemplateThrowExceptionOnLateReply()).isTrue();
323+
assertThat(integrationProperties.getReadOnlyHeaders()).containsOnly("ignoredHeader");
324+
assertThat(integrationProperties.getNoAutoStartupEndpoints()).containsOnly("notStartedEndpoint",
325+
"_org.springframework.integration.errorLogger");
326+
});
319327
}
320328

321329
@Test
322330
void integrationGlobalPropertiesUseConsistentDefault() {
331+
List<PropertyAccessor> properties = List
332+
.of("isChannelsAutoCreate", "getChannelsMaxUnicastSubscribers", "getChannelsMaxBroadcastSubscribers",
333+
"isErrorChannelRequireSubscribers", "isErrorChannelIgnoreFailures", "getEndpointsDefaultTimeout",
334+
"isMessagingTemplateThrowExceptionOnLateReply", "getReadOnlyHeaders", "getNoAutoStartupEndpoints")
335+
.stream()
336+
.map(PropertyAccessor::new)
337+
.toList();
338+
assertThat(properties).hasSameSizeAs(globalIntegrationPropertyNames());
323339
org.springframework.integration.context.IntegrationProperties defaultIntegrationProperties = new org.springframework.integration.context.IntegrationProperties();
324340
this.contextRunner.run((context) -> {
325341
assertThat(context).hasSingleBean(org.springframework.integration.context.IntegrationProperties.class);
326342
org.springframework.integration.context.IntegrationProperties integrationProperties = context
327343
.getBean(org.springframework.integration.context.IntegrationProperties.class);
328-
assertThat(integrationProperties.isChannelsAutoCreate())
329-
.isEqualTo(defaultIntegrationProperties.isChannelsAutoCreate());
330-
assertThat(integrationProperties.getChannelsMaxUnicastSubscribers())
331-
.isEqualTo(defaultIntegrationProperties.getChannelsMaxBroadcastSubscribers());
332-
assertThat(integrationProperties.getChannelsMaxBroadcastSubscribers())
333-
.isEqualTo(defaultIntegrationProperties.getChannelsMaxBroadcastSubscribers());
334-
assertThat(integrationProperties.isErrorChannelRequireSubscribers())
335-
.isEqualTo(defaultIntegrationProperties.isErrorChannelIgnoreFailures());
336-
assertThat(integrationProperties.isErrorChannelIgnoreFailures())
337-
.isEqualTo(defaultIntegrationProperties.isErrorChannelIgnoreFailures());
338-
assertThat(integrationProperties.isMessagingTemplateThrowExceptionOnLateReply())
339-
.isEqualTo(defaultIntegrationProperties.isMessagingTemplateThrowExceptionOnLateReply());
340-
assertThat(integrationProperties.getReadOnlyHeaders())
341-
.isEqualTo(defaultIntegrationProperties.getReadOnlyHeaders());
342-
assertThat(integrationProperties.getNoAutoStartupEndpoints())
343-
.isEqualTo(defaultIntegrationProperties.getNoAutoStartupEndpoints());
344+
properties.forEach((property) -> assertThat(property.get(integrationProperties))
345+
.isEqualTo(property.get(defaultIntegrationProperties)));
344346
});
345347
}
346348

349+
private List<String> globalIntegrationPropertyNames() {
350+
return Stream
351+
.of(PropertyAccessorFactory
352+
.forBeanPropertyAccess(new org.springframework.integration.context.IntegrationProperties())
353+
.getPropertyDescriptors())
354+
.map(PropertyDescriptor::getName)
355+
.filter((name) -> !"class".equals(name))
356+
.filter((name) -> !"taskSchedulerPoolSize".equals(name))
357+
.toList();
358+
}
359+
347360
@Test
348361
void integrationGlobalPropertiesUserBeanOverridesAutoConfiguration() {
349362
org.springframework.integration.context.IntegrationProperties userIntegrationProperties = new org.springframework.integration.context.IntegrationProperties();
@@ -604,4 +617,23 @@ MessageHandler handler(BlockingQueue<Message<?>> sink) {
604617

605618
}
606619

620+
static class PropertyAccessor {
621+
622+
private final String name;
623+
624+
PropertyAccessor(String name) {
625+
this.name = name;
626+
}
627+
628+
Object get(org.springframework.integration.context.IntegrationProperties properties) {
629+
return ReflectionTestUtils.invokeMethod(properties, this.name);
630+
}
631+
632+
@Override
633+
public String toString() {
634+
return this.name;
635+
}
636+
637+
}
638+
607639
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationPropertiesEnvironmentPostProcessorTests.java

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,12 +17,23 @@
1717
package org.springframework.boot.autoconfigure.integration;
1818

1919
import java.io.FileNotFoundException;
20+
import java.lang.reflect.Modifier;
21+
import java.util.ArrayList;
22+
import java.util.Collection;
2023
import java.util.Collections;
24+
import java.util.List;
25+
import java.util.Map;
2126
import java.util.function.Consumer;
2227

28+
import io.lettuce.core.dynamic.support.ReflectionUtils;
2329
import org.junit.jupiter.api.Test;
30+
import org.junit.jupiter.params.ParameterizedTest;
31+
import org.junit.jupiter.params.provider.MethodSource;
2432

2533
import org.springframework.boot.SpringApplication;
34+
import org.springframework.boot.context.properties.bind.BindResult;
35+
import org.springframework.boot.context.properties.bind.Bindable;
36+
import org.springframework.boot.context.properties.bind.Binder;
2637
import org.springframework.boot.origin.Origin;
2738
import org.springframework.boot.origin.OriginLookup;
2839
import org.springframework.boot.origin.TextResourceOrigin;
@@ -32,6 +43,10 @@
3243
import org.springframework.core.env.StandardEnvironment;
3344
import org.springframework.core.io.ClassPathResource;
3445
import org.springframework.core.io.Resource;
46+
import org.springframework.integration.context.IntegrationProperties;
47+
import org.springframework.mock.env.MockEnvironment;
48+
import org.springframework.test.util.ReflectionTestUtils;
49+
import org.springframework.util.ClassUtils;
3550

3651
import static org.assertj.core.api.Assertions.assertThat;
3752
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
@@ -114,6 +129,56 @@ void registerIntegrationPropertiesPropertySourceWithResourceCanRetrieveOrigin()
114129
.satisfies(textOrigin(resource, 2, 52));
115130
}
116131

132+
@Test
133+
@SuppressWarnings("unchecked")
134+
void hasMappingsForAllMappableProperties() throws Exception {
135+
Class<?> propertySource = ClassUtils.forName("%s.IntegrationPropertiesPropertySource"
136+
.formatted(IntegrationPropertiesEnvironmentPostProcessor.class.getName()), getClass().getClassLoader());
137+
Map<String, String> mappings = (Map<String, String>) ReflectionTestUtils.getField(propertySource,
138+
"KEYS_MAPPING");
139+
assertThat(mappings.values()).containsExactlyInAnyOrderElementsOf(integrationPropertyNames());
140+
}
141+
142+
private static List<String> integrationPropertyNames() {
143+
List<String> propertiesToMap = new ArrayList<>();
144+
ReflectionUtils.doWithFields(IntegrationProperties.class, (field) -> {
145+
String value = (String) ReflectionUtils.getField(field, null);
146+
if (value.startsWith(IntegrationProperties.INTEGRATION_PROPERTIES_PREFIX)
147+
&& value.length() > IntegrationProperties.INTEGRATION_PROPERTIES_PREFIX.length()) {
148+
propertiesToMap.add(value);
149+
}
150+
}, (field) -> Modifier.isStatic(field.getModifiers()) && field.getType().equals(String.class));
151+
propertiesToMap.remove(IntegrationProperties.TASK_SCHEDULER_POOL_SIZE);
152+
return propertiesToMap;
153+
}
154+
155+
@MethodSource("mappedConfigurationProperties")
156+
@ParameterizedTest
157+
void mappedPropertiesExistOnBootsIntegrationProperties(String mapping) {
158+
Bindable<org.springframework.boot.autoconfigure.integration.IntegrationProperties> bindable = Bindable
159+
.of(org.springframework.boot.autoconfigure.integration.IntegrationProperties.class);
160+
MockEnvironment environment = new MockEnvironment().withProperty(mapping,
161+
(mapping.contains("max") || mapping.contains("timeout")) ? "1" : "true");
162+
BindResult<org.springframework.boot.autoconfigure.integration.IntegrationProperties> result = Binder
163+
.get(environment)
164+
.bind("spring.integration", bindable);
165+
assertThat(result.isBound()).isTrue();
166+
}
167+
168+
@SuppressWarnings("unchecked")
169+
private static Collection<String> mappedConfigurationProperties() {
170+
try {
171+
Class<?> propertySource = ClassUtils.forName("%s.IntegrationPropertiesPropertySource"
172+
.formatted(IntegrationPropertiesEnvironmentPostProcessor.class.getName()), null);
173+
Map<String, String> mappings = (Map<String, String>) ReflectionTestUtils.getField(propertySource,
174+
"KEYS_MAPPING");
175+
return mappings.keySet();
176+
}
177+
catch (Exception ex) {
178+
throw new RuntimeException(ex);
179+
}
180+
}
181+
117182
private Consumer<Origin> textOrigin(Resource resource, int line, int column) {
118183
return (origin) -> {
119184
assertThat(origin).isInstanceOf(TextResourceOrigin.class);

0 commit comments

Comments
 (0)