diff --git a/doma-spring-boot-autoconfigure/pom.xml b/doma-spring-boot-autoconfigure/pom.xml index 1f6c4add..de48f93a 100644 --- a/doma-spring-boot-autoconfigure/pom.xml +++ b/doma-spring-boot-autoconfigure/pom.xml @@ -61,6 +61,11 @@ h2 test + + org.postgresql + postgresql + test + com.zaxxer HikariCP diff --git a/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaAutoConfiguration.java b/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaAutoConfiguration.java index 2c567531..0b79333b 100644 --- a/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaAutoConfiguration.java +++ b/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaAutoConfiguration.java @@ -39,6 +39,7 @@ import org.seasar.doma.jdbc.dialect.StandardDialect; import org.seasar.doma.jdbc.statistic.DefaultStatisticManager; import org.seasar.doma.jdbc.statistic.StatisticManager; +import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -47,11 +48,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; @@ -76,39 +77,41 @@ public class DomaAutoConfiguration { @Bean @ConditionalOnMissingBean - public Dialect dialect(Environment environment) { + public Dialect dialect(ObjectProvider connectionDetailsProvider) { DialectType dialectType = domaProperties.getDialect(); if (dialectType != null) { return dialectType.create(); } - String url = environment.getProperty("spring.datasource.url"); - if (url != null) { - DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(url); - switch (databaseDriver) { - case DB2: - return new Db2Dialect(); - case H2: - return new H2Dialect(); - case HSQLDB: - return new HsqldbDialect(); - case SQLSERVER: - case JTDS: - return new MssqlDialect(); - case MYSQL: - return new MysqlDialect(); - case ORACLE: - return new OracleDialect(); - case POSTGRESQL: - return new PostgresDialect(); - case SQLITE: - return new SqliteDialect(); - default: - break; - } + JdbcConnectionDetails connectionDetails = connectionDetailsProvider.getIfAvailable(); + if (connectionDetails == null) { + throw new BeanCreationException( + "No connection details available. You will probably have to set 'doma.dialect' explicitly."); + } + DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(connectionDetails.getJdbcUrl()); + switch (databaseDriver) { + case DB2: + return new Db2Dialect(); + case H2: + return new H2Dialect(); + case HSQLDB: + return new HsqldbDialect(); + case SQLSERVER: + case JTDS: + return new MssqlDialect(); + case MYSQL: + return new MysqlDialect(); + case ORACLE: + return new OracleDialect(); + case POSTGRESQL: + return new PostgresDialect(); + case SQLITE: + return new SqliteDialect(); + default: + break; } if (logger.isWarnEnabled()) { logger.warn( - "StandardDialect was selected because no explicit configuration and it is not possible to guess from 'spring.datasource.url property'"); + "StandardDialect was selected because no explicit configuration and it is not possible to guess from the connection details."); } return new StandardDialect(); } diff --git a/doma-spring-boot-autoconfigure/src/test/java/org/seasar/doma/boot/autoconfigure/DomaAutoConfigurationTest.java b/doma-spring-boot-autoconfigure/src/test/java/org/seasar/doma/boot/autoconfigure/DomaAutoConfigurationTest.java index d4105423..b5b068b0 100644 --- a/doma-spring-boot-autoconfigure/src/test/java/org/seasar/doma/boot/autoconfigure/DomaAutoConfigurationTest.java +++ b/doma-spring-boot-autoconfigure/src/test/java/org/seasar/doma/boot/autoconfigure/DomaAutoConfigurationTest.java @@ -1,5 +1,6 @@ package org.seasar.doma.boot.autoconfigure; +import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; @@ -7,6 +8,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; @@ -49,15 +51,16 @@ import org.seasar.doma.jdbc.criteria.NativeSql; import org.seasar.doma.jdbc.criteria.QueryDsl; import org.seasar.doma.jdbc.dialect.Dialect; -import org.seasar.doma.jdbc.dialect.H2Dialect; import org.seasar.doma.jdbc.dialect.MysqlDialect; import org.seasar.doma.jdbc.dialect.PostgresDialect; import org.seasar.doma.jdbc.dialect.StandardDialect; import org.seasar.doma.jdbc.statistic.DefaultStatisticManager; import org.seasar.doma.jdbc.statistic.StatisticManager; import org.seasar.doma.message.Message; +import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; @@ -69,6 +72,7 @@ import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.QueryTimeoutException; import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.jdbc.datasource.SimpleDriverDataSource; import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; public class DomaAutoConfigurationTest { @@ -263,11 +267,71 @@ public void testDialectByDataSourceUrl() { MutablePropertySources sources = context.getEnvironment() .getPropertySources(); sources.addFirst(new MapPropertySource("test", - Collections.singletonMap("spring.datasource.url", "jdbc:h2:mem:example"))); + Map.of("spring.datasource.url", "jdbc:postgresql://localhost:1234/example", + "doma.exception-translation-enabled", + "false" /* prevent database connections */))); this.context.register(DomaAutoConfiguration.class, DataSourceAutoConfiguration.class); this.context.refresh(); Dialect dialect = this.context.getBean(Dialect.class); - assertThat(dialect, is(instanceOf(H2Dialect.class))); + assertThat(dialect, is(instanceOf(PostgresDialect.class))); + } + + @Test + public void testDialectByJdbConnectionDetails() { + MutablePropertySources sources = context.getEnvironment() + .getPropertySources(); + sources.addFirst(new MapPropertySource("test", + Map.of("doma.exception-translation-enabled", + "false"/* prevent database connections */))); + this.context.register(DomaAutoConfiguration.class, DataSourceAutoConfiguration.class); + this.context.registerBean(JdbcConnectionDetails.class, () -> new JdbcConnectionDetails() { + @Override + public String getUsername() { + return "dummy"; + } + + @Override + public String getPassword() { + return "dummy"; + } + + @Override + public String getJdbcUrl() { + return "jdbc:postgresql://localhost:1234/example"; + } + }); + this.context.refresh(); + Dialect dialect = this.context.getBean(Dialect.class); + assertThat(dialect, is(instanceOf(PostgresDialect.class))); + } + + @Test + public void testDialectMissingJdbConnectionDetails() { + MutablePropertySources sources = context.getEnvironment() + .getPropertySources(); + sources.addFirst(new MapPropertySource("test", + Map.of("doma.exception-translation-enabled", + "false"/* prevent database connections */))); + this.context.register(DomaAutoConfiguration.class, DataSourceAutoConfiguration.class); + this.context.registerBean(DataSource.class, SimpleDriverDataSource::new); + BeanCreationException exception = assertThrows(BeanCreationException.class, + () -> this.context.refresh()); + assertThat(exception.getMessage(), containsString( + "No connection details available. You will probably have to set 'doma.dialect' explicitly.")); + } + + @Test + public void testDialectMissingJdbConnectionDetailsExplicitDialect() { + MutablePropertySources sources = context.getEnvironment() + .getPropertySources(); + sources.addFirst(new MapPropertySource("test", + Map.of("doma.dialect", "POSTGRES", "doma.exception-translation-enabled", + "false"/* prevent database connections */))); + this.context.register(DomaAutoConfiguration.class, DataSourceAutoConfiguration.class); + this.context.registerBean(DataSource.class, SimpleDriverDataSource::new); + this.context.refresh(); + Dialect dialect = this.context.getBean(Dialect.class); + assertThat(dialect, is(instanceOf(PostgresDialect.class))); } @Test