From 06f0b91429681210ceee489fecaeaa8213e2dcc0 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 1 Nov 2024 17:49:38 -0700 Subject: [PATCH] Add @Order to WebSocketMessageConverterConfiguration Add `@Order` to `WebSocketMessageConverterConfiguration` so that custom `WebSocketMessageBrokerConfigurer` implementations can be added before or after ours. Fixes gh-42924 --- .../WebSocketMessagingAutoConfiguration.java | 2 + ...SocketMessagingAutoConfigurationTests.java | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/servlet/WebSocketMessagingAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/servlet/WebSocketMessagingAutoConfiguration.java index 23afdce7b5a..9076c48a761 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/servlet/WebSocketMessagingAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/servlet/WebSocketMessagingAutoConfiguration.java @@ -32,6 +32,7 @@ import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.messaging.converter.ByteArrayMessageConverter; import org.springframework.messaging.converter.DefaultContentTypeResolver; @@ -60,6 +61,7 @@ public class WebSocketMessagingAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnBean({ DelegatingWebSocketMessageBrokerConfiguration.class, ObjectMapper.class }) @ConditionalOnClass({ ObjectMapper.class, AbstractMessageBrokerConfiguration.class }) + @Order(0) static class WebSocketMessageConverterConfiguration implements WebSocketMessageBrokerConfigurer { private final ObjectMapper objectMapper; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/websocket/servlet/WebSocketMessagingAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/websocket/servlet/WebSocketMessagingAutoConfigurationTests.java index 59c8046c66a..1cbb4522848 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/websocket/servlet/WebSocketMessagingAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/websocket/servlet/WebSocketMessagingAutoConfigurationTests.java @@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.tomcat.websocket.WsWebSocketContainer; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -40,12 +41,15 @@ import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; +import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration.WebSocketMessageConverterConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; @@ -62,6 +66,7 @@ import org.springframework.messaging.simp.stomp.StompSession; import org.springframework.messaging.simp.stomp.StompSessionHandler; import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter; import org.springframework.security.util.FieldUtils; +import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import org.springframework.web.client.RestTemplate; import org.springframework.web.socket.client.standard.StandardWebSocketClient; @@ -162,6 +167,26 @@ class WebSocketMessagingAutoConfigurationTests { assertThat(executor).isEqualTo(expectedExecutor); } + @Test + void webSocketMessageBrokerConfigurerOrdering() throws Throwable { + TestPropertyValues.of("server.port:0", "spring.jackson.serialization.indent-output:true").applyTo(this.context); + this.context.register(WebSocketMessagingConfiguration.class, CustomLowWebSocketMessageBrokerConfigurer.class, + CustomHighWebSocketMessageBrokerConfigurer.class); + this.context.refresh(); + DelegatingWebSocketMessageBrokerConfiguration delegatingConfiguration = this.context + .getBean(DelegatingWebSocketMessageBrokerConfiguration.class); + CustomHighWebSocketMessageBrokerConfigurer high = this.context + .getBean(CustomHighWebSocketMessageBrokerConfigurer.class); + WebSocketMessageConverterConfiguration autoConfiguration = this.context + .getBean(WebSocketMessagingAutoConfiguration.WebSocketMessageConverterConfiguration.class); + WebSocketMessagingConfiguration configuration = this.context.getBean(WebSocketMessagingConfiguration.class); + CustomLowWebSocketMessageBrokerConfigurer low = this.context + .getBean(CustomLowWebSocketMessageBrokerConfigurer.class); + assertThat(delegatingConfiguration).extracting("configurers") + .asInstanceOf(InstanceOfAssertFactories.LIST) + .containsExactly(high, autoConfiguration, configuration, low); + } + private List getCustomizedConverters() { List customizedConverters = new ArrayList<>(); WebSocketMessagingAutoConfiguration.WebSocketMessageConverterConfiguration configuration = new WebSocketMessagingAutoConfiguration.WebSocketMessageConverterConfiguration( @@ -246,6 +271,7 @@ class WebSocketMessagingAutoConfigurationTests { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/messaging").withSockJS(); } @@ -271,6 +297,18 @@ class WebSocketMessagingAutoConfigurationTests { } + @Component + @Order(Ordered.HIGHEST_PRECEDENCE) + static class CustomHighWebSocketMessageBrokerConfigurer implements WebSocketMessageBrokerConfigurer { + + } + + @Component + @Order(Ordered.LOWEST_PRECEDENCE) + static class CustomLowWebSocketMessageBrokerConfigurer implements WebSocketMessageBrokerConfigurer { + + } + @Controller static class MessagingController {