From 989ce28f7c6cf9c345ad0cc9d329337d85a2ca01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 22 Nov 2023 15:03:00 +0100 Subject: [PATCH] More consistent exceptions for unconfigured datasources Critically, this opens the way to handling other datasource access problems, e.g. deactivated datasources. --- .../quarkus/agroal/runtime/DataSources.java | 1 + extensions/datasource/common/pom.xml | 4 ++++ .../common/runtime/DataSourceUtil.java | 16 +++++++++++++ ...nsionConfigEmptyDefaultDatasourceTest.java | 11 +++++++-- ...StartDefaultDatasourceConfigEmptyTest.java | 6 ++++- .../flyway/runtime/FlywayRecorder.java | 23 ++++++++++++++----- ...UnconfiguredDataSourceFlywayContainer.java | 10 +++++--- .../orm/deployment/HibernateOrmProcessor.java | 21 +++++++---------- ...ithExplicitUnconfiguredDatasourceTest.java | 3 ++- ...ithImplicitUnconfiguredDatasourceTest.java | 8 ++++--- ...ithExplicitUnconfiguredDatasourceTest.java | 3 ++- .../FastBootHibernatePersistenceProvider.java | 16 +++++-------- .../orm/runtime/PersistenceUnitUtil.java | 10 ++++++++ ...nsionConfigEmptyDefaultDatasourceTest.java | 7 ++++-- ...StartDefaultDatasourceConfigEmptyTest.java | 7 ++++-- .../liquibase/runtime/LiquibaseRecorder.java | 15 +++++++++--- 16 files changed, 114 insertions(+), 47 deletions(-) diff --git a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java index 9f7f77b88326e..0e6e827b06a42 100644 --- a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java +++ b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java @@ -152,6 +152,7 @@ public AgroalDataSource doCreateDataSource(String dataSourceName) { DataSourceJdbcBuildTimeConfig dataSourceJdbcBuildTimeConfig = dataSourcesJdbcBuildTimeConfig .dataSources().get(dataSourceName).jdbc(); DataSourceRuntimeConfig dataSourceRuntimeConfig = dataSourcesRuntimeConfig.dataSources().get(dataSourceName); + DataSourceJdbcRuntimeConfig dataSourceJdbcRuntimeConfig = dataSourcesJdbcRuntimeConfig .getDataSourceJdbcRuntimeConfig(dataSourceName); diff --git a/extensions/datasource/common/pom.xml b/extensions/datasource/common/pom.xml index 6527c853e4c84..acdedbcd44a0c 100644 --- a/extensions/datasource/common/pom.xml +++ b/extensions/datasource/common/pom.xml @@ -12,6 +12,10 @@ quarkus-datasource-common Quarkus - Datasource - Common + + io.quarkus + quarkus-core + org.junit.jupiter junit-jupiter diff --git a/extensions/datasource/common/src/main/java/io/quarkus/datasource/common/runtime/DataSourceUtil.java b/extensions/datasource/common/src/main/java/io/quarkus/datasource/common/runtime/DataSourceUtil.java index f0a4b3378f1ba..7b11b9e4aab7a 100644 --- a/extensions/datasource/common/src/main/java/io/quarkus/datasource/common/runtime/DataSourceUtil.java +++ b/extensions/datasource/common/src/main/java/io/quarkus/datasource/common/runtime/DataSourceUtil.java @@ -2,6 +2,10 @@ import java.util.Collection; import java.util.List; +import java.util.Locale; +import java.util.Set; + +import io.quarkus.runtime.configuration.ConfigurationException; public final class DataSourceUtil { @@ -34,6 +38,18 @@ public static List dataSourcePropertyKeys(String datasourceName, String } } + public static ConfigurationException dataSourceNotConfigured(String dataSourceName) { + return new ConfigurationException(String.format(Locale.ROOT, + "Datasource '%s' is not configured." + + " To solve this, configure datasource '%s'." + + " Refer to https://quarkus.io/guides/datasource for guidance.", + dataSourceName, dataSourceName), + Set.of(dataSourcePropertyKey(dataSourceName, "db-kind"), + dataSourcePropertyKey(dataSourceName, "username"), + dataSourcePropertyKey(dataSourceName, "password"), + dataSourcePropertyKey(dataSourceName, "jdbc.url"))); + } + private DataSourceUtil() { } diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyDefaultDatasourceTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyDefaultDatasourceTest.java index 5b32fb0a12fcb..c172cdecb9a73 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyDefaultDatasourceTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyDefaultDatasourceTest.java @@ -32,7 +32,11 @@ public class FlywayExtensionConfigEmptyDefaultDatasourceTest { public void testBootSucceedsButFlywayDeactivated() { assertThatThrownBy(flywayForDefaultDatasource::get) .isInstanceOf(CreationException.class) - .hasMessageContaining("Cannot get a Flyway instance for unconfigured datasource "); + .cause() + .hasMessageContainingAll("Unable to find datasource '' for Flyway", + "Datasource '' is not configured.", + "To solve this, configure datasource ''.", + "Refer to https://quarkus.io/guides/datasource for guidance."); } @Test @@ -40,7 +44,10 @@ public void testBootSucceedsButFlywayDeactivated() { public void testBootSucceedsWithInjectedBeanDependingOnFlywayButFlywayDeactivated() { assertThatThrownBy(() -> myBean.useFlyway()) .cause() - .hasMessageContaining("Cannot get a Flyway instance for unconfigured datasource "); + .hasMessageContainingAll("Unable to find datasource '' for Flyway", + "Datasource '' is not configured.", + "To solve this, configure datasource ''.", + "Refer to https://quarkus.io/guides/datasource for guidance."); } @ApplicationScoped diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java index b2b024f6e83dd..0f9f506d16d0a 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java @@ -31,7 +31,11 @@ public class FlywayExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest { public void testBootSucceedsButFlywayDeactivated() { assertThatThrownBy(flywayForDefaultDatasource::get) .isInstanceOf(CreationException.class) - .hasMessageContaining("Cannot get a Flyway instance for unconfigured datasource "); + .cause() + .hasMessageContainingAll("Unable to find datasource '' for Flyway", + "Datasource '' is not configured.", + "To solve this, configure datasource ''.", + "Refer to https://quarkus.io/guides/datasource for guidance."); } } diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java index f8df08e4e7825..4e858dcf71a3b 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java @@ -2,6 +2,7 @@ import java.lang.annotation.Annotation; import java.util.Collection; +import java.util.Locale; import java.util.Map; import java.util.function.Function; @@ -31,6 +32,7 @@ import io.quarkus.flyway.FlywayDataSource.FlywayDataSourceLiteral; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; +import io.quarkus.runtime.configuration.ConfigurationException; @Recorder public class FlywayRecorder { @@ -64,15 +66,24 @@ public Function, FlywayContainer> fl return new Function<>() { @Override public FlywayContainer apply(SyntheticCreationalContext context) { - DataSource dataSource = context.getInjectedReference(DataSources.class).getDataSource(dataSourceName); - if (dataSource instanceof UnconfiguredDataSource) { - return new UnconfiguredDataSourceFlywayContainer(dataSourceName); + DataSource dataSource; + try { + dataSource = context.getInjectedReference(DataSources.class).getDataSource(dataSourceName); + if (dataSource instanceof UnconfiguredDataSource) { + throw DataSourceUtil.dataSourceNotConfigured(dataSourceName); + } + } catch (ConfigurationException e) { + // TODO do we really want to enable retrieval of a FlywayContainer for an unconfigured datasource? + // Assigning ApplicationScoped to the FlywayContainer + // and throwing UnsatisfiedResolutionException on bean creation (first access) + // would probably make more sense. + return new UnconfiguredDataSourceFlywayContainer(dataSourceName, String.format(Locale.ROOT, + "Unable to find datasource '%s' for Flyway: %s", + dataSourceName, e.getMessage()), e); } FlywayContainerProducer flywayProducer = context.getInjectedReference(FlywayContainerProducer.class); - FlywayContainer flywayContainer = flywayProducer.createFlyway(dataSource, dataSourceName, hasMigrations, - createPossible); - return flywayContainer; + return flywayProducer.createFlyway(dataSource, dataSourceName, hasMigrations, createPossible); } }; } diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/UnconfiguredDataSourceFlywayContainer.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/UnconfiguredDataSourceFlywayContainer.java index a3206cd8141ae..5011c9898ce0d 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/UnconfiguredDataSourceFlywayContainer.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/UnconfiguredDataSourceFlywayContainer.java @@ -4,13 +4,17 @@ public class UnconfiguredDataSourceFlywayContainer extends FlywayContainer { - public UnconfiguredDataSourceFlywayContainer(String dataSourceName) { + private final String message; + private final Throwable cause; + + public UnconfiguredDataSourceFlywayContainer(String dataSourceName, String message, Throwable cause) { super(null, false, false, false, false, false, dataSourceName, false, false); + this.message = message; + this.cause = cause; } @Override public Flyway getFlyway() { - throw new UnsupportedOperationException( - "Cannot get a Flyway instance for unconfigured datasource " + getDataSourceName()); + throw new UnsupportedOperationException(message, cause); } } diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java index 7c90798d1ade0..2ad2bb9e78ac7 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java @@ -871,13 +871,10 @@ private void handleHibernateORMWithNoPersistenceXml( && (!hibernateOrmConfig.defaultPersistenceUnit.datasource.isPresent() || DataSourceUtil.isDefault(hibernateOrmConfig.defaultPersistenceUnit.datasource.get())) && !defaultJdbcDataSource.isPresent()) { - throw new ConfigurationException( - "Model classes are defined for the default persistence unit, but no default datasource was found." - + " The default EntityManagerFactory will not be created." - + " To solve this, configure the default datasource." - + " Refer to https://quarkus.io/guides/datasource for guidance.", - new HashSet<>(Arrays.asList("quarkus.datasource.db-kind", "quarkus.datasource.username", - "quarkus.datasource.password", "quarkus.datasource.jdbc.url"))); + String persistenceUnitName = PersistenceUnitUtil.DEFAULT_PERSISTENCE_UNIT_NAME; + String dataSourceName = DataSourceUtil.DEFAULT_DATASOURCE_NAME; + throw PersistenceUnitUtil.unableToFindDataSource(persistenceUnitName, dataSourceName, + DataSourceUtil.dataSourceNotConfigured(dataSourceName)); } for (Entry persistenceUnitEntry : hibernateOrmConfig.persistenceUnits @@ -1228,14 +1225,12 @@ private static void collectDialectConfigForPersistenceXml(String persistenceUnit private static Optional findJdbcDataSource(String persistenceUnitName, HibernateOrmConfigPersistenceUnit persistenceUnitConfig, List jdbcDataSources) { if (persistenceUnitConfig.datasource.isPresent()) { + String dataSourceName = persistenceUnitConfig.datasource.get(); return Optional.of(jdbcDataSources.stream() - .filter(i -> persistenceUnitConfig.datasource.get().equals(i.getName())) + .filter(i -> dataSourceName.equals(i.getName())) .findFirst() - .orElseThrow(() -> new ConfigurationException(String.format(Locale.ROOT, - "The datasource '%1$s' is not configured but the persistence unit '%2$s' uses it." - + " To solve this, configure datasource '%1$s'." - + " Refer to https://quarkus.io/guides/datasource for guidance.", - persistenceUnitConfig.datasource.get(), persistenceUnitName)))); + .orElseThrow(() -> PersistenceUnitUtil.unableToFindDataSource(persistenceUnitName, dataSourceName, + DataSourceUtil.dataSourceNotConfigured(dataSourceName)))); } else if (PersistenceUnitUtil.isDefaultPersistenceUnit(persistenceUnitName)) { return jdbcDataSources.stream() .filter(i -> i.isDefault()) diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java index e8d0b468572c4..95da175428278 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java @@ -21,7 +21,8 @@ public class EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest { .assertException(t -> assertThat(t) .isInstanceOf(ConfigurationException.class) .hasMessageContainingAll( - "The datasource 'ds-1' is not configured but the persistence unit '' uses it.", + "Unable to find datasource 'ds-1' for persistence unit ''", + "Datasource 'ds-1' is not configured.", "To solve this, configure datasource 'ds-1'.", "Refer to https://quarkus.io/guides/datasource for guidance.")); diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java index 5f3baf8404b51..5e301b02be941 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java @@ -7,6 +7,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.hibernate.orm.config.MyEntity; +import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.test.QuarkusUnitTest; public class EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest { @@ -18,10 +19,11 @@ public class EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest { // The datasource won't be truly "unconfigured" if dev services are enabled .overrideConfigKey("quarkus.devservices.enabled", "false") .assertException(t -> assertThat(t) - .isInstanceOf(RuntimeException.class) + .isInstanceOf(ConfigurationException.class) .hasMessageContainingAll( - "Model classes are defined for persistence unit but configured datasource not found", - "To solve this, configure the default datasource.", + "Unable to find datasource '' for persistence unit ''", + "Datasource '' is not configured.", + "To solve this, configure datasource ''.", "Refer to https://quarkus.io/guides/datasource for guidance.")); @Test diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitUnconfiguredDatasourceTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitUnconfiguredDatasourceTest.java index 5fc829242492a..bc7f76483c09a 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitUnconfiguredDatasourceTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitUnconfiguredDatasourceTest.java @@ -21,7 +21,8 @@ public class EntitiesInNamedPUWithExplicitUnconfiguredDatasourceTest { .assertException(t -> assertThat(t) .isInstanceOf(ConfigurationException.class) .hasMessageContainingAll( - "The datasource 'ds-1' is not configured but the persistence unit 'pu-1' uses it.", + "Unable to find datasource 'ds-1' for persistence unit 'pu-1'", + "Datasource 'ds-1' is not configured.", "To solve this, configure datasource 'ds-1'.", "Refer to https://quarkus.io/guides/datasource for guidance.")); diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java index 3a4048d252485..f98ba87694899 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java @@ -27,6 +27,7 @@ import io.quarkus.agroal.runtime.DataSources; import io.quarkus.agroal.runtime.UnconfiguredDataSource; import io.quarkus.arc.Arc; +import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.hibernate.orm.runtime.RuntimeSettings.Builder; import io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder; import io.quarkus.hibernate.orm.runtime.boot.RuntimePersistenceUnitDescriptor; @@ -389,16 +390,11 @@ private static void injectDataSource(String persistenceUnitName, String dataSour DataSource dataSource; try { dataSource = Arc.container().instance(DataSources.class).get().getDataSource(dataSourceName); - } catch (IllegalArgumentException e) { - throw new IllegalStateException( - "No datasource " + dataSourceName + " has been defined for persistence unit " + persistenceUnitName); - } - - if (dataSource instanceof UnconfiguredDataSource) { - throw new IllegalStateException( - "Model classes are defined for persistence unit " + persistenceUnitName - + " but configured datasource " + dataSourceName - + " not found: the default EntityManagerFactory will not be created. To solve this, configure the default datasource. Refer to https://quarkus.io/guides/datasource for guidance."); + if (dataSource instanceof UnconfiguredDataSource) { + throw DataSourceUtil.dataSourceNotConfigured(dataSourceName); + } + } catch (RuntimeException e) { + throw PersistenceUnitUtil.unableToFindDataSource(persistenceUnitName, dataSourceName, e); } runtimeSettingsBuilder.put(AvailableSettings.DATASOURCE, dataSource); } diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitUtil.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitUtil.java index b91894c052e68..a3194b02f77ad 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitUtil.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitUtil.java @@ -13,6 +13,7 @@ import io.quarkus.arc.InjectableInstance; import io.quarkus.hibernate.orm.PersistenceUnit; import io.quarkus.hibernate.orm.PersistenceUnitExtension; +import io.quarkus.runtime.configuration.ConfigurationException; public class PersistenceUnitUtil { private static final Logger LOG = Logger.getLogger(PersistenceUnitUtil.class); @@ -104,4 +105,13 @@ public static InjectableInstance legacySingleExtensionInstanceForPersiste private static boolean isDefaultBean(InjectableInstance instance) { return instance.isResolvable() && instance.getHandle().getBean().isDefaultBean(); } + + public static ConfigurationException unableToFindDataSource(String persistenceUnitName, + String dataSourceName, + Throwable cause) { + return new ConfigurationException(String.format(Locale.ROOT, + "Unable to find datasource '%s' for persistence unit '%s': %s", + dataSourceName, persistenceUnitName, cause.getMessage()), + cause); + } } diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyDefaultDatasourceTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyDefaultDatasourceTest.java index 5a3350d35f812..ac28eb20acf10 100644 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyDefaultDatasourceTest.java +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyDefaultDatasourceTest.java @@ -15,8 +15,11 @@ public class LiquibaseExtensionConfigEmptyDefaultDatasourceTest { static final QuarkusUnitTest config = new QuarkusUnitTest() // The datasource won't be truly "unconfigured" if dev services are enabled .overrideConfigKey("quarkus.devservices.enabled", "false") - .assertException(t -> assertThat(t).rootCause() - .hasMessageContaining("No datasource has been configured")); + .assertException(t -> assertThat(t).cause().cause() + .hasMessageContainingAll("Unable to find datasource '' for Liquibase", + "Datasource '' is not configured.", + "To solve this, configure datasource ''.", + "Refer to https://quarkus.io/guides/datasource for guidance.")); @Test @DisplayName("If there is no config for the default datasource, the application should fail to boot") diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java index c6f28a7edd526..bad255b85ccf3 100644 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java @@ -18,8 +18,11 @@ public class LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest { .overrideConfigKey("quarkus.liquibase.migrate-at-start", "true") // The datasource won't be truly "unconfigured" if dev services are enabled .overrideConfigKey("quarkus.devservices.enabled", "false") - .assertException(t -> assertThat(t).rootCause() - .hasMessageContaining("No datasource has been configured")); + .assertException(t -> assertThat(t).cause().cause() + .hasMessageContainingAll("Unable to find datasource '' for Liquibase", + "Datasource '' is not configured.", + "To solve this, configure datasource ''.", + "Refer to https://quarkus.io/guides/datasource for guidance.")); @Test @DisplayName("If there is no config for the default datasource, and if migrate-at-start is enabled, the application should fail to boot") diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java index d85785d61e35b..4b045a357417b 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java @@ -1,5 +1,6 @@ package io.quarkus.liquibase.runtime; +import java.util.Locale; import java.util.function.Function; import javax.sql.DataSource; @@ -13,6 +14,7 @@ import io.quarkus.arc.InjectableInstance; import io.quarkus.arc.InstanceHandle; import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.liquibase.LiquibaseFactory; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; @@ -32,9 +34,16 @@ public Function, LiquibaseFactory> return new Function, LiquibaseFactory>() { @Override public LiquibaseFactory apply(SyntheticCreationalContext context) { - DataSource dataSource = context.getInjectedReference(DataSources.class).getDataSource(dataSourceName); - if (dataSource instanceof UnconfiguredDataSource) { - throw new UnsatisfiedResolutionException("No datasource has been configured"); + DataSource dataSource; + try { + dataSource = context.getInjectedReference(DataSources.class).getDataSource(dataSourceName); + if (dataSource instanceof UnconfiguredDataSource) { + throw DataSourceUtil.dataSourceNotConfigured(dataSourceName); + } + } catch (RuntimeException e) { + throw new UnsatisfiedResolutionException(String.format(Locale.ROOT, + "Unable to find datasource '%s' for Liquibase: %s", + dataSourceName, e.getMessage()), e); } LiquibaseFactoryProducer liquibaseProducer = context.getInjectedReference(LiquibaseFactoryProducer.class);