mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Stop using @ConditionalOnClass on @Bean methods
See gh-47429 Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
This commit is contained in:
committed by
Phillip Webb
parent
4e4d3dafe3
commit
ba88ec7ed1
+9
-2
@@ -70,15 +70,19 @@ import org.gradle.api.tasks.VerificationException;
|
||||
*/
|
||||
public abstract class ArchitectureCheck extends DefaultTask {
|
||||
|
||||
private static final String CONDITIONAL_ON_CLASS_ANNOTATION = "org.springframework.boot.autoconfigure.condition.ConditionalOnClass";
|
||||
|
||||
private FileCollection classes;
|
||||
|
||||
public ArchitectureCheck() {
|
||||
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
|
||||
getConditionalOnClassAnnotation().convention(CONDITIONAL_ON_CLASS_ANNOTATION);
|
||||
getRules().addAll(getProhibitObjectsRequireNonNull().convention(true)
|
||||
.map(whenTrue(ArchitectureRules::noClassesShouldCallObjectsRequireNonNull)));
|
||||
getRules().addAll(ArchitectureRules.standard());
|
||||
getRules().addAll(whenMainSources(
|
||||
() -> Collections.singletonList(ArchitectureRules.allBeanMethodsShouldReturnNonPrivateType())));
|
||||
getRules().addAll(whenMainSources(() -> List
|
||||
.of(ArchitectureRules.allBeanMethodsShouldReturnNonPrivateType(), ArchitectureRules
|
||||
.allBeanMethodsShouldNotHaveConditionalOnClassAnnotation(getConditionalOnClassAnnotation().get()))));
|
||||
getRuleDescriptions().set(getRules().map(this::asDescriptions));
|
||||
}
|
||||
|
||||
@@ -186,4 +190,7 @@ public abstract class ArchitectureCheck extends DefaultTask {
|
||||
@Input // Use descriptions as input since rules aren't serializable
|
||||
abstract ListProperty<String> getRuleDescriptions();
|
||||
|
||||
@Internal
|
||||
abstract Property<String> getConditionalOnClassAnnotation();
|
||||
|
||||
}
|
||||
|
||||
+9
@@ -108,6 +108,15 @@ final class ArchitectureRules {
|
||||
.allowEmptyShould(true);
|
||||
}
|
||||
|
||||
static ArchRule allBeanMethodsShouldNotHaveConditionalOnClassAnnotation(String annotationName) {
|
||||
return methodsThatAreAnnotatedWith("org.springframework.context.annotation.Bean").should()
|
||||
.notBeAnnotatedWith(annotationName)
|
||||
.because("@ConditionalOnClass on @Bean methods is ineffective - it doesn't prevent "
|
||||
+ "the method signature from being loaded. Such condition need to be placed"
|
||||
+ " on a @Configuration class, allowing the condition to back off before the type is loaded.")
|
||||
.allowEmptyShould(true);
|
||||
}
|
||||
|
||||
private static ArchRule allPackagesShouldBeFreeOfTangles() {
|
||||
return SlicesRuleDefinition.slices().matching("(**)").should().beFreeOfCycles();
|
||||
}
|
||||
|
||||
+68
-13
@@ -26,6 +26,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.testkit.runner.BuildResult;
|
||||
@@ -39,6 +40,7 @@ import org.junit.jupiter.api.io.TempDir;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
|
||||
import org.springframework.boot.build.architecture.annotations.TestConditionalOnClass;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -180,7 +182,7 @@ class ArchitectureCheckTests {
|
||||
void whenClassCallsObjectsRequireNonNullWithMessageAndProhibitObjectsRequireNonNullIsFalseShouldSucceedAndWriteEmptyReport(
|
||||
Task task) throws IOException {
|
||||
prepareTask(task, "objects/requireNonNullWithString");
|
||||
build(this.gradleBuild.withProhibitObjectsRequireNonNull(task, false), task);
|
||||
build(this.gradleBuild.withProhibitObjectsRequireNonNull(false), task);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}")
|
||||
@@ -195,7 +197,7 @@ class ArchitectureCheckTests {
|
||||
void whenClassCallsObjectsRequireNonNullWithSupplierAndProhibitObjectsRequireNonNullIsFalseShouldSucceedAndWriteEmptyReport(
|
||||
Task task) throws IOException {
|
||||
prepareTask(task, "objects/requireNonNullWithSupplier");
|
||||
build(this.gradleBuild.withProhibitObjectsRequireNonNull(task, false), task);
|
||||
build(this.gradleBuild.withProhibitObjectsRequireNonNull(false), task);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}")
|
||||
@@ -295,6 +297,25 @@ class ArchitectureCheckTests {
|
||||
"should not have a value that is the same as the type of the method's first parameter");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenConditionalOnClassUsedOnBeanMethodsWithMainSourcesShouldFailAndWriteReport() throws IOException {
|
||||
prepareTask(Task.CHECK_ARCHITECTURE_MAIN, "conditionalonclass", "annotations");
|
||||
GradleBuild gradleBuild = this.gradleBuild.withDependencies(SPRING_CONTEXT)
|
||||
.withConditionalOnClassAnnotation(TestConditionalOnClass.class.getName());
|
||||
buildAndFail(gradleBuild, Task.CHECK_ARCHITECTURE_MAIN,
|
||||
"because @ConditionalOnClass on @Bean methods is ineffective - it doesn't prevent"
|
||||
+ " the method signature from being loaded. Such condition need to be placed"
|
||||
+ " on a @Configuration class, allowing the condition to back off before the type is loaded");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenConditionalOnClassUsedOnBeanMethodsWithTestSourcesShouldSucceedAndWriteEmptyReport() throws IOException {
|
||||
prepareTask(Task.CHECK_ARCHITECTURE_TEST, "conditionalonclass", "annotations");
|
||||
GradleBuild gradleBuild = this.gradleBuild.withDependencies(SPRING_CONTEXT)
|
||||
.withConditionalOnClassAnnotation(TestConditionalOnClass.class.getName());
|
||||
build(gradleBuild, Task.CHECK_ARCHITECTURE_TEST);
|
||||
}
|
||||
|
||||
private void prepareTask(Task task, String... sourceDirectories) throws IOException {
|
||||
for (String sourceDirectory : sourceDirectories) {
|
||||
FileSystemUtils.copyRecursively(
|
||||
@@ -310,7 +331,7 @@ class ArchitectureCheckTests {
|
||||
private void build(GradleBuild gradleBuild, Task task) throws IOException {
|
||||
try {
|
||||
BuildResult buildResult = gradleBuild.build(task.toString());
|
||||
assertThat(buildResult.taskPaths(TaskOutcome.SUCCESS)).contains(":" + task);
|
||||
assertThat(buildResult.taskPaths(TaskOutcome.SUCCESS)).as(buildResult.getOutput()).contains(":" + task);
|
||||
assertThat(task.getFailureReport(gradleBuild.getProjectDir())).isEmpty();
|
||||
}
|
||||
catch (UnexpectedBuildFailure ex) {
|
||||
@@ -326,7 +347,7 @@ class ArchitectureCheckTests {
|
||||
private void buildAndFail(GradleBuild gradleBuild, Task task, String... messages) throws IOException {
|
||||
try {
|
||||
BuildResult buildResult = gradleBuild.buildAndFail(task.toString());
|
||||
assertThat(buildResult.taskPaths(TaskOutcome.FAILED)).contains(":" + task);
|
||||
assertThat(buildResult.taskPaths(TaskOutcome.FAILED)).as(buildResult.getOutput()).contains(":" + task);
|
||||
assertThat(task.getFailureReport(gradleBuild.getProjectDir())).contains(messages);
|
||||
}
|
||||
catch (UnexpectedBuildSuccess ex) {
|
||||
@@ -371,7 +392,7 @@ class ArchitectureCheckTests {
|
||||
|
||||
private final Set<String> dependencies = new LinkedHashSet<>();
|
||||
|
||||
private final Map<Task, Boolean> prohibitObjectsRequireNonNull = new LinkedHashMap<>();
|
||||
private final Map<Task, TaskConfiguration> taskConfigurations = new LinkedHashMap<>();
|
||||
|
||||
private GradleBuild(Path projectDir) {
|
||||
this.projectDir = projectDir;
|
||||
@@ -381,12 +402,28 @@ class ArchitectureCheckTests {
|
||||
return this.projectDir;
|
||||
}
|
||||
|
||||
GradleBuild withProhibitObjectsRequireNonNull(Task task, boolean prohibitObjectsRequireNonNull) {
|
||||
this.prohibitObjectsRequireNonNull.put(task, prohibitObjectsRequireNonNull);
|
||||
GradleBuild withProhibitObjectsRequireNonNull(Boolean prohibitObjectsRequireNonNull) {
|
||||
for (Task task : Task.values()) {
|
||||
configureTask(task, (configuration) -> configuration
|
||||
.withProhibitObjectsRequireNonNull(prohibitObjectsRequireNonNull));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
GradleBuild withConditionalOnClassAnnotation(String annotationName) {
|
||||
for (Task task : Task.values()) {
|
||||
configureTask(task, (configuration) -> configuration.withConditionalOnClassAnnotation(annotationName));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void configureTask(Task task, UnaryOperator<TaskConfiguration> configurer) {
|
||||
this.taskConfigurations.computeIfAbsent(task, (key) -> new TaskConfiguration(null, null));
|
||||
this.taskConfigurations.compute(task, (key, value) -> configurer.apply(value));
|
||||
}
|
||||
|
||||
GradleBuild withDependencies(String... dependencies) {
|
||||
this.dependencies.clear();
|
||||
this.dependencies.addAll(Arrays.asList(dependencies));
|
||||
return this;
|
||||
}
|
||||
@@ -415,15 +452,22 @@ class ArchitectureCheckTests {
|
||||
if (!this.dependencies.isEmpty()) {
|
||||
buildFile.append("dependencies {\n");
|
||||
for (String dependency : this.dependencies) {
|
||||
buildFile.append(" implementation '%s'\n".formatted(dependency));
|
||||
buildFile.append("\n implementation ").append(StringUtils.quote(dependency));
|
||||
}
|
||||
buildFile.append("}\n");
|
||||
}
|
||||
this.prohibitObjectsRequireNonNull.forEach((task, prohibitObjectsRequireNonNull) -> buildFile.append(task)
|
||||
.append(" {\n")
|
||||
.append(" prohibitObjectsRequireNonNull = ")
|
||||
.append(prohibitObjectsRequireNonNull)
|
||||
.append("\n}\n\n"));
|
||||
this.taskConfigurations.forEach((task, configuration) -> {
|
||||
buildFile.append(task).append(" {");
|
||||
if (configuration.conditionalOnClassAnnotation() != null) {
|
||||
buildFile.append("\n conditionalOnClassAnnotation = ")
|
||||
.append(StringUtils.quote(configuration.conditionalOnClassAnnotation()));
|
||||
}
|
||||
if (configuration.prohibitObjectsRequireNonNull() != null) {
|
||||
buildFile.append("\n prohibitObjectsRequireNonNull = ")
|
||||
.append(configuration.prohibitObjectsRequireNonNull());
|
||||
}
|
||||
buildFile.append("\n}\n");
|
||||
});
|
||||
Files.writeString(this.projectDir.resolve("build.gradle"), buildFile, StandardCharsets.UTF_8);
|
||||
return GradleRunner.create()
|
||||
.withProjectDir(this.projectDir.toFile())
|
||||
@@ -431,6 +475,17 @@ class ArchitectureCheckTests {
|
||||
.withPluginClasspath();
|
||||
}
|
||||
|
||||
private record TaskConfiguration(Boolean prohibitObjectsRequireNonNull, String conditionalOnClassAnnotation) {
|
||||
|
||||
private TaskConfiguration withConditionalOnClassAnnotation(String annotationName) {
|
||||
return new TaskConfiguration(this.prohibitObjectsRequireNonNull, annotationName);
|
||||
}
|
||||
|
||||
private TaskConfiguration withProhibitObjectsRequireNonNull(Boolean prohibitObjectsRequireNonNull) {
|
||||
return new TaskConfiguration(prohibitObjectsRequireNonNull, this.conditionalOnClassAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2012-present 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.build.architecture.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* {@code @ConditionalOnClass} analogue for architecture checks.
|
||||
*
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TestConditionalOnClass {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
|
||||
String[] name() default {};
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012-present 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.build.architecture.conditionalonclass;
|
||||
|
||||
import org.springframework.boot.build.architecture.annotations.TestConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
class OnBeanMethod {
|
||||
|
||||
@Bean
|
||||
@TestConditionalOnClass(String.class)
|
||||
String helloWorld() {
|
||||
return "Hello World";
|
||||
}
|
||||
|
||||
}
|
||||
+19
-8
@@ -31,6 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link AuditEvent}s.
|
||||
@@ -50,18 +51,28 @@ public class AuditAutoConfiguration {
|
||||
return new AuditListener(auditEventRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.springframework.security.authentication.event.AbstractAuthenticationEvent")
|
||||
@ConditionalOnMissingBean(AbstractAuthenticationAuditListener.class)
|
||||
public AuthenticationAuditListener authenticationAuditListener() {
|
||||
return new AuthenticationAuditListener();
|
||||
static class AuthenticationAuditConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(AbstractAuthenticationAuditListener.class)
|
||||
AuthenticationAuditListener authenticationAuditListener() {
|
||||
return new AuthenticationAuditListener();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.springframework.security.access.event.AbstractAuthorizationEvent")
|
||||
@ConditionalOnMissingBean(AbstractAuthorizationAuditListener.class)
|
||||
public AuthorizationAuditListener authorizationAuditListener() {
|
||||
return new AuthorizationAuditListener();
|
||||
static class AuthorizationAuditConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(AbstractAuthorizationAuditListener.class)
|
||||
AuthorizationAuditListener authorizationAuditListener() {
|
||||
return new AuthorizationAuditListener();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -36,12 +36,12 @@ import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@AutoConfiguration(after = JacksonAutoConfiguration.class)
|
||||
@ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class })
|
||||
public class JacksonEndpointAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "management.endpoints.jackson.isolated-object-mapper", matchIfMissing = true)
|
||||
@ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class })
|
||||
public EndpointObjectMapper endpointObjectMapper() {
|
||||
EndpointObjectMapper endpointObjectMapper() {
|
||||
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
|
||||
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
|
||||
SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)
|
||||
|
||||
-1
@@ -53,7 +53,6 @@ public class SecurityRequestMatchersManagementContextConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(DispatcherServlet.class)
|
||||
public RequestMatcherProvider requestMatcherProvider(DispatcherServletPath servletPath) {
|
||||
return new AntPathRequestMatcherProvider(servletPath::getRelativePath);
|
||||
}
|
||||
|
||||
+24
-9
@@ -81,22 +81,37 @@ class ServletManagementChildContextConfiguration {
|
||||
return new ServletManagementWebServerFactoryCustomizer(beanFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "io.undertow.Undertow")
|
||||
UndertowAccessLogCustomizer undertowManagementAccessLogCustomizer() {
|
||||
return new UndertowAccessLogCustomizer();
|
||||
static class UndertowConfiguration {
|
||||
|
||||
@Bean
|
||||
UndertowAccessLogCustomizer undertowManagementAccessLogCustomizer() {
|
||||
return new UndertowAccessLogCustomizer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.apache.catalina.valves.AccessLogValve")
|
||||
TomcatAccessLogCustomizer tomcatManagementAccessLogCustomizer() {
|
||||
return new TomcatAccessLogCustomizer();
|
||||
static class TomcatConfiguration {
|
||||
|
||||
@Bean
|
||||
TomcatAccessLogCustomizer tomcatManagementAccessLogCustomizer() {
|
||||
return new TomcatAccessLogCustomizer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.eclipse.jetty.server.Server")
|
||||
JettyAccessLogCustomizer jettyManagementAccessLogCustomizer() {
|
||||
return new JettyAccessLogCustomizer();
|
||||
static class JettyConfiguration {
|
||||
|
||||
@Bean
|
||||
JettyAccessLogCustomizer jettyManagementAccessLogCustomizer() {
|
||||
return new JettyAccessLogCustomizer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
||||
+34
-18
@@ -144,24 +144,6 @@ public class FlywayAutoConfiguration {
|
||||
return new PropertiesFlywayConnectionDetails(this.properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.flywaydb.database.sqlserver.SQLServerConfigurationExtension")
|
||||
SqlServerFlywayConfigurationCustomizer sqlServerFlywayConfigurationCustomizer() {
|
||||
return new SqlServerFlywayConfigurationCustomizer(this.properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.flywaydb.database.oracle.OracleConfigurationExtension")
|
||||
OracleFlywayConfigurationCustomizer oracleFlywayConfigurationCustomizer() {
|
||||
return new OracleFlywayConfigurationCustomizer(this.properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.flywaydb.database.postgresql.PostgreSQLConfigurationExtension")
|
||||
PostgresqlFlywayConfigurationCustomizer postgresqlFlywayConfigurationCustomizer() {
|
||||
return new PostgresqlFlywayConfigurationCustomizer(this.properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
Flyway flyway(FlywayConnectionDetails connectionDetails, ResourceLoader resourceLoader,
|
||||
ObjectProvider<DataSource> dataSource, @FlywayDataSource ObjectProvider<DataSource> flywayDataSource,
|
||||
@@ -355,6 +337,40 @@ public class FlywayAutoConfiguration {
|
||||
return new FlywayMigrationInitializer(flyway, migrationStrategy.getIfAvailable());
|
||||
}
|
||||
|
||||
@ConditionalOnClass(name = "org.flywaydb.database.sqlserver.SQLServerConfigurationExtension")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SqlServerConfiguration {
|
||||
|
||||
@Bean
|
||||
SqlServerFlywayConfigurationCustomizer sqlServerFlywayConfigurationCustomizer(FlywayProperties properties) {
|
||||
return new SqlServerFlywayConfigurationCustomizer(properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.flywaydb.database.oracle.OracleConfigurationExtension")
|
||||
static class OracleConfiguration {
|
||||
|
||||
@Bean
|
||||
OracleFlywayConfigurationCustomizer oracleFlywayConfigurationCustomizer(FlywayProperties properties) {
|
||||
return new OracleFlywayConfigurationCustomizer(properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnClass(name = "org.flywaydb.database.postgresql.PostgreSQLConfigurationExtension")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class PostgresqlConfiguration {
|
||||
|
||||
@Bean
|
||||
PostgresqlFlywayConfigurationCustomizer postgresqlFlywayConfigurationCustomizer(
|
||||
FlywayProperties properties) {
|
||||
return new PostgresqlFlywayConfigurationCustomizer(properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class LocationResolver {
|
||||
|
||||
+9
-4
@@ -57,13 +57,18 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
||||
@EnableConfigurationProperties(HateoasProperties.class)
|
||||
public class HypermediaAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper")
|
||||
@ConditionalOnProperty(prefix = "spring.hateoas", name = "use-hal-as-default-json-media-type",
|
||||
matchIfMissing = true)
|
||||
HalConfiguration applicationJsonHalConfiguration() {
|
||||
return new HalConfiguration().withMediaType(MediaType.APPLICATION_JSON);
|
||||
static class JacksonJsonHalConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
HalConfiguration applicationJsonHalConfiguration() {
|
||||
return new HalConfiguration().withMediaType(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
||||
+15
-10
@@ -87,16 +87,6 @@ public class PulsarReactiveAutoConfiguration {
|
||||
return AdaptedReactivePulsarClientFactory.create(pulsarClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ProducerCacheProvider.class)
|
||||
@ConditionalOnClass(CaffeineShadedProducerCacheProvider.class)
|
||||
@ConditionalOnProperty(name = "spring.pulsar.producer.cache.enabled", havingValue = "true", matchIfMissing = true)
|
||||
CaffeineShadedProducerCacheProvider reactivePulsarProducerCacheProvider() {
|
||||
PulsarProperties.Producer.Cache properties = this.properties.getProducer().getCache();
|
||||
return new CaffeineShadedProducerCacheProvider(properties.getExpireAfterAccess(), Duration.ofMinutes(10),
|
||||
properties.getMaximumSize(), properties.getInitialCapacity());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(name = "spring.pulsar.producer.cache.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@@ -205,6 +195,21 @@ public class PulsarReactiveAutoConfiguration {
|
||||
return new ReactivePulsarTemplate<>(reactivePulsarSenderFactory, schemaResolver, topicResolver);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(CaffeineShadedProducerCacheProvider.class)
|
||||
@ConditionalOnProperty(name = "spring.pulsar.producer.cache.enabled", havingValue = "true", matchIfMissing = true)
|
||||
static class PulsarCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ProducerCacheProvider.class)
|
||||
CaffeineShadedProducerCacheProvider reactivePulsarProducerCacheProvider(PulsarProperties pulsarProperties) {
|
||||
PulsarProperties.Producer.Cache properties = pulsarProperties.getProducer().getCache();
|
||||
return new CaffeineShadedProducerCacheProvider(properties.getExpireAfterAccess(), Duration.ofMinutes(10),
|
||||
properties.getMaximumSize(), properties.getInitialCapacity());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableReactivePulsar
|
||||
@ConditionalOnMissingBean(
|
||||
|
||||
+13
-7
@@ -36,6 +36,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -69,13 +70,6 @@ public class ReactiveWebServerFactoryAutoConfiguration {
|
||||
return new ReactiveWebServerFactoryCustomizer(serverProperties, sslBundles.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
|
||||
public TomcatReactiveWebServerFactoryCustomizer tomcatReactiveWebServerFactoryCustomizer(
|
||||
ServerProperties serverProperties) {
|
||||
return new TomcatReactiveWebServerFactoryCustomizer(serverProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework")
|
||||
@@ -83,6 +77,18 @@ public class ReactiveWebServerFactoryAutoConfiguration {
|
||||
return new ForwardedHeaderTransformer();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
|
||||
static class TomcatConfiguration {
|
||||
|
||||
@Bean
|
||||
TomcatReactiveWebServerFactoryCustomizer tomcatReactiveWebServerFactoryCustomizer(
|
||||
ServerProperties serverProperties) {
|
||||
return new TomcatReactiveWebServerFactoryCustomizer(serverProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
|
||||
* {@link ImportBeanDefinitionRegistrar} for early registration.
|
||||
|
||||
+20
-10
@@ -81,11 +81,16 @@ public class ServletWebServerFactoryAutoConfiguration {
|
||||
cookieSameSiteSuppliers.orderedStream().toList(), sslBundles.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
|
||||
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
|
||||
ServerProperties serverProperties) {
|
||||
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
|
||||
static class TomcatConfiguration {
|
||||
|
||||
@Bean
|
||||
TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
|
||||
ServerProperties serverProperties) {
|
||||
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -93,12 +98,6 @@ public class ServletWebServerFactoryAutoConfiguration {
|
||||
@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
|
||||
static class ForwardedHeaderFilterConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
|
||||
ForwardedHeaderFilterCustomizer tomcatForwardedHeaderFilterCustomizer(ServerProperties serverProperties) {
|
||||
return (filter) -> filter.setRelativeRedirects(serverProperties.getTomcat().isUseRelativeRedirects());
|
||||
}
|
||||
|
||||
@Bean
|
||||
FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter(
|
||||
ObjectProvider<ForwardedHeaderFilterCustomizer> customizerProvider) {
|
||||
@@ -110,6 +109,17 @@ public class ServletWebServerFactoryAutoConfiguration {
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
|
||||
static class TomcatConfiguration {
|
||||
|
||||
@Bean
|
||||
ForwardedHeaderFilterCustomizer tomcatForwardedHeaderFilterCustomizer(ServerProperties serverProperties) {
|
||||
return (filter) -> filter.setRelativeRedirects(serverProperties.getTomcat().isUseRelativeRedirects());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface ForwardedHeaderFilterCustomizer {
|
||||
|
||||
Reference in New Issue
Block a user