From 7cb53b3c4514d8bd43fda3462151397d2495a0cd Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 17 Jun 2022 12:02:04 -0700 Subject: [PATCH] Remove session store type in favor of defined order Closes gh-27756 --- .../session/AbstractSessionCondition.java | 69 ------ .../HazelcastSessionConfiguration.java | 2 - .../session/JdbcSessionConfiguration.java | 1 - .../MongoReactiveSessionConfiguration.java | 2 - .../session/MongoSessionConfiguration.java | 2 - .../NoOpReactiveSessionConfiguration.java | 35 ---- .../session/NoOpSessionConfiguration.java | 34 --- .../NonUniqueSessionRepositoryException.java | 47 ----- ...niqueSessionRepositoryFailureAnalyzer.java | 45 ---- .../session/ReactiveSessionCondition.java | 32 --- .../RedisReactiveSessionConfiguration.java | 2 - .../session/RedisSessionConfiguration.java | 2 - .../session/ServletSessionCondition.java | 35 ---- .../session/SessionAutoConfiguration.java | 197 +----------------- .../session/SessionProperties.java | 13 -- ...SessionRepositoryUnavailableException.java | 40 ---- .../session/SessionStoreMappings.java | 94 --------- .../boot/autoconfigure/session/StoreType.java | 54 ----- .../main/resources/META-INF/spring.factories | 3 +- ...SessionRepositoryFailureAnalyzerTests.java | 65 ------ ...iveSessionAutoConfigurationMongoTests.java | 60 ++---- ...iveSessionAutoConfigurationRedisTests.java | 68 +++--- ...essionAutoConfigurationHazelcastTests.java | 55 +++-- ...sionAutoConfigurationIntegrationTests.java | 91 -------- .../SessionAutoConfigurationJdbcTests.java | 136 +++++------- .../SessionAutoConfigurationMongoTests.java | 16 +- .../SessionAutoConfigurationRedisTests.java | 23 +- .../SessionAutoConfigurationTests.java | 65 +++--- .../src/docs/asciidoc/web/spring-session.adoc | 28 +-- 29 files changed, 208 insertions(+), 1108 deletions(-) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/AbstractSessionCondition.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NoOpReactiveSessionConfiguration.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NoOpSessionConfiguration.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryException.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryFailureAnalyzer.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/ReactiveSessionCondition.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/ServletSessionCondition.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionRepositoryUnavailableException.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/StoreType.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryFailureAnalyzerTests.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationIntegrationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/AbstractSessionCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/AbstractSessionCondition.java deleted file mode 100644 index 52cc494519..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/AbstractSessionCondition.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2012-2019 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.session; - -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.autoconfigure.condition.ConditionMessage; -import org.springframework.boot.autoconfigure.condition.ConditionOutcome; -import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.boot.context.properties.bind.BindException; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.env.Environment; -import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.core.type.AnnotationMetadata; - -/** - * Base class for Servlet and reactive session conditions. - * - * @author Tommy Ludwig - * @author Stephane Nicoll - * @author Madhura Bhave - * @author Andy Wilkinson - */ -abstract class AbstractSessionCondition extends SpringBootCondition { - - private final WebApplicationType webApplicationType; - - protected AbstractSessionCondition(WebApplicationType webApplicationType) { - this.webApplicationType = webApplicationType; - } - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { - ConditionMessage.Builder message = ConditionMessage.forCondition("Session Condition"); - Environment environment = context.getEnvironment(); - StoreType required = SessionStoreMappings.getType(this.webApplicationType, - ((AnnotationMetadata) metadata).getClassName()); - if (!environment.containsProperty("spring.session.store-type")) { - return ConditionOutcome.match(message.didNotFind("property", "properties") - .items(ConditionMessage.Style.QUOTE, "spring.session.store-type")); - } - try { - Binder binder = Binder.get(environment); - return binder.bind("spring.session.store-type", StoreType.class) - .map((t) -> new ConditionOutcome(t == required, - message.found("spring.session.store-type property").items(t))) - .orElseGet(() -> ConditionOutcome - .noMatch(message.didNotFind("spring.session.store-type property").atAll())); - } - catch (BindException ex) { - return ConditionOutcome.noMatch(message.found("invalid spring.session.store-type property").atAll()); - } - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/HazelcastSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/HazelcastSessionConfiguration.java index 15fbb27b0d..f34ffd22ba 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/HazelcastSessionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/HazelcastSessionConfiguration.java @@ -26,7 +26,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.session.SessionRepository; import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository; @@ -44,7 +43,6 @@ import org.springframework.session.hazelcast.config.annotation.web.http.Hazelcas @ConditionalOnClass(HazelcastIndexedSessionRepository.class) @ConditionalOnMissingBean(SessionRepository.class) @ConditionalOnBean(HazelcastInstance.class) -@Conditional(ServletSessionCondition.class) @EnableConfigurationProperties(HazelcastSessionProperties.class) class HazelcastSessionConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java index 2eae122820..a34505193e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java @@ -50,7 +50,6 @@ import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessi @ConditionalOnClass({ JdbcTemplate.class, JdbcIndexedSessionRepository.class }) @ConditionalOnMissingBean(SessionRepository.class) @ConditionalOnBean(DataSource.class) -@Conditional(ServletSessionCondition.class) @EnableConfigurationProperties(JdbcSessionProperties.class) @Import(DatabaseInitializationDependencyConfigurer.class) class JdbcSessionConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoReactiveSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoReactiveSessionConfiguration.java index de5fadcd72..8de291207b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoReactiveSessionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoReactiveSessionConfiguration.java @@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.session.ReactiveSessionRepository; @@ -41,7 +40,6 @@ import org.springframework.session.data.mongo.config.annotation.web.reactive.Rea @ConditionalOnClass({ ReactiveMongoOperations.class, ReactiveMongoSessionRepository.class }) @ConditionalOnMissingBean(ReactiveSessionRepository.class) @ConditionalOnBean(ReactiveMongoOperations.class) -@Conditional(ReactiveSessionCondition.class) @EnableConfigurationProperties(MongoSessionProperties.class) class MongoReactiveSessionConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionConfiguration.java index 2118bdbdc6..5980dff007 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionConfiguration.java @@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.session.SessionRepository; @@ -41,7 +40,6 @@ import org.springframework.session.data.mongo.config.annotation.web.http.MongoHt @ConditionalOnClass({ MongoOperations.class, MongoIndexedSessionRepository.class }) @ConditionalOnMissingBean(SessionRepository.class) @ConditionalOnBean(MongoOperations.class) -@Conditional(ServletSessionCondition.class) @EnableConfigurationProperties(MongoSessionProperties.class) class MongoSessionConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NoOpReactiveSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NoOpReactiveSessionConfiguration.java deleted file mode 100644 index f19dd61f2a..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NoOpReactiveSessionConfiguration.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2012-2019 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.session; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.ReactiveSessionRepository; - -/** - * No-op session configuration used to disable Spring Session using the environment. - * - * @author Tommy Ludwig - * @author Andy Wilkinson - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnMissingBean(ReactiveSessionRepository.class) -@Conditional(ReactiveSessionCondition.class) -class NoOpReactiveSessionConfiguration { - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NoOpSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NoOpSessionConfiguration.java deleted file mode 100644 index 7c7e385332..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NoOpSessionConfiguration.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2012-2019 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.session; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.SessionRepository; - -/** - * No-op session configuration used to disable Spring Session using the environment. - * - * @author Tommy Ludwig - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnMissingBean(SessionRepository.class) -@Conditional(ServletSessionCondition.class) -class NoOpSessionConfiguration { - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryException.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryException.java deleted file mode 100644 index 775869adb6..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2012-2019 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.session; - -import java.util.Collections; -import java.util.List; - -import org.springframework.session.SessionRepository; -import org.springframework.util.ObjectUtils; - -/** - * Exception thrown when multiple {@link SessionRepository} implementations are available - * with no way to know which implementation should be used. - * - * @author Stephane Nicoll - * @since 2.0.0 - */ -public class NonUniqueSessionRepositoryException extends RuntimeException { - - private final List> availableCandidates; - - public NonUniqueSessionRepositoryException(List> availableCandidates) { - super("Multiple session repository candidates are available, set the " - + "'spring.session.store-type' property accordingly"); - this.availableCandidates = (!ObjectUtils.isEmpty(availableCandidates) ? availableCandidates - : Collections.emptyList()); - } - - public List> getAvailableCandidates() { - return this.availableCandidates; - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryFailureAnalyzer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryFailureAnalyzer.java deleted file mode 100644 index 3cbb89f57b..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryFailureAnalyzer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2012-2021 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.session; - -import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; -import org.springframework.boot.diagnostics.FailureAnalysis; - -/** - * An {@link AbstractFailureAnalyzer} for {@link NonUniqueSessionRepositoryException}. - * - * @author Stephane Nicoll - */ -class NonUniqueSessionRepositoryFailureAnalyzer extends AbstractFailureAnalyzer { - - @Override - protected FailureAnalysis analyze(Throwable rootFailure, NonUniqueSessionRepositoryException cause) { - StringBuilder message = new StringBuilder(); - message.append( - String.format("Multiple Spring Session store implementations are available on the classpath:%n")); - for (Class candidate : cause.getAvailableCandidates()) { - message.append(String.format(" - %s%n", candidate.getName())); - } - StringBuilder action = new StringBuilder(); - action.append(String.format("Consider any of the following:%n")); - action.append( - String.format(" - Define the 'spring.session.store-type' property to the store you want to use%n")); - action.append(String.format(" - Review your classpath and remove the unwanted store implementation(s)%n")); - return new FailureAnalysis(message.toString(), action.toString(), cause); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/ReactiveSessionCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/ReactiveSessionCondition.java deleted file mode 100644 index 66e7f64563..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/ReactiveSessionCondition.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2012-2019 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.session; - -import org.springframework.boot.WebApplicationType; - -/** - * General condition used with all reactive session configuration classes. - * - * @author Andy Wilkinson - */ -class ReactiveSessionCondition extends AbstractSessionCondition { - - ReactiveSessionCondition() { - super(WebApplicationType.REACTIVE); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisReactiveSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisReactiveSessionConfiguration.java index b807f93bd7..b1b906dba6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisReactiveSessionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisReactiveSessionConfiguration.java @@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; import org.springframework.session.ReactiveSessionRepository; @@ -41,7 +40,6 @@ import org.springframework.session.data.redis.config.annotation.web.server.Redis @ConditionalOnClass({ ReactiveRedisConnectionFactory.class, ReactiveRedisSessionRepository.class }) @ConditionalOnMissingBean(ReactiveSessionRepository.class) @ConditionalOnBean(ReactiveRedisConnectionFactory.class) -@Conditional(ReactiveSessionCondition.class) @EnableConfigurationProperties(RedisSessionProperties.class) class RedisReactiveSessionConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisSessionConfiguration.java index 79e0115944..04dfbd47a0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisSessionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisSessionConfiguration.java @@ -25,7 +25,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; @@ -48,7 +47,6 @@ import org.springframework.session.data.redis.config.annotation.web.http.RedisIn @ConditionalOnClass({ RedisTemplate.class, RedisIndexedSessionRepository.class }) @ConditionalOnMissingBean(SessionRepository.class) @ConditionalOnBean(RedisConnectionFactory.class) -@Conditional(ServletSessionCondition.class) @EnableConfigurationProperties(RedisSessionProperties.class) class RedisSessionConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/ServletSessionCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/ServletSessionCondition.java deleted file mode 100644 index 9d9fe8373b..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/ServletSessionCondition.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2012-2019 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.session; - -import org.springframework.boot.WebApplicationType; - -/** - * General condition used with all servlet session configuration classes. - * - * @author Tommy Ludwig - * @author Stephane Nicoll - * @author Madhura Bhave - * @author Andy Wilkinson - */ -class ServletSessionCondition extends AbstractSessionCondition { - - ServletSessionCondition() { - super(WebApplicationType.SERVLET); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java index 9d64cf2ce3..e281d3f34f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java @@ -17,14 +17,8 @@ package org.springframework.boot.autoconfigure.session; import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; @@ -49,13 +43,10 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.web.server.Cookie.SameSite; import org.springframework.boot.web.servlet.server.Session.Cookie; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.ImportSelector; -import org.springframework.core.type.AnnotationMetadata; import org.springframework.security.web.authentication.RememberMeServices; import org.springframework.session.ReactiveSessionRepository; import org.springframework.session.Session; @@ -90,7 +81,7 @@ public class SessionAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) - @Import({ ServletSessionRepositoryValidator.class, SessionRepositoryFilterConfiguration.class }) + @Import(SessionRepositoryFilterConfiguration.class) static class ServletSessionConfiguration { @Bean @@ -125,8 +116,8 @@ public class SessionAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(SessionRepository.class) - @Import({ ServletSessionRepositoryImplementationValidator.class, - ServletSessionConfigurationImportSelector.class }) + @Import({ RedisSessionConfiguration.class, MongoSessionConfiguration.class, HazelcastSessionConfiguration.class, + JdbcSessionConfiguration.class }) static class ServletSessionRepositoryConfiguration { } @@ -135,17 +126,10 @@ public class SessionAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.REACTIVE) - @Import(ReactiveSessionRepositoryValidator.class) + @ConditionalOnMissingBean(ReactiveSessionRepository.class) + @Import({ RedisReactiveSessionConfiguration.class, MongoReactiveSessionConfiguration.class }) static class ReactiveSessionConfiguration { - @Configuration(proxyBeanMethods = false) - @ConditionalOnMissingBean(ReactiveSessionRepository.class) - @Import({ ReactiveSessionRepositoryImplementationValidator.class, - ReactiveSessionConfigurationImportSelector.class }) - static class ReactiveSessionRepositoryConfiguration { - - } - } /** @@ -173,175 +157,4 @@ public class SessionAutoConfiguration { } - /** - * {@link ImportSelector} base class to add {@link StoreType} configuration classes. - */ - abstract static class SessionConfigurationImportSelector implements ImportSelector { - - protected final String[] selectImports(WebApplicationType webApplicationType) { - return Arrays.stream(StoreType.values()) - .map((type) -> SessionStoreMappings.getConfigurationClass(webApplicationType, type)) - .toArray(String[]::new); - } - - } - - /** - * {@link ImportSelector} to add {@link StoreType} configuration classes for reactive - * web applications. - */ - static class ReactiveSessionConfigurationImportSelector extends SessionConfigurationImportSelector { - - @Override - public String[] selectImports(AnnotationMetadata importingClassMetadata) { - return super.selectImports(WebApplicationType.REACTIVE); - } - - } - - /** - * {@link ImportSelector} to add {@link StoreType} configuration classes for Servlet - * web applications. - */ - static class ServletSessionConfigurationImportSelector extends SessionConfigurationImportSelector { - - @Override - public String[] selectImports(AnnotationMetadata importingClassMetadata) { - return super.selectImports(WebApplicationType.SERVLET); - } - - } - - /** - * Base class for beans used to validate that only one supported implementation is - * available in the classpath when the store-type property is not set. - */ - abstract static class AbstractSessionRepositoryImplementationValidator { - - private final List candidates; - - private final ClassLoader classLoader; - - private final SessionProperties sessionProperties; - - AbstractSessionRepositoryImplementationValidator(ApplicationContext applicationContext, - SessionProperties sessionProperties, List candidates) { - this.classLoader = applicationContext.getClassLoader(); - this.sessionProperties = sessionProperties; - this.candidates = candidates; - checkAvailableImplementations(); - } - - private void checkAvailableImplementations() { - List> availableCandidates = new ArrayList<>(); - for (String candidate : this.candidates) { - addCandidateIfAvailable(availableCandidates, candidate); - } - StoreType storeType = this.sessionProperties.getStoreType(); - if (availableCandidates.size() > 1 && storeType == null) { - throw new NonUniqueSessionRepositoryException(availableCandidates); - } - } - - private void addCandidateIfAvailable(List> candidates, String type) { - try { - candidates.add(Class.forName(type, false, this.classLoader)); - } - catch (Throwable ex) { - // Ignore - } - } - - } - - /** - * Bean used to validate that only one supported implementation is available in the - * classpath when the store-type property is not set. - */ - static class ServletSessionRepositoryImplementationValidator - extends AbstractSessionRepositoryImplementationValidator { - - ServletSessionRepositoryImplementationValidator(ApplicationContext applicationContext, - SessionProperties sessionProperties) { - super(applicationContext, sessionProperties, - Arrays.asList("org.springframework.session.hazelcast.HazelcastIndexedSessionRepository", - "org.springframework.session.jdbc.JdbcIndexedSessionRepository", - "org.springframework.session.data.mongo.MongoIndexedSessionRepository", - "org.springframework.session.data.redis.RedisIndexedSessionRepository")); - } - - } - - /** - * Bean used to validate that only one supported implementation is available in the - * classpath when the store-type property is not set. - */ - static class ReactiveSessionRepositoryImplementationValidator - extends AbstractSessionRepositoryImplementationValidator { - - ReactiveSessionRepositoryImplementationValidator(ApplicationContext applicationContext, - SessionProperties sessionProperties) { - super(applicationContext, sessionProperties, - Arrays.asList("org.springframework.session.data.redis.ReactiveRedisSessionRepository", - "org.springframework.session.data.mongo.ReactiveMongoSessionRepository")); - } - - } - - /** - * Base class for validating that a (reactive) session repository bean exists. - */ - abstract static class AbstractSessionRepositoryValidator implements InitializingBean { - - private final SessionProperties sessionProperties; - - private final ObjectProvider sessionRepositoryProvider; - - protected AbstractSessionRepositoryValidator(SessionProperties sessionProperties, - ObjectProvider sessionRepositoryProvider) { - this.sessionProperties = sessionProperties; - this.sessionRepositoryProvider = sessionRepositoryProvider; - } - - @Override - public void afterPropertiesSet() { - StoreType storeType = this.sessionProperties.getStoreType(); - if (storeType != StoreType.NONE && this.sessionRepositoryProvider.getIfAvailable() == null - && storeType != null) { - throw new SessionRepositoryUnavailableException( - "No session repository could be auto-configured, check your " - + "configuration (session store type is '" - + storeType.name().toLowerCase(Locale.ENGLISH) + "')", - storeType); - } - } - - } - - /** - * Bean used to validate that a {@link SessionRepository} exists and provide a - * meaningful message if that's not the case. - */ - static class ServletSessionRepositoryValidator extends AbstractSessionRepositoryValidator { - - ServletSessionRepositoryValidator(SessionProperties sessionProperties, - ObjectProvider> sessionRepositoryProvider) { - super(sessionProperties, sessionRepositoryProvider); - } - - } - - /** - * Bean used to validate that a {@link ReactiveSessionRepository} exists and provide a - * meaningful message if that's not the case. - */ - static class ReactiveSessionRepositoryValidator extends AbstractSessionRepositoryValidator { - - ReactiveSessionRepositoryValidator(SessionProperties sessionProperties, - ObjectProvider> sessionRepositoryProvider) { - super(sessionProperties, sessionRepositoryProvider); - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionProperties.java index 2e9f4d3378..3bb8b7e6fd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionProperties.java @@ -39,11 +39,6 @@ import org.springframework.session.web.http.SessionRepositoryFilter; @ConfigurationProperties(prefix = "spring.session") public class SessionProperties { - /** - * Session store type. - */ - private StoreType storeType; - /** * Session timeout. If a duration suffix is not specified, seconds will be used. */ @@ -52,14 +47,6 @@ public class SessionProperties { private Servlet servlet = new Servlet(); - public StoreType getStoreType() { - return this.storeType; - } - - public void setStoreType(StoreType storeType) { - this.storeType = storeType; - } - public Duration getTimeout() { return this.timeout; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionRepositoryUnavailableException.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionRepositoryUnavailableException.java deleted file mode 100644 index 923258baab..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionRepositoryUnavailableException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2012-2019 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.session; - -import org.springframework.session.SessionRepository; - -/** - * Exception thrown when no {@link SessionRepository} is available. - * - * @author Stephane Nicoll - * @since 2.0.0 - */ -public class SessionRepositoryUnavailableException extends RuntimeException { - - private final StoreType storeType; - - public SessionRepositoryUnavailableException(String message, StoreType storeType) { - super(message); - this.storeType = storeType; - } - - public StoreType getStoreType() { - return this.storeType; - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java deleted file mode 100644 index d1412f385e..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2012-2019 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.session; - -import java.util.Collections; -import java.util.EnumMap; -import java.util.Map; - -import org.springframework.boot.WebApplicationType; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; - -/** - * Mappings between {@link StoreType} and {@code @Configuration}. - * - * @author Tommy Ludwig - * @author Eddú Meléndez - */ -final class SessionStoreMappings { - - private static final Map MAPPINGS; - - static { - Map mappings = new EnumMap<>(StoreType.class); - mappings.put(StoreType.REDIS, - new Configurations(RedisSessionConfiguration.class, RedisReactiveSessionConfiguration.class)); - mappings.put(StoreType.MONGODB, - new Configurations(MongoSessionConfiguration.class, MongoReactiveSessionConfiguration.class)); - mappings.put(StoreType.JDBC, new Configurations(JdbcSessionConfiguration.class, null)); - mappings.put(StoreType.HAZELCAST, new Configurations(HazelcastSessionConfiguration.class, null)); - mappings.put(StoreType.NONE, - new Configurations(NoOpSessionConfiguration.class, NoOpReactiveSessionConfiguration.class)); - MAPPINGS = Collections.unmodifiableMap(mappings); - } - - private SessionStoreMappings() { - } - - static String getConfigurationClass(WebApplicationType webApplicationType, StoreType sessionStoreType) { - Configurations configurations = MAPPINGS.get(sessionStoreType); - Assert.state(configurations != null, () -> "Unknown session store type " + sessionStoreType); - return configurations.getConfiguration(webApplicationType); - } - - static StoreType getType(WebApplicationType webApplicationType, String configurationClass) { - return MAPPINGS.entrySet().stream() - .filter((entry) -> ObjectUtils.nullSafeEquals(configurationClass, - entry.getValue().getConfiguration(webApplicationType))) - .map(Map.Entry::getKey).findFirst() - .orElseThrow(() -> new IllegalStateException("Unknown configuration class " + configurationClass)); - } - - private static class Configurations { - - private final Class servletConfiguration; - - private final Class reactiveConfiguration; - - Configurations(Class servletConfiguration, Class reactiveConfiguration) { - this.servletConfiguration = servletConfiguration; - this.reactiveConfiguration = reactiveConfiguration; - } - - String getConfiguration(WebApplicationType webApplicationType) { - switch (webApplicationType) { - case SERVLET: - return getName(this.servletConfiguration); - case REACTIVE: - return getName(this.reactiveConfiguration); - } - return null; - } - - String getName(Class configuration) { - return (configuration != null) ? configuration.getName() : null; - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/StoreType.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/StoreType.java deleted file mode 100644 index 51b3cdcef8..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/StoreType.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012-2019 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.session; - -/** - * Supported Spring Session data store types. - * - * @author Tommy Ludwig - * @author Eddú Meléndez - * @author Vedran Pavic - * @since 1.4.0 - */ -public enum StoreType { - - /** - * Redis backed sessions. - */ - REDIS, - - /** - * MongoDB backed sessions. - */ - MONGODB, - - /** - * JDBC backed sessions. - */ - JDBC, - - /** - * Hazelcast backed sessions. - */ - HAZELCAST, - - /** - * No session data-store. - */ - NONE - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 2987879569..55db145823 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -32,8 +32,7 @@ org.springframework.boot.autoconfigure.jooq.NoDslContextBeanFailureAnalyzer,\ org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\ org.springframework.boot.autoconfigure.r2dbc.MissingR2dbcPoolDependencyFailureAnalyzer,\ org.springframework.boot.autoconfigure.r2dbc.MultipleConnectionPoolConfigurationsFailureAnalzyer,\ -org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer,\ -org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer +org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer # Template availability providers org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryFailureAnalyzerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryFailureAnalyzerTests.java deleted file mode 100644 index 09f3047588..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/NonUniqueSessionRepositoryFailureAnalyzerTests.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2012-2020 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.session; - -import java.util.Arrays; - -import org.junit.jupiter.api.Test; - -import org.springframework.boot.diagnostics.FailureAnalysis; -import org.springframework.boot.diagnostics.FailureAnalyzer; -import org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter; -import org.springframework.session.SessionRepository; -import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository; -import org.springframework.session.jdbc.JdbcIndexedSessionRepository; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link NonUniqueSessionRepositoryFailureAnalyzer}. - * - * @author Stephane Nicoll - */ -class NonUniqueSessionRepositoryFailureAnalyzerTests { - - private final FailureAnalyzer analyzer = new NonUniqueSessionRepositoryFailureAnalyzer(); - - @Test - void failureAnalysisWithMultipleCandidates() { - FailureAnalysis analysis = analyzeFailure( - createFailure(JdbcIndexedSessionRepository.class, HazelcastIndexedSessionRepository.class)); - assertThat(analysis).isNotNull(); - assertThat(analysis.getDescription()).contains(JdbcIndexedSessionRepository.class.getName(), - HazelcastIndexedSessionRepository.class.getName()); - assertThat(analysis.getAction()).contains("spring.session.store-type"); - } - - @SafeVarargs - @SuppressWarnings("varargs") - private final Exception createFailure(Class>... candidates) { - return new NonUniqueSessionRepositoryException(Arrays.asList(candidates)); - } - - private FailureAnalysis analyzeFailure(Exception failure) { - FailureAnalysis analysis = this.analyzer.analyze(failure); - if (analysis != null) { - new LoggingFailureAnalysisReporter().report(analysis); - } - return analysis; - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationMongoTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationMongoTests.java index fc30e246f2..8c6ef0464b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationMongoTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationMongoTests.java @@ -55,35 +55,21 @@ class ReactiveSessionAutoConfigurationMongoTests extends AbstractSessionAutoConf .withStartupTimeout(Duration.ofMinutes(5)); private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class)); + .withClassLoader(new FilteredClassLoader(ReactiveRedisSessionRepository.class)) + .withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class, MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class, + MongoReactiveDataAutoConfiguration.class)); @Test void defaultConfig() { - this.contextRunner - .withPropertyValues("spring.session.store-type=mongodb", - "spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()) - .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, - MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class)) - .run(validateSpringSessionUsesMongo("sessions")); - } - - @Test - void defaultConfigWithUniqueStoreImplementation() { - this.contextRunner.withClassLoader(new FilteredClassLoader(ReactiveRedisSessionRepository.class)) - .withPropertyValues("spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()) - .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, - MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class)) + this.contextRunner.withPropertyValues("spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()) .run(validateSpringSessionUsesMongo("sessions")); } @Test void defaultConfigWithCustomTimeout() { - this.contextRunner - .withPropertyValues("spring.session.store-type=mongodb", "spring.session.timeout=1m", - "spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()) - .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, - MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class)) - .run((context) -> { + this.contextRunner.withPropertyValues("spring.session.timeout=1m", + "spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()).run((context) -> { ReactiveMongoSessionRepository repository = validateSessionRepository(context, ReactiveMongoSessionRepository.class); assertThat(repository).hasFieldOrPropertyWithValue("maxInactiveIntervalInSeconds", 60); @@ -92,12 +78,8 @@ class ReactiveSessionAutoConfigurationMongoTests extends AbstractSessionAutoConf @Test void defaultConfigWithCustomSessionTimeout() { - this.contextRunner - .withPropertyValues("spring.session.store-type=mongodb", "server.reactive.session.timeout=1m", - "spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()) - .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, - MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class)) - .run((context) -> { + this.contextRunner.withPropertyValues("server.reactive.session.timeout=1m", + "spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()).run((context) -> { ReactiveMongoSessionRepository repository = validateSessionRepository(context, ReactiveMongoSessionRepository.class); assertThat(repository).hasFieldOrPropertyWithValue("maxInactiveIntervalInSeconds", 60); @@ -107,24 +89,26 @@ class ReactiveSessionAutoConfigurationMongoTests extends AbstractSessionAutoConf @Test void mongoSessionStoreWithCustomizations() { this.contextRunner - .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, - MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class)) - .withPropertyValues("spring.session.store-type=mongodb", "spring.session.mongodb.collection-name=foo", + .withPropertyValues("spring.session.mongodb.collection-name=foo", "spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()) .run(validateSpringSessionUsesMongo("foo")); } @Test void sessionCookieConfigurationIsAppliedToAutoConfiguredWebSessionIdResolver() { - AutoConfigurations autoConfigurations = AutoConfigurations.of(MongoAutoConfiguration.class, - MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class, + AutoConfigurations autoConfigurations = AutoConfigurations.of(SessionAutoConfiguration.class, + MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class); - this.contextRunner.withConfiguration(autoConfigurations).withUserConfiguration(Config.class).withPropertyValues( - "spring.session.store-type=mongodb", "server.reactive.session.cookie.name:JSESSIONID", - "server.reactive.session.cookie.domain:.example.com", "server.reactive.session.cookie.path:/example", - "server.reactive.session.cookie.max-age:60", "server.reactive.session.cookie.http-only:false", - "server.reactive.session.cookie.secure:false", "server.reactive.session.cookie.same-site:strict", - "spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()).run(assertExchangeWithSession((exchange) -> { + new ReactiveWebApplicationContextRunner().withConfiguration(autoConfigurations) + .withUserConfiguration(Config.class) + .withClassLoader(new FilteredClassLoader(ReactiveRedisSessionRepository.class)) + .withPropertyValues("server.reactive.session.cookie.name:JSESSIONID", + "server.reactive.session.cookie.domain:.example.com", + "server.reactive.session.cookie.path:/example", "server.reactive.session.cookie.max-age:60", + "server.reactive.session.cookie.http-only:false", "server.reactive.session.cookie.secure:false", + "server.reactive.session.cookie.same-site:strict", + "spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()) + .run(assertExchangeWithSession((exchange) -> { List cookies = exchange.getResponse().getCookies().get("JSESSIONID"); assertThat(cookies).isNotEmpty(); assertThat(cookies).allMatch((cookie) -> cookie.getDomain().equals(".example.com")); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationRedisTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationRedisTests.java index 6525a57201..5c05b2535d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationRedisTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationRedisTests.java @@ -56,73 +56,57 @@ class ReactiveSessionAutoConfigurationRedisTests extends AbstractSessionAutoConf .withStartupTimeout(Duration.ofMinutes(10)); protected final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() - .withConfiguration( - AutoConfigurations.of(SessionAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class)); + .withClassLoader(new FilteredClassLoader(ReactiveMongoSessionRepository.class)).withConfiguration( + AutoConfigurations.of(SessionAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class, + RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)); @Test void defaultConfig() { - this.contextRunner.withPropertyValues("spring.session.store-type=redis") - .withConfiguration( - AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)) - .run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE)); + this.contextRunner.run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE)); } @Test - void defaultConfigWithUniqueStoreImplementation() { - this.contextRunner.withClassLoader(new FilteredClassLoader(ReactiveMongoSessionRepository.class)) - .withConfiguration( - AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)) - .run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE)); + void redisTakesPrecedenceMultipleImplementations() { + ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner().withConfiguration( + AutoConfigurations.of(SessionAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class, + RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)); + contextRunner.run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE)); } @Test void defaultConfigWithCustomTimeout() { - this.contextRunner.withPropertyValues("spring.session.store-type=redis", "spring.session.timeout=1m") - .withConfiguration( - AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)) - .run((context) -> { - ReactiveRedisSessionRepository repository = validateSessionRepository(context, - ReactiveRedisSessionRepository.class); - assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60); - }); + this.contextRunner.withPropertyValues("spring.session.timeout=1m").run((context) -> { + ReactiveRedisSessionRepository repository = validateSessionRepository(context, + ReactiveRedisSessionRepository.class); + assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60); + }); } @Test void defaultConfigWithCustomWebFluxTimeout() { - this.contextRunner.withPropertyValues("spring.session.store-type=redis", "server.reactive.session.timeout=1m") - .withConfiguration( - AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)) - .run((context) -> { - ReactiveRedisSessionRepository repository = validateSessionRepository(context, - ReactiveRedisSessionRepository.class); - assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60); - }); + this.contextRunner.withPropertyValues("server.reactive.session.timeout=1m").run((context) -> { + ReactiveRedisSessionRepository repository = validateSessionRepository(context, + ReactiveRedisSessionRepository.class); + assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60); + }); } @Test void redisSessionStoreWithCustomizations() { this.contextRunner - .withConfiguration( - AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)) - .withPropertyValues("spring.session.store-type=redis", "spring.session.redis.namespace=foo", + .withPropertyValues("spring.session.redis.namespace=foo", "spring.session.redis.save-mode=on-get-attribute") .run(validateSpringSessionUsesRedis("foo:", SaveMode.ON_GET_ATTRIBUTE)); } @Test void sessionCookieConfigurationIsAppliedToAutoConfiguredWebSessionIdResolver() { - this.contextRunner - .withConfiguration( - AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)) - .withUserConfiguration(Config.class) - .withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(), - "spring.redis.port=" + redis.getFirstMappedPort(), "spring.session.store-type=redis", - "server.reactive.session.cookie.name:JSESSIONID", - "server.reactive.session.cookie.domain:.example.com", - "server.reactive.session.cookie.path:/example", "server.reactive.session.cookie.max-age:60", - "server.reactive.session.cookie.http-only:false", "server.reactive.session.cookie.secure:false", - "server.reactive.session.cookie.same-site:strict") - .run(assertExchangeWithSession((exchange) -> { + this.contextRunner.withUserConfiguration(Config.class).withPropertyValues( + "spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort(), + "server.reactive.session.cookie.name:JSESSIONID", "server.reactive.session.cookie.domain:.example.com", + "server.reactive.session.cookie.path:/example", "server.reactive.session.cookie.max-age:60", + "server.reactive.session.cookie.http-only:false", "server.reactive.session.cookie.secure:false", + "server.reactive.session.cookie.same-site:strict").run(assertExchangeWithSession((exchange) -> { List cookies = exchange.getResponse().getCookies().get("JSESSIONID"); assertThat(cookies).isNotEmpty(); assertThat(cookies).allMatch((cookie) -> cookie.getDomain().equals(".example.com")); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationHazelcastTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationHazelcastTests.java index d51ee41bfb..48fa1694d7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationHazelcastTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationHazelcastTests.java @@ -47,30 +47,30 @@ import static org.mockito.Mockito.mock; class SessionAutoConfigurationHazelcastTests extends AbstractSessionAutoConfigurationTests { private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withClassLoader(new FilteredClassLoader(JdbcIndexedSessionRepository.class, + RedisIndexedSessionRepository.class, MongoIndexedSessionRepository.class)) .withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class)) .withUserConfiguration(HazelcastConfiguration.class); @Test void defaultConfig() { - this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast").run(this::validateDefaultConfig); + this.contextRunner.run(this::validateDefaultConfig); } @Test - void defaultConfigWithUniqueStoreImplementation() { - this.contextRunner - .withClassLoader(new FilteredClassLoader(JdbcIndexedSessionRepository.class, - RedisIndexedSessionRepository.class, MongoIndexedSessionRepository.class)) + void hazelcastTakesPrecedenceOverJdbc() { + this.contextRunner.withClassLoader( + new FilteredClassLoader(RedisIndexedSessionRepository.class, MongoIndexedSessionRepository.class)) .run(this::validateDefaultConfig); } @Test void defaultConfigWithCustomTimeout() { - this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast", "spring.session.timeout=1m") - .run((context) -> { - HazelcastIndexedSessionRepository repository = validateSessionRepository(context, - HazelcastIndexedSessionRepository.class); - assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60); - }); + this.contextRunner.withPropertyValues("spring.session.timeout=1m").run((context) -> { + HazelcastIndexedSessionRepository repository = validateSessionRepository(context, + HazelcastIndexedSessionRepository.class); + assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60); + }); } private void validateDefaultConfig(AssertableWebApplicationContext context) { @@ -84,32 +84,29 @@ class SessionAutoConfigurationHazelcastTests extends AbstractSessionAutoConfigur @Test void customMapName() { - this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast", - "spring.session.hazelcast.map-name=foo:bar:biz").run((context) -> { - validateSessionRepository(context, HazelcastIndexedSessionRepository.class); - HazelcastInstance hazelcastInstance = context.getBean(HazelcastInstance.class); - then(hazelcastInstance).should().getMap("foo:bar:biz"); - }); + this.contextRunner.withPropertyValues("spring.session.hazelcast.map-name=foo:bar:biz").run((context) -> { + validateSessionRepository(context, HazelcastIndexedSessionRepository.class); + HazelcastInstance hazelcastInstance = context.getBean(HazelcastInstance.class); + then(hazelcastInstance).should().getMap("foo:bar:biz"); + }); } @Test void customFlushMode() { - this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast", - "spring.session.hazelcast.flush-mode=immediate").run((context) -> { - HazelcastIndexedSessionRepository repository = validateSessionRepository(context, - HazelcastIndexedSessionRepository.class); - assertThat(repository).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE); - }); + this.contextRunner.withPropertyValues("spring.session.hazelcast.flush-mode=immediate").run((context) -> { + HazelcastIndexedSessionRepository repository = validateSessionRepository(context, + HazelcastIndexedSessionRepository.class); + assertThat(repository).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE); + }); } @Test void customSaveMode() { - this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast", - "spring.session.hazelcast.save-mode=on-get-attribute").run((context) -> { - HazelcastIndexedSessionRepository repository = validateSessionRepository(context, - HazelcastIndexedSessionRepository.class); - assertThat(repository).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE); - }); + this.contextRunner.withPropertyValues("spring.session.hazelcast.save-mode=on-get-attribute").run((context) -> { + HazelcastIndexedSessionRepository repository = validateSessionRepository(context, + HazelcastIndexedSessionRepository.class); + assertThat(repository).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE); + }); } @Configuration(proxyBeanMethods = false) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationIntegrationTests.java deleted file mode 100644 index 81ffebc6cf..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationIntegrationTests.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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.session; - -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.map.IMap; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; -import org.springframework.boot.test.context.runner.WebApplicationContextRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.jdbc.JdbcIndexedSessionRepository; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * Integration tests for {@link SessionAutoConfiguration}. - * - * @author Stephane Nicoll - */ -class SessionAutoConfigurationIntegrationTests extends AbstractSessionAutoConfigurationTests { - - private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, - DataSourceTransactionManagerAutoConfiguration.class, SessionAutoConfiguration.class)) - .withPropertyValues("spring.datasource.generate-unique-name=true"); - - @Test - void severalCandidatesWithNoSessionStore() { - this.contextRunner.withUserConfiguration(HazelcastConfiguration.class).run((context) -> { - assertThat(context).hasFailed(); - assertThat(context).getFailure().rootCause().isInstanceOf(NonUniqueSessionRepositoryException.class) - .hasMessageContaining("Multiple session repository candidates are available") - .hasMessageContaining("set the 'spring.session.store-type' property accordingly"); - }); - } - - @Test - void severalCandidatesWithWrongSessionStore() { - this.contextRunner.withUserConfiguration(HazelcastConfiguration.class) - .withPropertyValues("spring.session.store-type=redis").run((context) -> { - assertThat(context).hasFailed(); - assertThat(context).getFailure().hasCauseInstanceOf(SessionRepositoryUnavailableException.class); - assertThat(context).getFailure() - .hasMessageContaining("No session repository could be auto-configured"); - assertThat(context).getFailure().hasMessageContaining("session store type is 'redis'"); - }); - } - - @Test - void severalCandidatesWithValidSessionStore() { - this.contextRunner.withUserConfiguration(HazelcastConfiguration.class) - .withPropertyValues("spring.session.store-type=jdbc") - .run((context) -> validateSessionRepository(context, JdbcIndexedSessionRepository.class)); - } - - @Configuration(proxyBeanMethods = false) - static class HazelcastConfiguration { - - @Bean - @SuppressWarnings("unchecked") - HazelcastInstance hazelcastInstance() { - IMap map = mock(IMap.class); - HazelcastInstance mock = mock(HazelcastInstance.class); - given(mock.getMap("spring:session:sessions")).willReturn(map); - given(mock.getMap("foo:bar:biz")).willReturn(map); - return mock; - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java index 966f5dd7ab..21f2142e75 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java @@ -62,6 +62,8 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfigurationTests { private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class, + MongoIndexedSessionRepository.class, RedisIndexedSessionRepository.class)) .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class, SessionAutoConfiguration.class)) @@ -69,15 +71,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration @Test void defaultConfig() { - this.contextRunner.withPropertyValues("spring.session.store-type=jdbc").run(this::validateDefaultConfig); - } - - @Test - void defaultConfigWithUniqueStoreImplementation() { - this.contextRunner - .withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class, - MongoIndexedSessionRepository.class, RedisIndexedSessionRepository.class)) - .run(this::validateDefaultConfig); + this.contextRunner.run(this::validateDefaultConfig); } private void validateDefaultConfig(AssertableWebApplicationContext context) { @@ -96,46 +90,39 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration @Test void filterOrderCanBeCustomized() { - this.contextRunner - .withPropertyValues("spring.session.store-type=jdbc", "spring.session.servlet.filter-order=123") - .run((context) -> { - FilterRegistrationBean registration = context.getBean(FilterRegistrationBean.class); - assertThat(registration.getOrder()).isEqualTo(123); - }); + this.contextRunner.withPropertyValues("spring.session.servlet.filter-order=123").run((context) -> { + FilterRegistrationBean registration = context.getBean(FilterRegistrationBean.class); + assertThat(registration.getOrder()).isEqualTo(123); + }); } @Test void disableDataSourceInitializer() { - this.contextRunner - .withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never") - .run((context) -> { - assertThat(context).doesNotHaveBean(JdbcSessionDataSourceScriptDatabaseInitializer.class); - JdbcIndexedSessionRepository repository = validateSessionRepository(context, - JdbcIndexedSessionRepository.class); - assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION"); - assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema()) - .isEqualTo(DatabaseInitializationMode.NEVER); - assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy( - () -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")); - }); + this.contextRunner.withPropertyValues("spring.session.jdbc.initialize-schema=never").run((context) -> { + assertThat(context).doesNotHaveBean(JdbcSessionDataSourceScriptDatabaseInitializer.class); + JdbcIndexedSessionRepository repository = validateSessionRepository(context, + JdbcIndexedSessionRepository.class); + assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION"); + assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema()) + .isEqualTo(DatabaseInitializationMode.NEVER); + assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy( + () -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")); + }); } @Test void customTimeout() { - this.contextRunner.withPropertyValues("spring.session.store-type=jdbc", "spring.session.timeout=1m") - .run((context) -> { - JdbcIndexedSessionRepository repository = validateSessionRepository(context, - JdbcIndexedSessionRepository.class); - assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60); - }); + this.contextRunner.withPropertyValues("spring.session.timeout=1m").run((context) -> { + JdbcIndexedSessionRepository repository = validateSessionRepository(context, + JdbcIndexedSessionRepository.class); + assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60); + }); } @Test void customTableName() { - this.contextRunner - .withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.table-name=FOO_BAR", - "spring.session.jdbc.schema=classpath:session/custom-schema-h2.sql") - .run((context) -> { + this.contextRunner.withPropertyValues("spring.session.jdbc.table-name=FOO_BAR", + "spring.session.jdbc.schema=classpath:session/custom-schema-h2.sql").run((context) -> { JdbcIndexedSessionRepository repository = validateSessionRepository(context, JdbcIndexedSessionRepository.class); assertThat(repository).hasFieldOrPropertyWithValue("tableName", "FOO_BAR"); @@ -147,60 +134,51 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration @Test void customCleanupCron() { - this.contextRunner - .withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.cleanup-cron=0 0 12 * * *") - .run((context) -> { - assertThat(context.getBean(JdbcSessionProperties.class).getCleanupCron()).isEqualTo("0 0 12 * * *"); - SpringBootJdbcHttpSessionConfiguration configuration = context - .getBean(SpringBootJdbcHttpSessionConfiguration.class); - assertThat(configuration).hasFieldOrPropertyWithValue("cleanupCron", "0 0 12 * * *"); - }); + this.contextRunner.withPropertyValues("spring.session.jdbc.cleanup-cron=0 0 12 * * *").run((context) -> { + assertThat(context.getBean(JdbcSessionProperties.class).getCleanupCron()).isEqualTo("0 0 12 * * *"); + SpringBootJdbcHttpSessionConfiguration configuration = context + .getBean(SpringBootJdbcHttpSessionConfiguration.class); + assertThat(configuration).hasFieldOrPropertyWithValue("cleanupCron", "0 0 12 * * *"); + }); } @Test void customFlushMode() { - this.contextRunner - .withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.flush-mode=immediate") - .run((context) -> { - assertThat(context.getBean(JdbcSessionProperties.class).getFlushMode()) - .isEqualTo(FlushMode.IMMEDIATE); - SpringBootJdbcHttpSessionConfiguration configuration = context - .getBean(SpringBootJdbcHttpSessionConfiguration.class); - assertThat(configuration).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE); - }); + this.contextRunner.withPropertyValues("spring.session.jdbc.flush-mode=immediate").run((context) -> { + assertThat(context.getBean(JdbcSessionProperties.class).getFlushMode()).isEqualTo(FlushMode.IMMEDIATE); + SpringBootJdbcHttpSessionConfiguration configuration = context + .getBean(SpringBootJdbcHttpSessionConfiguration.class); + assertThat(configuration).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE); + }); } @Test void customSaveMode() { - this.contextRunner - .withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.save-mode=on-get-attribute") - .run((context) -> { - assertThat(context.getBean(JdbcSessionProperties.class).getSaveMode()) - .isEqualTo(SaveMode.ON_GET_ATTRIBUTE); - SpringBootJdbcHttpSessionConfiguration configuration = context - .getBean(SpringBootJdbcHttpSessionConfiguration.class); - assertThat(configuration).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE); - }); + this.contextRunner.withPropertyValues("spring.session.jdbc.save-mode=on-get-attribute").run((context) -> { + assertThat(context.getBean(JdbcSessionProperties.class).getSaveMode()).isEqualTo(SaveMode.ON_GET_ATTRIBUTE); + SpringBootJdbcHttpSessionConfiguration configuration = context + .getBean(SpringBootJdbcHttpSessionConfiguration.class); + assertThat(configuration).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE); + }); } @Test void sessionDataSourceIsUsedWhenAvailable() { - this.contextRunner.withUserConfiguration(SessionDataSourceConfiguration.class) - .withPropertyValues("spring.session.store-type=jdbc").run((context) -> { - JdbcIndexedSessionRepository repository = validateSessionRepository(context, - JdbcIndexedSessionRepository.class); - DataSource sessionDataSource = context.getBean("sessionDataSource", DataSource.class); - assertThat(repository).extracting("jdbcOperations.dataSource").isEqualTo(sessionDataSource); - assertThat(context.getBean(JdbcSessionDataSourceScriptDatabaseInitializer.class)) - .hasFieldOrPropertyWithValue("dataSource", sessionDataSource); - assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy( - () -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")); - }); + this.contextRunner.withUserConfiguration(SessionDataSourceConfiguration.class).run((context) -> { + JdbcIndexedSessionRepository repository = validateSessionRepository(context, + JdbcIndexedSessionRepository.class); + DataSource sessionDataSource = context.getBean("sessionDataSource", DataSource.class); + assertThat(repository).extracting("jdbcOperations.dataSource").isEqualTo(sessionDataSource); + assertThat(context.getBean(JdbcSessionDataSourceScriptDatabaseInitializer.class)) + .hasFieldOrPropertyWithValue("dataSource", sessionDataSource); + assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy( + () -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")); + }); } @Test void sessionRepositoryBeansDependOnJdbcSessionDataSourceInitializer() { - this.contextRunner.withPropertyValues("spring.session.store-type=jdbc").run((context) -> { + this.contextRunner.run((context) -> { ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); String[] sessionRepositoryNames = beanFactory.getBeanNamesForType(JdbcIndexedSessionRepository.class); assertThat(sessionRepositoryNames).isNotEmpty(); @@ -214,8 +192,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration @Test void sessionRepositoryBeansDependOnFlyway() { this.contextRunner.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) - .withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never") - .run((context) -> { + .withPropertyValues("spring.session.jdbc.initialize-schema=never").run((context) -> { ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); String[] sessionRepositoryNames = beanFactory .getBeanNamesForType(JdbcIndexedSessionRepository.class); @@ -230,8 +207,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration @Test void sessionRepositoryBeansDependOnLiquibase() { this.contextRunner.withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class)) - .withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never") - .run((context) -> { + .withPropertyValues("spring.session.jdbc.initialize-schema=never").run((context) -> { ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); String[] sessionRepositoryNames = beanFactory .getBeanNamesForType(JdbcIndexedSessionRepository.class); @@ -248,7 +224,6 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration this.contextRunner.withUserConfiguration(CustomJdbcSessionDatabaseInitializerConfiguration.class) .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class)) - .withPropertyValues("spring.session.store-type=jdbc") .run((context) -> assertThat(context) .hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class) .doesNotHaveBean("jdbcSessionDataSourceScriptDatabaseInitializer") @@ -260,7 +235,6 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration this.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class) .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class)) - .withPropertyValues("spring.session.store-type=jdbc") .run((context) -> assertThat(context) .hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class) .hasBean("customInitializer")); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationMongoTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationMongoTests.java index 904ab733ce..1fb10788a3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationMongoTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationMongoTests.java @@ -52,34 +52,32 @@ class SessionAutoConfigurationMongoTests extends AbstractSessionAutoConfiguratio .withStartupTimeout(Duration.ofMinutes(5)); private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class, + JdbcIndexedSessionRepository.class, RedisIndexedSessionRepository.class)) .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, SessionAutoConfiguration.class)) .withPropertyValues("spring.data.mongodb.uri=" + mongoDB.getReplicaSetUrl()); @Test void defaultConfig() { - this.contextRunner.withPropertyValues("spring.session.store-type=mongodb") - .run(validateSpringSessionUsesMongo("sessions")); + this.contextRunner.run(validateSpringSessionUsesMongo("sessions")); } @Test - void defaultConfigWithUniqueStoreImplementation() { - this.contextRunner - .withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class, - JdbcIndexedSessionRepository.class, RedisIndexedSessionRepository.class)) + void mongoTakesPrecedenceOverJdbcAndHazelcast() { + this.contextRunner.withClassLoader(new FilteredClassLoader(RedisIndexedSessionRepository.class)) .run(validateSpringSessionUsesMongo("sessions")); } @Test void defaultConfigWithCustomTimeout() { - this.contextRunner.withPropertyValues("spring.session.store-type=mongodb", "spring.session.timeout=1m") + this.contextRunner.withPropertyValues("spring.session.timeout=1m") .run(validateSpringSessionUsesMongo("sessions", Duration.ofMinutes(1))); } @Test void mongoSessionStoreWithCustomizations() { - this.contextRunner - .withPropertyValues("spring.session.store-type=mongodb", "spring.session.mongodb.collection-name=foo") + this.contextRunner.withPropertyValues("spring.session.mongodb.collection-name=foo") .run(validateSpringSessionUsesMongo("foo")); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java index e4ce1d5e85..bffcd2f401 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java @@ -60,12 +60,14 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio .withStartupTimeout(Duration.ofMinutes(10)); protected final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class, + JdbcIndexedSessionRepository.class, MongoIndexedSessionRepository.class)) .withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class)); @Test void defaultConfig() { this.contextRunner - .withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(), + .withPropertyValues("spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort()) .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) .run(validateSpringSessionUsesRedis("spring:session:event:0:created:", FlushMode.ON_SAVE, @@ -73,11 +75,8 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio } @Test - void defaultConfigWithUniqueStoreImplementation() { - this.contextRunner - .withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class, - JdbcIndexedSessionRepository.class, MongoIndexedSessionRepository.class)) - .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) + void redisTakesPrecedenceMultipleImplementations() { + this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) .withPropertyValues("spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort()) .run(validateSpringSessionUsesRedis("spring:session:event:0:created:", FlushMode.ON_SAVE, @@ -87,7 +86,7 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio @Test void defaultConfigWithCustomTimeout() { this.contextRunner - .withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(), + .withPropertyValues("spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort(), "spring.session.timeout=1m") .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)).run((context) -> { RedisIndexedSessionRepository repository = validateSessionRepository(context, @@ -99,8 +98,8 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio @Test void redisSessionStoreWithCustomizations() { this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) - .withPropertyValues("spring.session.store-type=redis", "spring.session.redis.namespace=foo", - "spring.session.redis.flush-mode=immediate", "spring.session.redis.save-mode=on-get-attribute", + .withPropertyValues("spring.session.redis.namespace=foo", "spring.session.redis.flush-mode=immediate", + "spring.session.redis.save-mode=on-get-attribute", "spring.session.redis.cleanup-cron=0 0 12 * * *", "spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort()) .run(validateSpringSessionUsesRedis("foo:event:0:created:", FlushMode.IMMEDIATE, @@ -110,7 +109,7 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio @Test void redisSessionWithConfigureActionNone() { this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) - .withPropertyValues("spring.session.store-type=redis", "spring.session.redis.configure-action=none", + .withPropertyValues("spring.session.redis.configure-action=none", "spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort()) .run(validateStrategy(ConfigureRedisAction.NO_OP.getClass())); } @@ -118,7 +117,7 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio @Test void redisSessionWithDefaultConfigureActionNone() { this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) - .withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(), + .withPropertyValues("spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort()) .run(validateStrategy(ConfigureNotifyKeyspaceEventsAction.class, entry("notify-keyspace-events", "gxE"))); @@ -128,7 +127,7 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio void redisSessionWithCustomConfigureRedisActionBean() { this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) .withUserConfiguration(MaxEntriesRedisAction.class) - .withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(), + .withPropertyValues("spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort()) .run(validateStrategy(MaxEntriesRedisAction.class, entry("set-max-intset-entries", "1024"))); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java index f6754c67c8..03773dd0ee 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java @@ -26,14 +26,22 @@ import org.mockito.InOrder; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.session.MapSessionRepository; +import org.springframework.session.ReactiveMapSessionRepository; import org.springframework.session.SessionRepository; import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession; +import org.springframework.session.config.annotation.web.server.EnableSpringWebSession; +import org.springframework.session.data.mongo.MongoIndexedSessionRepository; +import org.springframework.session.data.redis.RedisIndexedSessionRepository; +import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository; +import org.springframework.session.jdbc.JdbcIndexedSessionRepository; import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices; import org.springframework.session.web.http.CookieHttpSessionIdResolver; import org.springframework.session.web.http.DefaultCookieSerializer; @@ -60,37 +68,31 @@ class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTest .withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class)); @Test - void contextFailsIfMultipleStoresAreAvailable() { - this.contextRunner.run((context) -> { - assertThat(context).hasFailed(); - assertThat(context).getFailure().rootCause().isInstanceOf(NonUniqueSessionRepositoryException.class) - .hasMessageContaining("Multiple session repository candidates are available"); - }); - } - - @Test - void contextFailsIfStoreTypeNotAvailable() { - this.contextRunner.withPropertyValues("spring.session.store-type=jdbc").run((context) -> { - assertThat(context).hasFailed(); - assertThat(context).getFailure().hasCauseInstanceOf(SessionRepositoryUnavailableException.class); - assertThat(context).getFailure().hasMessageContaining("No session repository could be auto-configured"); - assertThat(context).getFailure().hasMessageContaining("session store type is 'jdbc'"); - }); - } - - @Test - void autoConfigurationDisabledIfStoreTypeSetToNone() { - this.contextRunner.withPropertyValues("spring.session.store-type=none") + void autoConfigurationDisabledIfNoImplementationMatches() { + this.contextRunner + .withClassLoader(new FilteredClassLoader(RedisIndexedSessionRepository.class, + HazelcastIndexedSessionRepository.class, JdbcIndexedSessionRepository.class, + MongoIndexedSessionRepository.class)) .run((context) -> assertThat(context).doesNotHaveBean(SessionRepository.class)); } @Test void backOffIfSessionRepositoryIsPresent() { - this.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class) - .withPropertyValues("spring.session.store-type=redis").run((context) -> { - MapSessionRepository repository = validateSessionRepository(context, MapSessionRepository.class); - assertThat(context).getBean("mySessionRepository").isSameAs(repository); - }); + this.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class).run((context) -> { + MapSessionRepository repository = validateSessionRepository(context, MapSessionRepository.class); + assertThat(context).getBean("mySessionRepository").isSameAs(repository); + }); + } + + @Test + void backOffIfReactiveSessionRepositoryIsPresent() { + ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class)); + contextRunner.withUserConfiguration(ReactiveSessionRepositoryConfiguration.class).run((context) -> { + ReactiveMapSessionRepository repository = validateSessionRepository(context, + ReactiveMapSessionRepository.class); + assertThat(context).getBean("mySessionRepository").isSameAs(repository); + }); } @Test @@ -220,6 +222,17 @@ class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTest } + @Configuration(proxyBeanMethods = false) + @EnableSpringWebSession + static class ReactiveSessionRepositoryConfiguration { + + @Bean + ReactiveMapSessionRepository mySessionRepository() { + return new ReactiveMapSessionRepository(Collections.emptyMap()); + } + + } + @EnableConfigurationProperties(ServerProperties.class) static class ServerPropertiesConfiguration { diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/spring-session.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/spring-session.adoc index 005840d9cc..d96f16468d 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/spring-session.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/spring-session.adoc @@ -3,15 +3,25 @@ Spring Boot provides {spring-session}[Spring Session] auto-configuration for a wide range of data stores. When building a servlet web application, the following stores can be auto-configured: -* JDBC * Redis -* Hazelcast * MongoDB +* Hazelcast +* JDBC Additionally, {spring-boot-for-apache-geode}[Spring Boot for Apache Geode] provides {spring-boot-for-apache-geode-docs}#geode-session[auto-configuration for using Apache Geode as a session store]. The servlet auto-configuration replaces the need to use `@Enable*HttpSession`. +If a single Spring Session module is present on the classpath, Spring Boot uses that store implementation automatically. +If you have more than one implementation, Spring Boot uses the following order for choosing a specific implementation: + +. Redis +. MongoDB +. Hazelcast +. JDBC +. If none of Redis, MongoDB, Hazelcast and JDBC are available, we do not configure a `SessionRepository`. + + When building a reactive web application, the following stores can be auto-configured: * Redis @@ -19,18 +29,12 @@ When building a reactive web application, the following stores can be auto-confi The reactive auto-configuration replaces the need to use `@Enable*WebSession`. -If a single Spring Session module is present on the classpath, Spring Boot uses that store implementation automatically. -If you have more than one implementation, you must choose the {spring-boot-autoconfigure-module-code}/session/StoreType.java[`StoreType`] that you wish to use to store the sessions. -For instance, to use JDBC as the back-end store, you can configure your application as follows: +Similar to the servlet configuration, if you have more than one implementation, Spring Boot uses the following order for choosing a specific implementation: -[source,yaml,indent=0,subs="verbatim",configprops,configblocks] ----- - spring: - session: - store-type: "jdbc" ----- +. Redis +. MongoDB +. If neither Redis nor MongoDB are available, we do not configure a `ReactiveSessionRepository`. -TIP: You can disable Spring Session by setting the `store-type` to `none`. Each store has specific additional settings. For instance, it is possible to customize the name of the table for the JDBC store, as shown in the following example: