items) {
+ items.forEach(this::produce);
+ }
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBuildItem.java
index f58313c940ae5..5e491ed3da0e3 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourceBuildItem.java
@@ -2,15 +2,21 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import io.quarkus.builder.item.MultiBuildItem;
+import io.quarkus.deployment.util.ArtifactResourceResolver;
+import io.quarkus.maven.dependency.ArtifactCoords;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.paths.PathFilter;
+import io.quarkus.util.GlobUtil;
/**
* A build item that indicates that a static resource should be included in the native image.
*
* A static resource is a file that is not processed by the build steps, but is included in the native image as-is.
- * The resource path passed to the constructor is a {@code /}-separated path name (with the same semantics as the parameters
+ * The resource path passed to the constructor is a {@code /}-separated path name (with the same semantics as the parameters)
* passed to {@link java.lang.ClassLoader#getResources(String)}.
*
* Related build items:
@@ -23,6 +29,23 @@ public final class NativeImageResourceBuildItem extends MultiBuildItem {
private final List resources;
+ /**
+ * Builds a {@code NativeImageResourceBuildItem} for the given artifact and path
+ *
+ * @param dependencies the resolved dependencies of the build
+ * @param artifactCoordinates the coordinates of the artifact containing the resources
+ * @param resourceFilter the filter for the resources in glob syntax (see {@link GlobUtil})
+ * @return
+ */
+ public static NativeImageResourceBuildItem ofDependencyResources(
+ Collection dependencies,
+ ArtifactCoords artifactCoordinates,
+ PathFilter resourceFilter) {
+
+ var resolver = ArtifactResourceResolver.of(dependencies, artifactCoordinates);
+ return new NativeImageResourceBuildItem(resolver.resourceList(resourceFilter));
+ }
+
public NativeImageResourceBuildItem(String... resources) {
this.resources = Arrays.asList(resources);
}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ServiceProviderBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ServiceProviderBuildItem.java
index 28854dcb5bfc1..590adea75ab3f 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ServiceProviderBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ServiceProviderBuildItem.java
@@ -11,7 +11,11 @@
import java.util.Set;
import io.quarkus.builder.item.MultiBuildItem;
+import io.quarkus.deployment.util.ArtifactResourceResolver;
import io.quarkus.deployment.util.ServiceUtil;
+import io.quarkus.maven.dependency.ArtifactCoords;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.paths.PathFilter;
/**
* Represents a Service Provider registration.
@@ -21,6 +25,8 @@
public final class ServiceProviderBuildItem extends MultiBuildItem {
public static final String SPI_ROOT = "META-INF/services/";
+ private static final PathFilter SPI_FILTER = PathFilter.forIncludes(List.of(SPI_ROOT + "*"));
+
private final String serviceInterface;
private final List providers;
@@ -52,7 +58,7 @@ public static ServiceProviderBuildItem allProviders(final String serviceInterfac
line = line.substring(0, commentIndex);
}
line = line.trim();
- if (line.length() != 0) {
+ if (!line.isEmpty()) {
classNames.add(line);
}
}
@@ -87,6 +93,48 @@ public static ServiceProviderBuildItem allProvidersFromClassPath(final String se
}
}
+ /**
+ * Creates a new {@link Collection} of {@code ServiceProviderBuildItem}s for the selected artifact.
+ * It includes all the providers, that are contained in all the service interface descriptor files defined in
+ * {@code "META-INF/services/"} in the selected artifact.
+ *
+ * @param dependencies the resolved dependencies of the build
+ * @param artifactCoordinates the coordinates of the artifact containing the service definitions
+ * @return a {@link Collection} of {@code ServiceProviderBuildItem}s containing all the found service providers
+ */
+ public static Collection allProvidersOfDependency(
+ Collection dependencies,
+ ArtifactCoords artifactCoordinates) {
+
+ return allProvidersOfDependencies(dependencies, List.of(artifactCoordinates));
+ }
+
+ /**
+ * Creates a new {@link Collection} of {@code ServiceProviderBuildItem}s for the selected artifacts.
+ * It includes all the providers, that are contained in all the service interface descriptor files defined in
+ * {@code "META-INF/services/"} in all the selected artifacts.
+ *
+ * @param dependencies the resolved dependencies of the build
+ * @param artifactCoordinatesCollection a {@link Collection} of coordinates of the artifacts containing the service
+ * definitions
+ * @return a {@link Collection} of {@code ServiceProviderBuildItem}s containing all the found service providers
+ */
+ public static Collection allProvidersOfDependencies(
+ Collection dependencies,
+ Collection artifactCoordinatesCollection) {
+
+ var resolver = ArtifactResourceResolver.of(dependencies, artifactCoordinatesCollection);
+ return resolver.resourcePathList(SPI_FILTER).stream()
+ .map(ServiceProviderBuildItem::ofSpiPath)
+ .toList();
+ }
+
+ private static ServiceProviderBuildItem ofSpiPath(Path spiPath) {
+ return new ServiceProviderBuildItem(
+ spiPath.getFileName().toString(),
+ ServiceUtil.classNamesNamedIn(spiPath.toString()));
+ }
+
/**
* Registers the specified service interface descriptor to be embedded and allow reflection (instantiation only)
* of the specified provider classes. Note that the service interface descriptor file has to exist and match the
@@ -136,12 +184,12 @@ private ServiceProviderBuildItem(String serviceInterfaceClassName, List
this.providers = providers;
// Validation
- if (serviceInterface.length() == 0) {
+ if (serviceInterface.isEmpty()) {
throw new IllegalArgumentException("The serviceDescriptorFile interface cannot be blank");
}
providers.forEach(s -> {
- if (s == null || s.length() == 0) {
+ if (s == null || s.isEmpty()) {
throw new IllegalArgumentException("The provider class name cannot be null or blank");
}
});
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/util/ArtifactResourceResolver.java b/core/deployment/src/main/java/io/quarkus/deployment/util/ArtifactResourceResolver.java
new file mode 100644
index 0000000000000..2eb6b98a21ed6
--- /dev/null
+++ b/core/deployment/src/main/java/io/quarkus/deployment/util/ArtifactResourceResolver.java
@@ -0,0 +1,101 @@
+package io.quarkus.deployment.util;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import io.quarkus.maven.dependency.ArtifactCoords;
+import io.quarkus.maven.dependency.ArtifactCoordsPattern;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.paths.PathFilter;
+import io.quarkus.paths.PathVisit;
+import io.quarkus.util.GlobUtil;
+
+/**
+ * Utility class to extract a list of resource paths from a given artifact and path.
+ */
+public final class ArtifactResourceResolver {
+ private final Collection artifacts;
+
+ /**
+ * Creates a {@code ArtifactResourceResolver} for the given artifact
+ *
+ * @param dependencies the resolved dependencies of the build
+ * @param artifactCoordinates the coordinates of the artifact containing the resources
+ */
+ public static ArtifactResourceResolver of(
+ Collection dependencies, ArtifactCoords artifactCoordinates) {
+
+ return new ArtifactResourceResolver(dependencies, List.of(artifactCoordinates));
+ }
+
+ /**
+ * Creates a {@code ArtifactResourceResolver} for the given artifact
+ *
+ * @param dependencies the resolved dependencies of the build
+ * @param artifactCoordinatesCollection a coordinates {@link Collection} for the artifacts containing the resources
+ */
+ public static ArtifactResourceResolver of(
+ Collection dependencies, Collection artifactCoordinatesCollection) {
+
+ return new ArtifactResourceResolver(dependencies, artifactCoordinatesCollection);
+ }
+
+ private ArtifactResourceResolver(
+ Collection dependencies, Collection artifactCoordinates) {
+
+ var patterns = ArtifactCoordsPattern.toPatterns(artifactCoordinates);
+ artifacts = patterns.stream()
+ .map(p -> findArtifact(dependencies, p))
+ .collect(Collectors.toSet());
+ }
+
+ private static ResolvedDependency findArtifact(
+ Collection dependencies, ArtifactCoordsPattern pattern) {
+
+ return dependencies.stream()
+ .filter(pattern::matches)
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException(
+ "%s artifact not found".formatted(pattern.toString())));
+ }
+
+ /**
+ * Extracts a {@link Collection} of resource paths with the given filter
+ *
+ * @param pathFilter the filter for the resources in glob syntax (see {@link GlobUtil})
+ * @return a collection of the found resource paths
+ */
+ public Collection resourcePathList(PathFilter pathFilter) {
+ return artifacts.stream()
+ .map(a -> pathsForArtifact(a, pathFilter))
+ .flatMap(Collection::stream)
+ .toList();
+ }
+
+ private Collection pathsForArtifact(ResolvedDependency artifact, PathFilter pathFilter) {
+ var pathList = new ArrayList();
+ var pathTree = artifact.getContentTree(pathFilter);
+ pathTree.walk(visit -> pathList.add(relativePath(visit)));
+ return pathList;
+ }
+
+ private Path relativePath(PathVisit visit) {
+ var path = visit.getPath();
+ return path.getRoot().relativize(path);
+ }
+
+ /**
+ * Extracts a {@link List} of resource paths as strings with the given filter
+ *
+ * @param pathFilter the filter for the resources in glob syntax (see {@link GlobUtil})
+ * @return a list of the found resource paths as strings
+ */
+ public List resourceList(PathFilter pathFilter) {
+ return resourcePathList(pathFilter).stream()
+ .map(Path::toString)
+ .toList();
+ }
+}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/util/ServiceUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/util/ServiceUtil.java
index b45ee1f1f52f9..16f396f3efe0c 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/util/ServiceUtil.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/util/ServiceUtil.java
@@ -19,6 +19,7 @@
/**
*/
public final class ServiceUtil {
+
private ServiceUtil() {
}
@@ -59,6 +60,14 @@ public static Set classNamesNamedIn(Path path) throws IOException {
return set;
}
+ public static Set classNamesNamedIn(String filePath) {
+ try {
+ return classNamesNamedIn(Thread.currentThread().getContextClassLoader(), filePath);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
/**
* - Lines starting by a # (or white spaces and a #) are ignored. - For
* lines containing data before a comment (#) are parsed and only the value
diff --git a/extensions/liquibase-mongodb/deployment/pom.xml b/extensions/liquibase-mongodb/deployment/pom.xml
index 6ac0f8adb7e93..cc4f53053719e 100644
--- a/extensions/liquibase-mongodb/deployment/pom.xml
+++ b/extensions/liquibase-mongodb/deployment/pom.xml
@@ -16,6 +16,12 @@
io.quarkus
quarkus-liquibase-mongodb
+
+
+ org.liquibase
+ liquibase-commercial
+
+
io.quarkus
diff --git a/extensions/liquibase-mongodb/deployment/src/main/java/io/quarkus/liquibase/mongodb/deployment/LiquibaseMongodbProcessor.java b/extensions/liquibase-mongodb/deployment/src/main/java/io/quarkus/liquibase/mongodb/deployment/LiquibaseMongodbProcessor.java
index febc0a6b9c47a..cb070ce870ee0 100644
--- a/extensions/liquibase-mongodb/deployment/src/main/java/io/quarkus/liquibase/mongodb/deployment/LiquibaseMongodbProcessor.java
+++ b/extensions/liquibase-mongodb/deployment/src/main/java/io/quarkus/liquibase/mongodb/deployment/LiquibaseMongodbProcessor.java
@@ -1,7 +1,5 @@
package io.quarkus.liquibase.mongodb.deployment;
-import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT;
-
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -13,7 +11,6 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import java.util.stream.Stream;
import jakarta.enterprise.context.ApplicationScoped;
@@ -42,13 +39,17 @@
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
+import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
import io.quarkus.deployment.util.ServiceUtil;
import io.quarkus.liquibase.mongodb.LiquibaseMongodbFactory;
import io.quarkus.liquibase.mongodb.runtime.LiquibaseMongodbBuildTimeConfig;
import io.quarkus.liquibase.mongodb.runtime.LiquibaseMongodbConfig;
import io.quarkus.liquibase.mongodb.runtime.LiquibaseMongodbRecorder;
+import io.quarkus.maven.dependency.ArtifactCoords;
+import io.quarkus.maven.dependency.Dependency;
import io.quarkus.mongodb.runtime.MongodbConfig;
+import io.quarkus.paths.PathFilter;
import liquibase.change.Change;
import liquibase.change.DatabaseChangeProperty;
import liquibase.change.core.CreateProcedureChange;
@@ -68,6 +69,17 @@ class LiquibaseMongodbProcessor {
private static final Logger LOGGER = Logger.getLogger(LiquibaseMongodbProcessor.class);
+ private static final ArtifactCoords LIQUIBASE_ARTIFACT = Dependency.of(
+ "org.liquibase", "liquibase-core", "*");
+ private static final ArtifactCoords LIQUIBASE_MONGODB_ARTIFACT = Dependency.of(
+ "org.liquibase.ext", "liquibase-mongodb", "*");
+ private static final PathFilter LIQUIBASE_RESOURCE_FILTER = PathFilter.forIncludes(List.of(
+ "*.properties",
+ "www.liquibase.org/xml/ns/dbchangelog/*.xsd"));
+ private static final PathFilter LIQUIBASE_MONGODB_RESOURCE_FILTER = PathFilter.forIncludes(List.of(
+ "www.liquibase.org/xml/ns/mongodb/*.xsd",
+ "liquibase.parser.core.xml/*.xsd"));
+
private static final DotName DATABASE_CHANGE_PROPERTY = DotName.createSimple(DatabaseChangeProperty.class.getName());
@BuildStep
@@ -78,16 +90,16 @@ FeatureBuildItem feature() {
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
List indexLiquibase() {
return List.of(
- new IndexDependencyBuildItem("org.liquibase", "liquibase-core"),
- new IndexDependencyBuildItem("org.liquibase.ext", "liquibase-mongodb"));
+ new IndexDependencyBuildItem(LIQUIBASE_ARTIFACT.getGroupId(), LIQUIBASE_ARTIFACT.getArtifactId()),
+ new IndexDependencyBuildItem(
+ LIQUIBASE_MONGODB_ARTIFACT.getGroupId(), LIQUIBASE_MONGODB_ARTIFACT.getArtifactId()));
}
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
- @Record(STATIC_INIT)
void nativeImageConfiguration(
- LiquibaseMongodbRecorder recorder,
LiquibaseMongodbBuildTimeConfig liquibaseBuildConfig,
CombinedIndexBuildItem combinedIndex,
+ CurateOutcomeBuildItem curateOutcome,
BuildProducer reflective,
BuildProducer resource,
BuildProducer services,
@@ -113,6 +125,7 @@ void nativeImageConfiguration(
liquibase.command.CommandFactory.class.getName(),
liquibase.database.LiquibaseTableNamesFactory.class.getName(),
liquibase.configuration.ConfiguredValueModifierFactory.class.getName(),
+ liquibase.changelog.FastCheckService.class.getName(),
// deprecated, but still used by liquibase.nosql.lockservice.AbstractNoSqlLockService
liquibase.configuration.GlobalConfiguration.class.getName())
.constructors().build());
@@ -154,82 +167,39 @@ void nativeImageConfiguration(
resource.produce(
new NativeImageResourceBuildItem(getChangeLogs(liquibaseBuildConfig).toArray(new String[0])));
- Stream.of(liquibase.change.Change.class,
- liquibase.changelog.ChangeLogHistoryService.class,
- liquibase.changeset.ChangeSetService.class,
- liquibase.database.Database.class,
- liquibase.database.DatabaseConnection.class,
- liquibase.datatype.LiquibaseDataType.class,
- liquibase.diff.compare.DatabaseObjectComparator.class,
- liquibase.diff.DiffGenerator.class,
- liquibase.diff.output.changelog.ChangeGenerator.class,
- liquibase.executor.Executor.class,
- liquibase.license.LicenseService.class,
- liquibase.lockservice.LockService.class,
- liquibase.logging.LogService.class,
- liquibase.parser.ChangeLogParser.class,
- liquibase.parser.LiquibaseSqlParser.class,
- liquibase.parser.NamespaceDetails.class,
- liquibase.parser.SnapshotParser.class,
- liquibase.precondition.Precondition.class,
- liquibase.report.ShowSummaryGenerator.class,
- liquibase.serializer.ChangeLogSerializer.class,
- liquibase.serializer.SnapshotSerializer.class,
- liquibase.servicelocator.ServiceLocator.class,
- liquibase.snapshot.SnapshotGenerator.class,
- liquibase.sqlgenerator.SqlGenerator.class,
- liquibase.structure.DatabaseObject.class,
- liquibase.logging.mdc.MdcManager.class)
- .forEach(t -> addService(services, reflective, t, false));
-
// Register Precondition services, and the implementation class for reflection while also registering fields for reflection
- addService(services, reflective, liquibase.precondition.Precondition.class, true);
+ addService(services, reflective, liquibase.precondition.Precondition.class.getName(), true);
// CommandStep implementations are needed (just like in non-mongodb variant)
- addService(services, reflective, liquibase.command.CommandStep.class, false,
+ addService(services, reflective, liquibase.command.CommandStep.class.getName(), false,
"liquibase.command.core.StartH2CommandStep");
- // liquibase XSD
- resource.produce(new NativeImageResourceBuildItem(
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.7.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.8.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.9.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.10.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.11.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.12.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.13.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.14.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.15.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.16.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.17.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.18.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.19.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.21.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.22.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.23.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.24.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.25.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd",
- "www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd",
- "liquibase.build.properties"));
+ var dependencies = curateOutcome.getApplicationModel().getRuntimeDependencies();
+
+ resource.produce(NativeImageResourceBuildItem.ofDependencyResources(
+ dependencies, LIQUIBASE_ARTIFACT, LIQUIBASE_RESOURCE_FILTER));
+ resource.produce(NativeImageResourceBuildItem.ofDependencyResources(
+ dependencies, LIQUIBASE_MONGODB_ARTIFACT, LIQUIBASE_MONGODB_RESOURCE_FILTER));
+ services.produce(ServiceProviderBuildItem.allProvidersOfDependencies(
+ dependencies, List.of(LIQUIBASE_ARTIFACT, LIQUIBASE_MONGODB_ARTIFACT)));
// liquibase resource bundles
resourceBundle.produce(new NativeImageResourceBundleBuildItem("liquibase/i18n/liquibase-core"));
+ resourceBundle.produce(new NativeImageResourceBundleBuildItem("liquibase/i18n/liquibase-mongo"));
}
private void addService(BuildProducer services,
- BuildProducer reflective, Class> serviceClass,
+ BuildProducer reflective, String serviceClassName,
boolean shouldRegisterFieldForReflection, String... excludedImpls) {
try {
- String service = "META-INF/services/" + serviceClass.getName();
+ String service = ServiceProviderBuildItem.SPI_ROOT + serviceClassName;
Set implementations = ServiceUtil.classNamesNamedIn(Thread.currentThread().getContextClassLoader(),
service);
if (excludedImpls.length > 0) {
implementations = new HashSet<>(implementations);
- implementations.removeAll(Arrays.asList(excludedImpls));
+ Arrays.asList(excludedImpls).forEach(implementations::remove);
}
- services.produce(new ServiceProviderBuildItem(serviceClass.getName(), implementations.toArray(new String[0])));
+ services.produce(new ServiceProviderBuildItem(serviceClassName, implementations.toArray(new String[0])));
reflective.produce(ReflectiveClassBuildItem.builder(
implementations.toArray(new String[0]))
@@ -289,25 +259,21 @@ private List getChangeLogs(LiquibaseMongodbBuildTimeConfig liquibaseBuil
ChangeLogParserFactory changeLogParserFactory = ChangeLogParserFactory.getInstance();
- Set resources = new LinkedHashSet<>();
+ try (var classLoaderResourceAccessor = new ClassLoaderResourceAccessor(
+ Thread.currentThread().getContextClassLoader())) {
- ClassLoaderResourceAccessor classLoaderResourceAccessor = new ClassLoaderResourceAccessor(
- Thread.currentThread().getContextClassLoader());
-
- try {
- resources.addAll(findAllChangeLogFiles(liquibaseBuildConfig.changeLog, changeLogParserFactory,
- classLoaderResourceAccessor, changeLogParameters));
+ Set resources = new LinkedHashSet<>(
+ findAllChangeLogFiles(liquibaseBuildConfig.changeLog, changeLogParserFactory,
+ classLoaderResourceAccessor, changeLogParameters));
LOGGER.debugf("Liquibase changeLogs: %s", resources);
return new ArrayList<>(resources);
- } finally {
- try {
- classLoaderResourceAccessor.close();
- } catch (Exception ignored) {
- // close() really shouldn't declare that exception, see also https://github.com/liquibase/liquibase/pull/2576
- }
+ } catch (Exception ex) {
+ // close() really shouldn't declare that exception, see also https://github.com/liquibase/liquibase/pull/2576
+ throw new IllegalStateException(
+ "Error while loading the liquibase changelogs: %s".formatted(ex.getMessage()), ex);
}
}
@@ -350,20 +316,16 @@ private Set findAllChangeLogFiles(String file, ChangeLogParserFactory ch
private Optional extractChangeFile(Change change, String changeSetFilePath) {
String path = null;
Boolean relative = null;
- if (change instanceof LoadDataChange) {
- LoadDataChange loadDataChange = (LoadDataChange) change;
+ if (change instanceof LoadDataChange loadDataChange) {
path = loadDataChange.getFile();
relative = loadDataChange.isRelativeToChangelogFile();
- } else if (change instanceof SQLFileChange) {
- SQLFileChange sqlFileChange = (SQLFileChange) change;
+ } else if (change instanceof SQLFileChange sqlFileChange) {
path = sqlFileChange.getPath();
relative = sqlFileChange.isRelativeToChangelogFile();
- } else if (change instanceof CreateProcedureChange) {
- CreateProcedureChange createProcedureChange = (CreateProcedureChange) change;
+ } else if (change instanceof CreateProcedureChange createProcedureChange) {
path = createProcedureChange.getPath();
relative = createProcedureChange.isRelativeToChangelogFile();
- } else if (change instanceof CreateViewChange) {
- CreateViewChange createViewChange = (CreateViewChange) change;
+ } else if (change instanceof CreateViewChange createViewChange) {
path = createViewChange.getPath();
relative = createViewChange.getRelativeToChangelogFile();
}
diff --git a/extensions/liquibase-mongodb/runtime/pom.xml b/extensions/liquibase-mongodb/runtime/pom.xml
index 42a277a255599..df90bef0fcdeb 100644
--- a/extensions/liquibase-mongodb/runtime/pom.xml
+++ b/extensions/liquibase-mongodb/runtime/pom.xml
@@ -36,6 +36,12 @@
org.liquibase.ext
liquibase-mongodb
+
+
+ org.liquibase
+ liquibase-commercial
+
+
org.graalvm.sdk
diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/graal/SubstituteStringUtil.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/graal/SubstituteStringUtil.java
deleted file mode 100644
index 29bb32d1001e1..0000000000000
--- a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/graal/SubstituteStringUtil.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package io.quarkus.liquibase.mongodb.runtime.graal;
-
-import java.security.SecureRandom;
-
-import com.oracle.svm.core.annotate.Alias;
-import com.oracle.svm.core.annotate.InjectAccessors;
-import com.oracle.svm.core.annotate.TargetClass;
-
-@TargetClass(className = "liquibase.util.StringUtil")
-final class SubstituteStringUtil {
-
- @Alias
- @InjectAccessors(SecureRandomAccessors.class)
- private static SecureRandom rnd;
-
- public static final class SecureRandomAccessors {
-
- private static volatile SecureRandom volatileRandom;
-
- public static SecureRandom get() {
- SecureRandom localVolatileRandom = volatileRandom;
- if (localVolatileRandom == null) {
- synchronized (SecureRandomAccessors.class) {
- localVolatileRandom = volatileRandom;
- if (localVolatileRandom == null) {
- volatileRandom = localVolatileRandom = new SecureRandom();
- }
- }
- }
- return localVolatileRandom;
- }
-
- public static void set(SecureRandom rnd) {
- throw new IllegalStateException("The setter for liquibase.util.StringUtil#rnd shouldn't be called.");
- }
- }
-}
diff --git a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java
index 0afcedac241e0..29c6bdb104346 100644
--- a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java
+++ b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java
@@ -4,8 +4,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
@@ -66,7 +64,9 @@
import io.quarkus.liquibase.runtime.LiquibaseDataSourceBuildTimeConfig;
import io.quarkus.liquibase.runtime.LiquibaseFactoryProducer;
import io.quarkus.liquibase.runtime.LiquibaseRecorder;
-import io.quarkus.paths.PathTree;
+import io.quarkus.maven.dependency.ArtifactCoords;
+import io.quarkus.maven.dependency.Dependency;
+import io.quarkus.paths.PathFilter;
import io.quarkus.runtime.util.StringUtil;
import liquibase.change.Change;
import liquibase.change.DatabaseChangeProperty;
@@ -91,11 +91,10 @@ class LiquibaseProcessor {
private static final Logger LOGGER = Logger.getLogger(LiquibaseProcessor.class);
private static final String LIQUIBASE_BEAN_NAME_PREFIX = "liquibase_";
- private static final String LIQUIBASE_GROUP_ID = "org.liquibase";
- private static final String LIQUIBASE_ARTIFACT_ID = "liquibase-core";
- private static final String LIQUIBASE_PROPERTIES_PATH = "";
- private static final String LIQUIBASE_DB_CHANGELOG_XSD_PATH = "www.liquibase.org/xml/ns/dbchangelog";
- private static final String LIQUIBASE_SERVICE_PATH = "META-INF/services/";
+ private static final ArtifactCoords LIQUIBASE_ARTIFACT = Dependency.of("org.liquibase", "liquibase-core", "*");
+ private static final PathFilter LIQUIBASE_RESOURCE_FILTER = PathFilter.forIncludes(List.of(
+ "*.properties",
+ "www.liquibase.org/xml/ns/dbchangelog/*.xsd"));
private static final DotName DATABASE_CHANGE_PROPERTY = DotName.createSimple(DatabaseChangeProperty.class.getName());
@@ -106,7 +105,7 @@ FeatureBuildItem feature() {
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
IndexDependencyBuildItem indexLiquibase() {
- return new IndexDependencyBuildItem("org.liquibase", "liquibase-core");
+ return new IndexDependencyBuildItem(LIQUIBASE_ARTIFACT.getGroupId(), LIQUIBASE_ARTIFACT.getArtifactId());
}
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
@@ -139,7 +138,8 @@ void nativeImageConfiguration(
reflective.produce(ReflectiveClassBuildItem.builder(
liquibase.command.CommandFactory.class.getName(),
liquibase.database.LiquibaseTableNamesFactory.class.getName(),
- liquibase.configuration.ConfiguredValueModifierFactory.class.getName())
+ liquibase.configuration.ConfiguredValueModifierFactory.class.getName(),
+ liquibase.changelog.FastCheckService.class.getName())
.constructors().build());
reflective.produce(ReflectiveClassBuildItem.builder(
@@ -203,7 +203,10 @@ void nativeImageConfiguration(
}
});
- resolveLiquibaseResources(curateOutcome, services, reflective, resource);
+ var dependencies = curateOutcome.getApplicationModel().getRuntimeDependencies();
+ resource.produce(NativeImageResourceBuildItem.ofDependencyResources(
+ dependencies, LIQUIBASE_ARTIFACT, LIQUIBASE_RESOURCE_FILTER));
+ services.produce(ServiceProviderBuildItem.allProvidersOfDependency(dependencies, LIQUIBASE_ARTIFACT));
// liquibase resource bundles
resourceBundle.produce(new NativeImageResourceBundleBuildItem("liquibase/i18n/liquibase-core"));
@@ -219,7 +222,7 @@ private static Predicate commandStepPredicate(Capabilities capabilities)
private void consumeService(String serviceClassName, BiConsumer> consumer) {
try {
- String service = LIQUIBASE_SERVICE_PATH + serviceClassName;
+ String service = ServiceProviderBuildItem.SPI_ROOT + serviceClassName;
Set implementations = ServiceUtil.classNamesNamedIn(Thread.currentThread().getContextClassLoader(),
service);
consumer.accept(serviceClassName, implementations);
@@ -228,78 +231,6 @@ private void consumeService(String serviceClassName, BiConsumer services,
- BuildProducer reflective,
- BuildProducer resource) {
-
- var dependencies = curateOutcome.getApplicationModel().getDependencies();
- var liquibaseDependency = dependencies.stream()
- .filter(d -> LIQUIBASE_GROUP_ID.equals(d.getGroupId())
- && LIQUIBASE_ARTIFACT_ID.equals(d.getArtifactId()))
- .findFirst()
- .orElseThrow(() -> new IllegalStateException("Liquibase dependency not found"));
-
- var tree = liquibaseDependency.getContentTree();
- loadLiquibaseRootProperties(tree, resource);
- loadLiquibaseXsdResources(tree, resource);
- loadLiquibaseServiceProviderConfig(tree, services, reflective);
- }
-
- private List getResourceNames(PathTree pathTree, String basePath, String fileExtension, boolean stripPath) {
- return pathTree.apply(basePath, visit -> {
- try (var pathStream = Files.list(visit.getPath())) {
- return pathStream
- .map(p -> stripPath ? p.getFileName() : p.subpath(0, p.getNameCount()))
- .map(Path::toString)
- .filter(s -> s.endsWith(fileExtension))
- .toList();
- } catch (IOException ex) {
- throw new IllegalStateException(ex);
- }
- });
- }
-
- private void loadLiquibaseRootProperties(
- PathTree tree,
- BuildProducer resource) {
-
- var rootProperties = getResourceNames(
- tree,
- LIQUIBASE_PROPERTIES_PATH,
- ".properties",
- true);
- resource.produce(new NativeImageResourceBuildItem(rootProperties));
- }
-
- private void loadLiquibaseXsdResources(
- PathTree tree,
- BuildProducer resource) {
-
- var xsdResources = getResourceNames(
- tree,
- LIQUIBASE_DB_CHANGELOG_XSD_PATH,
- ".xsd",
- false);
- resource.produce(new NativeImageResourceBuildItem(xsdResources));
- }
-
- private void loadLiquibaseServiceProviderConfig(
- PathTree tree,
- BuildProducer services,
- BuildProducer reflective) {
-
- getResourceNames(tree, LIQUIBASE_SERVICE_PATH, "", true)
- .forEach(t -> consumeService(t, (serviceClassName, implementations) -> {
- services.produce(new ServiceProviderBuildItem(
- serviceClassName,
- implementations.toArray(String[]::new)));
- reflective.produce(ReflectiveClassBuildItem.builder(implementations.toArray(String[]::new))
- .constructors().methods().build());
- }));
- }
-
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void createBeans(LiquibaseRecorder recorder,
diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/graal/SubstituteStringUtil.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/graal/SubstituteStringUtil.java
deleted file mode 100644
index d4f28a00e8464..0000000000000
--- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/graal/SubstituteStringUtil.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package io.quarkus.liquibase.runtime.graal;
-
-import java.security.SecureRandom;
-
-import com.oracle.svm.core.annotate.Alias;
-import com.oracle.svm.core.annotate.InjectAccessors;
-import com.oracle.svm.core.annotate.TargetClass;
-
-@TargetClass(className = "liquibase.util.StringUtil")
-final class SubstituteStringUtil {
-
- @Alias
- @InjectAccessors(SecureRandomAccessors.class)
- private static SecureRandom rnd;
-
- public static final class SecureRandomAccessors {
-
- private static volatile SecureRandom volatileRandom;
-
- public static SecureRandom get() {
- SecureRandom localVolatileRandom = volatileRandom;
- if (localVolatileRandom == null) {
- synchronized (SecureRandomAccessors.class) {
- localVolatileRandom = volatileRandom;
- if (localVolatileRandom == null) {
- volatileRandom = localVolatileRandom = new SecureRandom();
- }
- }
- }
- return localVolatileRandom;
- }
-
- public static void set(SecureRandom rnd) {
- throw new IllegalStateException("The setter for liquibase.util.StringUtil#rnd shouldn't be called.");
- }
- }
-}