diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java index 45cd6424d478a..428a05ee3ab95 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java @@ -784,6 +784,11 @@ public NativeImageInvokerInfo build() { for (NativeImageFeatureBuildItem nativeImageFeature : nativeImageFeatures) { featuresList.add(nativeImageFeature.getQualifiedName()); } + if (!nativeConfig.autoServiceLoaderRegistration()) { + featuresList.add("io.quarkus.runtime.graal.SkipConsoleServiceProvidersFeature"); + // required by the feature + nativeImageArgs.add("-J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk=ALL-UNNAMED"); + } nativeImageArgs.add("--features=" + String.join(",", featuresList)); if (nativeConfig.debug().enabled()) { diff --git a/core/runtime/src/main/java/io/quarkus/runtime/graal/SkipConsoleServiceProvidersFeature.java b/core/runtime/src/main/java/io/quarkus/runtime/graal/SkipConsoleServiceProvidersFeature.java new file mode 100644 index 0000000000000..e472cfce4b6e7 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/graal/SkipConsoleServiceProvidersFeature.java @@ -0,0 +1,54 @@ +package io.quarkus.runtime.graal; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import org.graalvm.nativeimage.hosted.Feature; + +/** + * Removes {@code jdk.internal.io.JdkConsoleProvider} service providers from the {@code ServiceCatalog} in a similar way to + * GraalVM's {@code ServiceLoaderFeature} which Quarkus disables by default. + */ +public class SkipConsoleServiceProvidersFeature implements Feature { + static final HashMap> omittedServiceProviders; + + @Override + public String getDescription() { + return "Skip unsupported console service providers when quarkus.native.auto-service-loader-registration is false"; + } + + static { + omittedServiceProviders = new HashMap<>(1); + omittedServiceProviders.put("jdk.internal.io.JdkConsoleProvider", + new HashSet<>(Arrays.asList("jdk.jshell.execution.impl.ConsoleImpl$ConsoleProviderImpl", + "jdk.internal.org.jline.JdkConsoleProviderImpl"))); + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + Class serviceCatalogSupport; + Method singleton; + Method removeServices; + try { + serviceCatalogSupport = Class.forName("com.oracle.svm.core.jdk.ServiceCatalogSupport"); + singleton = serviceCatalogSupport.getDeclaredMethod("singleton"); + removeServices = serviceCatalogSupport.getDeclaredMethod("removeServicesFromServicesCatalog", String.class, + Set.class); + var result = singleton.invoke(null); + omittedServiceProviders.forEach((key, value) -> { + try { + removeServices.invoke(result, key, value); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + }); + } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + +}