diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/SetClassPathSystemPropBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/SetClassPathSystemPropBuildItem.java new file mode 100644 index 0000000000000..7461e22f7a73f --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/SetClassPathSystemPropBuildItem.java @@ -0,0 +1,12 @@ +package io.quarkus.deployment.builditem; + +import io.quarkus.builder.item.MultiBuildItem; + +/** + * A marker build item to make Quarkus set the {@code java.class.path} system property. + * This system property is used in rare by libraries (Truffle for example) to create their own ClassLoaders. + * The value of the system property is simply best effort, as there is no way to faithfully represent + * the Quarkus ClassLoader hierarchies in a system property value. + */ +public final class SetClassPathSystemPropBuildItem extends MultiBuildItem { +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ClassPathSystemPropBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ClassPathSystemPropBuildStep.java new file mode 100644 index 0000000000000..feda25cbade14 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ClassPathSystemPropBuildStep.java @@ -0,0 +1,53 @@ +package io.quarkus.deployment.steps; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.ExecutionTime; +import io.quarkus.deployment.annotations.Record; +import io.quarkus.deployment.builditem.SetClassPathSystemPropBuildItem; +import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; +import io.quarkus.maven.dependency.ResolvedDependency; +import io.quarkus.runtime.ClassPathSystemPropertyRecorder; + +public class ClassPathSystemPropBuildStep { + + @BuildStep + public void produce(BuildProducer producer, CurateOutcomeBuildItem curateOutcome) { + boolean truffleUsed = curateOutcome.getApplicationModel().getDependencies().stream() + .anyMatch(d -> d.getGroupId().equals("org.graalvm.polyglot")); + if (truffleUsed) { + producer.produce(new SetClassPathSystemPropBuildItem()); + } + } + + @BuildStep + @Record(ExecutionTime.STATIC_INIT) + public void set(List setCPItems, + CurateOutcomeBuildItem curateOutcome, + ClassPathSystemPropertyRecorder recorder) { + if (setCPItems.isEmpty()) { + return; + } + Collection runtimeDependencies = curateOutcome.getApplicationModel().getRuntimeDependencies(); + List parentFirst = new ArrayList<>(); + List regular = new ArrayList<>(); + for (ResolvedDependency dependency : runtimeDependencies) { + if (dependency.isClassLoaderParentFirst()) { + parentFirst.addAll(dependency.getContentTree().getRoots()); + } else { + regular.addAll(dependency.getContentTree().getRoots()); + + } + } + String classPathValue = Stream.concat(parentFirst.stream(), regular.stream()).map(p -> p.toAbsolutePath().toString()) + .collect(Collectors.joining(":")); + recorder.set(classPathValue); + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/ClassPathSystemPropertyRecorder.java b/core/runtime/src/main/java/io/quarkus/runtime/ClassPathSystemPropertyRecorder.java new file mode 100644 index 0000000000000..fdca4fcb0cb65 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/ClassPathSystemPropertyRecorder.java @@ -0,0 +1,11 @@ +package io.quarkus.runtime; + +import io.quarkus.runtime.annotations.Recorder; + +@Recorder +public class ClassPathSystemPropertyRecorder { + + public void set(String value) { + System.setProperty("java.class.path", value); + } +}