diff --git a/.gitignore b/.gitignore index 663c85de..bf86c194 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ target .settings .factorypath .apt_generated +.vscode/ \ No newline at end of file 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 f8b1411c..2c567531 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 @@ -1,19 +1,29 @@ package org.seasar.doma.boot.autoconfigure; +import java.util.Optional; +import java.util.function.Predicate; + import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.seasar.doma.boot.DomaPersistenceExceptionTranslator; +import org.seasar.doma.boot.DomaSpringBootSqlBuilderSettings; +import org.seasar.doma.boot.ResourceLoaderScriptFileLoader; import org.seasar.doma.boot.TryLookupEntityListenerProvider; import org.seasar.doma.boot.autoconfigure.DomaProperties.DialectType; import org.seasar.doma.boot.event.DomaEventEntityListener; import org.seasar.doma.boot.event.DomaEventListenerFactory; import org.seasar.doma.jdbc.Config; +import org.seasar.doma.jdbc.ConfigSupport; +import org.seasar.doma.jdbc.DuplicateColumnHandler; import org.seasar.doma.jdbc.EntityListenerProvider; import org.seasar.doma.jdbc.JdbcLogger; import org.seasar.doma.jdbc.Naming; +import org.seasar.doma.jdbc.ScriptFileLoader; +import org.seasar.doma.jdbc.SqlBuilderSettings; import org.seasar.doma.jdbc.SqlFileRepository; +import org.seasar.doma.jdbc.ThrowingDuplicateColumnHandler; import org.seasar.doma.jdbc.criteria.Entityql; import org.seasar.doma.jdbc.criteria.NativeSql; import org.seasar.doma.jdbc.criteria.QueryDsl; @@ -27,7 +37,11 @@ import org.seasar.doma.jdbc.dialect.PostgresDialect; import org.seasar.doma.jdbc.dialect.SqliteDialect; 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; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -38,6 +52,7 @@ 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; @@ -99,8 +114,7 @@ public Dialect dialect(Environment environment) { } @Bean - @ConditionalOnProperty(prefix = DomaProperties.DOMA_PREFIX, name = "exception-translation-enabled", - matchIfMissing = true) + @ConditionalOnProperty(prefix = DomaProperties.DOMA_PREFIX, name = "exception-translation-enabled", matchIfMissing = true) public PersistenceExceptionTranslator exceptionTranslator(Config config) { return new DomaPersistenceExceptionTranslator( new SQLErrorCodeSQLExceptionTranslator(config.getDataSource())); @@ -141,6 +155,44 @@ public EntityListenerProvider tryLookupEntityListenerProvider() { return new TryLookupEntityListenerProvider(); } + @Bean + @ConditionalOnMissingBean + public DuplicateColumnHandler duplicateColumnHandler() { + if (domaProperties.isThrowExceptionIfDuplicateColumn()) { + return new ThrowingDuplicateColumnHandler(); + } + return ConfigSupport.defaultDuplicateColumnHandler; + } + + @Bean + @ConditionalOnMissingBean + public ScriptFileLoader scriptFileLoader(ResourceLoader resourceLoader) { + return new ResourceLoaderScriptFileLoader(resourceLoader); + } + + @Bean + @ConditionalOnMissingBean + public SqlBuilderSettings sqlBuilderSettings( + @Qualifier("shouldRemoveBlockComment") Optional> shouldRemoveBlockCommentOpt, + @Qualifier("shouldRemoveLineComment") Optional> shouldRemoveLineCommentOpt) { + Predicate shouldRemoveBlockComment = shouldRemoveBlockCommentOpt + .orElseGet(() -> comment -> false); + Predicate shouldRemoveLineComment = shouldRemoveLineCommentOpt + .orElseGet(() -> comment -> false); + boolean shouldRemoveBlankLines = domaProperties.getSqlBuilderSettings() + .isShouldRemoveBlankLines(); + boolean shouldRequireInListPadding = domaProperties.getSqlBuilderSettings() + .isShouldRequireInListPadding(); + return new DomaSpringBootSqlBuilderSettings(shouldRemoveBlockComment, + shouldRemoveLineComment, shouldRemoveBlankLines, shouldRequireInListPadding); + } + + @Bean + @ConditionalOnMissingBean + public StatisticManager statisticManager() { + return new DefaultStatisticManager(domaProperties.getStatisticManager().isEnabled()); + } + @Bean @ConditionalOnMissingBean public DomaConfigBuilder domaConfigBuilder() { @@ -152,7 +204,9 @@ public DomaConfigBuilder domaConfigBuilder() { public DomaConfig config(DataSource dataSource, Dialect dialect, SqlFileRepository sqlFileRepository, Naming naming, JdbcLogger jdbcLogger, EntityListenerProvider entityListenerProvider, - DomaConfigBuilder domaConfigBuilder) { + DomaConfigBuilder domaConfigBuilder, DuplicateColumnHandler duplicateColumnHandler, + ScriptFileLoader scriptFileLoader, SqlBuilderSettings sqlBuilderSettings, + StatisticManager statisticManager) { if (domaConfigBuilder.dataSource() == null) { domaConfigBuilder.dataSource(dataSource); } @@ -171,6 +225,18 @@ public DomaConfig config(DataSource dataSource, Dialect dialect, if (domaConfigBuilder.entityListenerProvider() == null) { domaConfigBuilder.entityListenerProvider(entityListenerProvider); } + if (domaConfigBuilder.duplicateColumnHandler() == null) { + domaConfigBuilder.duplicateColumnHandler(duplicateColumnHandler); + } + if (domaConfigBuilder.scriptFileLoader() == null) { + domaConfigBuilder.scriptFileLoader(scriptFileLoader); + } + if (domaConfigBuilder.sqlBuilderSettings() == null) { + domaConfigBuilder.sqlBuilderSettings(sqlBuilderSettings); + } + if (domaConfigBuilder.statisticManager() == null) { + domaConfigBuilder.statisticManager(statisticManager); + } return domaConfigBuilder.build(); } diff --git a/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaConfig.java b/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaConfig.java index 1c049ecc..ad0dedd2 100644 --- a/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaConfig.java +++ b/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaConfig.java @@ -4,6 +4,7 @@ import org.seasar.doma.jdbc.*; import org.seasar.doma.jdbc.dialect.Dialect; +import org.seasar.doma.jdbc.statistic.StatisticManager; /** * {@link Config} implementation used in doma-spring-boot. @@ -26,6 +27,10 @@ public class DomaConfig implements Config { private final Commenter commenter; private final EntityListenerProvider entityListenerProvider; private final DomaProperties domaProperties; + private final DuplicateColumnHandler duplicateColumnHandler; + private final ScriptFileLoader scriptFileLoader; + private final SqlBuilderSettings sqlBuilderSettings; + private final StatisticManager statisticManager; public DomaConfig(DomaConfigBuilder builder, DomaProperties domaProperties) { this.dataSource = builder.dataSource(); @@ -41,6 +46,10 @@ public DomaConfig(DomaConfigBuilder builder, DomaProperties domaProperties) { this.mapKeyNaming = builder.mapKeyNaming(); this.commenter = builder.commenter(); this.entityListenerProvider = builder.entityListenerProvider(); + this.duplicateColumnHandler = builder.duplicateColumnHandler(); + this.scriptFileLoader = builder.scriptFileLoader(); + this.sqlBuilderSettings = builder.sqlBuilderSettings(); + this.statisticManager = builder.statisticManager(); this.domaProperties = domaProperties; } @@ -140,15 +149,22 @@ public EntityListenerProvider getEntityListenerProvider() { } @Override - public String toString() { - return "DomaConfig{" + "dataSource=" + dataSource + ", dialect=" + dialect - + ", jdbcLogger=" + jdbcLogger + ", sqlFileRepository=" - + sqlFileRepository + ", requiresNewController=" + requiresNewController - + ", classHelper=" + classHelper + ", commandImplementors=" - + commandImplementors + ", queryImplementors=" + queryImplementors - + ", unknownColumnHandler=" + unknownColumnHandler + ", naming=" + naming - + ", mapKeyNaming=" + mapKeyNaming + ", commenter=" + commenter - + ", entityListenerProvider=" + entityListenerProvider - + ", domaProperties=" + domaProperties + '}'; + public DuplicateColumnHandler getDuplicateColumnHandler() { + return this.duplicateColumnHandler; + } + + @Override + public ScriptFileLoader getScriptFileLoader() { + return this.scriptFileLoader; + } + + @Override + public SqlBuilderSettings getSqlBuilderSettings() { + return this.sqlBuilderSettings; + } + + @Override + public StatisticManager getStatisticManager() { + return this.statisticManager; } } diff --git a/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaConfigBuilder.java b/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaConfigBuilder.java index 9f5c86fb..ced71c3e 100644 --- a/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaConfigBuilder.java +++ b/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaConfigBuilder.java @@ -6,6 +6,7 @@ import org.seasar.doma.jdbc.*; import org.seasar.doma.jdbc.dialect.Dialect; +import org.seasar.doma.jdbc.statistic.StatisticManager; import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; /** @@ -40,6 +41,10 @@ public class DomaConfigBuilder { private MapKeyNaming mapKeyNaming = ConfigSupport.defaultMapKeyNaming; private Commenter commenter = ConfigSupport.defaultCommenter; private EntityListenerProvider entityListenerProvider; + private DuplicateColumnHandler duplicateColumnHandler; + private ScriptFileLoader scriptFileLoader; + private SqlBuilderSettings sqlBuilderSettings; + private StatisticManager statisticManager; public DomaConfigBuilder(DomaProperties domaProperties) { this.domaProperties = Objects.requireNonNull(domaProperties); @@ -174,6 +179,42 @@ public DomaConfigBuilder entityListenerProvider( return this; } + public DuplicateColumnHandler duplicateColumnHandler() { + return duplicateColumnHandler; + } + + public DomaConfigBuilder duplicateColumnHandler(DuplicateColumnHandler duplicateColumnHandler) { + this.duplicateColumnHandler = duplicateColumnHandler; + return this; + } + + public ScriptFileLoader scriptFileLoader() { + return scriptFileLoader; + } + + public DomaConfigBuilder scriptFileLoader(ScriptFileLoader scriptFileLoader) { + this.scriptFileLoader = scriptFileLoader; + return this; + } + + public SqlBuilderSettings sqlBuilderSettings() { + return sqlBuilderSettings; + } + + public DomaConfigBuilder sqlBuilderSettings(SqlBuilderSettings sqlBuilderSettings) { + this.sqlBuilderSettings = sqlBuilderSettings; + return this; + } + + public StatisticManager statisticManager() { + return statisticManager; + } + + public DomaConfigBuilder statisticManager(StatisticManager statisticManager) { + this.statisticManager = statisticManager; + return this; + } + public DomaConfig build() { return new DomaConfig(this, domaProperties); } diff --git a/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaProperties.java b/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaProperties.java index 36273151..396e340c 100644 --- a/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaProperties.java +++ b/doma-spring-boot-autoconfigure/src/main/java/org/seasar/doma/boot/autoconfigure/DomaProperties.java @@ -97,6 +97,21 @@ public class DomaProperties { */ private int batchSize = 0; + /** + * Properties for org.seasar.doma.jdbc.SqlBuilderSettings. + */ + private SqlBuilderSettings sqlBuilderSettings = new SqlBuilderSettings(); + + /** + * Whether to throw an exception when duplicate columns are detected. + */ + private boolean throwExceptionIfDuplicateColumn = false; + + /** + * Properties for org.seasar.doma.jdbc.statistic.DefaultStatisticManager. + */ + private StatisticManager statisticManager = new StatisticManager(); + public DialectType getDialect() { return dialect; } @@ -185,6 +200,30 @@ public void setBatchSize(int batchSize) { this.batchSize = batchSize; } + public SqlBuilderSettings getSqlBuilderSettings() { + return sqlBuilderSettings; + } + + public void setSqlBuilderSettings(SqlBuilderSettings sqlBuilderSettings) { + this.sqlBuilderSettings = sqlBuilderSettings; + } + + public boolean isThrowExceptionIfDuplicateColumn() { + return throwExceptionIfDuplicateColumn; + } + + public void setThrowExceptionIfDuplicateColumn(boolean throwExceptionIfDuplicateColumn) { + this.throwExceptionIfDuplicateColumn = throwExceptionIfDuplicateColumn; + } + + public StatisticManager getStatisticManager() { + return statisticManager; + } + + public void setStatisticManager(StatisticManager statisticManager) { + this.statisticManager = statisticManager; + } + public DomaConfigBuilder initializeDomaConfigBuilder() { return new DomaConfigBuilder(this).dialect(dialect.create()) .sqlFileRepository(sqlFileRepository.create()).naming(naming.naming()); @@ -267,7 +306,9 @@ private static JdbcLogger slf4jJdbcLogger() { return (JdbcLogger) Class.forName("org.seasar.doma.jdbc.Slf4jJdbcLogger") .getConstructor().newInstance(); } catch (ReflectiveOperationException roe) { - logger.warn("org.seasar.doma.jdbc.Slf4jJdbcLogger could not be instantiated either.", roe); + logger.warn( + "org.seasar.doma.jdbc.Slf4jJdbcLogger could not be instantiated either.", + roe); } throw e; } @@ -284,15 +325,45 @@ public JdbcLogger create() { } } - @Override - public String toString() { - return "DomaProperties{" + "dialect=" + dialect + ", sqlFileRepository=" - + sqlFileRepository + ", naming=" + naming - + ", exceptionTranslationEnabled=" + exceptionTranslationEnabled - + ", dataSourceName='" + dataSourceName + '\'' + ", exceptionSqlLogType=" - + exceptionSqlLogType + ", jdbcLogger=" - + jdbcLogger + ", maxRows=" + maxRows + ", fetchSize=" - + fetchSize + ", queryTimeout=" + queryTimeout + ", batchSize=" - + batchSize + '}'; + public static class SqlBuilderSettings { + + /** + * Whether the blank lines should be removed. + */ + private boolean shouldRemoveBlankLines = false; + + /** + * Whether padding is required for elements in an "IN" list in SQL queries. + */ + private boolean shouldRequireInListPadding = false; + + public boolean isShouldRemoveBlankLines() { + return shouldRemoveBlankLines; + } + + public void setShouldRemoveBlankLines(boolean shouldRemoveBlankLines) { + this.shouldRemoveBlankLines = shouldRemoveBlankLines; + } + + public boolean isShouldRequireInListPadding() { + return shouldRequireInListPadding; + } + + public void setShouldRequireInListPadding(boolean shouldRequireInListPadding) { + this.shouldRequireInListPadding = shouldRequireInListPadding; + } + } + + public static class StatisticManager { + + private boolean enabled = false; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } } } 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 85b8ecaa..d4105423 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 @@ -5,13 +5,23 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; 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.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import java.sql.SQLException; import java.sql.SQLTimeoutException; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; import javax.sql.DataSource; @@ -19,14 +29,21 @@ import org.junit.Before; import org.junit.Test; import org.seasar.doma.boot.DomaPersistenceExceptionTranslator; +import org.seasar.doma.boot.DomaSpringBootSqlBuilderSettings; +import org.seasar.doma.boot.ResourceLoaderScriptFileLoader; import org.seasar.doma.jdbc.Config; +import org.seasar.doma.jdbc.ConfigSupport; +import org.seasar.doma.jdbc.DuplicateColumnHandler; import org.seasar.doma.jdbc.EntityListenerProvider; import org.seasar.doma.jdbc.GreedyCacheSqlFileRepository; import org.seasar.doma.jdbc.JdbcException; import org.seasar.doma.jdbc.JdbcLogger; import org.seasar.doma.jdbc.Naming; import org.seasar.doma.jdbc.NoCacheSqlFileRepository; +import org.seasar.doma.jdbc.ScriptFileLoader; +import org.seasar.doma.jdbc.SqlBuilderSettings; import org.seasar.doma.jdbc.SqlFileRepository; +import org.seasar.doma.jdbc.ThrowingDuplicateColumnHandler; import org.seasar.doma.jdbc.UtilLoggingJdbcLogger; import org.seasar.doma.jdbc.criteria.Entityql; import org.seasar.doma.jdbc.criteria.NativeSql; @@ -36,6 +53,8 @@ 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.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @@ -75,6 +94,13 @@ public void testAutoRegisteredConfig() { assertThat(config.getNaming(), is(Naming.DEFAULT)); assertThat(config.getJdbcLogger(), is(instanceOf(UtilLoggingJdbcLogger.class))); assertThat(config.getEntityListenerProvider(), is(notNullValue())); + assertThat(config.getDuplicateColumnHandler(), + is(ConfigSupport.defaultDuplicateColumnHandler)); + assertThat(config.getScriptFileLoader(), + is(instanceOf(ResourceLoaderScriptFileLoader.class))); + assertThat(config.getSqlBuilderSettings(), + is(instanceOf(DomaSpringBootSqlBuilderSettings.class))); + assertThat(config.getStatisticManager(), is(instanceOf(DefaultStatisticManager.class))); PersistenceExceptionTranslator translator = this.context .getBean(PersistenceExceptionTranslator.class); assertThat(translator, is(instanceOf(DomaPersistenceExceptionTranslator.class))); @@ -96,6 +122,12 @@ public void testConfigWithDomaConfigBuilder() { assertThat(config.getJdbcLogger(), is(instanceOf(UtilLoggingJdbcLogger.class))); assertThat(config.getEntityListenerProvider(), is(instanceOf(TestEntityListenerProvider.class))); + assertThat(config.getDuplicateColumnHandler(), + is(ConfigBuilderConfigure.testDuplicateColumnHandler)); + assertThat(config.getScriptFileLoader(), is(ConfigBuilderConfigure.testScriptFileLoader)); + assertThat(config.getSqlBuilderSettings(), + is(ConfigBuilderConfigure.testSqlBuilderSettings)); + assertThat(config.getStatisticManager(), is(ConfigBuilderConfigure.testStatisticManager)); PersistenceExceptionTranslator translator = this.context .getBean(PersistenceExceptionTranslator.class); assertThat(translator, is(instanceOf(DomaPersistenceExceptionTranslator.class))); @@ -117,6 +149,12 @@ public void testConfigWithConfig() { assertThat(config.getJdbcLogger(), is(instanceOf(UtilLoggingJdbcLogger.class))); assertThat(config.getEntityListenerProvider(), is(instanceOf(TestEntityListenerProvider.class))); + assertThat(config.getDuplicateColumnHandler(), + is(ConfigConfigure.testDuplicateColumnHandler)); + assertThat(config.getScriptFileLoader(), is(ConfigConfigure.testScriptFileLoader)); + assertThat(config.getSqlBuilderSettings(), + is(ConfigConfigure.testSqlBuilderSettings)); + assertThat(config.getStatisticManager(), is(ConfigConfigure.testStatisticManager)); PersistenceExceptionTranslator translator = this.context .getBean(PersistenceExceptionTranslator.class); assertThat(translator, is(instanceOf(DomaPersistenceExceptionTranslator.class))); @@ -277,6 +315,123 @@ public void testQueryDslWithConfig() { assertNotNull(queryDslBeans.get("myQueryDsl")); } + @Test + public void testThrowExceptionIfDuplicateColumn() { + EnvironmentTestUtils.addEnvironment(this.context, + "doma.throw-exception-if-duplicate-column:true"); + this.context.register(DomaAutoConfiguration.class, DataSourceAutoConfiguration.class); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + assertThat(config.getDuplicateColumnHandler(), + is(instanceOf(ThrowingDuplicateColumnHandler.class))); + } + + @Test + public void testCustomizeShouldRemoveBlockComment() { + Predicate predicate = mock(Predicate.class); + when(predicate.test(anyString())).thenReturn(true); + + this.context.register(DomaAutoConfiguration.class, DataSourceAutoConfiguration.class); + this.context.registerBean("shouldRemoveBlockComment", Predicate.class, () -> predicate); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + config.getSqlBuilderSettings().shouldRemoveBlockComment("shouldRemoveBlockComment"); + config.getSqlBuilderSettings().shouldRemoveLineComment("shouldRemoveLineComment"); + + verify(predicate, times(1)).test("shouldRemoveBlockComment"); + verifyNoMoreInteractions(predicate); + } + + @Test + public void testCustomizeShouldRemoveLineComment() { + Predicate predicate = mock(Predicate.class); + when(predicate.test(anyString())).thenReturn(true); + + this.context.register(DomaAutoConfiguration.class, DataSourceAutoConfiguration.class); + this.context.registerBean("shouldRemoveLineComment", Predicate.class, () -> predicate); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + config.getSqlBuilderSettings().shouldRemoveBlockComment("shouldRemoveBlockComment"); + config.getSqlBuilderSettings().shouldRemoveLineComment("shouldRemoveLineComment"); + + verify(predicate, times(1)).test("shouldRemoveLineComment"); + verifyNoMoreInteractions(predicate); + } + + @Test + public void testAnonymousPredicateAreNotAffected() { + Predicate predicate = mock(Predicate.class); + when(predicate.test(anyString())).thenReturn(true); + + this.context.register(DomaAutoConfiguration.class, DataSourceAutoConfiguration.class); + this.context.registerBean(Predicate.class, () -> predicate); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + config.getSqlBuilderSettings().shouldRemoveBlockComment("shouldRemoveBlockComment"); + config.getSqlBuilderSettings().shouldRemoveLineComment("shouldRemoveLineComment"); + + verifyNoInteractions(predicate); + } + + @Test + public void testShouldRemoveBlankLinesDefaultValue() { + this.context.register(DomaAutoConfiguration.class, + DataSourceAutoConfiguration.class); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + assertFalse(config.getSqlBuilderSettings().shouldRemoveBlankLines()); + } + + @Test + public void testShouldRemoveBlankLinesChangedValue() { + EnvironmentTestUtils.addEnvironment(this.context, + "doma.sql-builder-settings.should-remove-blank-lines:true"); + this.context.register(DomaAutoConfiguration.class, + DataSourceAutoConfiguration.class); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + assertTrue(config.getSqlBuilderSettings().shouldRemoveBlankLines()); + } + + @Test + public void testShouldRequireInListPaddingDefaultValue() { + this.context.register(DomaAutoConfiguration.class, + DataSourceAutoConfiguration.class); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + assertFalse(config.getSqlBuilderSettings().shouldRequireInListPadding()); + } + + @Test + public void testShouldRequireInListPaddingChangedValue() { + EnvironmentTestUtils.addEnvironment(this.context, + "doma.sql-builder-settings.should-require-in-list-padding:true"); + this.context.register(DomaAutoConfiguration.class, + DataSourceAutoConfiguration.class); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + assertTrue(config.getSqlBuilderSettings().shouldRequireInListPadding()); + } + + @Test + public void testStatisticManagerDefaultValue() { + this.context.register(DomaAutoConfiguration.class, + DataSourceAutoConfiguration.class); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + assertFalse(config.getStatisticManager().isEnabled()); + } + + @Test + public void testStatisticManagerChangedValue() { + EnvironmentTestUtils.addEnvironment(this.context, "doma.statistic-manager.enabled:true"); + this.context.register(DomaAutoConfiguration.class, + DataSourceAutoConfiguration.class); + this.context.refresh(); + Config config = this.context.getBean(Config.class); + assertTrue(config.getStatisticManager().isEnabled()); + } + @After public void tearDown() { if (this.context != null) { @@ -286,18 +441,38 @@ public void tearDown() { @Configuration public static class ConfigBuilderConfigure { + static DuplicateColumnHandler testDuplicateColumnHandler = new DuplicateColumnHandler() { + }; + static ScriptFileLoader testScriptFileLoader = new ScriptFileLoader() { + }; + static SqlBuilderSettings testSqlBuilderSettings = new SqlBuilderSettings() { + }; + static StatisticManager testStatisticManager = new DefaultStatisticManager(); + @Bean DomaConfigBuilder myDomaConfigBuilder(DomaProperties domaProperties) { return new DomaConfigBuilder(domaProperties).dialect(new MysqlDialect()) .sqlFileRepository(new NoCacheSqlFileRepository()) .jdbcLogger(new UtilLoggingJdbcLogger()) .naming(Naming.SNAKE_UPPER_CASE) - .entityListenerProvider(new TestEntityListenerProvider()); + .entityListenerProvider(new TestEntityListenerProvider()) + .duplicateColumnHandler(testDuplicateColumnHandler) + .scriptFileLoader(testScriptFileLoader) + .sqlBuilderSettings(testSqlBuilderSettings) + .statisticManager(testStatisticManager); } } @Configuration public static class ConfigConfigure { + static DuplicateColumnHandler testDuplicateColumnHandler = new DuplicateColumnHandler() { + }; + static ScriptFileLoader testScriptFileLoader = new ScriptFileLoader() { + }; + static SqlBuilderSettings testSqlBuilderSettings = new SqlBuilderSettings() { + }; + static StatisticManager testStatisticManager = new DefaultStatisticManager(); + @Bean Config myConfig(DataSource dataSource) { return new Config() { @@ -330,6 +505,26 @@ public JdbcLogger getJdbcLogger() { public EntityListenerProvider getEntityListenerProvider() { return new TestEntityListenerProvider(); } + + @Override + public DuplicateColumnHandler getDuplicateColumnHandler() { + return testDuplicateColumnHandler; + } + + @Override + public ScriptFileLoader getScriptFileLoader() { + return testScriptFileLoader; + } + + @Override + public SqlBuilderSettings getSqlBuilderSettings() { + return testSqlBuilderSettings; + } + + @Override + public StatisticManager getStatisticManager() { + return testStatisticManager; + } }; } } diff --git a/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/DomaSpringBootSqlBuilderSettings.java b/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/DomaSpringBootSqlBuilderSettings.java new file mode 100644 index 00000000..6453e130 --- /dev/null +++ b/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/DomaSpringBootSqlBuilderSettings.java @@ -0,0 +1,42 @@ +package org.seasar.doma.boot; + +import java.util.function.Predicate; + +import org.seasar.doma.jdbc.SqlBuilderSettings; + +public class DomaSpringBootSqlBuilderSettings implements SqlBuilderSettings { + + private final Predicate shouldRemoveBlockComment; + private final Predicate shouldRemoveLineComment; + private final boolean shouldRemoveBlankLines; + private final boolean shouldRequireInListPadding; + + public DomaSpringBootSqlBuilderSettings(Predicate shouldRemoveBlockComment, + Predicate shouldRemoveLineComment, boolean shouldRemoveBlankLines, + boolean shouldRequireInListPadding) { + this.shouldRemoveBlockComment = shouldRemoveBlockComment; + this.shouldRemoveLineComment = shouldRemoveLineComment; + this.shouldRemoveBlankLines = shouldRemoveBlankLines; + this.shouldRequireInListPadding = shouldRequireInListPadding; + } + + @Override + public boolean shouldRemoveBlockComment(String comment) { + return shouldRemoveBlockComment.test(comment); + } + + @Override + public boolean shouldRemoveLineComment(String comment) { + return shouldRemoveLineComment.test(comment); + } + + @Override + public boolean shouldRemoveBlankLines() { + return shouldRemoveBlankLines; + } + + @Override + public boolean shouldRequireInListPadding() { + return shouldRequireInListPadding; + } +} diff --git a/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/ResourceLoaderScriptFileLoader.java b/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/ResourceLoaderScriptFileLoader.java new file mode 100644 index 00000000..1e1cd17c --- /dev/null +++ b/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/ResourceLoaderScriptFileLoader.java @@ -0,0 +1,34 @@ +package org.seasar.doma.boot; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URL; + +import org.seasar.doma.jdbc.ScriptFileLoader; +import org.springframework.core.io.ResourceLoader; + +public class ResourceLoaderScriptFileLoader implements ScriptFileLoader { + + private final ResourceLoader resourceLoader; + + public ResourceLoaderScriptFileLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + @Override + public URL loadAsURL(String path) { + try { + var resource = resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + path); + if (resource.exists()) { + return resource.getURL(); + } + resource = resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + "/" + path); + if (resource.exists()) { + return resource.getURL(); + } + return null; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/TryLookupEntityListenerProvider.java b/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/TryLookupEntityListenerProvider.java index d74b1fe8..7835e5a2 100644 --- a/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/TryLookupEntityListenerProvider.java +++ b/doma-spring-boot-core/src/main/java/org/seasar/doma/boot/TryLookupEntityListenerProvider.java @@ -12,7 +12,7 @@ /** * {@link EntityListenerProvider} implementation that {@link EntityListener} managed by * Spring Framework, or else created by Doma. - * + * * @author backpaper0 * */ diff --git a/doma-spring-boot-core/src/test/java/org/seasar/doma/boot/ResourceLoaderScriptFileLoaderTest.java b/doma-spring-boot-core/src/test/java/org/seasar/doma/boot/ResourceLoaderScriptFileLoaderTest.java new file mode 100644 index 00000000..cbf65865 --- /dev/null +++ b/doma-spring-boot-core/src/test/java/org/seasar/doma/boot/ResourceLoaderScriptFileLoaderTest.java @@ -0,0 +1,70 @@ +package org.seasar.doma.boot; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.net.URL; + +import org.junit.jupiter.api.Test; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; + +public class ResourceLoaderScriptFileLoaderTest { + + @Test + void testLoadAsURL() throws Exception { + var location = "META-INF/com/example/dao/TestDao/test.script"; + var expectedURL = new URL("file:///" + location); + var resourceLoader = mock(ResourceLoader.class); + var resource = mock(Resource.class); + + when(resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + location)) + .thenReturn(resource); + when(resource.exists()).thenReturn(true); + when(resource.getURL()).thenReturn(expectedURL); + + var sut = new ResourceLoaderScriptFileLoader(resourceLoader); + var actualURL = sut.loadAsURL(location); + assertEquals(expectedURL, actualURL); + } + + @Test + void testLoadAsURLFallback() throws Exception { + var location = "META-INF/com/example/dao/TestDao/test.script"; + var expectedURL = new URL("file:///" + location); + var resourceLoader = mock(ResourceLoader.class); + var resource = mock(Resource.class); + var notExistsResource = mock(Resource.class); + + when(resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + location)) + .thenReturn(notExistsResource); + when(resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + "/" + location)) + .thenReturn(resource); + when(notExistsResource.exists()).thenReturn(false); + when(resource.exists()).thenReturn(true); + when(resource.getURL()).thenReturn(expectedURL); + + var sut = new ResourceLoaderScriptFileLoader(resourceLoader); + var actualURL = sut.loadAsURL(location); + assertEquals(expectedURL, actualURL); + } + + @Test + void testLoadAsURLScriptNotFound() { + var location = "META-INF/com/example/dao/TestDao/test.script"; + var resourceLoader = mock(ResourceLoader.class); + var notExistsResource = mock(Resource.class); + + when(resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + location)) + .thenReturn(notExistsResource); + when(resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + "/" + location)) + .thenReturn(notExistsResource); + when(notExistsResource.exists()).thenReturn(false); + + var sut = new ResourceLoaderScriptFileLoader(resourceLoader); + var actualURL = sut.loadAsURL(location); + assertNull(actualURL); + } +} diff --git a/doma-spring-boot-samples/doma-spring-boot-sample-two-datasource/src/main/java/org/seasar/doma/boot/sample/configuration/DataSourceConfiguration.java b/doma-spring-boot-samples/doma-spring-boot-sample-two-datasource/src/main/java/org/seasar/doma/boot/sample/configuration/DataSourceConfiguration.java index 97ab7617..5eb62501 100644 --- a/doma-spring-boot-samples/doma-spring-boot-sample-two-datasource/src/main/java/org/seasar/doma/boot/sample/configuration/DataSourceConfiguration.java +++ b/doma-spring-boot-samples/doma-spring-boot-sample-two-datasource/src/main/java/org/seasar/doma/boot/sample/configuration/DataSourceConfiguration.java @@ -67,7 +67,8 @@ public SqlDataSourceScriptDatabaseInitializer dataSourceInitializer(DataSource d @Secondary @Bean - public SqlDataSourceScriptDatabaseInitializer secondaryDataSourceInitializer(@Secondary DataSource dataSource, + public SqlDataSourceScriptDatabaseInitializer secondaryDataSourceInitializer( + @Secondary DataSource dataSource, @Secondary SqlInitializationProperties properties) { return new SqlDataSourceScriptDatabaseInitializer(dataSource, properties); } diff --git a/doma-spring-boot-samples/doma-spring-boot-sample-two-datasource/src/main/java/org/seasar/doma/boot/sample/configuration/DomaConfiguration.java b/doma-spring-boot-samples/doma-spring-boot-sample-two-datasource/src/main/java/org/seasar/doma/boot/sample/configuration/DomaConfiguration.java index 905519ac..77253c21 100644 --- a/doma-spring-boot-samples/doma-spring-boot-sample-two-datasource/src/main/java/org/seasar/doma/boot/sample/configuration/DomaConfiguration.java +++ b/doma-spring-boot-samples/doma-spring-boot-sample-two-datasource/src/main/java/org/seasar/doma/boot/sample/configuration/DomaConfiguration.java @@ -6,8 +6,12 @@ import org.seasar.doma.boot.autoconfigure.DomaProperties; import org.seasar.doma.boot.sample.annotation.Secondary; import org.seasar.doma.jdbc.Config; +import org.seasar.doma.jdbc.DuplicateColumnHandler; import org.seasar.doma.jdbc.EntityListenerProvider; import org.seasar.doma.jdbc.JdbcLogger; +import org.seasar.doma.jdbc.ScriptFileLoader; +import org.seasar.doma.jdbc.SqlBuilderSettings; +import org.seasar.doma.jdbc.statistic.StatisticManager; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -45,24 +49,35 @@ public DomaConfigBuilder secondaryDomaConfigBuilder(@Secondary DomaProperties pr @Primary @Bean public Config config(DomaConfigBuilder domaConfigBuilder, DataSource dataSource, - JdbcLogger jdbcLogger, - EntityListenerProvider entityListenerProvider) { + JdbcLogger jdbcLogger, EntityListenerProvider entityListenerProvider, + DuplicateColumnHandler duplicateColumnHandler, ScriptFileLoader scriptFileLoader, + SqlBuilderSettings sqlBuilderSettings, StatisticManager statisticManager) { return domaConfigBuilder .dataSource(dataSource) .jdbcLogger(jdbcLogger) .entityListenerProvider(entityListenerProvider) + .duplicateColumnHandler(duplicateColumnHandler) + .scriptFileLoader(scriptFileLoader) + .sqlBuilderSettings(sqlBuilderSettings) + .statisticManager(statisticManager) .build(); } @Secondary @Bean public Config secondaryConfig(@Secondary DomaConfigBuilder domaConfigBuilder, - @Secondary DataSource dataSource, - JdbcLogger jdbcLogger, EntityListenerProvider entityListenerProvider) { + @Secondary DataSource dataSource, JdbcLogger jdbcLogger, + EntityListenerProvider entityListenerProvider, + DuplicateColumnHandler duplicateColumnHandler, ScriptFileLoader scriptFileLoader, + SqlBuilderSettings sqlBuilderSettings, StatisticManager statisticManager) { return domaConfigBuilder .dataSource(dataSource) .jdbcLogger(jdbcLogger) .entityListenerProvider(entityListenerProvider) + .duplicateColumnHandler(duplicateColumnHandler) + .scriptFileLoader(scriptFileLoader) + .sqlBuilderSettings(sqlBuilderSettings) + .statisticManager(statisticManager) .build(); } } diff --git a/pom.xml b/pom.xml index 6e73d76e..ed04fe25 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ 2.24.1 2.18.0 3.2.7 - ${project.basedir} + ${env.PWD}