This commit is contained in:
Phillip Webb
2017-09-14 18:33:03 -07:00
parent 796d400318
commit 324a00fd6d
26 changed files with 189 additions and 226 deletions

View File

@@ -72,8 +72,8 @@ public class SecurityProperties implements SecurityPrerequisite {
/**
* Security filter chain dispatcher types.
*/
private Set<DispatcherType> dispatcherTypes = new HashSet<>(Arrays
.asList(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));
private Set<DispatcherType> dispatcherTypes = new HashSet<>(Arrays.asList(
DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));
public int getOrder() {
return this.order;

View File

@@ -31,17 +31,16 @@ import org.springframework.util.ObjectUtils;
*/
public class NonUniqueSessionRepositoryException extends RuntimeException {
private final List<Class<? extends SessionRepository<?>>> availableCandidates;
private final List<Class<?>> availableCandidates;
public NonUniqueSessionRepositoryException(
List<Class<? extends SessionRepository<?>>> availableCandidates) {
public NonUniqueSessionRepositoryException(List<Class<?>> 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<Class<? extends SessionRepository<?>>> getAvailableCandidates() {
public List<Class<?>> getAvailableCandidates() {
return this.availableCandidates;
}

View File

@@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.session;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.springframework.session.SessionRepository;
/**
* A {@link AbstractFailureAnalyzer} for {@link NonUniqueSessionRepositoryException}.
@@ -34,8 +33,7 @@ class NonUniqueSessionRepositoryFailureAnalyzer
StringBuilder message = new StringBuilder();
message.append(String.format("Multiple Spring Session store implementations are "
+ "available on the classpath:%n"));
for (Class<? extends SessionRepository<?>> candidate : cause
.getAvailableCandidates()) {
for (Class<?> candidate : cause.getAvailableCandidates()) {
message.append(String.format(" - %s%n", candidate.getName()));
}
StringBuilder action = new StringBuilder();

View File

@@ -106,7 +106,7 @@ public class SessionAutoConfiguration {
@PostConstruct
public void checkAvailableImplementations() {
List<Class<? extends SessionRepository<?>>> candidates = new ArrayList<>();
List<Class<?>> candidates = new ArrayList<>();
addCandidate(candidates,
"org.springframework.session.hazelcast.HazelcastSessionRepository");
addCandidate(candidates,
@@ -119,12 +119,9 @@ public class SessionAutoConfiguration {
}
}
@SuppressWarnings("unchecked")
private void addCandidate(List<Class<? extends SessionRepository<?>>> candidates,
String fqn) {
private void addCandidate(List<Class<?>> candidates, String type) {
try {
Class<? extends SessionRepository<?>> candidate = (Class<? extends SessionRepository<?>>) this.classLoader
.loadClass(fqn);
Class<?> candidate = this.classLoader.loadClass(type);
if (candidate != null) {
candidates.add(candidate);
}

View File

@@ -52,7 +52,6 @@ public class ResourceProperties {
private final Chain chain = new Chain();
public String[] getStaticLocations() {
return this.staticLocations;
}

View File

@@ -166,7 +166,8 @@ public class WebMvcAutoConfiguration {
@Configuration
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware {
public static class WebMvcAutoConfigurationAdapter
implements WebMvcConfigurer, ResourceLoaderAware {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
@@ -316,8 +317,8 @@ public class WebMvcAutoConfiguration {
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(
getResourceLocations(this.resourceProperties.getStaticLocations()))
.addResourceLocations(getResourceLocations(
this.resourceProperties.getStaticLocations()))
.setCachePeriod(cachePeriod));
}
}
@@ -329,29 +330,32 @@ public class WebMvcAutoConfiguration {
}
static String[] getResourceLocations(String[] staticLocations) {
String[] locations = new String[staticLocations.length + SERVLET_LOCATIONS.length];
String[] locations = new String[staticLocations.length
+ SERVLET_LOCATIONS.length];
System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);
System.arraycopy(SERVLET_LOCATIONS, 0, locations,
staticLocations.length, SERVLET_LOCATIONS.length);
System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length,
SERVLET_LOCATIONS.length);
return locations;
}
private Optional<Resource> getWelcomePage() {
return Arrays.stream(getResourceLocations(this.resourceProperties.getStaticLocations()))
.map(location -> this.resourceLoader.getResource(location + "index.html"))
.filter(resource -> {
try {
if (resource.exists()) {
resource.getURL();
return true;
}
}
catch (Exception ex) {
// Ignore
}
return false;
})
.findFirst();
String[] locations = getResourceLocations(
this.resourceProperties.getStaticLocations());
return Arrays.stream(locations).map(this::getIndexHtml)
.filter(this::isReadable).findFirst();
}
private Resource getIndexHtml(String location) {
return this.resourceLoader.getResource(location + "index.html");
}
private boolean isReadable(Resource resource) {
try {
return resource.exists() && (resource.getURL() != null);
}
catch (Exception ex) {
return false;
}
}
private void customizeResourceHandlerRegistration(
@@ -359,7 +363,6 @@ public class WebMvcAutoConfiguration {
if (this.resourceHandlerRegistrationCustomizer != null) {
this.resourceHandlerRegistrationCustomizer.customize(registration);
}
}
@Bean
@@ -403,10 +406,11 @@ public class WebMvcAutoConfiguration {
}
private List<Resource> resolveFaviconLocations() {
String[] resourceLocations = getResourceLocations(this.resourceProperties.getStaticLocations());
List<Resource> locations = new ArrayList<>(resourceLocations.length + 1);
Arrays.stream(resourceLocations)
.forEach(location -> locations.add(this.resourceLoader.getResource(location)));
String[] staticLocations = getResourceLocations(
this.resourceProperties.getStaticLocations());
List<Resource> locations = new ArrayList<>(staticLocations.length + 1);
Arrays.stream(staticLocations).map(this.resourceLoader::getResource)
.forEach(locations::add);
locations.add(new ClassPathResource("/"));
return Collections.unmodifiableList(locations);
}

View File

@@ -121,8 +121,8 @@ public class OAuth2RestOperationsConfigurationTests {
}
@Configuration
@Import({ SecurityProperties.class,
OAuth2ClientConfiguration.class, OAuth2RestOperationsConfiguration.class })
@Import({ SecurityProperties.class, OAuth2ClientConfiguration.class,
OAuth2RestOperationsConfiguration.class })
protected static class ConfigForSessionScopedConfiguration
extends WebApplicationConfiguration {

View File

@@ -52,23 +52,22 @@ public class SessionAutoConfigurationHazelcastTests
@Test
public void defaultConfig() {
this.contextRunner
.withPropertyValues("spring.session.store-type=hazelcast")
this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast")
.run(this::validateDefaultConfig);
}
@Test
public void defaultConfigWithUniqueStoreImplementation() {
this.contextRunner.withClassLoader(new HideClassesClassLoader(
JdbcOperationsSessionRepository.class,
RedisOperationsSessionRepository.class)).run(
this::validateDefaultConfig);
this.contextRunner
.withClassLoader(
new HideClassesClassLoader(JdbcOperationsSessionRepository.class,
RedisOperationsSessionRepository.class))
.run(this::validateDefaultConfig);
}
private void validateDefaultConfig(AssertableWebApplicationContext context) {
validateSessionRepository(context, HazelcastSessionRepository.class);
HazelcastInstance hazelcastInstance = context
.getBean(HazelcastInstance.class);
HazelcastInstance hazelcastInstance = context.getBean(HazelcastInstance.class);
verify(hazelcastInstance, times(1)).getMap("spring:session:sessions");
}
@@ -95,7 +94,7 @@ public class SessionAutoConfigurationHazelcastTests
context, HazelcastSessionRepository.class);
assertThat(new DirectFieldAccessor(repository)
.getPropertyValue("hazelcastFlushMode"))
.isEqualTo(HazelcastFlushMode.IMMEDIATE);
.isEqualTo(HazelcastFlushMode.IMMEDIATE);
});
}

View File

@@ -46,32 +46,32 @@ public class SessionAutoConfigurationIntegrationTests
SessionAutoConfiguration.class))
.withPropertyValues("spring.datasource.generate-unique-name=true");
@Test
public void severalCandidatesWithNoSessionStore() {
this.contextRunner.withUserConfiguration(HazelcastConfiguration.class).run((context) -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.hasCauseInstanceOf(NonUniqueSessionRepositoryException.class);
assertThat(context).getFailure().hasMessageContaining(
"Multiple session repository candidates are available");
assertThat(context).getFailure().hasMessageContaining(
"set the 'spring.session.store-type' property accordingly");
});
this.contextRunner.withUserConfiguration(HazelcastConfiguration.class)
.run((context) -> {
assertThat(context).hasFailed();
assertThat(context).getFailure().hasCauseInstanceOf(
NonUniqueSessionRepositoryException.class);
assertThat(context).getFailure().hasMessageContaining(
"Multiple session repository candidates are available");
assertThat(context).getFailure().hasMessageContaining(
"set the 'spring.session.store-type' property accordingly");
});
}
@Test
public 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'");
});
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
@@ -82,7 +82,6 @@ public class SessionAutoConfigurationIntegrationTests
JdbcOperationsSessionRepository.class));
}
@Configuration
static class HazelcastConfiguration {

View File

@@ -58,8 +58,7 @@ public class SessionAutoConfigurationJdbcTests
@Test
public void defaultConfig() {
this.contextRunner
.withPropertyValues("spring.session.store-type=jdbc")
this.contextRunner.withPropertyValues("spring.session.store-type=jdbc")
.withConfiguration(
AutoConfigurations.of(JdbcTemplateAutoConfiguration.class))
.run(this::validateDefaultConfig);
@@ -68,22 +67,20 @@ public class SessionAutoConfigurationJdbcTests
@Test
public void defaultConfigWithUniqueStoreImplementation() {
this.contextRunner
.withClassLoader(new HideClassesClassLoader(
HazelcastSessionRepository.class,
RedisOperationsSessionRepository.class)
)
.withClassLoader(
new HideClassesClassLoader(HazelcastSessionRepository.class,
RedisOperationsSessionRepository.class))
.withConfiguration(
AutoConfigurations.of(JdbcTemplateAutoConfiguration.class))
.run(this::validateDefaultConfig);
}
private void validateDefaultConfig(AssertableWebApplicationContext context) {
JdbcOperationsSessionRepository repository = validateSessionRepository(
context, JdbcOperationsSessionRepository.class);
assertThat(new DirectFieldAccessor(repository)
.getPropertyValue("tableName")).isEqualTo("SPRING_SESSION");
assertThat(context.getBean(JdbcSessionProperties.class)
.getInitializeSchema())
JdbcOperationsSessionRepository repository = validateSessionRepository(context,
JdbcOperationsSessionRepository.class);
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
.isEqualTo("SPRING_SESSION");
assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())
.isEqualTo(DatabaseInitializationMode.EMBEDDED);
assertThat(context.getBean(JdbcOperations.class)
.queryForList("select * from SPRING_SESSION")).isEmpty();

View File

@@ -50,8 +50,7 @@ public class SessionAutoConfigurationRedisTests
@Test
public void defaultConfig() {
this.contextRunner
.withPropertyValues("spring.session.store-type=redis")
this.contextRunner.withPropertyValues("spring.session.store-type=redis")
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
.run(validateSpringSessionUsesRedis("spring:session:event:created:",
RedisFlushMode.ON_SAVE));
@@ -60,9 +59,9 @@ public class SessionAutoConfigurationRedisTests
@Test
public void defaultConfigWithUniqueStoreImplementation() {
this.contextRunner
.withClassLoader(new HideClassesClassLoader(
HazelcastSessionRepository.class,
JdbcOperationsSessionRepository.class))
.withClassLoader(
new HideClassesClassLoader(HazelcastSessionRepository.class,
JdbcOperationsSessionRepository.class))
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
.run(validateSpringSessionUsesRedis("spring:session:event:created:",
RedisFlushMode.ON_SAVE));

View File

@@ -66,12 +66,12 @@ public class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurat
this.contextRunner.withPropertyValues("spring.session.store-type=jdbc")
.run((context) -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.hasCauseInstanceOf(SessionRepositoryUnavailableException.class);
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'");
assertThat(context).getFailure()
.hasMessageContaining("session store type is 'jdbc'");
});
}
@@ -86,18 +86,17 @@ public class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurat
public 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);
});
MapSessionRepository repository = validateSessionRepository(context,
MapSessionRepository.class);
assertThat(context).getBean("mySessionRepository")
.isSameAs(repository);
});
}
@Test
public void springSessionTimeoutIsNotAValidProperty() {
this.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)
.withPropertyValues("spring.session.timeout=3000")
.run((context) -> {
.withPropertyValues("spring.session.timeout=3000").run((context) -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.isInstanceOf(BeanCreationException.class);