46 changed files with 2201 additions and 2 deletions
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import org.jooq.impl.DefaultConfiguration; |
||||
|
||||
/** |
||||
* Callback interface that can be implemented by beans wishing to customize the |
||||
* {@link DefaultConfiguration} whilst retaining default auto-configuration. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 2.5.0 |
||||
*/ |
||||
@FunctionalInterface |
||||
public interface DefaultConfigurationCustomizer { |
||||
|
||||
/** |
||||
* Customize the {@link DefaultConfiguration jOOQ Configuration}. |
||||
* @param configuration the configuration to customize |
||||
*/ |
||||
void customize(DefaultConfiguration configuration); |
||||
|
||||
} |
||||
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import org.jooq.DSLContext; |
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; |
||||
import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor; |
||||
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector; |
||||
|
||||
/** |
||||
* {@link BeanFactoryPostProcessor} that can be used to dynamically declare that all |
||||
* {@link DSLContext} beans should "depend on" one or more specific beans. |
||||
* |
||||
* @author Eddú Meléndez |
||||
* @since 2.3.9 |
||||
* @see BeanDefinition#setDependsOn(String[]) |
||||
* @deprecated since 2.5.0 for removal in 2.7.0 in favor of |
||||
* {@link DependsOnDatabaseInitializationDetector} |
||||
*/ |
||||
@Deprecated |
||||
public class DslContextDependsOnPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor { |
||||
|
||||
/** |
||||
* Creates a new {@code DslContextDependsOnPostProcessor} that will set up |
||||
* dependencies upon beans with the given names. |
||||
* @param dependsOn names of the beans to depend upon |
||||
*/ |
||||
public DslContextDependsOnPostProcessor(String... dependsOn) { |
||||
super(DSLContext.class, dependsOn); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new {@code DslContextDependsOnPostProcessor} that will set up |
||||
* dependencies upon beans with the given types. |
||||
* @param dependsOn types of the beans to depend upon |
||||
*/ |
||||
public DslContextDependsOnPostProcessor(Class<?>... dependsOn) { |
||||
super(DSLContext.class, dependsOn); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,154 @@
@@ -0,0 +1,154 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import org.jooq.ConnectionProvider; |
||||
import org.jooq.DSLContext; |
||||
import org.jooq.ExecuteListenerProvider; |
||||
import org.jooq.ExecutorProvider; |
||||
import org.jooq.RecordListenerProvider; |
||||
import org.jooq.RecordMapperProvider; |
||||
import org.jooq.RecordUnmapperProvider; |
||||
import org.jooq.TransactionListenerProvider; |
||||
import org.jooq.TransactionProvider; |
||||
import org.jooq.VisitListenerProvider; |
||||
import org.jooq.conf.Settings; |
||||
import org.jooq.impl.DataSourceConnectionProvider; |
||||
import org.jooq.impl.DefaultConfiguration; |
||||
import org.jooq.impl.DefaultDSLContext; |
||||
import org.jooq.impl.DefaultExecuteListenerProvider; |
||||
|
||||
import org.springframework.beans.factory.ObjectProvider; |
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.core.Ordered; |
||||
import org.springframework.core.annotation.Order; |
||||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; |
||||
import org.springframework.transaction.PlatformTransactionManager; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for JOOQ. |
||||
* |
||||
* @author Andreas Ahlenstorf |
||||
* @author Michael Simons |
||||
* @author Dmytro Nosan |
||||
* @since 1.3.0 |
||||
*/ |
||||
@Configuration(proxyBeanMethods = false) |
||||
@ConditionalOnClass(DSLContext.class) |
||||
@ConditionalOnBean(DataSource.class) |
||||
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class }) |
||||
public class JooqAutoConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(ConnectionProvider.class) |
||||
public DataSourceConnectionProvider dataSourceConnectionProvider(DataSource dataSource) { |
||||
return new DataSourceConnectionProvider(new TransactionAwareDataSourceProxy(dataSource)); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnBean(PlatformTransactionManager.class) |
||||
public SpringTransactionProvider transactionProvider(PlatformTransactionManager txManager) { |
||||
return new SpringTransactionProvider(txManager); |
||||
} |
||||
|
||||
@Bean |
||||
@Order(0) |
||||
public DefaultExecuteListenerProvider jooqExceptionTranslatorExecuteListenerProvider() { |
||||
return new DefaultExecuteListenerProvider(new JooqExceptionTranslator()); |
||||
} |
||||
|
||||
@Configuration(proxyBeanMethods = false) |
||||
@ConditionalOnMissingBean(DSLContext.class) |
||||
@EnableConfigurationProperties(JooqProperties.class) |
||||
public static class DslContextConfiguration { |
||||
|
||||
@Bean |
||||
public DefaultDSLContext dslContext(org.jooq.Configuration configuration) { |
||||
return new DefaultDSLContext(configuration); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(org.jooq.Configuration.class) |
||||
public DefaultConfiguration jooqConfiguration(JooqProperties properties, ConnectionProvider connectionProvider, |
||||
DataSource dataSource, ObjectProvider<ExecuteListenerProvider> executeListenerProviders, |
||||
ObjectProvider<DefaultConfigurationCustomizer> configurationCustomizers) { |
||||
DefaultConfiguration configuration = new DefaultConfiguration(); |
||||
configuration.set(properties.determineSqlDialect(dataSource)); |
||||
configuration.set(connectionProvider); |
||||
configuration.set(executeListenerProviders.orderedStream().toArray(ExecuteListenerProvider[]::new)); |
||||
configurationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(configuration)); |
||||
return configuration; |
||||
} |
||||
|
||||
@Bean |
||||
@Deprecated |
||||
public DefaultConfigurationCustomizer jooqProvidersDefaultConfigurationCustomizer( |
||||
ObjectProvider<TransactionProvider> transactionProvider, |
||||
ObjectProvider<RecordMapperProvider> recordMapperProvider, |
||||
ObjectProvider<RecordUnmapperProvider> recordUnmapperProvider, ObjectProvider<Settings> settings, |
||||
ObjectProvider<RecordListenerProvider> recordListenerProviders, |
||||
ObjectProvider<VisitListenerProvider> visitListenerProviders, |
||||
ObjectProvider<TransactionListenerProvider> transactionListenerProviders, |
||||
ObjectProvider<ExecutorProvider> executorProvider) { |
||||
return new OrderedDefaultConfigurationCustomizer((configuration) -> { |
||||
transactionProvider.ifAvailable(configuration::set); |
||||
recordMapperProvider.ifAvailable(configuration::set); |
||||
recordUnmapperProvider.ifAvailable(configuration::set); |
||||
settings.ifAvailable(configuration::set); |
||||
executorProvider.ifAvailable(configuration::set); |
||||
configuration.set(recordListenerProviders.orderedStream().toArray(RecordListenerProvider[]::new)); |
||||
configuration.set(visitListenerProviders.orderedStream().toArray(VisitListenerProvider[]::new)); |
||||
configuration.setTransactionListenerProvider( |
||||
transactionListenerProviders.orderedStream().toArray(TransactionListenerProvider[]::new)); |
||||
}); |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class OrderedDefaultConfigurationCustomizer implements DefaultConfigurationCustomizer, Ordered { |
||||
|
||||
private final DefaultConfigurationCustomizer delegate; |
||||
|
||||
OrderedDefaultConfigurationCustomizer(DefaultConfigurationCustomizer delegate) { |
||||
this.delegate = delegate; |
||||
} |
||||
|
||||
@Override |
||||
public void customize(DefaultConfiguration configuration) { |
||||
this.delegate.customize(configuration); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return 0; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,97 @@
@@ -0,0 +1,97 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import java.sql.SQLException; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.jooq.ExecuteContext; |
||||
import org.jooq.SQLDialect; |
||||
import org.jooq.impl.DefaultExecuteListener; |
||||
|
||||
import org.springframework.dao.DataAccessException; |
||||
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; |
||||
import org.springframework.jdbc.support.SQLExceptionTranslator; |
||||
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; |
||||
|
||||
/** |
||||
* Transforms {@link java.sql.SQLException} into a Spring-specific |
||||
* {@link DataAccessException}. |
||||
* |
||||
* @author Lukas Eder |
||||
* @author Andreas Ahlenstorf |
||||
* @author Phillip Webb |
||||
* @author Stephane Nicoll |
||||
* @since 1.5.10 |
||||
*/ |
||||
public class JooqExceptionTranslator extends DefaultExecuteListener { |
||||
|
||||
// Based on the jOOQ-spring-example from https://github.com/jOOQ/jOOQ
|
||||
|
||||
private static final Log logger = LogFactory.getLog(JooqExceptionTranslator.class); |
||||
|
||||
@Override |
||||
public void exception(ExecuteContext context) { |
||||
SQLExceptionTranslator translator = getTranslator(context); |
||||
// The exception() callback is not only triggered for SQL exceptions but also for
|
||||
// "normal" exceptions. In those cases sqlException() returns null.
|
||||
SQLException exception = context.sqlException(); |
||||
while (exception != null) { |
||||
handle(context, translator, exception); |
||||
exception = exception.getNextException(); |
||||
} |
||||
} |
||||
|
||||
private SQLExceptionTranslator getTranslator(ExecuteContext context) { |
||||
SQLDialect dialect = context.configuration().dialect(); |
||||
if (dialect != null && dialect.thirdParty() != null) { |
||||
String dbName = dialect.thirdParty().springDbName(); |
||||
if (dbName != null) { |
||||
return new SQLErrorCodeSQLExceptionTranslator(dbName); |
||||
} |
||||
} |
||||
return new SQLStateSQLExceptionTranslator(); |
||||
} |
||||
|
||||
/** |
||||
* Handle a single exception in the chain. SQLExceptions might be nested multiple |
||||
* levels deep. The outermost exception is usually the least interesting one ("Call |
||||
* getNextException to see the cause."). Therefore the innermost exception is |
||||
* propagated and all other exceptions are logged. |
||||
* @param context the execute context |
||||
* @param translator the exception translator |
||||
* @param exception the exception |
||||
*/ |
||||
private void handle(ExecuteContext context, SQLExceptionTranslator translator, SQLException exception) { |
||||
DataAccessException translated = translate(context, translator, exception); |
||||
if (exception.getNextException() == null) { |
||||
if (translated != null) { |
||||
context.exception(translated); |
||||
} |
||||
} |
||||
else { |
||||
logger.error("Execution of SQL statement failed.", (translated != null) ? translated : exception); |
||||
} |
||||
} |
||||
|
||||
private DataAccessException translate(ExecuteContext context, SQLExceptionTranslator translator, |
||||
SQLException exception) { |
||||
return translator.translate("jOOQ", context.sql(), exception); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import org.jooq.SQLDialect; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* Configuration properties for the JOOQ database library. |
||||
* |
||||
* @author Andreas Ahlenstorf |
||||
* @author Michael Simons |
||||
* @since 1.3.0 |
||||
*/ |
||||
@ConfigurationProperties(prefix = "spring.jooq") |
||||
public class JooqProperties { |
||||
|
||||
/** |
||||
* SQL dialect to use. Auto-detected by default. |
||||
*/ |
||||
private SQLDialect sqlDialect; |
||||
|
||||
public SQLDialect getSqlDialect() { |
||||
return this.sqlDialect; |
||||
} |
||||
|
||||
public void setSqlDialect(SQLDialect sqlDialect) { |
||||
this.sqlDialect = sqlDialect; |
||||
} |
||||
|
||||
/** |
||||
* Determine the {@link SQLDialect} to use based on this configuration and the primary |
||||
* {@link DataSource}. |
||||
* @param dataSource the data source |
||||
* @return the {@code SQLDialect} to use for that {@link DataSource} |
||||
*/ |
||||
public SQLDialect determineSqlDialect(DataSource dataSource) { |
||||
if (this.sqlDialect != null) { |
||||
return this.sqlDialect; |
||||
} |
||||
return SqlDialectLookup.getDialect(dataSource); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import org.jooq.DSLContext; |
||||
|
||||
import org.springframework.beans.BeansException; |
||||
import org.springframework.beans.factory.BeanFactory; |
||||
import org.springframework.beans.factory.BeanFactoryAware; |
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException; |
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration; |
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; |
||||
import org.springframework.boot.diagnostics.FailureAnalysis; |
||||
import org.springframework.core.Ordered; |
||||
|
||||
class NoDslContextBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBeanDefinitionException> |
||||
implements Ordered, BeanFactoryAware { |
||||
|
||||
private BeanFactory beanFactory; |
||||
|
||||
@Override |
||||
protected FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause) { |
||||
if (DSLContext.class.equals(cause.getBeanType()) && hasR2dbcAutoConfiguration()) { |
||||
return new FailureAnalysis( |
||||
"jOOQ has not been auto-configured as R2DBC has been auto-configured in favor of JDBC and jOOQ " |
||||
+ "auto-configuration does not yet support R2DBC. ", |
||||
"To use jOOQ with JDBC, exclude R2dbcAutoConfiguration. To use jOOQ with R2DBC, define your own " |
||||
+ "jOOQ configuration.", |
||||
cause); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private boolean hasR2dbcAutoConfiguration() { |
||||
try { |
||||
this.beanFactory.getBean(R2dbcAutoConfiguration.class); |
||||
return true; |
||||
} |
||||
catch (Exception ex) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { |
||||
this.beanFactory = beanFactory; |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import org.jooq.Transaction; |
||||
|
||||
import org.springframework.transaction.TransactionStatus; |
||||
|
||||
/** |
||||
* Adapts a Spring transaction for JOOQ. |
||||
* |
||||
* @author Lukas Eder |
||||
* @author Andreas Ahlenstorf |
||||
* @author Phillip Webb |
||||
*/ |
||||
class SpringTransaction implements Transaction { |
||||
|
||||
// Based on the jOOQ-spring-example from https://github.com/jOOQ/jOOQ
|
||||
|
||||
private final TransactionStatus transactionStatus; |
||||
|
||||
SpringTransaction(TransactionStatus transactionStatus) { |
||||
this.transactionStatus = transactionStatus; |
||||
} |
||||
|
||||
TransactionStatus getTxStatus() { |
||||
return this.transactionStatus; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import org.jooq.TransactionContext; |
||||
import org.jooq.TransactionProvider; |
||||
|
||||
import org.springframework.transaction.PlatformTransactionManager; |
||||
import org.springframework.transaction.TransactionDefinition; |
||||
import org.springframework.transaction.TransactionStatus; |
||||
import org.springframework.transaction.support.DefaultTransactionDefinition; |
||||
|
||||
/** |
||||
* Allows Spring Transaction to be used with JOOQ. |
||||
* |
||||
* @author Lukas Eder |
||||
* @author Andreas Ahlenstorf |
||||
* @author Phillip Webb |
||||
* @since 1.5.10 |
||||
*/ |
||||
public class SpringTransactionProvider implements TransactionProvider { |
||||
|
||||
// Based on the jOOQ-spring-example from https://github.com/jOOQ/jOOQ
|
||||
|
||||
private final PlatformTransactionManager transactionManager; |
||||
|
||||
public SpringTransactionProvider(PlatformTransactionManager transactionManager) { |
||||
this.transactionManager = transactionManager; |
||||
} |
||||
|
||||
@Override |
||||
public void begin(TransactionContext context) { |
||||
TransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_NESTED); |
||||
TransactionStatus status = this.transactionManager.getTransaction(definition); |
||||
context.transaction(new SpringTransaction(status)); |
||||
} |
||||
|
||||
@Override |
||||
public void commit(TransactionContext ctx) { |
||||
this.transactionManager.commit(getTransactionStatus(ctx)); |
||||
} |
||||
|
||||
@Override |
||||
public void rollback(TransactionContext ctx) { |
||||
this.transactionManager.rollback(getTransactionStatus(ctx)); |
||||
} |
||||
|
||||
private TransactionStatus getTransactionStatus(TransactionContext ctx) { |
||||
SpringTransaction transaction = (SpringTransaction) ctx.transaction(); |
||||
return transaction.getTxStatus(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import java.sql.DatabaseMetaData; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.jooq.SQLDialect; |
||||
import org.jooq.tools.jdbc.JDBCUtils; |
||||
|
||||
import org.springframework.jdbc.support.JdbcUtils; |
||||
import org.springframework.jdbc.support.MetaDataAccessException; |
||||
|
||||
/** |
||||
* Utility to lookup well known {@link SQLDialect SQLDialects} from a {@link DataSource}. |
||||
* |
||||
* @author Michael Simons |
||||
* @author Lukas Eder |
||||
*/ |
||||
final class SqlDialectLookup { |
||||
|
||||
private static final Log logger = LogFactory.getLog(SqlDialectLookup.class); |
||||
|
||||
private SqlDialectLookup() { |
||||
} |
||||
|
||||
/** |
||||
* Return the most suitable {@link SQLDialect} for the given {@link DataSource}. |
||||
* @param dataSource the source {@link DataSource} |
||||
* @return the most suitable {@link SQLDialect} |
||||
*/ |
||||
static SQLDialect getDialect(DataSource dataSource) { |
||||
if (dataSource == null) { |
||||
return SQLDialect.DEFAULT; |
||||
} |
||||
try { |
||||
String url = JdbcUtils.extractDatabaseMetaData(dataSource, DatabaseMetaData::getURL); |
||||
SQLDialect sqlDialect = JDBCUtils.dialect(url); |
||||
if (sqlDialect != null) { |
||||
return sqlDialect; |
||||
} |
||||
} |
||||
catch (MetaDataAccessException ex) { |
||||
logger.warn("Unable to determine jdbc url from datasource", ex); |
||||
} |
||||
return SQLDialect.DEFAULT; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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. |
||||
*/ |
||||
|
||||
/** |
||||
* Auto-configuration for JOOQ. |
||||
*/ |
||||
package org.springframework.boot.autoconfigure.jooq; |
||||
@ -0,0 +1,262 @@
@@ -0,0 +1,262 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import org.jooq.CharsetProvider; |
||||
import org.jooq.ConnectionProvider; |
||||
import org.jooq.ConverterProvider; |
||||
import org.jooq.DSLContext; |
||||
import org.jooq.ExecuteListener; |
||||
import org.jooq.ExecuteListenerProvider; |
||||
import org.jooq.ExecutorProvider; |
||||
import org.jooq.RecordListenerProvider; |
||||
import org.jooq.RecordMapperProvider; |
||||
import org.jooq.RecordUnmapperProvider; |
||||
import org.jooq.SQLDialect; |
||||
import org.jooq.TransactionListenerProvider; |
||||
import org.jooq.TransactionalRunnable; |
||||
import org.jooq.VisitListenerProvider; |
||||
import org.jooq.impl.DataSourceConnectionProvider; |
||||
import org.jooq.impl.DefaultExecuteListenerProvider; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations; |
||||
import org.springframework.boot.jdbc.DataSourceBuilder; |
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.core.annotation.Order; |
||||
import org.springframework.dao.DataIntegrityViolationException; |
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager; |
||||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; |
||||
import org.springframework.transaction.PlatformTransactionManager; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link JooqAutoConfiguration}. |
||||
* |
||||
* @author Andreas Ahlenstorf |
||||
* @author Phillip Webb |
||||
* @author Andy Wilkinson |
||||
* @author Stephane Nicoll |
||||
* @author Dmytro Nosan |
||||
*/ |
||||
class JooqAutoConfigurationTests { |
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() |
||||
.withConfiguration(AutoConfigurations.of(JooqAutoConfiguration.class)) |
||||
.withPropertyValues("spring.datasource.name:jooqtest"); |
||||
|
||||
@Test |
||||
void noDataSource() { |
||||
this.contextRunner.run((context) -> assertThat(context.getBeansOfType(DSLContext.class)).isEmpty()); |
||||
} |
||||
|
||||
@Test |
||||
void jooqWithoutTx() { |
||||
this.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class).run((context) -> { |
||||
assertThat(context).doesNotHaveBean(PlatformTransactionManager.class); |
||||
assertThat(context).doesNotHaveBean(SpringTransactionProvider.class); |
||||
DSLContext dsl = context.getBean(DSLContext.class); |
||||
dsl.execute("create table jooqtest (name varchar(255) primary key);"); |
||||
dsl.transaction(new AssertFetch(dsl, "select count(*) as total from jooqtest;", "0")); |
||||
dsl.transaction(new ExecuteSql(dsl, "insert into jooqtest (name) values ('foo');")); |
||||
dsl.transaction(new AssertFetch(dsl, "select count(*) as total from jooqtest;", "1")); |
||||
assertThatExceptionOfType(DataIntegrityViolationException.class) |
||||
.isThrownBy(() -> dsl.transaction(new ExecuteSql(dsl, "insert into jooqtest (name) values ('bar');", |
||||
"insert into jooqtest (name) values ('foo');"))); |
||||
dsl.transaction(new AssertFetch(dsl, "select count(*) as total from jooqtest;", "2")); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void jooqWithTx() { |
||||
this.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class, TxManagerConfiguration.class) |
||||
.run((context) -> { |
||||
assertThat(context).hasSingleBean(PlatformTransactionManager.class); |
||||
DSLContext dsl = context.getBean(DSLContext.class); |
||||
assertThat(dsl.configuration().dialect()).isEqualTo(SQLDialect.HSQLDB); |
||||
dsl.execute("create table jooqtest_tx (name varchar(255) primary key);"); |
||||
dsl.transaction(new AssertFetch(dsl, "select count(*) as total from jooqtest_tx;", "0")); |
||||
dsl.transaction(new ExecuteSql(dsl, "insert into jooqtest_tx (name) values ('foo');")); |
||||
dsl.transaction(new AssertFetch(dsl, "select count(*) as total from jooqtest_tx;", "1")); |
||||
assertThatExceptionOfType(DataIntegrityViolationException.class).isThrownBy( |
||||
() -> dsl.transaction(new ExecuteSql(dsl, "insert into jooqtest (name) values ('bar');", |
||||
"insert into jooqtest (name) values ('foo');"))); |
||||
dsl.transaction(new AssertFetch(dsl, "select count(*) as total from jooqtest_tx;", "1")); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void jooqWithDefaultConnectionProvider() { |
||||
this.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class).run((context) -> { |
||||
DSLContext dsl = context.getBean(DSLContext.class); |
||||
ConnectionProvider connectionProvider = dsl.configuration().connectionProvider(); |
||||
assertThat(connectionProvider).isInstanceOf(DataSourceConnectionProvider.class); |
||||
DataSource connectionProviderDataSource = ((DataSourceConnectionProvider) connectionProvider).dataSource(); |
||||
assertThat(connectionProviderDataSource).isInstanceOf(TransactionAwareDataSourceProxy.class); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void jooqWithDefaultExecuteListenerProvider() { |
||||
this.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class).run((context) -> { |
||||
DSLContext dsl = context.getBean(DSLContext.class); |
||||
assertThat(dsl.configuration().executeListenerProviders()).hasSize(1); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void jooqWithSeveralExecuteListenerProviders() { |
||||
this.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class, TestExecuteListenerProvider.class) |
||||
.run((context) -> { |
||||
DSLContext dsl = context.getBean(DSLContext.class); |
||||
ExecuteListenerProvider[] executeListenerProviders = dsl.configuration().executeListenerProviders(); |
||||
assertThat(executeListenerProviders).hasSize(2); |
||||
assertThat(executeListenerProviders[0]).isInstanceOf(DefaultExecuteListenerProvider.class); |
||||
assertThat(executeListenerProviders[1]).isInstanceOf(TestExecuteListenerProvider.class); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void dslContextWithConfigurationCustomizersAreApplied() { |
||||
ConverterProvider converterProvider = mock(ConverterProvider.class); |
||||
CharsetProvider charsetProvider = mock(CharsetProvider.class); |
||||
this.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class) |
||||
.withBean("configurationCustomizer1", DefaultConfigurationCustomizer.class, |
||||
() -> (configuration) -> configuration.set(converterProvider)) |
||||
.withBean("configurationCustomizer2", DefaultConfigurationCustomizer.class, |
||||
() -> (configuration) -> configuration.set(charsetProvider)) |
||||
.run((context) -> { |
||||
DSLContext dsl = context.getBean(DSLContext.class); |
||||
assertThat(dsl.configuration().converterProvider()).isSameAs(converterProvider); |
||||
assertThat(dsl.configuration().charsetProvider()).isSameAs(charsetProvider); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
@Deprecated |
||||
void customProvidersArePickedUp() { |
||||
RecordMapperProvider recordMapperProvider = mock(RecordMapperProvider.class); |
||||
RecordUnmapperProvider recordUnmapperProvider = mock(RecordUnmapperProvider.class); |
||||
RecordListenerProvider recordListenerProvider = mock(RecordListenerProvider.class); |
||||
VisitListenerProvider visitListenerProvider = mock(VisitListenerProvider.class); |
||||
TransactionListenerProvider transactionListenerProvider = mock(TransactionListenerProvider.class); |
||||
ExecutorProvider executorProvider = mock(ExecutorProvider.class); |
||||
this.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class, TxManagerConfiguration.class) |
||||
.withBean(RecordMapperProvider.class, () -> recordMapperProvider) |
||||
.withBean(RecordUnmapperProvider.class, () -> recordUnmapperProvider) |
||||
.withBean(RecordListenerProvider.class, () -> recordListenerProvider) |
||||
.withBean(VisitListenerProvider.class, () -> visitListenerProvider) |
||||
.withBean(TransactionListenerProvider.class, () -> transactionListenerProvider) |
||||
.withBean(ExecutorProvider.class, () -> executorProvider).run((context) -> { |
||||
DSLContext dsl = context.getBean(DSLContext.class); |
||||
assertThat(dsl.configuration().recordMapperProvider()).isSameAs(recordMapperProvider); |
||||
assertThat(dsl.configuration().recordUnmapperProvider()).isSameAs(recordUnmapperProvider); |
||||
assertThat(dsl.configuration().executorProvider()).isSameAs(executorProvider); |
||||
assertThat(dsl.configuration().recordListenerProviders()).containsExactly(recordListenerProvider); |
||||
assertThat(dsl.configuration().visitListenerProviders()).containsExactly(visitListenerProvider); |
||||
assertThat(dsl.configuration().transactionListenerProviders()) |
||||
.containsExactly(transactionListenerProvider); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void relaxedBindingOfSqlDialect() { |
||||
this.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class) |
||||
.withPropertyValues("spring.jooq.sql-dialect:PoSTGrES") |
||||
.run((context) -> assertThat(context.getBean(org.jooq.Configuration.class).dialect()) |
||||
.isEqualTo(SQLDialect.POSTGRES)); |
||||
} |
||||
|
||||
static class AssertFetch implements TransactionalRunnable { |
||||
|
||||
private final DSLContext dsl; |
||||
|
||||
private final String sql; |
||||
|
||||
private final String expected; |
||||
|
||||
AssertFetch(DSLContext dsl, String sql, String expected) { |
||||
this.dsl = dsl; |
||||
this.sql = sql; |
||||
this.expected = expected; |
||||
} |
||||
|
||||
@Override |
||||
public void run(org.jooq.Configuration configuration) { |
||||
assertThat(this.dsl.fetch(this.sql).getValue(0, 0).toString()).isEqualTo(this.expected); |
||||
} |
||||
|
||||
} |
||||
|
||||
static class ExecuteSql implements TransactionalRunnable { |
||||
|
||||
private final DSLContext dsl; |
||||
|
||||
private final String[] sql; |
||||
|
||||
ExecuteSql(DSLContext dsl, String... sql) { |
||||
this.dsl = dsl; |
||||
this.sql = sql; |
||||
} |
||||
|
||||
@Override |
||||
public void run(org.jooq.Configuration configuration) { |
||||
for (String statement : this.sql) { |
||||
this.dsl.execute(statement); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration(proxyBeanMethods = false) |
||||
static class JooqDataSourceConfiguration { |
||||
|
||||
@Bean |
||||
DataSource jooqDataSource() { |
||||
return DataSourceBuilder.create().url("jdbc:hsqldb:mem:jooqtest").username("sa").build(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration(proxyBeanMethods = false) |
||||
static class TxManagerConfiguration { |
||||
|
||||
@Bean |
||||
PlatformTransactionManager transactionManager(DataSource dataSource) { |
||||
return new DataSourceTransactionManager(dataSource); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Order(100) |
||||
static class TestExecuteListenerProvider implements ExecuteListenerProvider { |
||||
|
||||
@Override |
||||
public ExecuteListener provide() { |
||||
return null; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import java.sql.SQLException; |
||||
|
||||
import org.jooq.Configuration; |
||||
import org.jooq.ExecuteContext; |
||||
import org.jooq.SQLDialect; |
||||
import org.junit.jupiter.api.Test; |
||||
import org.junit.jupiter.params.ParameterizedTest; |
||||
import org.junit.jupiter.params.provider.MethodSource; |
||||
import org.mockito.ArgumentCaptor; |
||||
|
||||
import org.springframework.jdbc.BadSqlGrammarException; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.BDDMockito.given; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.times; |
||||
import static org.mockito.Mockito.verify; |
||||
|
||||
/** |
||||
* Tests for {@link JooqExceptionTranslator} |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
class JooqExceptionTranslatorTests { |
||||
|
||||
private final JooqExceptionTranslator exceptionTranslator = new JooqExceptionTranslator(); |
||||
|
||||
@ParameterizedTest(name = "{0}") |
||||
@MethodSource |
||||
void exceptionTranslation(SQLDialect dialect, SQLException sqlException) { |
||||
ExecuteContext context = mock(ExecuteContext.class); |
||||
Configuration configuration = mock(Configuration.class); |
||||
given(context.configuration()).willReturn(configuration); |
||||
given(configuration.dialect()).willReturn(dialect); |
||||
given(context.sqlException()).willReturn(sqlException); |
||||
this.exceptionTranslator.exception(context); |
||||
ArgumentCaptor<RuntimeException> captor = ArgumentCaptor.forClass(RuntimeException.class); |
||||
verify(context).exception(captor.capture()); |
||||
assertThat(captor.getValue()).isInstanceOf(BadSqlGrammarException.class); |
||||
} |
||||
|
||||
@Test |
||||
void whenExceptionCannotBeTranslatedThenExecuteContextExceptionIsNotCalled() { |
||||
ExecuteContext context = mock(ExecuteContext.class); |
||||
Configuration configuration = mock(Configuration.class); |
||||
given(context.configuration()).willReturn(configuration); |
||||
given(configuration.dialect()).willReturn(SQLDialect.POSTGRES); |
||||
given(context.sqlException()).willReturn(new SQLException(null, null, 123456789)); |
||||
this.exceptionTranslator.exception(context); |
||||
verify(context, times(0)).exception(any()); |
||||
} |
||||
|
||||
static Object[] exceptionTranslation() { |
||||
return new Object[] { new Object[] { SQLDialect.DERBY, sqlException("42802") }, |
||||
new Object[] { SQLDialect.H2, sqlException(42000) }, |
||||
new Object[] { SQLDialect.HSQLDB, sqlException(-22) }, |
||||
new Object[] { SQLDialect.MARIADB, sqlException(1054) }, |
||||
new Object[] { SQLDialect.MYSQL, sqlException(1054) }, |
||||
new Object[] { SQLDialect.POSTGRES, sqlException("03000") }, |
||||
new Object[] { SQLDialect.SQLITE, sqlException("21000") } }; |
||||
} |
||||
|
||||
private static SQLException sqlException(String sqlState) { |
||||
return new SQLException(null, sqlState); |
||||
} |
||||
|
||||
private static SQLException sqlException(int vendorCode) { |
||||
return new SQLException(null, null, vendorCode); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,122 @@
@@ -0,0 +1,122 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import java.sql.Connection; |
||||
import java.sql.DatabaseMetaData; |
||||
import java.sql.SQLException; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import org.jooq.SQLDialect; |
||||
import org.junit.jupiter.api.AfterEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.boot.test.util.TestPropertyValues; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.BDDMockito.given; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.never; |
||||
import static org.mockito.Mockito.verify; |
||||
|
||||
/** |
||||
* Tests for {@link JooqProperties}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class JooqPropertiesTests { |
||||
|
||||
private AnnotationConfigApplicationContext context; |
||||
|
||||
@AfterEach |
||||
void close() { |
||||
if (this.context != null) { |
||||
this.context.close(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
void determineSqlDialectNoCheckIfDialectIsSet() throws SQLException { |
||||
JooqProperties properties = load("spring.jooq.sql-dialect=postgres"); |
||||
DataSource dataSource = mockStandaloneDataSource(); |
||||
SQLDialect sqlDialect = properties.determineSqlDialect(dataSource); |
||||
assertThat(sqlDialect).isEqualTo(SQLDialect.POSTGRES); |
||||
verify(dataSource, never()).getConnection(); |
||||
} |
||||
|
||||
@Test |
||||
void determineSqlDialectWithKnownUrl() { |
||||
JooqProperties properties = load(); |
||||
SQLDialect sqlDialect = properties.determineSqlDialect(mockDataSource("jdbc:h2:mem:testdb")); |
||||
assertThat(sqlDialect).isEqualTo(SQLDialect.H2); |
||||
} |
||||
|
||||
@Test |
||||
void determineSqlDialectWithKnownUrlAndUserConfig() { |
||||
JooqProperties properties = load("spring.jooq.sql-dialect=mysql"); |
||||
SQLDialect sqlDialect = properties.determineSqlDialect(mockDataSource("jdbc:h2:mem:testdb")); |
||||
assertThat(sqlDialect).isEqualTo(SQLDialect.MYSQL); |
||||
} |
||||
|
||||
@Test |
||||
void determineSqlDialectWithUnknownUrl() { |
||||
JooqProperties properties = load(); |
||||
SQLDialect sqlDialect = properties.determineSqlDialect(mockDataSource("jdbc:unknown://localhost")); |
||||
assertThat(sqlDialect).isEqualTo(SQLDialect.DEFAULT); |
||||
} |
||||
|
||||
private DataSource mockStandaloneDataSource() throws SQLException { |
||||
DataSource ds = mock(DataSource.class); |
||||
given(ds.getConnection()).willThrow(SQLException.class); |
||||
return ds; |
||||
} |
||||
|
||||
private DataSource mockDataSource(String jdbcUrl) { |
||||
DataSource ds = mock(DataSource.class); |
||||
try { |
||||
DatabaseMetaData metadata = mock(DatabaseMetaData.class); |
||||
given(metadata.getURL()).willReturn(jdbcUrl); |
||||
Connection connection = mock(Connection.class); |
||||
given(connection.getMetaData()).willReturn(metadata); |
||||
given(ds.getConnection()).willReturn(connection); |
||||
} |
||||
catch (SQLException ex) { |
||||
// Do nothing
|
||||
} |
||||
return ds; |
||||
} |
||||
|
||||
private JooqProperties load(String... environment) { |
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); |
||||
TestPropertyValues.of(environment).applyTo(ctx); |
||||
ctx.register(TestConfiguration.class); |
||||
ctx.refresh(); |
||||
this.context = ctx; |
||||
return this.context.getBean(JooqProperties.class); |
||||
} |
||||
|
||||
@Configuration(proxyBeanMethods = false) |
||||
@EnableConfigurationProperties(JooqProperties.class) |
||||
static class TestConfiguration { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import org.jooq.DSLContext; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException; |
||||
import org.springframework.boot.autoconfigure.AutoConfigurations; |
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration; |
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link NoDslContextBeanFailureAnalyzer}. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
class NoDslContextBeanFailureAnalyzerTests { |
||||
|
||||
private final NoDslContextBeanFailureAnalyzer failureAnalyzer = new NoDslContextBeanFailureAnalyzer(); |
||||
|
||||
@Test |
||||
void noAnalysisWithoutR2dbcAutoConfiguration() { |
||||
new ApplicationContextRunner().run((context) -> { |
||||
this.failureAnalyzer.setBeanFactory(context.getBeanFactory()); |
||||
assertThat(this.failureAnalyzer.analyze(new NoSuchBeanDefinitionException(DSLContext.class))).isNull(); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void analysisWithR2dbcAutoConfiguration() { |
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class)) |
||||
.run((context) -> { |
||||
this.failureAnalyzer.setBeanFactory(context.getBeanFactory()); |
||||
assertThat(this.failureAnalyzer.analyze(new NoSuchBeanDefinitionException(DSLContext.class))) |
||||
.isNotNull(); |
||||
}); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import java.sql.Connection; |
||||
import java.sql.DatabaseMetaData; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import org.jooq.SQLDialect; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.BDDMockito.given; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link SqlDialectLookup}. |
||||
* |
||||
* @author Michael Simons |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class SqlDialectLookupTests { |
||||
|
||||
@Test |
||||
void getSqlDialectWhenDataSourceIsNullShouldReturnDefault() { |
||||
assertThat(SqlDialectLookup.getDialect(null)).isEqualTo(SQLDialect.DEFAULT); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenDataSourceIsUnknownShouldReturnDefault() throws Exception { |
||||
testGetSqlDialect("jdbc:idontexist:", SQLDialect.DEFAULT); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenDerbyShouldReturnDerby() throws Exception { |
||||
testGetSqlDialect("jdbc:derby:", SQLDialect.DERBY); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenH2ShouldReturnH2() throws Exception { |
||||
testGetSqlDialect("jdbc:h2:", SQLDialect.H2); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenHsqldbShouldReturnHsqldb() throws Exception { |
||||
testGetSqlDialect("jdbc:hsqldb:", SQLDialect.HSQLDB); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenMysqlShouldReturnMysql() throws Exception { |
||||
testGetSqlDialect("jdbc:mysql:", SQLDialect.MYSQL); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenOracleShouldReturnDefault() throws Exception { |
||||
testGetSqlDialect("jdbc:oracle:", SQLDialect.DEFAULT); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenPostgresShouldReturnPostgres() throws Exception { |
||||
testGetSqlDialect("jdbc:postgresql:", SQLDialect.POSTGRES); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenSqlserverShouldReturnDefault() throws Exception { |
||||
testGetSqlDialect("jdbc:sqlserver:", SQLDialect.DEFAULT); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenDb2ShouldReturnDefault() throws Exception { |
||||
testGetSqlDialect("jdbc:db2:", SQLDialect.DEFAULT); |
||||
} |
||||
|
||||
@Test |
||||
void getSqlDialectWhenInformixShouldReturnDefault() throws Exception { |
||||
testGetSqlDialect("jdbc:informix-sqli:", SQLDialect.DEFAULT); |
||||
} |
||||
|
||||
private void testGetSqlDialect(String url, SQLDialect expected) throws Exception { |
||||
DataSource dataSource = mock(DataSource.class); |
||||
Connection connection = mock(Connection.class); |
||||
DatabaseMetaData metaData = mock(DatabaseMetaData.class); |
||||
given(dataSource.getConnection()).willReturn(connection); |
||||
given(connection.getMetaData()).willReturn(metaData); |
||||
given(metaData.getURL()).willReturn(url); |
||||
SQLDialect sqlDialect = SqlDialectLookup.getDialect(dataSource); |
||||
assertThat(sqlDialect).isEqualTo(expected); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,46 @@
@@ -0,0 +1,46 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.docs.data.sql.jooq.dslcontext; |
||||
|
||||
import java.util.GregorianCalendar; |
||||
import java.util.List; |
||||
|
||||
import org.jooq.DSLContext; |
||||
|
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import static org.springframework.boot.docs.data.sql.jooq.dslcontext.Tables.AUTHOR; |
||||
|
||||
@Component |
||||
public class MyBean { |
||||
|
||||
private final DSLContext create; |
||||
|
||||
public MyBean(DSLContext dslContext) { |
||||
this.create = dslContext; |
||||
} |
||||
|
||||
// tag::method[]
|
||||
public List<GregorianCalendar> authorsBornAfter1980() { |
||||
// @formatter:off
|
||||
return this.create.selectFrom(AUTHOR) |
||||
.where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1))) |
||||
.fetch(AUTHOR.DATE_OF_BIRTH); |
||||
// @formatter:on
|
||||
} // end::method[]
|
||||
|
||||
} |
||||
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.docs.data.sql.jooq.dslcontext; |
||||
|
||||
import java.util.GregorianCalendar; |
||||
|
||||
import org.jooq.Name; |
||||
import org.jooq.Table; |
||||
import org.jooq.TableField; |
||||
import org.jooq.impl.TableImpl; |
||||
import org.jooq.impl.TableRecordImpl; |
||||
|
||||
abstract class Tables { |
||||
|
||||
static final TAuthor AUTHOR = null; |
||||
|
||||
abstract class TAuthor extends TableImpl<TAuthorRecord> { |
||||
|
||||
TAuthor(Name name) { |
||||
super(name); |
||||
} |
||||
|
||||
public final TableField<TAuthorRecord, GregorianCalendar> DATE_OF_BIRTH = null; |
||||
|
||||
} |
||||
|
||||
abstract class TAuthorRecord extends TableRecordImpl<TAuthorRecord> { |
||||
|
||||
TAuthorRecord(Table<TAuthorRecord> table) { |
||||
super(table); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.docs.features.testing.springbootapplications.autoconfiguredjooq; |
||||
|
||||
import org.jooq.DSLContext; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.test.autoconfigure.jooq.JooqTest; |
||||
|
||||
@JooqTest |
||||
class MyJooqTests { |
||||
|
||||
@Autowired |
||||
@SuppressWarnings("unused") |
||||
private DSLContext dslContext; |
||||
|
||||
// ...
|
||||
|
||||
} |
||||
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
plugins { |
||||
id "org.springframework.boot.starter" |
||||
} |
||||
|
||||
description = "Starter for using jOOQ to access SQL databases with JDBC. An alternative to spring-boot-starter-data-jpa or spring-boot-starter-jdbc" |
||||
|
||||
dependencies { |
||||
api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-jdbc")) |
||||
api("org.springframework:spring-tx") |
||||
api("org.jooq:jooq") |
||||
} |
||||
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.jooq; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration; |
||||
|
||||
/** |
||||
* {@link ImportAutoConfiguration Auto-configuration imports} for typical jOOQ tests. Most |
||||
* tests should consider using {@link JooqTest @JooqTest} rather than using this |
||||
* annotation directly. |
||||
* |
||||
* @author Michael Simons |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
@Inherited |
||||
@ImportAutoConfiguration |
||||
public @interface AutoConfigureJooq { |
||||
|
||||
} |
||||
@ -0,0 +1,113 @@
@@ -0,0 +1,113 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.jooq; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith; |
||||
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; |
||||
import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; |
||||
import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; |
||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; |
||||
import org.springframework.context.annotation.ComponentScan.Filter; |
||||
import org.springframework.core.annotation.AliasFor; |
||||
import org.springframework.core.env.Environment; |
||||
import org.springframework.test.context.BootstrapWith; |
||||
import org.springframework.test.context.junit.jupiter.SpringExtension; |
||||
import org.springframework.transaction.annotation.Transactional; |
||||
|
||||
/** |
||||
* Annotation for a jOOQ test that focuses <strong>only</strong> on jOOQ-based components. |
||||
* <p> |
||||
* Using this annotation will disable full auto-configuration and instead apply only |
||||
* configuration relevant to jOOQ tests. |
||||
* <p> |
||||
* By default, tests annotated with {@code @JooqTest} use the configured database. If you |
||||
* want to replace any explicit or usually auto-configured DataSource by an embedded |
||||
* in-memory database, the {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} |
||||
* annotation can be used to override these settings. |
||||
* <p> |
||||
* When using JUnit 4, this annotation should be used in combination with |
||||
* {@code @RunWith(SpringRunner.class)}. |
||||
* |
||||
* @author Michael Simons |
||||
* @author Stephane Nicoll |
||||
* @author Artsiom Yudovin |
||||
* @since 2.0.0 |
||||
*/ |
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
@Inherited |
||||
@BootstrapWith(JooqTestContextBootstrapper.class) |
||||
@ExtendWith(SpringExtension.class) |
||||
@OverrideAutoConfiguration(enabled = false) |
||||
@TypeExcludeFilters(JooqTypeExcludeFilter.class) |
||||
@Transactional |
||||
@AutoConfigureCache |
||||
@AutoConfigureJooq |
||||
@ImportAutoConfiguration |
||||
public @interface JooqTest { |
||||
|
||||
/** |
||||
* Properties in form {@literal key=value} that should be added to the Spring |
||||
* {@link Environment} before the test runs. |
||||
* @return the properties to add |
||||
* @since 2.1.0 |
||||
*/ |
||||
String[] properties() default {}; |
||||
|
||||
/** |
||||
* Determines if default filtering should be used with |
||||
* {@link SpringBootApplication @SpringBootApplication}. By default no beans are |
||||
* included. |
||||
* @see #includeFilters() |
||||
* @see #excludeFilters() |
||||
* @return if default filters should be used |
||||
*/ |
||||
boolean useDefaultFilters() default true; |
||||
|
||||
/** |
||||
* A set of include filters which can be used to add otherwise filtered beans to the |
||||
* application context. |
||||
* @return include filters to apply |
||||
*/ |
||||
Filter[] includeFilters() default {}; |
||||
|
||||
/** |
||||
* A set of exclude filters which can be used to filter beans that would otherwise be |
||||
* added to the application context. |
||||
* @return exclude filters to apply |
||||
*/ |
||||
Filter[] excludeFilters() default {}; |
||||
|
||||
/** |
||||
* Auto-configuration exclusions that should be applied for this test. |
||||
* @return auto-configuration exclusions to apply |
||||
*/ |
||||
@AliasFor(annotation = ImportAutoConfiguration.class, attribute = "exclude") |
||||
Class<?>[] excludeAutoConfiguration() default {}; |
||||
|
||||
} |
||||
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.jooq; |
||||
|
||||
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; |
||||
import org.springframework.core.annotation.MergedAnnotations; |
||||
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; |
||||
import org.springframework.test.context.TestContextBootstrapper; |
||||
|
||||
/** |
||||
* {@link TestContextBootstrapper} for {@link JooqTest @JooqTest} support. |
||||
* |
||||
* @author Artsiom Yudovin |
||||
*/ |
||||
class JooqTestContextBootstrapper extends SpringBootTestContextBootstrapper { |
||||
|
||||
@Override |
||||
protected String[] getProperties(Class<?> testClass) { |
||||
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS).get(JooqTest.class) |
||||
.getValue("properties", String[].class).orElse(null); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.jooq; |
||||
|
||||
import org.springframework.boot.context.TypeExcludeFilter; |
||||
import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter; |
||||
|
||||
/** |
||||
* {@link TypeExcludeFilter} for {@link JooqTest @JooqTest}. |
||||
* |
||||
* @author Michael Simons |
||||
* @since 2.2.1 |
||||
*/ |
||||
public final class JooqTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<JooqTest> { |
||||
|
||||
JooqTypeExcludeFilter(Class<?> testClass) { |
||||
super(testClass); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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. |
||||
*/ |
||||
|
||||
/** |
||||
* Auto-configuration for jOOQ tests. |
||||
*/ |
||||
package org.springframework.boot.test.autoconfigure.jooq; |
||||
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.jooq; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; |
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; |
||||
|
||||
/** |
||||
* Example {@link SpringBootApplication @SpringBootApplication} used with |
||||
* {@link JooqTest @JooqTest} tests. |
||||
* |
||||
* @author Michael Simons |
||||
*/ |
||||
@SpringBootApplication |
||||
public class ExampleJooqApplication { |
||||
|
||||
@Bean |
||||
public DataSource dataSource() { |
||||
return new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL).build(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.jooq; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import org.jooq.DSLContext; |
||||
import org.jooq.SQLDialect; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; |
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.ExampleComponent; |
||||
import org.springframework.context.ApplicationContext; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
||||
import static org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration; |
||||
|
||||
/** |
||||
* Integration tests for {@link JooqTest @JooqTest}. |
||||
* |
||||
* @author Michael Simons |
||||
*/ |
||||
@JooqTest |
||||
class JooqTestIntegrationTests { |
||||
|
||||
@Autowired |
||||
private DSLContext dsl; |
||||
|
||||
@Autowired |
||||
private DataSource dataSource; |
||||
|
||||
@Autowired |
||||
private ApplicationContext applicationContext; |
||||
|
||||
@Test |
||||
void testDSLContext() { |
||||
assertThat(this.dsl.selectCount().from("INFORMATION_SCHEMA.TABLES").fetchOne(0, Integer.class)) |
||||
.isGreaterThan(0); |
||||
} |
||||
|
||||
@Test |
||||
void useDefinedDataSource() throws Exception { |
||||
String product = this.dataSource.getConnection().getMetaData().getDatabaseProductName(); |
||||
assertThat(product).startsWith("HSQL"); |
||||
assertThat(this.dsl.configuration().dialect()).isEqualTo(SQLDialect.HSQLDB); |
||||
} |
||||
|
||||
@Test |
||||
void didNotInjectExampleComponent() { |
||||
assertThatExceptionOfType(NoSuchBeanDefinitionException.class) |
||||
.isThrownBy(() -> this.applicationContext.getBean(ExampleComponent.class)); |
||||
} |
||||
|
||||
@Test |
||||
void flywayAutoConfigurationWasImported() { |
||||
assertThat(this.applicationContext).has(importedAutoConfiguration(FlywayAutoConfiguration.class)); |
||||
} |
||||
|
||||
@Test |
||||
void liquibaseAutoConfigurationWasImported() { |
||||
assertThat(this.applicationContext).has(importedAutoConfiguration(LiquibaseAutoConfiguration.class)); |
||||
} |
||||
|
||||
@Test |
||||
void cacheAutoConfigurationWasImported() { |
||||
assertThat(this.applicationContext).has(importedAutoConfiguration(CacheAutoConfiguration.class)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.jooq; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.core.env.Environment; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for the {@link JooqTest#properties properties} attribute of |
||||
* {@link JooqTest @JooqTest}. |
||||
* |
||||
* @author Artsiom Yudovin |
||||
*/ |
||||
@JooqTest(properties = "spring.profiles.active=test") |
||||
class JooqTestPropertiesIntegrationTests { |
||||
|
||||
@Autowired |
||||
private Environment environment; |
||||
|
||||
@Test |
||||
void environmentWithNewProfile() { |
||||
assertThat(this.environment.getActiveProfiles()).containsExactly("test"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.test.autoconfigure.jooq; |
||||
|
||||
import javax.sql.DataSource; |
||||
|
||||
import org.jooq.DSLContext; |
||||
import org.jooq.SQLDialect; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; |
||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Integration tests for {@link JooqTest @JooqTest}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
@JooqTest |
||||
@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2) |
||||
class JooqTestWithAutoConfigureTestDatabaseIntegrationTests { |
||||
|
||||
@Autowired |
||||
private DSLContext dsl; |
||||
|
||||
@Autowired |
||||
private DataSource dataSource; |
||||
|
||||
@Test |
||||
void replacesAutoConfiguredDataSource() throws Exception { |
||||
String product = this.dataSource.getConnection().getMetaData().getDatabaseProductName(); |
||||
assertThat(product).startsWith("H2"); |
||||
assertThat(this.dsl.configuration().dialect()).isEqualTo(SQLDialect.H2); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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.jooq; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.Set; |
||||
|
||||
import org.jooq.DSLContext; |
||||
|
||||
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector; |
||||
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector; |
||||
|
||||
/** |
||||
* {@link DependsOnDatabaseInitializationDetector} for jOOQ. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
class JooqDependsOnDatabaseInitializationDetector extends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector { |
||||
|
||||
@Override |
||||
protected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() { |
||||
return Collections.singleton(DSLContext.class); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 |
||||
* |
||||
* https://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. |
||||
*/ |
||||
|
||||
/** |
||||
* Support for jOOQ. |
||||
* |
||||
* @see org.springframework.boot.json.JsonParser |
||||
*/ |
||||
package org.springframework.boot.jooq; |
||||
Loading…
Reference in new issue