diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java index 69b179b7e9c..c2e743120cc 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java @@ -34,11 +34,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.jdbc.CommonsDataSourceConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.boot.autoconfigure.jdbc.HikariDataSourceConfiguration; -import org.springframework.boot.autoconfigure.jdbc.TomcatDataSourceConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration; import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration; @@ -54,11 +50,9 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; * @since 1.1.0 */ @Configuration -@AutoConfigureAfter({ DataSourceAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, CommonsDataSourceConfiguration.class, - HikariDataSourceConfiguration.class, TomcatDataSourceConfiguration.class, - MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, - RedisAutoConfiguration.class, RabbitAutoConfiguration.class }) +@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class, RedisAutoConfiguration.class, + RabbitAutoConfiguration.class }) public class HealthIndicatorAutoConfiguration { @Bean diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointSerializationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointSerializationTests.java new file mode 100644 index 00000000000..70ea3b1fa62 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointSerializationTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2013-2014 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 + * + * http://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.actuate.endpoint; + +import java.util.Map; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetaData; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class ConfigurationPropertiesReportEndpointSerializationTests { + + private AnnotationConfigApplicationContext context; + + @Before + public void setup() { + this.context = new AnnotationConfigApplicationContext(); + } + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + @SuppressWarnings("unchecked") + public void testNaming() throws Exception { + this.context.register(Config.class); + EnvironmentTestUtils.addEnvironment(this.context, "foo.name:foo"); + this.context.refresh(); + ConfigurationPropertiesReportEndpoint report = this.context + .getBean(ConfigurationPropertiesReportEndpoint.class); + Map properties = report.invoke(); + Map nestedProperties = (Map) properties + .get("foo"); + assertNotNull(nestedProperties); + assertEquals("foo", nestedProperties.get("prefix")); + Map map = (Map) nestedProperties + .get("properties"); + assertNotNull(map); + assertEquals(1, map.size()); + assertEquals("foo", map.get("name")); + } + + @Configuration + @EnableConfigurationProperties + public static class Config { + + @Bean + public ConfigurationPropertiesReportEndpoint endpoint( + ConfigurationBeanFactoryMetaData beanFactoryMetaData) { + ConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(); + endpoint.setConfigurationBeanFactoryMetaData(beanFactoryMetaData); + return endpoint; + } + + @Bean + @ConfigurationProperties(prefix = "foo") + public Foo foo() { + return new Foo(); + } + + } + + public static class Foo { + + private String name = "654321"; + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + // No setter so it doesn't appear in the report + public String getSummary() { + return "Name: " + this.name; + } + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/CommonsDataSourceConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/CommonsDataSourceConfiguration.java deleted file mode 100644 index ff9d65b5e2b..00000000000 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/CommonsDataSourceConfiguration.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2012-2014 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 - * - * http://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.jdbc; - -import java.sql.SQLException; - -import javax.annotation.PreDestroy; -import javax.sql.DataSource; - -import org.apache.commons.dbcp.BasicDataSource; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.dao.DataAccessResourceFailureException; - -/** - * Configuration for a Commons DBCP database pool. The DBCP pool is popular but not - * recommended in high volume environments (the Tomcat DataSource is more reliable). - * - * @author Dave Syer - * @see DataSourceAutoConfiguration - */ -@Configuration -public class CommonsDataSourceConfiguration extends AbstractDataSourceConfiguration { - - private static Log logger = LogFactory.getLog(CommonsDataSourceConfiguration.class); - - private BasicDataSource pool; - - public CommonsDataSourceConfiguration() { - // Ensure to set the correct default value for Commons DBCP - setInitialSize(0); - } - - @Bean(destroyMethod = "close") - public DataSource dataSource() { - logger.info("Hint: using Commons DBCP BasicDataSource. It's going to work, " - + "but the Tomcat DataSource is more reliable."); - this.pool = createAndConfigurePool(); - return this.pool; - } - - private BasicDataSource createAndConfigurePool() { - BasicDataSource pool = new BasicDataSource(); - pool.setDriverClassName(getDriverClassName()); - pool.setUrl(getUrl()); - if (getUsername() != null) { - pool.setUsername(getUsername()); - } - if (getPassword() != null) { - pool.setPassword(getPassword()); - } - pool.setInitialSize(getInitialSize()); - pool.setMaxActive(getMaxActive()); - pool.setMaxIdle(getMaxIdle()); - pool.setMinIdle(getMinIdle()); - pool.setTestOnBorrow(isTestOnBorrow()); - pool.setTestOnReturn(isTestOnReturn()); - pool.setTestWhileIdle(isTestWhileIdle()); - pool.setValidationQuery(getValidationQuery()); - if (getTimeBetweenEvictionRunsMillis() != null) { - pool.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis()); - } - if (getMinEvictableIdleTimeMillis() != null) { - pool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis()); - } - if (getMaxWaitMillis() != null) { - pool.setMaxWait(getMaxWaitMillis()); - } - return pool; - } - - @PreDestroy - public void close() { - if (this.pool != null) { - try { - this.pool.close(); - } - catch (SQLException ex) { - throw new DataAccessResourceFailureException( - "Could not close data source", ex); - } - } - } - -} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java index dc067c899f8..266fcecd63e 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java @@ -35,16 +35,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; -import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.jdbc.core.JdbcOperations; @@ -54,7 +53,6 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; -import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -65,7 +63,8 @@ import org.springframework.util.StringUtils; */ @Configuration @ConditionalOnClass(EmbeddedDatabaseType.class) -public class DataSourceAutoConfiguration implements EnvironmentAware { +@EnableConfigurationProperties(DataSourceProperties.class) +public class DataSourceAutoConfiguration { private static Log logger = LogFactory.getLog(DataSourceAutoConfiguration.class); @@ -77,26 +76,20 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { @Autowired private ApplicationContext applicationContext; - private RelaxedPropertyResolver datasourceProperties; - - @Override - public void setEnvironment(Environment environment) { - this.datasourceProperties = new RelaxedPropertyResolver(environment, - CONFIGURATION_PREFIX + "."); - } + @Autowired + private DataSourceProperties properties; @PostConstruct protected void initialize() throws Exception { - boolean initialize = this.datasourceProperties.getProperty("initialize", - Boolean.class, true); + boolean initialize = this.properties.isInitialize(); if (this.dataSource == null || !initialize) { logger.debug("No DataSource found so not initializing"); return; } - String schema = this.datasourceProperties.getProperty("schema"); + String schema = this.properties.getSchema(); if (schema == null) { - String platform = this.datasourceProperties.getProperty("platform", "all"); + String platform = this.properties.getPlatform(); schema = "classpath*:schema-" + platform + ".sql,"; schema += "classpath*:schema.sql,"; schema += "classpath*:data-" + platform + ".sql,"; @@ -109,8 +102,7 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { .getResources(schemaLocation))); } - boolean continueOnError = this.datasourceProperties.getProperty( - "continueOnError", Boolean.class, false); + boolean continueOnError = this.properties.isContinueOnError(); boolean exists = false; ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); for (Resource resource : resources) { @@ -120,7 +112,7 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { populator.setContinueOnError(continueOnError); } } - populator.setSeparator(this.datasourceProperties.getProperty("separator", ";")); + populator.setSeparator(this.properties.getSeparator()); if (exists) { DatabasePopulatorUtils.execute(populator, this.dataSource); @@ -151,24 +143,26 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { } - @Conditional(DataSourceAutoConfiguration.TomcatDatabaseCondition.class) + @Conditional(DataSourceAutoConfiguration.NonEmbeddedDatabaseCondition.class) @ConditionalOnMissingBean(DataSource.class) - @Import(TomcatDataSourceConfiguration.class) - protected static class TomcatConfiguration { + protected static class NonEmbeddedConfiguration { - } + @Autowired + private DataSourceProperties properties; - @Conditional(DataSourceAutoConfiguration.HikariDatabaseCondition.class) - @ConditionalOnMissingBean(DataSource.class) - @Import(HikariDataSourceConfiguration.class) - protected static class HikariConfiguration { - - } - - @Conditional(DataSourceAutoConfiguration.BasicDatabaseCondition.class) - @ConditionalOnMissingBean(DataSource.class) - @Import(CommonsDataSourceConfiguration.class) - protected static class DbcpConfiguration { + @ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX) + @Bean + public DataSource dataSource() { + // @formatter:off + DataSourceFactory factory = DataSourceFactory + .create(this.properties.getClassLoader()) + .driverClassName(this.properties.getDriverClassName()) + .url(this.properties.getUrl()) + .username(this.properties.getUsername()) + .password(this.properties.getPassword()); + // @formatter:on + return factory.build(); + } } @@ -196,35 +190,18 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { /** * Base {@link Condition} for non-embedded database checks. */ - static abstract class NonEmbeddedDatabaseCondition extends SpringBootCondition { - - protected abstract String getDataSourceClassName(); + static class NonEmbeddedDatabaseCondition extends SpringBootCondition { @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { - if (!ClassUtils.isPresent(getDataSourceClassName(), context.getClassLoader())) { - return ConditionOutcome.noMatch(getDataSourceClassName() - + " DataSource class not found"); - } - - String driverClassName = getDriverClassName(context.getEnvironment(), - getDataSourceClassLoader(context)); - if (driverClassName == null) { - return ConditionOutcome.noMatch("no database driver"); - } - - String url = getUrl(context.getEnvironment(), context.getClassLoader()); - if (url == null) { - return ConditionOutcome.noMatch("no database URL"); - } - - if (ClassUtils.isPresent(driverClassName, context.getClassLoader())) { - return ConditionOutcome.match("found database driver " + driverClassName); + ClassLoader dataSourceClassLoader = getDataSourceClassLoader(context); + if (dataSourceClassLoader != null) { + return ConditionOutcome.match("Supported DataSource class found"); } - return ConditionOutcome.noMatch("missing database driver " + driverClassName); + return ConditionOutcome.noMatch("missing supported DataSource"); } /** @@ -232,94 +209,12 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { * the driver class can actually be loaded by the data source. */ private ClassLoader getDataSourceClassLoader(ConditionContext context) { - try { - Class dataSourceClass = ClassUtils.forName(getDataSourceClassName(), - context.getClassLoader()); - return dataSourceClass.getClassLoader(); - } - catch (ClassNotFoundException ex) { - throw new IllegalStateException(ex); - } - } - - private String getDriverClassName(Environment environment, ClassLoader classLoader) { - String driverClassName = environment == null ? null : environment - .getProperty(CONFIGURATION_PREFIX + ".driverClassName"); - if (driverClassName == null) { - driverClassName = EmbeddedDatabaseConnection.get(classLoader) - .getDriverClassName(); - } - return driverClassName; - } - - private String getUrl(Environment environment, ClassLoader classLoader) { - String url = (environment == null ? null : environment - .getProperty(CONFIGURATION_PREFIX + ".url")); - if (url == null) { - url = EmbeddedDatabaseConnection.get(classLoader).getUrl(); - } - return url; - } - - } - - /** - * {@link Condition} to detect when a commons-dbcp {@code BasicDataSource} backed - * database is used. - */ - static class BasicDatabaseCondition extends NonEmbeddedDatabaseCondition { - - private final Condition hikariCondition = new HikariDatabaseCondition(); - - private final Condition tomcatCondition = new TomcatDatabaseCondition(); - - @Override - protected String getDataSourceClassName() { - return "org.apache.commons.dbcp.BasicDataSource"; - } - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, - AnnotatedTypeMetadata metadata) { - if (anyMatches(context, metadata, this.hikariCondition, this.tomcatCondition)) { - return ConditionOutcome.noMatch("other DataSource"); - } - return super.getMatchOutcome(context, metadata); - } - - } - - /** - * {@link Condition} to detect when a Hikari DataSource backed database is used. - */ - static class HikariDatabaseCondition extends NonEmbeddedDatabaseCondition { - - private final Condition tomcatCondition = new TomcatDatabaseCondition(); - - @Override - protected String getDataSourceClassName() { - return "com.zaxxer.hikari.HikariDataSource"; - } - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, - AnnotatedTypeMetadata metadata) { - if (anyMatches(context, metadata, this.tomcatCondition)) { - return ConditionOutcome.noMatch("Tomcat DataSource"); + Class dataSourceClass = new DataSourceFactory(context.getClassLoader()) + .findType(); + if (dataSourceClass == null) { + return null; } - return super.getMatchOutcome(context, metadata); - } - - } - - /** - * {@link Condition} to detect when a Tomcat DataSource backed database is used. - */ - static class TomcatDatabaseCondition extends NonEmbeddedDatabaseCondition { - - @Override - protected String getDataSourceClassName() { - return "org.apache.tomcat.jdbc.pool.DataSource"; + return dataSourceClass.getClassLoader(); } } @@ -329,17 +224,12 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { */ static class EmbeddedDatabaseCondition extends SpringBootCondition { - private final SpringBootCondition hikariCondition = new HikariDatabaseCondition(); - - private final SpringBootCondition tomcatCondition = new TomcatDatabaseCondition(); - - private final SpringBootCondition dbcpCondition = new BasicDatabaseCondition(); + private final SpringBootCondition nonEmbedded = new NonEmbeddedDatabaseCondition(); @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { - if (anyMatches(context, metadata, this.hikariCondition, this.tomcatCondition, - this.dbcpCondition)) { + if (anyMatches(context, metadata, this.nonEmbedded)) { return ConditionOutcome .noMatch("existing non-embedded database detected"); } @@ -358,11 +248,7 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { */ static class DatabaseCondition extends SpringBootCondition { - private final SpringBootCondition hikariCondition = new HikariDatabaseCondition(); - - private final SpringBootCondition tomcatCondition = new TomcatDatabaseCondition(); - - private final SpringBootCondition dbcpCondition = new BasicDatabaseCondition(); + private final SpringBootCondition nonEmbedded = new NonEmbeddedDatabaseCondition(); private final SpringBootCondition embeddedCondition = new EmbeddedDatabaseCondition(); @@ -370,8 +256,7 @@ public class DataSourceAutoConfiguration implements EnvironmentAware { public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { - if (anyMatches(context, metadata, this.hikariCondition, this.tomcatCondition, - this.dbcpCondition, this.embeddedCondition)) { + if (anyMatches(context, metadata, this.nonEmbedded, this.embeddedCondition)) { return ConditionOutcome.match("existing auto database detected"); } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceFactory.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceFactory.java new file mode 100644 index 00000000000..139691b5f34 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceFactory.java @@ -0,0 +1,133 @@ +/* + * Copyright 2012-2013 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 + * + * http://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.jdbc; + +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValues; +import org.springframework.boot.bind.RelaxedDataBinder; +import org.springframework.util.ClassUtils; + +/** + * Convenience class for building a {@link DataSource} with common implementations and + * properties. If Tomcat, HikariCP or Commons DBCP are on the classpath one of them will + * be selected (in that order with Tomcat first). In the interest of a uniform interface, + * and so that there can be a fallback to an embedded database if one can be detected on + * the classpath, only a small set of common configuration properties are supported. To + * inject additional properties into the result you can downcast it, or use + * @ConfigurationProperties. + * + * @author Dave Syer + */ +public class DataSourceFactory { + + private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] { + "org.apache.tomcat.jdbc.pool.DataSource", + "com.zaxxer.hikari.HikariDataSource", + "org.apache.commons.dbcp.BasicDataSource" }; + + private Class type; + + private ClassLoader classLoader; + + private Map properties = new HashMap(); + + public static DataSourceFactory create() { + return new DataSourceFactory(null); + } + + public static DataSourceFactory create(ClassLoader classLoader) { + return new DataSourceFactory(classLoader); + } + + public DataSourceFactory(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public DataSource build() { + Class type = getType(); + DataSource result = BeanUtils.instantiate(type); + bind(result); + return result; + } + + private void bind(DataSource result) { + new RelaxedDataBinder(result).bind(getPropertyValues()); + } + + private PropertyValues getPropertyValues() { + if (getType().getName().contains("Hikari") && this.properties.containsKey("url")) { + this.properties.put("jdbcUrl", this.properties.get("url")); + this.properties.remove("url"); + } + return new MutablePropertyValues(this.properties); + } + + public DataSourceFactory type(Class type) { + this.type = type; + return this; + } + + public DataSourceFactory url(String url) { + this.properties.put("url", url); + return this; + } + + public DataSourceFactory driverClassName(String driverClassName) { + this.properties.put("driverClassName", driverClassName); + return this; + } + + public DataSourceFactory username(String username) { + this.properties.put("username", username); + return this; + } + + public DataSourceFactory password(String password) { + this.properties.put("password", password); + return this; + } + + public Class findType() { + if (this.type != null) { + return this.type; + } + for (String name : DATA_SOURCE_TYPE_NAMES) { + if (ClassUtils.isPresent(name, this.classLoader)) { + @SuppressWarnings("unchecked") + Class resolved = (Class) ClassUtils + .resolveClassName(name, this.classLoader); + return resolved; + } + } + return null; + } + + private Class getType() { + Class type = findType(); + if (type != null) { + return type; + } + throw new IllegalStateException("No supported DataSource type found"); + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/AbstractDataSourceConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java similarity index 56% rename from spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/AbstractDataSourceConfiguration.java rename to spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java index 87c85c8a2f1..5be2e7e5e60 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/AbstractDataSourceConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java @@ -20,7 +20,6 @@ import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.util.StringUtils; /** @@ -29,9 +28,7 @@ import org.springframework.util.StringUtils; * @author Dave Syer */ @ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX) -@EnableConfigurationProperties -public abstract class AbstractDataSourceConfiguration implements BeanClassLoaderAware, - InitializingBean { +public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean { private String driverClassName; @@ -41,29 +38,17 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader private String password; - private int maxActive = 100; - - private int maxIdle = 8; - - private int minIdle = 8; - - private int initialSize = 10; - - private String validationQuery; - - private boolean testOnBorrow; - - private boolean testOnReturn; + private ClassLoader classLoader; - private boolean testWhileIdle; + private boolean initialize = true; - private Integer timeBetweenEvictionRunsMillis; + private String platform = "all"; - private Integer minEvictableIdleTimeMillis; + private String schema; - private Integer maxWaitMillis; + private boolean continueOnError = false; - private ClassLoader classLoader; + private String separator = ";"; private EmbeddedDatabaseConnection embeddedDatabaseConnection = EmbeddedDatabaseConnection.NONE; @@ -78,7 +63,7 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader .get(this.classLoader); } - protected String getDriverClassName() { + public String getDriverClassName() { if (StringUtils.hasText(this.driverClassName)) { return this.driverClassName; } @@ -93,7 +78,7 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader return driverClassName; } - protected String getUrl() { + public String getUrl() { if (StringUtils.hasText(this.url)) { return this.url; } @@ -108,7 +93,7 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader return url; } - protected String getUsername() { + public String getUsername() { if (StringUtils.hasText(this.username)) { return this.username; } @@ -118,7 +103,7 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader return null; } - protected String getPassword() { + public String getPassword() { if (StringUtils.hasText(this.password)) { return this.password; } @@ -132,10 +117,6 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader this.driverClassName = driverClassName; } - public void setInitialSize(int initialSize) { - this.initialSize = initialSize; - } - public void setUrl(String url) { this.url = url; } @@ -148,88 +129,48 @@ public abstract class AbstractDataSourceConfiguration implements BeanClassLoader this.password = password; } - public void setMaxActive(int maxActive) { - this.maxActive = maxActive; - } - - public void setMaxIdle(int maxIdle) { - this.maxIdle = maxIdle; - } - - public void setMinIdle(int minIdle) { - this.minIdle = minIdle; - } - - public void setValidationQuery(String validationQuery) { - this.validationQuery = validationQuery; - } - - public void setTestOnBorrow(boolean testOnBorrow) { - this.testOnBorrow = testOnBorrow; - } - - public void setTestOnReturn(boolean testOnReturn) { - this.testOnReturn = testOnReturn; - } - - public void setTestWhileIdle(boolean testWhileIdle) { - this.testWhileIdle = testWhileIdle; - } - - public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) { - this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; - } - - public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { - this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; - } - - public void setMaxWait(int maxWaitMillis) { - this.maxWaitMillis = maxWaitMillis; - } - - public int getInitialSize() { - return this.initialSize; + public boolean isInitialize() { + return this.initialize; } - protected int getMaxActive() { - return this.maxActive; + public void setInitialize(boolean initialize) { + this.initialize = initialize; } - protected int getMaxIdle() { - return this.maxIdle; + public String getPlatform() { + return this.platform; } - protected int getMinIdle() { - return this.minIdle; + public void setPlatform(String platform) { + this.platform = platform; } - protected String getValidationQuery() { - return this.validationQuery; + public String getSchema() { + return this.schema; } - protected boolean isTestOnBorrow() { - return this.testOnBorrow; + public void setSchema(String schema) { + this.schema = schema; } - protected boolean isTestOnReturn() { - return this.testOnReturn; + public boolean isContinueOnError() { + return this.continueOnError; } - protected boolean isTestWhileIdle() { - return this.testWhileIdle; + public void setContinueOnError(boolean continueOnError) { + this.continueOnError = continueOnError; } - protected Integer getTimeBetweenEvictionRunsMillis() { - return this.timeBetweenEvictionRunsMillis; + public String getSeparator() { + return this.separator; } - protected Integer getMinEvictableIdleTimeMillis() { - return this.minEvictableIdleTimeMillis; + public void setSeparator(String separator) { + this.separator = separator; } - protected Integer getMaxWaitMillis() { - return this.maxWaitMillis; + public ClassLoader getClassLoader() { + return this.classLoader; } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfiguration.java deleted file mode 100644 index 00fa7953501..00000000000 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfiguration.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2012-2014 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 - * - * http://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.jdbc; - -import java.util.Properties; - -import javax.annotation.PreDestroy; -import javax.sql.DataSource; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.StringUtils; - -import com.zaxxer.hikari.HikariDataSource; - -/** - * Configuration for a HikariCP database pool. The HikariCP pool is a popular data source - * implementation that provides high performance as well as some useful opinionated - * defaults. For compatibility with other DataSource implementations accepts configuration - * via properties in "spring.datasource.*", e.g. "url", "driverClassName", "username", - * "password" (and some others but the full list supported by the Tomcat pool is not - * applicable). Note that the Hikari team recommends using a "dataSourceClassName" and a - * Properties instance (specified here as "spring.datasource.hikari.*"). This makes the - * binding potentially vendor specific, but gives you full control of all the native - * features in the vendor's DataSource. - * - * @author Dave Syer - * @see DataSourceAutoConfiguration - * @since 1.1.0 - */ -@Configuration -public class HikariDataSourceConfiguration extends AbstractDataSourceConfiguration { - - private String dataSourceClassName; - - private String username; - - private HikariDataSource pool; - - private Properties hikari = new Properties(); - - @Bean(destroyMethod = "shutdown") - public DataSource dataSource() { - this.pool = new HikariDataSource(); - if (this.dataSourceClassName == null) { - this.pool.setDriverClassName(getDriverClassName()); - } - else { - this.pool.setDataSourceClassName(this.dataSourceClassName); - this.pool.setDataSourceProperties(this.hikari); - } - this.pool.setJdbcUrl(getUrl()); - if (getUsername() != null) { - this.pool.setUsername(getUsername()); - } - if (getPassword() != null) { - this.pool.setPassword(getPassword()); - } - this.pool.setMaximumPoolSize(getMaxActive()); - this.pool.setMinimumIdle(getMinIdle()); - if (isTestOnBorrow()) { - this.pool.setConnectionInitSql(getValidationQuery()); - } - else { - this.pool.setConnectionTestQuery(getValidationQuery()); - } - if (getMaxWaitMillis() != null) { - this.pool.setMaxLifetime(getMaxWaitMillis()); - } - return this.pool; - } - - @PreDestroy - public void close() { - if (this.pool != null) { - this.pool.close(); - } - } - - /** - * @param dataSourceClassName the dataSourceClassName to set - */ - public void setDataSourceClassName(String dataSourceClassName) { - this.dataSourceClassName = dataSourceClassName; - } - - @Override - public void setUsername(String username) { - this.username = username; - } - - /** - * @return the hikari data source properties - */ - public Properties getHikari() { - return this.hikari; - } - - @Override - protected String getUsername() { - if (StringUtils.hasText(this.username)) { - return this.username; - } - if (this.dataSourceClassName == null - && EmbeddedDatabaseConnection.isEmbedded(getDriverClassName())) { - return "sa"; - } - return null; - } - -} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/RelaxedDataSourceFactory.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/RelaxedDataSourceFactory.java deleted file mode 100644 index 81fb1715a4b..00000000000 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/RelaxedDataSourceFactory.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2012-2013 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 - * - * http://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.jdbc; - -import javax.sql.DataSource; - -import org.springframework.beans.BeanUtils; -import org.springframework.boot.bind.PropertySourcesPropertyValues; -import org.springframework.boot.bind.RelaxedDataBinder; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.util.ClassUtils; - -/** - * @author Dave Syer - */ -public class RelaxedDataSourceFactory { - - private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] { - "com.zaxxer.hikari.HikariDataSource", - "org.apache.tomcat.jdbc.pool.DataSource", - "org.apache.commons.dbcp.BasicDataSource" }; - - private Class type; - - private ConfigurableEnvironment environment; - - public static RelaxedDataSourceFactory create(ConfigurableEnvironment environment) { - return new RelaxedDataSourceFactory(environment); - } - - public RelaxedDataSourceFactory(ConfigurableEnvironment environment) { - this.environment = environment; - } - - public DataSource build(String prefix) { - Class type = getType(); - DataSource result = BeanUtils.instantiate(type); - RelaxedDataBinder binder = new RelaxedDataBinder(result, prefix); - binder.bind(new PropertySourcesPropertyValues(this.environment - .getPropertySources())); - return result; - } - - public RelaxedDataSourceFactory type(Class type) { - this.type = type; - return this; - } - - private Class getType() { - if (this.type != null) { - return this.type; - } - for (String name : DATA_SOURCE_TYPE_NAMES) { - if (ClassUtils.isPresent(name, null)) { - @SuppressWarnings("unchecked") - Class resolved = (Class) ClassUtils - .resolveClassName(name, null); - return resolved; - } - } - throw new IllegalStateException("No supported DataSource type found"); - } - -} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/TomcatDataSourceConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/TomcatDataSourceConfiguration.java deleted file mode 100644 index 49e25239925..00000000000 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/TomcatDataSourceConfiguration.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2012-2014 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 - * - * http://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.jdbc; - -import javax.annotation.PreDestroy; -import javax.sql.DataSource; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Configuration for a Tomcat database pool. The Tomcat pool provides superior performance - * and tends not to deadlock in high volume environments. - * - * @author Dave Syer - * @see DataSourceAutoConfiguration - */ -@Configuration -public class TomcatDataSourceConfiguration extends AbstractDataSourceConfiguration { - - private String jdbcInterceptors; - private long validationInterval = 30000; - private org.apache.tomcat.jdbc.pool.DataSource pool; - - @Bean(destroyMethod = "close") - public DataSource dataSource() { - this.pool = new org.apache.tomcat.jdbc.pool.DataSource(); - this.pool.setDriverClassName(getDriverClassName()); - this.pool.setUrl(getUrl()); - if (getUsername() != null) { - this.pool.setUsername(getUsername()); - } - if (getPassword() != null) { - this.pool.setPassword(getPassword()); - } - this.pool.setInitialSize(getInitialSize()); - this.pool.setMaxActive(getMaxActive()); - this.pool.setMaxIdle(getMaxIdle()); - this.pool.setMinIdle(getMinIdle()); - this.pool.setTestOnBorrow(isTestOnBorrow()); - this.pool.setTestOnReturn(isTestOnReturn()); - this.pool.setTestWhileIdle(isTestWhileIdle()); - if (getTimeBetweenEvictionRunsMillis() != null) { - this.pool - .setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis()); - } - if (getMinEvictableIdleTimeMillis() != null) { - this.pool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis()); - } - this.pool.setValidationQuery(getValidationQuery()); - this.pool.setValidationInterval(this.validationInterval); - if (getMaxWaitMillis() != null) { - this.pool.setMaxWait(getMaxWaitMillis()); - } - if (this.jdbcInterceptors != null) { - this.pool.setJdbcInterceptors(this.jdbcInterceptors); - } - return this.pool; - } - - @PreDestroy - public void close() { - if (this.pool != null) { - this.pool.close(); - } - } - - public void setJdbcInterceptors(String jdbcInterceptors) { - this.jdbcInterceptors = jdbcInterceptors; - } - - public void setValidationInterval(long validationInterval) { - this.validationInterval = validationInterval; - } -} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/CommonsDataSourceConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/CommonsDataSourceConfigurationTests.java index 2cdb7457320..a94fe4841a5 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/CommonsDataSourceConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/CommonsDataSourceConfigurationTests.java @@ -21,8 +21,12 @@ import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.pool.impl.GenericObjectPool; import org.junit.Test; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -83,4 +87,16 @@ public class CommonsDataSourceConfigurationTests { assertEquals(GenericObjectPool.DEFAULT_MAX_WAIT, ds.getMaxWait()); } + @Configuration + @EnableConfigurationProperties + protected static class CommonsDataSourceConfiguration { + + @Bean + @ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX) + public DataSource dataSource() { + return DataSourceFactory.create().type(BasicDataSource.class).build(); + } + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java index 885aa73cd3d..108d80d43dc 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java @@ -23,8 +23,6 @@ import java.sql.Driver; import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; -import java.util.HashMap; -import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.logging.Logger; @@ -32,15 +30,16 @@ import java.util.logging.Logger; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.MapPropertySource; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; @@ -64,11 +63,17 @@ public class DataSourceAutoConfigurationTests { @Before public void init() { + EmbeddedDatabaseConnection.override = null; EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.initialize:false", "spring.datasource.url:jdbc:hsqldb:mem:testdb-" + new Random().nextInt()); } + @After + public void restore() { + EmbeddedDatabaseConnection.override = null; + } + @Test public void testDefaultDataSourceExists() throws Exception { this.context.register(DataSourceAutoConfiguration.class, @@ -78,7 +83,36 @@ public class DataSourceAutoConfigurationTests { } @Test - public void testTomcatIsFallback() throws Exception { + public void testDataSourceUrlHasEmbeddedDefault() throws Exception { + this.context.register(DataSourceAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + org.apache.tomcat.jdbc.pool.DataSource dataSource = this.context + .getBean(org.apache.tomcat.jdbc.pool.DataSource.class); + assertNotNull(dataSource.getUrl()); + assertNotNull(dataSource.getDriverClassName()); + } + + @Test(expected = BeanCreationException.class) + public void testBadUrl() throws Exception { + EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE; + this.context.register(DataSourceAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + assertNotNull(this.context.getBean(DataSource.class)); + } + + @Test(expected = BeanCreationException.class) + public void testBadDriverClass() throws Exception { + EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE; + this.context.register(DataSourceAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + assertNotNull(this.context.getBean(DataSource.class)); + } + + @Test + public void testHikariIsFallback() throws Exception { EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.driverClassName:org.hsqldb.jdbcDriver", "spring.datasource.url:jdbc:hsqldb:mem:testdb"); @@ -194,11 +228,12 @@ public class DataSourceAutoConfigurationTests { public void testDataSourceInitializedWithExplicitScript() throws Exception { this.context.register(DataSourceAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); - Map map = new HashMap(); - map.put(DataSourceAutoConfiguration.CONFIGURATION_PREFIX + ".schema", - ClassUtils.addResourcePathToPackagePath(getClass(), "schema.sql")); - this.context.getEnvironment().getPropertySources() - .addFirst(new MapPropertySource("test", map)); + EnvironmentTestUtils.addEnvironment( + this.context, + "spring.datasource.initialize:true", + "spring.datasource.schema:" + + ClassUtils.addResourcePathToPackagePath(getClass(), + "schema.sql")); this.context.refresh(); DataSource dataSource = this.context.getBean(DataSource.class); assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfigurationTests.java index 6593a8b46b9..7afe94aec9a 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/HikariDataSourceConfigurationTests.java @@ -22,10 +22,12 @@ import javax.sql.DataSource; import org.junit.After; import org.junit.Test; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.util.ReflectionUtils; import com.zaxxer.hikari.HikariDataSource; @@ -61,8 +63,8 @@ public class HikariDataSourceConfigurationTests { public void testDataSourcePropertiesOverridden() throws Exception { this.context.register(HikariDataSourceConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, PREFIX - + "url:jdbc:foo//bar/spam"); - EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "maxWait:1234"); + + "jdbcUrl:jdbc:foo//bar/spam"); + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "maxLifetime:1234"); this.context.refresh(); HikariDataSource ds = this.context.getBean(HikariDataSource.class); assertEquals("jdbc:foo//bar/spam", ds.getJdbcUrl()); @@ -74,11 +76,11 @@ public class HikariDataSourceConfigurationTests { public void testDataSourceGenericPropertiesOverridden() throws Exception { this.context.register(HikariDataSourceConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, PREFIX - + "hikari.databaseName:foo", PREFIX - + "dataSourceClassName:org.h2.JDBCDataSource"); + + "dataSourceProperties.dataSourceClassName:org.h2.JDBCDataSource"); this.context.refresh(); HikariDataSource ds = this.context.getBean(HikariDataSource.class); - assertEquals("foo", ds.getDataSourceProperties().getProperty("databaseName")); + assertEquals("org.h2.JDBCDataSource", + ds.getDataSourceProperties().getProperty("dataSourceClassName")); } @Test @@ -89,28 +91,23 @@ public class HikariDataSourceConfigurationTests { assertEquals(1800000, ds.getMaxLifetime()); } - @Test(expected = BeanCreationException.class) - public void testBadUrl() throws Exception { - EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE; - this.context.register(HikariDataSourceConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - this.context.refresh(); - assertNotNull(this.context.getBean(DataSource.class)); - } - - @Test(expected = BeanCreationException.class) - public void testBadDriverClass() throws Exception { - EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE; - this.context.register(HikariDataSourceConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - this.context.refresh(); - assertNotNull(this.context.getBean(DataSource.class)); - } - @SuppressWarnings("unchecked") public static T getField(Class target, String name) { Field field = ReflectionUtils.findField(target, name, null); ReflectionUtils.makeAccessible(field); return (T) ReflectionUtils.getField(field, target); } + + @Configuration + @EnableConfigurationProperties + protected static class HikariDataSourceConfiguration { + + @Bean + @ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX) + public DataSource dataSource() { + return DataSourceFactory.create().type(HikariDataSource.class).build(); + } + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/TomcatDataSourceConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/TomcatDataSourceConfigurationTests.java index 720bf3e240c..5820a20cc32 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/TomcatDataSourceConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/TomcatDataSourceConfigurationTests.java @@ -24,11 +24,14 @@ import org.apache.tomcat.jdbc.pool.DataSourceProxy; import org.apache.tomcat.jdbc.pool.PoolProperties; import org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport; import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.util.ReflectionUtils; import static org.junit.Assert.assertEquals; @@ -47,6 +50,11 @@ public class TomcatDataSourceConfigurationTests { private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + @Before + public void init() { + EnvironmentTestUtils.addEnvironment(this.context, PREFIX + "initialize:false"); + } + @After public void restore() { EmbeddedDatabaseConnection.override = null; @@ -115,28 +123,24 @@ public class TomcatDataSourceConfigurationTests { assertEquals(30000L, ds.getValidationInterval()); } - @Test(expected = BeanCreationException.class) - public void testBadUrl() throws Exception { - EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE; - this.context.register(TomcatDataSourceConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - this.context.refresh(); - assertNotNull(this.context.getBean(DataSource.class)); - } - - @Test(expected = BeanCreationException.class) - public void testBadDriverClass() throws Exception { - EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE; - this.context.register(TomcatDataSourceConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - this.context.refresh(); - assertNotNull(this.context.getBean(DataSource.class)); - } - @SuppressWarnings("unchecked") public static T getField(Class target, String name) { Field field = ReflectionUtils.findField(target, name, null); ReflectionUtils.makeAccessible(field); return (T) ReflectionUtils.getField(field, target); } + + @Configuration + @Import(DataSourceAutoConfiguration.class) + protected static class TomcatDataSourceConfiguration { + + @Bean + @ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX) + public DataSource dataSource() { + return DataSourceFactory.create() + .type(org.apache.tomcat.jdbc.pool.DataSource.class).build(); + } + + } + } diff --git a/spring-boot-samples/spring-boot-sample-actuator/build.gradle b/spring-boot-samples/spring-boot-sample-actuator/build.gradle index 451a4964b8b..1402d417fd1 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/build.gradle +++ b/spring-boot-samples/spring-boot-sample-actuator/build.gradle @@ -40,9 +40,11 @@ dependencies { } compile("org.springframework.boot:spring-boot-starter-actuator") + compile("org.springframework.boot:spring-boot-starter-jdbc") compile("org.springframework.boot:spring-boot-starter-security") compile("org.springframework.boot:spring-boot-starter-web") - + compile("com.h2database:h2") + testCompile("org.springframework.boot:spring-boot-starter-test") insecure configurations.runtime diff --git a/spring-boot-samples/spring-boot-sample-actuator/pom.xml b/spring-boot-samples/spring-boot-sample-actuator/pom.xml index 224106f0098..1f4fb2c63d8 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/pom.xml +++ b/spring-boot-samples/spring-boot-sample-actuator/pom.xml @@ -31,6 +31,10 @@ org.springframework.boot spring-boot-starter-security + + org.springframework.boot + spring-boot-starter-jdbc + org.springframework.boot spring-boot-starter-remote-shell @@ -39,6 +43,10 @@ org.hibernate hibernate-validator + + com.h2database + h2 + org.springframework.boot spring-boot-starter-test diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java index 3301d768a81..c81c2a27f77 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java @@ -32,6 +32,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Integration tests for endpoints configuration. @@ -66,7 +67,6 @@ public class EndpointsPropertiesSampleActuatorApplicationTests { ResponseEntity entity = new TestRestTemplate().getForEntity( "http://localhost:" + this.port + "/admin/health", String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - String body = entity.getBody(); - assertEquals("{\"status\":\"ok\"}", body); + assertTrue("Wrong body: " + entity.getBody(), entity.getBody().contains("\"status\":\"ok\"")); } } diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementAddressActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementAddressActuatorApplicationTests.java index 0c76153f2c8..43e1f63f4b4 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementAddressActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementAddressActuatorApplicationTests.java @@ -33,6 +33,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Integration tests for separate management and main service ports. @@ -71,7 +72,7 @@ public class ManagementAddressActuatorApplicationTests { "http://localhost:" + this.managementPort + "/admin/health", String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals("{\"status\":\"ok\"}", entity.getBody()); + assertTrue("Wrong body: " + entity.getBody(), entity.getBody().contains("\"status\":\"ok\"")); } } diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortSampleActuatorApplicationTests.java index fa70671af6d..0fec046a4d8 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortSampleActuatorApplicationTests.java @@ -33,6 +33,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Integration tests for separate management and main service ports. @@ -80,7 +81,7 @@ public class ManagementPortSampleActuatorApplicationTests { ResponseEntity entity = new TestRestTemplate().getForEntity( "http://localhost:" + this.managementPort + "/health", String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals("{\"status\":\"ok\"}", entity.getBody()); + assertTrue("Wrong body: " + entity.getBody(), entity.getBody().contains("\"status\":\"ok\"")); } @Test diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java index 89f61049e16..32ba32ffbe9 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java @@ -130,7 +130,7 @@ public class SampleActuatorApplicationTests { ResponseEntity entity = new TestRestTemplate().getForEntity( "http://localhost:" + this.port + "/health", String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals("{\"status\":\"ok\"}", entity.getBody()); + assertTrue("Wrong body: " + entity.getBody(), entity.getBody().contains("\"status\":\"ok\"")); } @Test