Commit 2f13449b authored by Stephane Nicoll's avatar Stephane Nicoll

Polish "Improve FailureAnalyzer for embedded datasource"

Closes gh-11953
parent e66745a9
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
package org.springframework.boot.autoconfigure.jdbc; package org.springframework.boot.autoconfigure.jdbc;
import java.util.Objects;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.DataSourceBeanCreationException; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.DataSourceBeanCreationException;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.diagnostics.FailureAnalysis;
...@@ -33,6 +31,7 @@ import org.springframework.util.StringUtils; ...@@ -33,6 +31,7 @@ import org.springframework.util.StringUtils;
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Patryk Kostrzewa * @author Patryk Kostrzewa
* @author Stephane Nicoll
*/ */
class DataSourceBeanCreationFailureAnalyzer class DataSourceBeanCreationFailureAnalyzer
extends AbstractFailureAnalyzer<DataSourceBeanCreationException> extends AbstractFailureAnalyzer<DataSourceBeanCreationException>
...@@ -41,47 +40,54 @@ class DataSourceBeanCreationFailureAnalyzer ...@@ -41,47 +40,54 @@ class DataSourceBeanCreationFailureAnalyzer
private Environment environment; private Environment environment;
@Override @Override
protected FailureAnalysis analyze(Throwable rootFailure, public void setEnvironment(Environment environment) {
DataSourceBeanCreationException cause) { this.environment = environment;
return getFailureAnalysis(cause);
} }
@Override @Override
public void setEnvironment(Environment environment) { protected FailureAnalysis analyze(Throwable rootFailure,
this.environment = environment; DataSourceBeanCreationException cause) {
return getFailureAnalysis(cause);
} }
private FailureAnalysis getFailureAnalysis(DataSourceBeanCreationException cause) { private FailureAnalysis getFailureAnalysis(DataSourceBeanCreationException cause) {
StringBuilder description = new StringBuilder();
boolean datasourceUrlSpecified = this.environment.containsProperty(
"spring.datasource.url");
description.append("Failed to auto-configure a DataSource: ");
if (!datasourceUrlSpecified) {
description.append("'spring.datasource.url' is not specified and ");
}
description.append(String.format(
"no embedded datasource could be auto-configured.%n"));
description.append(String.format("%nReason: %s%n", cause.getMessage()));
final EmbeddedDatabaseConnection connection = cause.getConnection(); StringBuilder action = new StringBuilder();
final String action; action.append(String.format("Consider the following:%n"));
if (EmbeddedDatabaseConnection.NONE == cause.getConnection()) {
if (EmbeddedDatabaseConnection.NONE == connection) { action.append(String.format("\tIf you want an embedded database (H2, HSQL or "
action = "If you want an embedded database " + "Derby), please put it on the classpath.%n"));
+ "please put a supported one on the classpath.";
} }
else { else {
action = "If you have database settings to be loaded " action.append(String.format("\tReview the configuration of %s%n.", cause.getConnection()));
+ "from a particular profile you may need to activate it"
+ getActiveProfiles();
} }
return new FailureAnalysis(cause.getMessage(), action, cause); action.append("\tIf you have database settings to be loaded from a particular "
+ "profile you may need to activate it").append(getActiveProfiles());
return new FailureAnalysis(description.toString(), action.toString(), cause);
} }
private String getActiveProfiles() { private String getActiveProfiles() {
StringBuilder message = new StringBuilder();
final StringBuilder message = new StringBuilder(); String[] profiles = this.environment.getActiveProfiles();
if (Objects.nonNull(this.environment)) { if (ObjectUtils.isEmpty(profiles)) {
String[] profiles = this.environment.getActiveProfiles(); message.append(" (no profiles are currently active).");
if (ObjectUtils.isEmpty(profiles)) { }
message.append(" (no profiles are currently active)."); else {
} message.append(" (the profiles ");
else { message.append(StringUtils.arrayToCommaDelimitedString(profiles));
message.append(" (the profiles "); message.append(" are currently active).");
message.append(StringUtils.arrayToCommaDelimitedString(profiles));
message.append(" are currently active).");
}
} }
return message.toString(); return message.toString();
} }
} }
...@@ -44,7 +44,6 @@ import org.springframework.util.StringUtils; ...@@ -44,7 +44,6 @@ import org.springframework.util.StringUtils;
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Benedikt Ritter * @author Benedikt Ritter
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Patryk Kostrzewa
* @since 1.1.0 * @since 1.1.0
*/ */
@ConfigurationProperties(prefix = "spring.datasource") @ConfigurationProperties(prefix = "spring.datasource")
...@@ -519,7 +518,6 @@ public class DataSourceProperties ...@@ -519,7 +518,6 @@ public class DataSourceProperties
DataSourceBeanCreationException(String message, DataSourceBeanCreationException(String message,
EmbeddedDatabaseConnection connection) { EmbeddedDatabaseConnection connection) {
super(message); super(message);
this.connection = connection; this.connection = connection;
} }
...@@ -527,5 +525,7 @@ public class DataSourceProperties ...@@ -527,5 +525,7 @@ public class DataSourceProperties
public EmbeddedDatabaseConnection getConnection() { public EmbeddedDatabaseConnection getConnection() {
return this.connection; return this.connection;
} }
} }
} }
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -26,6 +26,7 @@ import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions ...@@ -26,6 +26,7 @@ import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions
import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -33,27 +34,49 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -33,27 +34,49 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link DataSourceBeanCreationFailureAnalyzer}. * Tests for {@link DataSourceBeanCreationFailureAnalyzer}.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Stephane Nicoll
*/ */
@RunWith(ModifiedClassPathRunner.class) @RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions({ "h2-*.jar", "hsqldb-*.jar" }) @ClassPathExclusions({ "h2-*.jar", "hsqldb-*.jar" })
public class DataSourceBeanCreationFailureAnalyzerTests { public class DataSourceBeanCreationFailureAnalyzerTests {
private final MockEnvironment environment = new MockEnvironment();
@Test @Test
public void failureAnalysisIsPerformed() { public void failureAnalysisIsPerformed() {
FailureAnalysis failureAnalysis = performAnalysis(TestConfiguration.class); FailureAnalysis failureAnalysis = performAnalysis(TestConfiguration.class);
assertThat(failureAnalysis.getDescription()).isEqualTo("Failed to determine a suitable driver class"); assertThat(failureAnalysis.getDescription()).contains(
assertThat(failureAnalysis.getAction()).isEqualTo("If you want an embedded database please put a supported one on the classpath."); "'spring.datasource.url' is not specified",
"no embedded datasource could be auto-configured",
"Failed to determine a suitable driver class");
assertThat(failureAnalysis.getAction()).contains(
"If you want an embedded database (H2, HSQL or Derby), please put it on the classpath",
"If you have database settings to be loaded from a particular profile you may need to activate it",
"(no profiles are currently active)");
}
@Test
public void failureAnalysisIsPerformedWithActiveProfiles() {
this.environment.setActiveProfiles("first", "second");
FailureAnalysis failureAnalysis = performAnalysis(TestConfiguration.class);
assertThat(failureAnalysis.getAction()).contains(
"(the profiles first,¬second are currently active)");
} }
private FailureAnalysis performAnalysis(Class<?> configuration) { private FailureAnalysis performAnalysis(Class<?> configuration) {
BeanCreationException failure = createFailure(configuration); BeanCreationException failure = createFailure(configuration);
assertThat(failure).isNotNull(); assertThat(failure).isNotNull();
return new DataSourceBeanCreationFailureAnalyzer().analyze(failure); DataSourceBeanCreationFailureAnalyzer failureAnalyzer = new DataSourceBeanCreationFailureAnalyzer();
failureAnalyzer.setEnvironment(this.environment);
return failureAnalyzer.analyze(failure);
} }
private BeanCreationException createFailure(Class<?> configuration) { private BeanCreationException createFailure(Class<?> configuration) {
try { try {
new AnnotationConfigApplicationContext(configuration).close(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setEnvironment(this.environment);
context.register(configuration);
context.refresh();
return null; return null;
} }
catch (BeanCreationException ex) { catch (BeanCreationException ex) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment