From 37d2cd624873a49cefc8dc544e011943c55bc372 Mon Sep 17 00:00:00 2001 From: Toshiaki Maki Date: Fri, 25 Apr 2025 11:41:06 +0900 Subject: [PATCH 1/3] Use JdbcConnectionDetails to detect Dialect instead of Environment closes gh-286 --- doma-spring-boot-autoconfigure/pom.xml | 5 +++ .../autoconfigure/DomaAutoConfiguration.java | 7 ++-- .../DomaAutoConfigurationTest.java | 39 +++++++++++++++++-- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/doma-spring-boot-autoconfigure/pom.xml b/doma-spring-boot-autoconfigure/pom.xml index 1f6c4ad..de48f93 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 2c56753..6796a00 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,7 +39,6 @@ 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.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -47,11 +46,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,12 +75,12 @@ public class DomaAutoConfiguration { @Bean @ConditionalOnMissingBean - public Dialect dialect(Environment environment) { + public Dialect dialect(JdbcConnectionDetails connectionDetails) { DialectType dialectType = domaProperties.getDialect(); if (dialectType != null) { return dialectType.create(); } - String url = environment.getProperty("spring.datasource.url"); + String url = connectionDetails.getJdbcUrl(); if (url != null) { DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(url); switch (databaseDriver) { 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 d410542..53d7067 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 @@ -49,7 +49,6 @@ 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; @@ -58,6 +57,7 @@ import org.seasar.doma.message.Message; 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; @@ -263,11 +263,44 @@ 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 */))); + EnvironmentTestUtils.addEnvironment(this.context, + "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 From 3c193b4986296e5eed229024093e3558e42ac4ed Mon Sep 17 00:00:00 2001 From: Toshiaki Maki Date: Fri, 25 Apr 2025 13:26:52 +0900 Subject: [PATCH 2/3] Address a case where ConnectionDetails is not generated --- .../autoconfigure/DomaAutoConfiguration.java | 56 ++++++++++--------- .../DomaAutoConfigurationTest.java | 37 +++++++++++- 2 files changed, 65 insertions(+), 28 deletions(-) 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 6796a00..0b79333 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,8 @@ 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; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -75,39 +77,41 @@ public class DomaAutoConfiguration { @Bean @ConditionalOnMissingBean - public Dialect dialect(JdbcConnectionDetails connectionDetails) { + public Dialect dialect(ObjectProvider connectionDetailsProvider) { DialectType dialectType = domaProperties.getDialect(); if (dialectType != null) { return dialectType.create(); } - String url = connectionDetails.getJdbcUrl(); - 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 53d7067..c96e87e 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; @@ -55,6 +57,7 @@ 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; @@ -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 { @@ -279,8 +283,6 @@ public void testDialectByJdbConnectionDetails() { sources.addFirst(new MapPropertySource("test", Map.of("doma.exception-translation-enabled", "false"/* prevent database connections */))); - EnvironmentTestUtils.addEnvironment(this.context, - "doma.exception-translation-enabled:false"); // Prevent database connections this.context.register(DomaAutoConfiguration.class, DataSourceAutoConfiguration.class); this.context.registerBean(JdbcConnectionDetails.class, () -> new JdbcConnectionDetails() { @Override @@ -303,6 +305,37 @@ public String getJdbcUrl() { 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.")); + //Dialect dialect = this.context.getBean(Dialect.class); + //assertThat(dialect, is(instanceOf(PostgresDialect.class))); + } + + @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 public void testDialectByDomaPropertiesIgnoreDataSourceUrl() { MutablePropertySources sources = context.getEnvironment() From 675534708583b553e327e3326e19d9e505a9818e Mon Sep 17 00:00:00 2001 From: Toshiaki Maki Date: Fri, 25 Apr 2025 13:30:01 +0900 Subject: [PATCH 3/3] Clean up --- .../doma/boot/autoconfigure/DomaAutoConfigurationTest.java | 2 -- 1 file changed, 2 deletions(-) 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 c96e87e..b5b068b 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 @@ -318,8 +318,6 @@ public void testDialectMissingJdbConnectionDetails() { () -> this.context.refresh()); assertThat(exception.getMessage(), containsString( "No connection details available. You will probably have to set 'doma.dialect' explicitly.")); - //Dialect dialect = this.context.getBean(Dialect.class); - //assertThat(dialect, is(instanceOf(PostgresDialect.class))); } @Test