Skip to content

Commit 10293ad

Browse files
authored
Merge pull request #13845 from codeconsole/7.0.x-url-mappings-autoconfiguration
AutoConfiguration for Url Mappings and Controllers Plugins
2 parents b8c89b4 + 040d422 commit 10293ad

File tree

8 files changed

+149
-71
lines changed

8 files changed

+149
-71
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.grails.plugins.web.controllers;
2+
3+
import grails.config.Settings;
4+
import jakarta.servlet.DispatcherType;
5+
import jakarta.servlet.Filter;
6+
import org.grails.spring.config.http.GrailsFilters;
7+
import org.grails.web.filters.HiddenHttpMethodFilter;
8+
import org.grails.web.servlet.mvc.GrailsWebRequestFilter;
9+
import org.springframework.beans.factory.annotation.Value;
10+
import org.springframework.boot.autoconfigure.AutoConfiguration;
11+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
12+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
13+
import org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration;
14+
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
15+
import org.springframework.boot.web.servlet.FilterRegistrationBean;
16+
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
17+
import org.springframework.context.annotation.Bean;
18+
import org.springframework.context.annotation.Primary;
19+
import org.springframework.web.filter.CharacterEncodingFilter;
20+
21+
import java.util.EnumSet;
22+
23+
@AutoConfiguration(before = { HttpEncodingAutoConfiguration.class, WebMvcAutoConfiguration.class })
24+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
25+
public class ControllersAutoConfiguration {
26+
27+
@Value("${" + Settings.FILTER_ENCODING + ":utf-8}")
28+
private String filtersEncoding;
29+
30+
@Value("${" + Settings.FILTER_FORCE_ENCODING + ":false}")
31+
private boolean filtersForceEncoding;
32+
33+
@Bean
34+
@ConditionalOnMissingBean(CharacterEncodingFilter.class)
35+
public CharacterEncodingFilter characterEncodingFilter() {
36+
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
37+
OrderedCharacterEncodingFilter characterEncodingFilter = new OrderedCharacterEncodingFilter();
38+
characterEncodingFilter.setEncoding(filtersEncoding);
39+
characterEncodingFilter.setForceEncoding(filtersForceEncoding);
40+
characterEncodingFilter.setOrder(GrailsFilters.CHARACTER_ENCODING_FILTER.getOrder());
41+
return characterEncodingFilter;
42+
}
43+
44+
@Bean
45+
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
46+
public FilterRegistrationBean<Filter> hiddenHttpMethodFilter() {
47+
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
48+
registrationBean.setFilter(new HiddenHttpMethodFilter());
49+
registrationBean.addUrlPatterns(Settings.DEFAULT_WEB_SERVLET_PATH);
50+
registrationBean.setOrder(GrailsFilters.HIDDEN_HTTP_METHOD_FILTER.getOrder());
51+
return registrationBean;
52+
}
53+
54+
@Bean
55+
@ConditionalOnMissingBean(GrailsWebRequestFilter.class)
56+
public FilterRegistrationBean<Filter> grailsWebRequestFilter() {
57+
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
58+
registrationBean.setFilter(new GrailsWebRequestFilter());
59+
registrationBean.setDispatcherTypes(EnumSet.of(
60+
DispatcherType.FORWARD,
61+
DispatcherType.INCLUDE,
62+
DispatcherType.REQUEST)
63+
);
64+
registrationBean.addUrlPatterns(Settings.DEFAULT_WEB_SERVLET_PATH);
65+
registrationBean.setOrder(GrailsFilters.GRAILS_WEB_REQUEST_FILTER.getOrder());
66+
return registrationBean;
67+
}
68+
}

grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,19 @@ import groovy.transform.CompileStatic
2323
import groovy.util.logging.Slf4j
2424
import org.grails.core.artefact.ControllerArtefactHandler
2525
import org.grails.plugins.web.servlet.context.BootStrapClassRunner
26-
import org.grails.spring.config.http.GrailsFilters
2726
import org.grails.web.errors.GrailsExceptionResolver
28-
import org.grails.web.filters.HiddenHttpMethodFilter
2927
import org.grails.web.servlet.mvc.GrailsDispatcherServlet
30-
import org.grails.web.servlet.mvc.GrailsWebRequestFilter
3128
import org.grails.web.servlet.mvc.TokenResponseActionResultTransformer
3229
import org.grails.web.servlet.view.CompositeViewResolver
3330
import org.springframework.beans.factory.support.AbstractBeanDefinition
3431
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean
35-
import org.springframework.boot.web.servlet.FilterRegistrationBean
3632
import org.springframework.context.ApplicationContext
3733
import org.springframework.util.ClassUtils
38-
import org.springframework.web.filter.CharacterEncodingFilter
3934
import org.springframework.web.multipart.support.StandardServletMultipartResolver
4035
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
4136
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
4237
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
4338
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
44-
import jakarta.servlet.DispatcherType
4539
import jakarta.servlet.MultipartConfigElement
4640

4741
/**
@@ -71,8 +65,6 @@ class ControllersGrailsPlugin extends Plugin {
7165
long maxFileSize = config.getProperty(Settings.CONTROLLERS_UPLOAD_MAX_FILE_SIZE, Long, 128000L)
7266
long maxRequestSize = config.getProperty(Settings.CONTROLLERS_UPLOAD_MAX_REQUEST_SIZE, Long, 128000L)
7367
int fileSizeThreashold = config.getProperty(Settings.CONTROLLERS_UPLOAD_FILE_SIZE_THRESHOLD, Integer, 0)
74-
String filtersEncoding = config.getProperty(Settings.FILTER_ENCODING, 'utf-8')
75-
boolean filtersForceEncoding = config.getProperty(Settings.FILTER_FORCE_ENCODING, Boolean, false)
7668
boolean isTomcat = ClassUtils.isPresent("org.apache.catalina.startup.Tomcat", application.classLoader)
7769
String grailsServletPath = config.getProperty(Settings.WEB_SERVLET_PATH, isTomcat ? Settings.DEFAULT_TOMCAT_SERVLET_PATH : Settings.DEFAULT_WEB_SERVLET_PATH)
7870
int resourcesCachePeriod = config.getProperty(Settings.RESOURCES_CACHE_PERIOD, Integer, 0)
@@ -85,40 +77,10 @@ class ControllersGrailsPlugin extends Plugin {
8577

8678
tokenResponseActionResultTransformer(TokenResponseActionResultTransformer)
8779

88-
def catchAllMapping = [Settings.DEFAULT_WEB_SERVLET_PATH]
89-
90-
characterEncodingFilter(FilterRegistrationBean) {
91-
filter = bean(CharacterEncodingFilter) {
92-
encoding = filtersEncoding
93-
forceEncoding = filtersForceEncoding
94-
}
95-
urlPatterns = catchAllMapping
96-
order = GrailsFilters.CHARACTER_ENCODING_FILTER.order
97-
}
98-
99-
hiddenHttpMethodFilter(FilterRegistrationBean) {
100-
filter = bean(HiddenHttpMethodFilter)
101-
urlPatterns = catchAllMapping
102-
order = GrailsFilters.HIDDEN_HTTP_METHOD_FILTER.order
103-
}
104-
105-
grailsWebRequestFilter(FilterRegistrationBean) {
106-
filter = bean(GrailsWebRequestFilter)
107-
urlPatterns = catchAllMapping
108-
order = GrailsFilters.GRAILS_WEB_REQUEST_FILTER.order
109-
dispatcherTypes = EnumSet.of(
110-
DispatcherType.FORWARD,
111-
DispatcherType.INCLUDE,
112-
DispatcherType.REQUEST
113-
)
114-
}
115-
11680
exceptionHandler(GrailsExceptionResolver) {
11781
exceptionMappings = ['java.lang.Exception': '/error']
11882
}
11983

120-
multipartResolver(StandardServletMultipartResolver)
121-
12284
"${CompositeViewResolver.BEAN_NAME}"(CompositeViewResolver)
12385

12486
multipartConfigElement(MultipartConfigElement, uploadTmpDir, maxFileSize, maxRequestSize, fileSizeThreashold)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.grails.plugins.web.controllers.ControllersAutoConfiguration
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.grails.plugins.web.mapping;
2+
3+
import grails.config.Settings;
4+
import grails.util.Environment;
5+
import grails.web.CamelCaseUrlConverter;
6+
import grails.web.HyphenatedUrlConverter;
7+
import grails.web.UrlConverter;
8+
import grails.web.mapping.LinkGenerator;
9+
import grails.web.mapping.UrlMappings;
10+
import grails.web.mapping.cors.GrailsCorsConfiguration;
11+
import grails.web.mapping.cors.GrailsCorsFilter;
12+
import org.grails.web.mapping.CachingLinkGenerator;
13+
import org.grails.web.mapping.DefaultLinkGenerator;
14+
import org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter;
15+
import org.grails.web.mapping.servlet.UrlMappingsErrorPageCustomizer;
16+
import org.springframework.beans.factory.ObjectProvider;
17+
import org.springframework.beans.factory.annotation.Value;
18+
import org.springframework.boot.autoconfigure.AutoConfiguration;
19+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
20+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
22+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
23+
import org.springframework.context.annotation.*;
24+
25+
@AutoConfiguration
26+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
27+
@EnableConfigurationProperties({ GrailsCorsConfiguration.class })
28+
public class UrlMappingsAutoConfiguration {
29+
@Value("${" + Settings.WEB_LINK_GENERATOR_USE_CACHE + ":#{null}}")
30+
private Boolean cacheUrls;
31+
32+
@Value("${" + Settings.SERVER_URL + ":#{null}}")
33+
private String serverURL;
34+
35+
@Bean(UrlConverter.BEAN_NAME)
36+
@ConditionalOnMissingBean(name = UrlConverter.BEAN_NAME)
37+
@ConditionalOnProperty(name = Settings.WEB_URL_CONVERTER, havingValue = "camelCase", matchIfMissing = true)
38+
public UrlConverter camelCaseUrlConverter() {
39+
return new CamelCaseUrlConverter();
40+
}
41+
42+
@Bean(UrlConverter.BEAN_NAME)
43+
@ConditionalOnMissingBean(name = UrlConverter.BEAN_NAME)
44+
@ConditionalOnProperty(name = Settings.WEB_URL_CONVERTER, havingValue = "hyphenated")
45+
public UrlConverter hyphenatedUrlConverter() {
46+
return new HyphenatedUrlConverter();
47+
}
48+
49+
@Bean
50+
public LinkGenerator grailsLinkGenerator() {
51+
if (cacheUrls == null) {
52+
cacheUrls = !Environment.isDevelopmentMode() && !Environment.getCurrent().isReloadEnabled();
53+
}
54+
return cacheUrls? new CachingLinkGenerator(serverURL) : new DefaultLinkGenerator(serverURL);
55+
}
56+
57+
@Bean
58+
@ConditionalOnProperty(name = Settings.SETTING_CORS_FILTER, havingValue = "true", matchIfMissing = true)
59+
public GrailsCorsFilter grailsCorsFilter(GrailsCorsConfiguration grailsCorsConfiguration) {
60+
return new GrailsCorsFilter(grailsCorsConfiguration);
61+
}
62+
63+
@Bean
64+
public UrlMappingsErrorPageCustomizer urlMappingsErrorPageCustomizer(ObjectProvider<UrlMappings> urlMappingsProvider) {
65+
UrlMappingsErrorPageCustomizer errorPageCustomizer = new UrlMappingsErrorPageCustomizer();
66+
errorPageCustomizer.setUrlMappings(urlMappingsProvider.getIfAvailable());
67+
return errorPageCustomizer;
68+
}
69+
70+
@Bean
71+
public UrlMappingsInfoHandlerAdapter urlMappingsInfoHandlerAdapter() {
72+
return new UrlMappingsInfoHandlerAdapter();
73+
}
74+
}

grails-plugin-url-mappings/src/main/groovy/org/grails/plugins/web/mapping/UrlMappingsGrailsPlugin.groovy

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,16 @@ import grails.config.Settings
1919
import grails.plugins.Plugin
2020
import grails.util.Environment
2121
import grails.util.GrailsUtil
22-
import grails.web.CamelCaseUrlConverter
23-
import grails.web.HyphenatedUrlConverter
24-
import grails.web.mapping.cors.GrailsCorsFilter
2522
import groovy.transform.CompileDynamic
2623
import groovy.transform.CompileStatic
2724
import org.grails.core.artefact.UrlMappingsArtefactHandler
28-
import grails.web.mapping.cors.GrailsCorsConfiguration
2925
import org.grails.spring.beans.factory.HotSwappableTargetSourceFactoryBean
3026
import org.grails.web.mapping.CachingLinkGenerator
31-
import org.grails.web.mapping.DefaultLinkGenerator
3227
import grails.web.mapping.LinkGenerator
3328
import grails.web.mapping.UrlMappings
3429
import grails.web.mapping.UrlMappingsHolder
3530
import org.grails.web.mapping.UrlMappingsHolderFactoryBean
3631
import org.grails.web.mapping.mvc.UrlMappingsHandlerMapping
37-
import org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter
38-
import org.grails.web.mapping.servlet.UrlMappingsErrorPageCustomizer
3932
import org.springframework.aop.framework.ProxyFactoryBean
4033
import org.springframework.aop.target.HotSwappableTargetSource
4134
import org.springframework.context.ApplicationContext
@@ -61,31 +54,15 @@ class UrlMappingsGrailsPlugin extends Plugin {
6154
}
6255

6356
def config = application.config
64-
String serverURL = config.getProperty(Settings.SERVER_URL) ?: null
65-
String urlConverterType = config.getProperty(Settings.WEB_URL_CONVERTER)
6657
boolean isReloadEnabled = Environment.isDevelopmentMode() || Environment.current.isReloadEnabled()
67-
boolean cacheUrls = config.getProperty(Settings.WEB_LINK_GENERATOR_USE_CACHE, Boolean, !isReloadEnabled)
68-
69-
"${grails.web.UrlConverter.BEAN_NAME}"('hyphenated' == urlConverterType ? HyphenatedUrlConverter : CamelCaseUrlConverter)
70-
7158
boolean corsFilterEnabled = config.getProperty(Settings.SETTING_CORS_FILTER, Boolean, true)
7259

73-
grailsCorsConfiguration(GrailsCorsConfiguration)
74-
7560
urlMappingsHandlerMapping(UrlMappingsHandlerMapping, ref("grailsUrlMappingsHolder")) {
7661
if (!corsFilterEnabled) {
7762
grailsCorsConfiguration = ref("grailsCorsConfiguration")
7863
}
7964
}
8065

81-
if (corsFilterEnabled) {
82-
grailsCorsFilter(GrailsCorsFilter, ref("grailsCorsConfiguration"))
83-
}
84-
85-
urlMappingsInfoHandlerAdapter(UrlMappingsInfoHandlerAdapter)
86-
urlMappingsErrorPageCustomizer(UrlMappingsErrorPageCustomizer)
87-
grailsLinkGenerator(cacheUrls ? CachingLinkGenerator : DefaultLinkGenerator, serverURL)
88-
8966
if (isReloadEnabled) {
9067
urlMappingsTargetSource(HotSwappableTargetSourceFactoryBean) {
9168
it.lazyInit = true
@@ -98,7 +75,7 @@ class UrlMappingsGrailsPlugin extends Plugin {
9875
targetSource = urlMappingsTargetSource
9976
proxyInterfaces = [UrlMappings]
10077
}
101-
} else {
78+
} else {
10279
grailsUrlMappingsHolder(UrlMappingsHolderFactoryBean) { bean ->
10380
bean.lazyInit = true
10481
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.grails.plugins.web.mapping.UrlMappingsAutoConfiguration

grails-web-boot/src/test/groovy/grails/boot/EmbeddedContainerWithGrailsSpec.groovy

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ package grails.boot
33
import grails.artefact.Artefact
44
import grails.boot.config.GrailsAutoConfiguration
55
import grails.web.Controller
6+
import org.springframework.boot.autoconfigure.SpringBootApplication
67
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
78
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
89
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory
910
import org.springframework.context.annotation.Bean
10-
import org.springframework.context.annotation.Configuration
11-
import org.springframework.web.servlet.config.annotation.EnableWebMvc
1211
import spock.lang.Specification
1312

1413
/**
@@ -32,8 +31,7 @@ class EmbeddedContainerWithGrailsSpec extends Specification {
3231
new URL("http://localhost:${context.webServer.port}/foos").text == 'all foos'
3332
}
3433

35-
@Configuration
36-
@EnableWebMvc
34+
@SpringBootApplication
3735
static class Application extends GrailsAutoConfiguration {
3836
@Bean
3937
ConfigurableServletWebServerFactory webServerFactory() {

grails-web-boot/src/test/groovy/grails/boot/GrailsSpringApplicationSpec.groovy

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ package grails.boot
22

33
import grails.boot.config.GrailsAutoConfiguration
44
import org.springframework.boot.SpringApplication
5+
import org.springframework.boot.autoconfigure.SpringBootApplication
56
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
67
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
78
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory
8-
import org.springframework.context.ConfigurableApplicationContext
99
import org.springframework.context.annotation.Bean
10-
import org.springframework.context.annotation.Configuration
11-
import org.springframework.web.servlet.config.annotation.EnableWebMvc
1210
import spock.lang.Specification
1311

1412
/**
@@ -34,8 +32,7 @@ class GrailsSpringApplicationSpec extends Specification{
3432
}
3533

3634

37-
@Configuration
38-
@EnableWebMvc
35+
@SpringBootApplication
3936
static class Application extends GrailsAutoConfiguration {
4037
@Bean
4138
ConfigurableServletWebServerFactory webServerFactory() {

0 commit comments

Comments
 (0)