From 8d882fa09b572853365d37894613c4655290de1d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 23 Mar 2022 11:44:59 +0000 Subject: [PATCH] Fix possible duplicate templateEngine bean in Thymeleaf auto-config Closes gh-30384 --- .../TemplateEngineConfigurations.java | 79 +++++++++++++++++++ .../thymeleaf/ThymeleafAutoConfiguration.java | 46 +---------- 2 files changed, 83 insertions(+), 42 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/TemplateEngineConfigurations.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/TemplateEngineConfigurations.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/TemplateEngineConfigurations.java new file mode 100644 index 000000000000..bdf3c0e06cfb --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/TemplateEngineConfigurations.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.thymeleaf; + +import org.thymeleaf.ITemplateEngine; +import org.thymeleaf.dialect.IDialect; +import org.thymeleaf.spring5.ISpringTemplateEngine; +import org.thymeleaf.spring5.ISpringWebFluxTemplateEngine; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.SpringWebFluxTemplateEngine; +import org.thymeleaf.templateresolver.ITemplateResolver; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Configuration classes for Thymeleaf's {@link ITemplateEngine}. Imported by + * {@link ThymeleafAutoConfiguration}. + * + * @author Andy Wilkinson + */ +class TemplateEngineConfigurations { + + @Configuration(proxyBeanMethods = false) + static class DefaultTemplateEngineConfiguration { + + @Bean + @ConditionalOnMissingBean(ISpringTemplateEngine.class) + SpringTemplateEngine templateEngine(ThymeleafProperties properties, + ObjectProvider templateResolvers, ObjectProvider dialects) { + SpringTemplateEngine engine = new SpringTemplateEngine(); + engine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler()); + engine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes()); + templateResolvers.orderedStream().forEach(engine::addTemplateResolver); + dialects.orderedStream().forEach(engine::addDialect); + return engine; + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnWebApplication(type = Type.REACTIVE) + @ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true) + static class ReactiveTemplateEngineConfiguration { + + @Bean + @ConditionalOnMissingBean(ISpringWebFluxTemplateEngine.class) + SpringWebFluxTemplateEngine templateEngine(ThymeleafProperties properties, + ObjectProvider templateResolvers, ObjectProvider dialects) { + SpringWebFluxTemplateEngine engine = new SpringWebFluxTemplateEngine(); + engine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler()); + engine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes()); + templateResolvers.orderedStream().forEach(engine::addTemplateResolver); + dialects.orderedStream().forEach(engine::addDialect); + return engine; + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java index 0c0a26c4ae5d..4e54aebca332 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -24,20 +24,15 @@ import nz.net.ultraq.thymeleaf.LayoutDialect; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.thymeleaf.dialect.IDialect; import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect; import org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect; -import org.thymeleaf.spring5.ISpringTemplateEngine; import org.thymeleaf.spring5.ISpringWebFluxTemplateEngine; import org.thymeleaf.spring5.SpringTemplateEngine; -import org.thymeleaf.spring5.SpringWebFluxTemplateEngine; import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; import org.thymeleaf.spring5.view.ThymeleafViewResolver; import org.thymeleaf.spring5.view.reactive.ThymeleafReactiveViewResolver; import org.thymeleaf.templatemode.TemplateMode; -import org.thymeleaf.templateresolver.ITemplateResolver; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -57,6 +52,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.core.Ordered; import org.springframework.security.web.server.csrf.CsrfToken; import org.springframework.util.MimeType; @@ -80,6 +76,8 @@ @EnableConfigurationProperties(ThymeleafProperties.class) @ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class }) @AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class }) +@Import({ TemplateEngineConfigurations.ReactiveTemplateEngineConfiguration.class, + TemplateEngineConfigurations.DefaultTemplateEngineConfiguration.class }) public class ThymeleafAutoConfiguration { @Configuration(proxyBeanMethods = false) @@ -130,23 +128,6 @@ SpringResourceTemplateResolver defaultTemplateResolver() { } - @Configuration(proxyBeanMethods = false) - protected static class ThymeleafDefaultConfiguration { - - @Bean - @ConditionalOnMissingBean(ISpringTemplateEngine.class) - SpringTemplateEngine templateEngine(ThymeleafProperties properties, - ObjectProvider templateResolvers, ObjectProvider dialects) { - SpringTemplateEngine engine = new SpringTemplateEngine(); - engine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler()); - engine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes()); - templateResolvers.orderedStream().forEach(engine::addTemplateResolver); - dialects.orderedStream().forEach(engine::addDialect); - return engine; - } - - } - @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true) @@ -199,25 +180,6 @@ private String appendCharset(MimeType type, String charset) { } - @Configuration(proxyBeanMethods = false) - @ConditionalOnWebApplication(type = Type.REACTIVE) - @ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true) - static class ThymeleafReactiveConfiguration { - - @Bean - @ConditionalOnMissingBean(ISpringWebFluxTemplateEngine.class) - SpringWebFluxTemplateEngine templateEngine(ThymeleafProperties properties, - ObjectProvider templateResolvers, ObjectProvider dialects) { - SpringWebFluxTemplateEngine engine = new SpringWebFluxTemplateEngine(); - engine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler()); - engine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes()); - templateResolvers.orderedStream().forEach(engine::addTemplateResolver); - dialects.orderedStream().forEach(engine::addDialect); - return engine; - } - - } - @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.REACTIVE) @ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)