Skip to content

Commit 46acf0c

Browse files
committed
Fix CORS registration for IntGraphController
We fail with `NoClassDefFoundError` when we use `@EnableIntegrationGraphController` in WebFlux env without Spring MVC. Another issue that we don't register CORS for WebFlux * Extract top-level package protected classes for MVC and WebFlux to register CORS in the appropriate environment according classpath * Adjust `HttpIntegrationConfigurationInitializer` and `WebFluxIntegrationConfigurationInitializer` for native compatibility * Add `@Indexed` for `@MessagingGateway` for indexer support in Spring Boot and Spring Native **Cherry-pick to `5.4.x` & `5.3.x`** # Conflicts: # spring-integration-http/src/main/java/org/springframework/integration/http/config/IntegrationGraphControllerRegistrar.java
1 parent a6d5ed6 commit 46acf0c

File tree

7 files changed

+176
-47
lines changed

7 files changed

+176
-47
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ project('spring-integration-http') {
518518
api 'org.springframework:spring-webmvc'
519519
providedImplementation "javax.servlet:javax.servlet-api:$servletApiVersion"
520520
optionalApi "com.rometools:rome:$romeToolsVersion"
521+
optionalApi 'org.springframework:spring-webflux'
521522

522523
testImplementation project(':spring-integration-security')
523524
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"

spring-integration-core/src/main/java/org/springframework/integration/annotation/MessagingGateway.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2019 the original author or authors.
2+
* Copyright 2014-2021 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.
@@ -22,6 +22,8 @@
2222
import java.lang.annotation.RetentionPolicy;
2323
import java.lang.annotation.Target;
2424

25+
import org.springframework.stereotype.Indexed;
26+
2527
/**
2628
* A stereotype annotation to provide an Integration Messaging Gateway Proxy
2729
* ({@code <gateway/>}) as an abstraction over the messaging API. The target
@@ -44,6 +46,7 @@
4446
@Target(ElementType.TYPE)
4547
@Retention(RetentionPolicy.RUNTIME)
4648
@Documented
49+
@Indexed
4750
public @interface MessagingGateway {
4851

4952
/**

spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpIntegrationConfigurationInitializer.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2020 the original author or authors.
2+
* Copyright 2014-2021 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.
@@ -25,7 +25,6 @@
2525
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2626
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2727
import org.springframework.integration.config.IntegrationConfigurationInitializer;
28-
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
2928
import org.springframework.integration.http.inbound.IntegrationRequestMappingHandlerMapping;
3029

3130
/**
@@ -55,18 +54,22 @@ public void initialize(ConfigurableListableBeanFactory beanFactory) throws Beans
5554
* which could also be overridden by the user by simply registering
5655
* a {@link IntegrationRequestMappingHandlerMapping} {@code <bean>} with 'id'
5756
* {@link HttpContextUtils#HANDLER_MAPPING_BEAN_NAME}.
58-
* <p>
59-
* In addition, checks if the {@code javax.servlet.Servlet} class is present on the classpath.
57+
* <p> In addition, checks if the {@code javax.servlet.Servlet} class is present on the classpath.
6058
* When Spring Integration HTTP is used only as an HTTP client, there is no reason to use and register
6159
* the HTTP server components.
6260
*/
6361
private void registerRequestMappingHandlerMappingIfNecessary(BeanDefinitionRegistry registry) {
6462
if (HttpContextUtils.WEB_MVC_PRESENT &&
6563
!registry.containsBeanDefinition(HttpContextUtils.HANDLER_MAPPING_BEAN_NAME)) {
6664
BeanDefinitionBuilder requestMappingBuilder =
67-
BeanDefinitionBuilder.genericBeanDefinition(IntegrationRequestMappingHandlerMapping.class);
65+
BeanDefinitionBuilder.genericBeanDefinition(IntegrationRequestMappingHandlerMapping.class,
66+
() -> {
67+
IntegrationRequestMappingHandlerMapping mapping =
68+
new IntegrationRequestMappingHandlerMapping();
69+
mapping.setOrder(0);
70+
return mapping;
71+
});
6872
requestMappingBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
69-
requestMappingBuilder.addPropertyValue(IntegrationNamespaceUtils.ORDER, 0);
7073
registry.registerBeanDefinition(HttpContextUtils.HANDLER_MAPPING_BEAN_NAME,
7174
requestMappingBuilder.getBeanDefinition());
7275
}
Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2019 the original author or authors.
2+
* Copyright 2016-2021 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.
@@ -20,14 +20,19 @@
2020
import java.util.HashMap;
2121
import java.util.Map;
2222

23+
import org.apache.commons.logging.Log;
24+
import org.apache.commons.logging.LogFactory;
25+
2326
import org.springframework.beans.BeansException;
27+
import org.springframework.beans.factory.BeanFactory;
2428
import org.springframework.beans.factory.config.BeanDefinition;
2529
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
2630
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2731
import org.springframework.beans.factory.support.AbstractBeanDefinition;
2832
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2933
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
3034
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
35+
import org.springframework.beans.factory.support.GenericBeanDefinition;
3136
import org.springframework.beans.factory.support.RootBeanDefinition;
3237
import org.springframework.context.EnvironmentAware;
3338
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
@@ -39,8 +44,6 @@
3944
import org.springframework.integration.context.IntegrationContextUtils;
4045
import org.springframework.integration.graph.IntegrationGraphServer;
4146
import org.springframework.integration.http.management.IntegrationGraphController;
42-
import org.springframework.web.servlet.config.annotation.CorsRegistry;
43-
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
4447

4548
/**
4649
* Registers the necessary beans for {@link EnableIntegrationGraphController}.
@@ -50,10 +53,19 @@
5053
*
5154
* @since 4.3
5255
*/
53-
class IntegrationGraphControllerRegistrar implements ImportBeanDefinitionRegistrar {
56+
public class IntegrationGraphControllerRegistrar implements ImportBeanDefinitionRegistrar {
57+
58+
private static final Log LOGGER = LogFactory.getLog(IntegrationGraphControllerRegistrar.class);
5459

5560
@Override
5661
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
62+
if (!HttpContextUtils.WEB_MVC_PRESENT && !HttpContextUtils.WEB_FLUX_PRESENT) {
63+
LOGGER.warn("The 'IntegrationGraphController' isn't registered with the application context because" +
64+
" there is no 'org.springframework.web.servlet.DispatcherServlet' or" +
65+
" 'org.springframework.web.reactive.DispatcherHandler' in the classpath.");
66+
return;
67+
}
68+
5769
Map<String, Object> annotationAttributes =
5870
importingClassMetadata.getAnnotationAttributes(EnableIntegrationGraphController.class.getName());
5971
if (annotationAttributes == null) {
@@ -62,40 +74,67 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B
6274

6375
if (!registry.containsBeanDefinition(IntegrationContextUtils.INTEGRATION_GRAPH_SERVER_BEAN_NAME)) {
6476
registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_GRAPH_SERVER_BEAN_NAME,
65-
new RootBeanDefinition(IntegrationGraphServer.class));
77+
new RootBeanDefinition(IntegrationGraphServer.class, IntegrationGraphServer::new));
6678
}
6779

80+
String path = (String) annotationAttributes.get("value");
6881
String[] allowedOrigins = (String[]) annotationAttributes.get("allowedOrigins");
6982
if (allowedOrigins != null && allowedOrigins.length > 0) {
70-
AbstractBeanDefinition controllerCorsConfigurer =
71-
BeanDefinitionBuilder.genericBeanDefinition(IntegrationGraphCorsConfigurer.class)
72-
.addConstructorArgValue(annotationAttributes.get("value"))
73-
.addConstructorArgValue(allowedOrigins)
74-
.getBeanDefinition();
75-
BeanDefinitionReaderUtils.registerWithGeneratedName(controllerCorsConfigurer, registry);
83+
AbstractBeanDefinition controllerCorsConfigurer = null;
84+
if (HttpContextUtils.WEB_MVC_PRESENT) {
85+
controllerCorsConfigurer = webMvcControllerCorsConfigurerBean(path, allowedOrigins);
86+
}
87+
else if (HttpContextUtils.WEB_FLUX_PRESENT) {
88+
controllerCorsConfigurer = webFluxControllerCorsConfigurerBean(path, allowedOrigins);
89+
}
90+
91+
if (controllerCorsConfigurer != null) {
92+
BeanDefinitionReaderUtils.registerWithGeneratedName(controllerCorsConfigurer, registry);
93+
}
94+
else {
95+
LOGGER.warn("Nor Spring MVC, neither WebFlux is present to configure CORS origins " +
96+
"for Integration Graph Controller.");
97+
}
7698
}
7799

78100
if (!registry.containsBeanDefinition(HttpContextUtils.GRAPH_CONTROLLER_BEAN_NAME)) {
101+
Map<String, Object> properties = annotationAttributes;
79102
AbstractBeanDefinition controllerPropertiesPopulator =
80-
BeanDefinitionBuilder.genericBeanDefinition(GraphControllerPropertiesPopulator.class)
81-
.addConstructorArgValue(annotationAttributes)
103+
BeanDefinitionBuilder.genericBeanDefinition(GraphControllerPropertiesPopulator.class,
104+
() -> new GraphControllerPropertiesPopulator(properties))
82105
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
83106
.getBeanDefinition();
84107
BeanDefinitionReaderUtils.registerWithGeneratedName(controllerPropertiesPopulator, registry);
85108

86109
BeanDefinition graphController =
87-
BeanDefinitionBuilder.genericBeanDefinition(IntegrationGraphController.class)
88-
.addConstructorArgReference(IntegrationContextUtils.INTEGRATION_GRAPH_SERVER_BEAN_NAME)
89-
.getBeanDefinition();
110+
new RootBeanDefinition(IntegrationGraphController.class, () ->
111+
new IntegrationGraphController(
112+
((BeanFactory) registry)
113+
.getBean(IntegrationContextUtils.INTEGRATION_GRAPH_SERVER_BEAN_NAME,
114+
IntegrationGraphServer.class)));
90115

91116
registry.registerBeanDefinition(HttpContextUtils.GRAPH_CONTROLLER_BEAN_NAME, graphController);
92117
}
93118
}
94119

120+
private static AbstractBeanDefinition webMvcControllerCorsConfigurerBean(String path, String[] allowedOrigins) {
121+
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
122+
beanDefinition.setBeanClass(WebMvcIntegrationGraphCorsConfigurer.class);
123+
beanDefinition.setInstanceSupplier(() -> new WebMvcIntegrationGraphCorsConfigurer(path, allowedOrigins));
124+
return beanDefinition;
125+
}
126+
127+
private static AbstractBeanDefinition webFluxControllerCorsConfigurerBean(String path, String[] allowedOrigins) {
128+
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
129+
beanDefinition.setBeanClass(WebFluxIntegrationGraphCorsConfigurer.class);
130+
beanDefinition.setInstanceSupplier(() -> new WebFluxIntegrationGraphCorsConfigurer(path, allowedOrigins));
131+
return beanDefinition;
132+
}
133+
95134
private static final class GraphControllerPropertiesPopulator
96135
implements BeanFactoryPostProcessor, EnvironmentAware {
97136

98-
private final Map<String, Object> properties = new HashMap<String, Object>();
137+
private final Map<String, Object> properties = new HashMap<>();
99138

100139
private GraphControllerPropertiesPopulator(Map<String, Object> annotationAttributes) {
101140
Object graphControllerPath = annotationAttributes.get(AnnotationUtils.VALUE);
@@ -117,22 +156,4 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
117156

118157
}
119158

120-
private static final class IntegrationGraphCorsConfigurer implements WebMvcConfigurer {
121-
122-
private final String path;
123-
124-
private final String[] allowedOrigins;
125-
126-
private IntegrationGraphCorsConfigurer(String path, String[] allowedOrigins) { // NOSONAR
127-
this.path = path;
128-
this.allowedOrigins = allowedOrigins;
129-
}
130-
131-
@Override
132-
public void addCorsMappings(CorsRegistry registry) {
133-
registry.addMapping(this.path).allowedOrigins(this.allowedOrigins).allowedMethods("GET");
134-
}
135-
136-
}
137-
138159
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.integration.http.config;
18+
19+
import org.springframework.web.reactive.config.CorsRegistry;
20+
import org.springframework.web.reactive.config.WebFluxConfigurer;
21+
22+
/**
23+
* The {@link WebFluxConfigurer} implementation for CORS mapping on the Integration Graph Controller.
24+
*
25+
* @author Artem Bilan
26+
*
27+
* @since 5.3.9
28+
*
29+
* @see EnableIntegrationGraphController
30+
*/
31+
final class WebFluxIntegrationGraphCorsConfigurer implements WebFluxConfigurer {
32+
33+
private final String path;
34+
35+
private final String[] allowedOrigins;
36+
37+
WebFluxIntegrationGraphCorsConfigurer(String path, String[] allowedOrigins) { // NOSONAR
38+
this.path = path;
39+
this.allowedOrigins = allowedOrigins;
40+
}
41+
42+
@Override
43+
public void addCorsMappings(CorsRegistry registry) {
44+
registry.addMapping(this.path).allowedOrigins(this.allowedOrigins).allowedMethods("GET");
45+
}
46+
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.integration.http.config;
18+
19+
import org.springframework.web.reactive.config.WebFluxConfigurer;
20+
import org.springframework.web.servlet.config.annotation.CorsRegistry;
21+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
22+
23+
/**
24+
* The {@link WebMvcConfigurer} implementation for CORS mapping on the Integration Graph Controller.
25+
*
26+
* @author Artem Bilan
27+
*
28+
* @since 5.3.9
29+
*
30+
* @see EnableIntegrationGraphController
31+
*/
32+
final class WebMvcIntegrationGraphCorsConfigurer implements WebMvcConfigurer {
33+
34+
private final String path;
35+
36+
private final String[] allowedOrigins;
37+
38+
WebMvcIntegrationGraphCorsConfigurer(String path, String[] allowedOrigins) { // NOSONAR
39+
this.path = path;
40+
this.allowedOrigins = allowedOrigins;
41+
}
42+
43+
@Override
44+
public void addCorsMappings(CorsRegistry registry) {
45+
registry.addMapping(this.path).allowedOrigins(this.allowedOrigins).allowedMethods("GET");
46+
}
47+
48+
}

spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxIntegrationConfigurationInitializer.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2020 the original author or authors.
2+
* Copyright 2017-2021 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.
@@ -27,7 +27,6 @@
2727
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2828
import org.springframework.beans.factory.support.RootBeanDefinition;
2929
import org.springframework.integration.config.IntegrationConfigurationInitializer;
30-
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
3130
import org.springframework.integration.http.config.HttpContextUtils;
3231
import org.springframework.integration.webflux.inbound.IntegrationHandlerResultHandler;
3332
import org.springframework.integration.webflux.inbound.WebFluxIntegrationRequestMappingHandlerMapping;
@@ -69,15 +68,22 @@ public void initialize(ConfigurableListableBeanFactory beanFactory) throws Beans
6968
private void registerReactiveRequestMappingHandlerMappingIfNecessary(BeanDefinitionRegistry registry) {
7069
if (HttpContextUtils.WEB_FLUX_PRESENT &&
7170
!registry.containsBeanDefinition(WebFluxContextUtils.HANDLER_MAPPING_BEAN_NAME)) {
71+
7272
BeanDefinitionBuilder requestMappingBuilder =
73-
BeanDefinitionBuilder.genericBeanDefinition(WebFluxIntegrationRequestMappingHandlerMapping.class);
73+
BeanDefinitionBuilder.genericBeanDefinition(WebFluxIntegrationRequestMappingHandlerMapping.class,
74+
() -> {
75+
WebFluxIntegrationRequestMappingHandlerMapping mapping =
76+
new WebFluxIntegrationRequestMappingHandlerMapping();
77+
mapping.setOrder(0);
78+
return mapping;
79+
});
7480
requestMappingBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
75-
requestMappingBuilder.addPropertyValue(IntegrationNamespaceUtils.ORDER, 0);
7681
registry.registerBeanDefinition(WebFluxContextUtils.HANDLER_MAPPING_BEAN_NAME,
7782
requestMappingBuilder.getBeanDefinition());
7883

7984
BeanDefinitionReaderUtils.registerWithGeneratedName(
80-
new RootBeanDefinition(IntegrationHandlerResultHandler.class), registry);
85+
new RootBeanDefinition(IntegrationHandlerResultHandler.class, IntegrationHandlerResultHandler::new),
86+
registry);
8187
}
8288
}
8389

0 commit comments

Comments
 (0)