This commit is contained in:
Phillip Webb 2016-08-29 20:20:45 +01:00
parent 850141c405
commit 565ad79856
19 changed files with 151 additions and 137 deletions

View File

@ -364,6 +364,7 @@ public class EndpointWebMvcChildContextConfiguration {
}
abstract void customize(T container);
}
static class TomcatAccessLogCustomizer

View File

@ -188,8 +188,9 @@ public class HealthMvcEndpoint extends AbstractEndpointMvcAdapter<HealthEndpoint
}
if (isSpringSecurityAuthentication(principal)) {
Authentication authentication = (Authentication) principal;
List<String> roles = Arrays.asList(StringUtils.trimArrayElements(StringUtils
.commaDelimitedListToStringArray(this.roleResolver.getProperty("roles", "ROLE_ADMIN"))));
List<String> roles = Arrays.asList(StringUtils
.trimArrayElements(StringUtils.commaDelimitedListToStringArray(
this.roleResolver.getProperty("roles", "ROLE_ADMIN"))));
for (GrantedAuthority authority : authentication.getAuthorities()) {
String name = authority.getAuthority();
for (String role : roles) {

View File

@ -42,7 +42,7 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link EndpointWebMvcHypermediaManagementContextConfigurationTests}.
* Tests for {@link EndpointWebMvcHypermediaManagementContextConfiguration}.
*
* @author Andy Wilkinson
*/

View File

@ -60,15 +60,18 @@ public class HealthMvcEndpointTests {
private MockEnvironment environment;
private UsernamePasswordAuthenticationToken user = createAuthenticationToken("ROLE_USER");
private UsernamePasswordAuthenticationToken user = createAuthenticationToken(
"ROLE_USER");
private UsernamePasswordAuthenticationToken admin = createAuthenticationToken("ROLE_ADMIN");
private UsernamePasswordAuthenticationToken admin = createAuthenticationToken(
"ROLE_ADMIN");
private UsernamePasswordAuthenticationToken hero = createAuthenticationToken("ROLE_HERO");
private UsernamePasswordAuthenticationToken hero = createAuthenticationToken(
"ROLE_HERO");
private UsernamePasswordAuthenticationToken createAuthenticationToken(String authority) {
return new UsernamePasswordAuthenticationToken(
"user", "password",
private UsernamePasswordAuthenticationToken createAuthenticationToken(
String authority) {
return new UsernamePasswordAuthenticationToken("user", "password",
AuthorityUtils.commaSeparatedStringToAuthorityList(authority));
}

View File

@ -24,10 +24,10 @@ import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapt
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
/**
* A {@code RepositoryRestConfigurer} that applies that applies configuration items
* from the {@code spring.data.rest} namespace to Spring Data REST. Also, if a
* {@link Jackson2ObjectMapperBuilder} is available, it is used to configure Spring
* Data REST's {@link ObjectMapper ObjectMappers}.
* A {@code RepositoryRestConfigurer} that applies that applies configuration items from
* the {@code spring.data.rest} namespace to Spring Data REST. Also, if a
* {@link Jackson2ObjectMapperBuilder} is available, it is used to configure Spring Data
* REST's {@link ObjectMapper ObjectMappers}.
*
* @author Andy Wilkinson
* @author Stephane Nicoll

View File

@ -101,7 +101,7 @@ public class DataSourceAutoConfiguration {
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class,
DataSourceConfiguration.Dbcp.class, DataSourceConfiguration.Dbcp2.class,
DataSourceConfiguration.Generic.class})
DataSourceConfiguration.Generic.class })
protected static class PooledDataSourceConfiguration {
}
@ -139,10 +139,12 @@ public class DataSourceAutoConfiguration {
}
@ConditionalOnProperty(prefix = "spring.datasource", name = "type")
static class ExplicitType { }
static class ExplicitType {
}
@Conditional(PooledDataSourceAvailableCondition.class)
static class PooledDataSourceAvailable { }
static class PooledDataSourceAvailable {
}
}

View File

@ -114,10 +114,10 @@ abstract class DataSourceConfiguration {
static class Generic {
@Bean
public DataSource dataSource(
DataSourceProperties properties) {
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
}

View File

@ -166,15 +166,13 @@ public class DataSourceProperties
/**
* Initialize a {@link DataSourceBuilder} with the state of this instance.
* @return a {@link DataSourceBuilder} initialized with the customizations
* defined on this instance
* @return a {@link DataSourceBuilder} initialized with the customizations defined on
* this instance
*/
public DataSourceBuilder initializeDataSourceBuilder() {
return DataSourceBuilder.create(getClassLoader())
.type(getType())
.driverClassName(determineDriverClassName())
.url(determineUrl()).username(determineUsername())
.password(determinePassword());
return DataSourceBuilder.create(getClassLoader()).type(getType())
.driverClassName(determineDriverClassName()).url(determineUrl())
.username(determineUsername()).password(determinePassword());
}
public String getName() {

View File

@ -22,24 +22,28 @@ import org.springframework.boot.diagnostics.FailureAnalysis;
/**
* An {@link AbstractFailureAnalyzer} that performs analysis of a Hikari configuration
* failure caused by the use of the unsupported 'dataSourceClassName' property.
*
* @author Stephane Nicoll
*/
class HikariDriverConfigurationFailureAnalyzer extends AbstractFailureAnalyzer<IllegalStateException> {
class HikariDriverConfigurationFailureAnalyzer
extends AbstractFailureAnalyzer<IllegalStateException> {
static final String EXPECTED_MESSAGE = "both driverClassName and dataSourceClassName are " +
"specified, one or the other should be used";
private static final String EXPECTED_MESSAGE = "both driverClassName and "
+ "dataSourceClassName are specified, one or the other should be used";
@Override
protected FailureAnalysis analyze(Throwable rootFailure, IllegalStateException cause) {
protected FailureAnalysis analyze(Throwable rootFailure,
IllegalStateException cause) {
if (!EXPECTED_MESSAGE.equals(cause.getMessage())) {
return null;
}
return new FailureAnalysis("Configuration of the Hikari connection pool failed: " +
"'dataSourceClassName' is not supported.",
"Spring Boot auto-configures only a driver and can't specify a custom " +
"DataSource. Consider configuring the Hikari DataSource in your " +
"own configuration.", cause);
return new FailureAnalysis(
"Configuration of the Hikari connection pool failed: "
+ "'dataSourceClassName' is not supported.",
"Spring Boot auto-configures only a driver and can't specify a custom "
+ "DataSource. Consider configuring the Hikari DataSource in "
+ "your own configuration.",
cause);
}
}

View File

@ -186,8 +186,8 @@ public class DataSourceAutoConfigurationTests {
}
/**
* This test makes sure that if no supported data source is present, a datasource
* is still created if "spring.datasource.type" is present.
* This test makes sure that if no supported data source is present, a datasource is
* still created if "spring.datasource.type" is present.
*/
@Test
public void explicitTypeNoSupportedDataSource() {
@ -195,9 +195,9 @@ public class DataSourceAutoConfigurationTests {
"spring.datasource.driverClassName:org.hsqldb.jdbcDriver",
"spring.datasource.url:jdbc:hsqldb:mem:testdb",
"spring.datasource.type:" + SimpleDriverDataSource.class.getName());
this.context.setClassLoader(new HidePackagesClassLoader(
"org.apache.tomcat", "com.zaxxer.hikari", "org.apache.commons.dbcp",
"org.apache.commons.dbcp2"));
this.context.setClassLoader(
new HidePackagesClassLoader("org.apache.tomcat", "com.zaxxer.hikari",
"org.apache.commons.dbcp", "org.apache.commons.dbcp2"));
testExplicitType();
}
@ -329,7 +329,6 @@ public class DataSourceAutoConfigurationTests {
this.hiddenPackages = hiddenPackages;
}
@Override
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {

View File

@ -39,11 +39,11 @@ public class HikariDriverConfigurationFailureAnalyzerTests {
public void failureAnalysisIsPerformed() {
FailureAnalysis failureAnalysis = performAnalysis(TestConfiguration.class);
assertThat(failureAnalysis).isNotNull();
assertThat(failureAnalysis.getDescription()).isEqualTo(
"Configuration of the Hikari connection pool failed: " +
"'dataSourceClassName' is not supported.");
assertThat(failureAnalysis.getAction()).contains(
"Spring Boot auto-configures only a driver");
assertThat(failureAnalysis.getDescription())
.isEqualTo("Configuration of the Hikari connection pool failed: "
+ "'dataSourceClassName' is not supported.");
assertThat(failureAnalysis.getAction())
.contains("Spring Boot auto-configures only a driver");
}
@Test

View File

@ -23,7 +23,6 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.context.embedded.AbstractConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.Ssl;
import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.client.TestRestTemplate.HttpClientOption;
@ -86,6 +85,10 @@ class SpringBootTestContextCustomizer implements ContextCustomizer {
public static class TestRestTemplateFactory
implements FactoryBean<TestRestTemplate>, ApplicationContextAware {
private static final HttpClientOption[] DEFAULT_OPTIONS = {};
private static final HttpClientOption[] SSL_OPTIONS = { HttpClientOption.SSL };
private TestRestTemplate object;
@Override
@ -93,25 +96,19 @@ class SpringBootTestContextCustomizer implements ContextCustomizer {
throws BeansException {
RestTemplateBuilder builder = getRestTemplateBuilder(applicationContext);
boolean sslEnabled = isSslEnabled(applicationContext);
TestRestTemplate template;
if (sslEnabled) {
template = new TestRestTemplate(builder.build(), null, null,
HttpClientOption.SSL);
}
else {
template = new TestRestTemplate(builder.build());
}
template.setUriTemplateHandler(new LocalHostUriTemplateHandler(
applicationContext.getEnvironment(), sslEnabled ? "https" : "http"));
TestRestTemplate template = new TestRestTemplate(builder.build(), null, null,
sslEnabled ? SSL_OPTIONS : DEFAULT_OPTIONS);
LocalHostUriTemplateHandler handler = new LocalHostUriTemplateHandler(
applicationContext.getEnvironment(), sslEnabled ? "https" : "http");
template.setUriTemplateHandler(handler);
this.object = template;
}
private boolean isSslEnabled(ApplicationContext applicationContext) {
private boolean isSslEnabled(ApplicationContext context) {
try {
Ssl ssl = applicationContext
.getBean(AbstractConfigurableEmbeddedServletContainer.class)
.getSsl();
return ssl != null && ssl.isEnabled();
AbstractConfigurableEmbeddedServletContainer container = context
.getBean(AbstractConfigurableEmbeddedServletContainer.class);
return container.getSsl() != null && container.getSsl().isEnabled();
}
catch (NoSuchBeanDefinitionException ex) {
return false;

View File

@ -39,7 +39,6 @@ public class LocalHostUriTemplateHandler extends RootUriTemplateHandler {
/**
* Create a new {@code LocalHostUriTemplateHandler} that will generate {@code http}
* URIs using the given {@code environment} to determine the port.
*
* @param environment the environment used to determine the port
*/
public LocalHostUriTemplateHandler(Environment environment) {
@ -49,7 +48,6 @@ public class LocalHostUriTemplateHandler extends RootUriTemplateHandler {
/**
* Create a new {@code LocalHostUriTemplateHandler} the will generate URIs with the
* given {@code scheme} and use the given {@code environment} to determine the port.
*
* @param environment the environment used to determine the port
* @param scheme the scheme of the root uri
* @since 1.4.1

View File

@ -31,7 +31,8 @@ public final class ApplicationInfo {
private final Banner banner;
protected ApplicationInfo(SpringApplication application, ApplicationArguments applicationArguments, Banner banner) {
protected ApplicationInfo(SpringApplication application,
ApplicationArguments applicationArguments, Banner banner) {
this.mainApplicationClass = application.getMainApplicationClass();
this.applicationArguments = applicationArguments;
this.banner = banner;

View File

@ -28,6 +28,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@ -53,42 +54,23 @@ public final class FailureAnalyzers {
private final List<FailureAnalyzer> analyzers;
/**
* Create a new {@link FailureAnalyzers} instance.
* @param context the source application context
* @since 1.4.1
*/
public FailureAnalyzers(ConfigurableApplicationContext context) {
this.classLoader = context.getClassLoader();
this(context, null);
}
FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
Assert.notNull(context, "Context must not be null");
this.classLoader = (classLoader == null ? context.getClassLoader() : classLoader);
this.analyzers = loadFailureAnalyzers(this.classLoader);
prepareFailureAnalyzers(this.analyzers, context);
}
/**
* Analyze and report the specified {@code failure}.
*
* @param failure the failure to analyze
* @return {@code true} if the failure was handled
*/
public boolean analyzeAndReport(Throwable failure) {
FailureAnalysis analysis = analyze(failure, this.analyzers);
return report(analysis, this.classLoader);
}
/**
* Analyze and report the specified {@code failure}.
*
* @param failure the failure to analyze
* @param classLoader the classloader to use
* @param context the context to use
* @return {@code true} if the failure was handled
* @deprecated in favour of {@link #analyzeAndReport(Throwable)}
*/
@Deprecated
public static boolean analyzeAndReport(Throwable failure, ClassLoader classLoader,
ConfigurableApplicationContext context) {
List<FailureAnalyzer> analyzers = loadFailureAnalyzers(classLoader);
prepareFailureAnalyzers(analyzers, context);
FailureAnalysis analysis = analyze(failure, analyzers);
return report(analysis, classLoader);
}
private static List<FailureAnalyzer> loadFailureAnalyzers(ClassLoader classLoader) {
private List<FailureAnalyzer> loadFailureAnalyzers(ClassLoader classLoader) {
List<String> analyzerNames = SpringFactoriesLoader
.loadFactoryNames(FailureAnalyzer.class, classLoader);
List<FailureAnalyzer> analyzers = new ArrayList<FailureAnalyzer>();
@ -107,15 +89,31 @@ public final class FailureAnalyzers {
return analyzers;
}
private static void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers,
private void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers,
ConfigurableApplicationContext context) {
for (FailureAnalyzer analyzer : analyzers) {
prepareAnalyzer(context, analyzer);
}
}
private static FailureAnalysis analyze(Throwable failure,
List<FailureAnalyzer> analyzers) {
private void prepareAnalyzer(ConfigurableApplicationContext context,
FailureAnalyzer analyzer) {
if (analyzer instanceof BeanFactoryAware) {
((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
}
}
/**
* Analyze and report the specified {@code failure}.
* @param failure the failure to analyze
* @return {@code true} if the failure was handled
*/
public boolean analyzeAndReport(Throwable failure) {
FailureAnalysis analysis = analyze(failure, this.analyzers);
return report(analysis, this.classLoader);
}
private FailureAnalysis analyze(Throwable failure, List<FailureAnalyzer> analyzers) {
for (FailureAnalyzer analyzer : analyzers) {
FailureAnalysis analysis = analyzer.analyze(failure);
if (analysis != null) {
@ -125,15 +123,7 @@ public final class FailureAnalyzers {
return null;
}
private static void prepareAnalyzer(ConfigurableApplicationContext context,
FailureAnalyzer analyzer) {
if (analyzer instanceof BeanFactoryAware) {
((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
}
}
private static boolean report(FailureAnalysis analysis,
ClassLoader classLoader) {
private boolean report(FailureAnalysis analysis, ClassLoader classLoader) {
List<FailureAnalysisReporter> reporters = SpringFactoriesLoader
.loadFactories(FailureAnalysisReporter.class, classLoader);
if (analysis == null || reporters.isEmpty()) {
@ -145,4 +135,18 @@ public final class FailureAnalyzers {
return true;
}
/**
* Analyze and report the specified {@code failure}.
* @param failure the failure to analyze
* @param classLoader the classloader to use
* @param context the context to use
* @return {@code true} if the failure was handled
* @deprecated as of 1.4.1 in favor of {@link #analyzeAndReport(Throwable)}
*/
@Deprecated
public static boolean analyzeAndReport(Throwable failure, ClassLoader classLoader,
ConfigurableApplicationContext context) {
return new FailureAnalyzers(context, classLoader).analyzeAndReport(failure);
}
}

View File

@ -50,7 +50,8 @@ import org.springframework.util.ResourceUtils;
*/
public class EntityManagerFactoryBuilder {
private static final Log logger = LogFactory.getLog(EntityManagerFactoryBuilder.class);
private static final Log logger = LogFactory
.getLog(EntityManagerFactoryBuilder.class);
private JpaVendorAdapter jpaVendorAdapter;
@ -105,8 +106,8 @@ public class EntityManagerFactoryBuilder {
protected String determinePersistenceUnitRootLocation() {
if (this.applicationClass != null) {
try {
URL mainLocation = this.applicationClass.getProtectionDomain().
getCodeSource().getLocation();
URL mainLocation = this.applicationClass.getProtectionDomain()
.getCodeSource().getLocation();
return ResourceUtils.extractJarFileURL(mainLocation).toString();
}
catch (Exception ex) {
@ -116,7 +117,6 @@ public class EntityManagerFactoryBuilder {
return null;
}
/**
* A fluent builder for a LocalContainerEntityManagerFactoryBean.
*/

View File

@ -101,8 +101,8 @@ public class BannerTests {
this.context = application.run();
assertThat(this.context.containsBean("springBootBanner")).isTrue();
assertThat(this.context.containsBean("springApplicationInfo")).isTrue();
assertThat(this.context.getBean(
"springApplicationInfo", ApplicationInfo.class).getBanner()).isNotNull();
assertThat(this.context.getBean("springApplicationInfo", ApplicationInfo.class)
.getBanner()).isNotNull();
}
@Test
@ -132,8 +132,8 @@ public class BannerTests {
application.setWebEnvironment(false);
this.context = application.run();
assertThat(this.context.containsBean("springBootBanner")).isFalse();
assertThat(this.context.getBean("springApplicationInfo", ApplicationInfo.class).
getBanner()).isNull();
assertThat(this.context.getBean("springApplicationInfo", ApplicationInfo.class)
.getBanner()).isNull();
}
@Test
@ -150,8 +150,8 @@ public class BannerTests {
this.context = application.run();
assertThat(this.out.toString()).contains("I printed a deprecated banner");
assertThat(this.context.containsBean("springBootBanner")).isFalse();
assertThat(this.context.getBean("springApplicationInfo", ApplicationInfo.class).
getBanner()).isNull();
assertThat(this.context.getBean("springApplicationInfo", ApplicationInfo.class)
.getBanner()).isNull();
}
static class DummyBanner implements Banner {

View File

@ -785,8 +785,8 @@ public class SpringApplicationTests {
application.setWebEnvironment(false);
this.context = application.run("foo");
ApplicationInfo applicationInfo = this.context.getBean(ApplicationInfo.class);
assertThat(application.getMainApplicationClass()).isEqualTo(application
.getMainApplicationClass());
assertThat(application.getMainApplicationClass())
.isEqualTo(application.getMainApplicationClass());
assertThat(applicationInfo.getApplicationArguments()).isNotNull();
assertThat(applicationInfo.getApplicationArguments().getNonOptionArgs())
.containsExactly("foo");

View File

@ -68,24 +68,10 @@ public class FailureAnalyzersTests {
verify(failureAnalyzer, times(1)).analyze(failure);
}
private void analyzeAndReport(final String factoriesName, Throwable failure) {
private void analyzeAndReport(String factoriesName, Throwable failure) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setClassLoader(
new ClassLoader(getClass().getClassLoader()) {
@Override
public Enumeration<URL> getResources(String name) throws IOException {
if ("META-INF/spring.factories".equals(name)) {
return super.getResources(
"failure-analyzers-tests/" + factoriesName);
}
else {
return super.getResources(name);
}
}
});
new FailureAnalyzers(context).analyzeAndReport(failure);
ClassLoader classLoader = new CustomSpringFactoriesClassLoader(factoriesName);
new FailureAnalyzers(context, classLoader).analyzeAndReport(failure);
}
static class BasicFailureAnalyzer implements FailureAnalyzer {
@ -124,4 +110,24 @@ public class FailureAnalyzersTests {
}
static class CustomSpringFactoriesClassLoader extends ClassLoader {
private final String factoriesName;
CustomSpringFactoriesClassLoader(String factoriesName) {
super(CustomSpringFactoriesClassLoader.class.getClassLoader());
this.factoriesName = factoriesName;
}
@Override
public Enumeration<URL> getResources(String name) throws IOException {
if ("META-INF/spring.factories".equals(name)) {
return super.getResources(
"failure-analyzers-tests/" + this.factoriesName);
}
return super.getResources(name);
}
}
}