diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourcePatternsBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourcePatternsBuildItem.java index d5dbc44c36d010..57af118b7575d4 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourcePatternsBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeImageResourcePatternsBuildItem.java @@ -17,7 +17,7 @@ * Globs passed to the {@code includeGlob*()} methods of the {@link Builder} are transformed to regular expressions * internally. See {@link NativeConfig.ResourcesConfig#includes} for the supported glob syntax. *

- * The patterns are passed to the native image builder using the {@code com.oracle.svm.hosted.ResourcesFeature} API. + * The patterns are passed to the native image builder using {@code resource-config.json}. * The same mechanism (and regular expression syntax) is used by {@code native-image}'s * {@code -H:ResourceConfigurationFiles}, {@code -H:IncludeResources} and {@code -H:ExcludeResources} (since * GraalVM 20.3.0) command line options. 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 8da849d81a4d72..45a4c4e01d55a8 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 @@ -51,7 +51,6 @@ import io.quarkus.maven.dependency.ResolvedDependency; import io.quarkus.runtime.LocalesBuildTimeConfig; import io.quarkus.runtime.graal.DisableLoggingFeature; -import io.quarkus.runtime.graal.ResourcesFeature; public class NativeImageBuildStep { @@ -80,16 +79,9 @@ public class NativeImageBuildStep { private static final String MOVED_TRUST_STORE_NAME = "trustStore"; public static final String APP_SOURCES = "app-sources"; - @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class) - void addExportsToNativeImage(BuildProducer exports) { - // Needed by io.quarkus.runtime.ResourceHelper.registerResources - exports.produce(new JPMSExportBuildItem("org.graalvm.nativeimage.builder", "com.oracle.svm.core.jdk")); - } - @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class) void nativeImageFeatures(BuildProducer features) { features.produce(new NativeImageFeatureBuildItem(NativeImageFeatureStep.GRAAL_FEATURE)); - features.produce(new NativeImageFeatureBuildItem(ResourcesFeature.class)); features.produce(new NativeImageFeatureBuildItem(DisableLoggingFeature.class)); } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java index e20c9137197e37..0d89a7aff83ad2 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java @@ -3,9 +3,7 @@ import static io.quarkus.gizmo.MethodDescriptor.ofMethod; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.nio.charset.StandardCharsets; import java.util.List; import org.graalvm.home.Version; @@ -16,21 +14,13 @@ import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.builditem.GeneratedNativeImageClassBuildItem; -import io.quarkus.deployment.builditem.GeneratedResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.JPMSExportBuildItem; import io.quarkus.deployment.builditem.nativeimage.JniRuntimeAccessBuildItem; -import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; -import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem; -import io.quarkus.deployment.builditem.nativeimage.NativeImageResourcePatternsBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedPackageBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem; -import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.builditem.nativeimage.UnsafeAccessedFieldBuildItem; import io.quarkus.deployment.pkg.steps.GraalVM; -import io.quarkus.gizmo.AssignableResultHandle; -import io.quarkus.gizmo.BranchResult; -import io.quarkus.gizmo.BytecodeCreator; import io.quarkus.gizmo.CatchBlockCreator; import io.quarkus.gizmo.ClassCreator; import io.quarkus.gizmo.ClassOutput; @@ -38,15 +28,10 @@ import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; import io.quarkus.gizmo.TryBlock; -import io.quarkus.runtime.NativeImageFeatureUtils; -import io.quarkus.runtime.ResourceHelper; -import io.quarkus.runtime.graal.ResourcesFeature; public class NativeImageFeatureStep { public static final String GRAAL_FEATURE = "io.quarkus.runner.Feature"; - private static final MethodDescriptor VERSION_CURRENT = ofMethod(Version.class, "getCurrent", Version.class); - private static final MethodDescriptor VERSION_COMPARE_TO = ofMethod(Version.class, "compareTo", int.class, int[].class); private static final MethodDescriptor IMAGE_SINGLETONS_LOOKUP = ofMethod(ImageSingletons.class, "lookup", Object.class, Class.class); @@ -61,40 +46,7 @@ public class NativeImageFeatureStep { RUNTIME_CLASS_INITIALIZATION_SUPPORT, "rerunInitialization", void.class, Class.class, String.class); - public static final String CONFIGURATION_CONDITION = "org.graalvm.nativeimage.impl.ConfigurationCondition"; - private static final MethodDescriptor CONFIGURATION_ALWAYS_TRUE = ofMethod( - CONFIGURATION_CONDITION, - "alwaysTrue", CONFIGURATION_CONDITION); - - private static final MethodDescriptor LOOKUP_METHOD = ofMethod( - NativeImageFeatureUtils.class, - "lookupMethod", Method.class, Class.class, String.class, Class[].class); - - private static final MethodDescriptor FIND_MODULE_METHOD = ofMethod( - NativeImageFeatureUtils.class, - "findModule", Module.class, String.class); - private static final MethodDescriptor INVOKE = ofMethod( - Method.class, "invoke", Object.class, Object.class, Object[].class); static final String BEFORE_ANALYSIS_ACCESS = Feature.BeforeAnalysisAccess.class.getName(); - static final String LOCALIZATION_FEATURE = "com.oracle.svm.core.jdk.localization.LocalizationFeature"; - static final String RUNTIME_RESOURCE_SUPPORT = "org.graalvm.nativeimage.impl.RuntimeResourceSupport"; - - @BuildStep - GeneratedResourceBuildItem generateNativeResourcesList(List resources, - BuildProducer resourcePatternsBuildItemBuildProducer) { - StringBuilder sb = new StringBuilder(); - for (NativeImageResourceBuildItem i : resources) { - for (String r : i.getResources()) { - sb.append(r); - sb.append("\n"); - } - } - //we don't want this file in the final image - resourcePatternsBuildItemBuildProducer.produce(NativeImageResourcePatternsBuildItem.builder() - .excludePattern(ResourcesFeature.META_INF_QUARKUS_NATIVE_RESOURCES_TXT).build()); - return new GeneratedResourceBuildItem(ResourcesFeature.META_INF_QUARKUS_NATIVE_RESOURCES_TXT, - sb.toString().getBytes(StandardCharsets.UTF_8)); - } @BuildStep void addExportsToNativeImage(BuildProducer features, @@ -114,9 +66,6 @@ void generateFeature(BuildProducer nativeIma List runtimeInitializedClassBuildItems, List runtimeInitializedPackageBuildItems, List runtimeReinitializedClassBuildItems, - List resourcePatterns, - List resourceBundles, - List serviceProviderBuildItems, List unsafeAccessedFields) { ClassCreator file = new ClassCreator(new ClassOutput() { @Override @@ -234,155 +183,6 @@ public void write(String s, byte[] bytes) { overallCatch.invokeStaticMethod(runtimeReinitializedClasses.getMethodDescriptor()); } - /* Resource includes and excludes */ - if (!resourcePatterns.isEmpty()) { - MethodCreator resourceIncludesExcludes = file - .getMethodCreator("resourceIncludesExcludes", void.class) - .setModifiers(Modifier.PRIVATE | Modifier.STATIC); - - // Needed to access com.oracle.svm.core.configure.ResourcesRegistry.* in GraalVM 22.2 - exports.produce(new JPMSExportBuildItem("org.graalvm.nativeimage.builder", "com.oracle.svm.core.configure", - null, GraalVM.Version.VERSION_22_3_0)); - - TryBlock tc = resourceIncludesExcludes.tryBlock(); - - ResultHandle resourcesArgTypes = tc.marshalAsArray(Class.class, tc.loadClassFromTCCL(CONFIGURATION_CONDITION), - tc.loadClassFromTCCL(String.class)); - AssignableResultHandle resourcesArgs = tc.createVariable(Object[].class); - tc.assign(resourcesArgs, - tc.marshalAsArray(Object.class, tc.invokeStaticMethod(CONFIGURATION_ALWAYS_TRUE), tc.loadNull())); - - AssignableResultHandle ignoreResourcesMethod = tc.createVariable(Method.class); - AssignableResultHandle addResourcesMethod = tc.createVariable(Method.class); - AssignableResultHandle resourcesSingleton = tc.createVariable(Object.class); - - BranchResult graalVm22_3Test = tc.ifGreaterEqualZero(tc.invokeVirtualMethod(VERSION_COMPARE_TO, - tc.invokeStaticMethod(VERSION_CURRENT), - tc.marshalAsArray(int.class, tc.load(22), tc.load(3)))); - /* GraalVM >= 22.3 */ - try (BytecodeCreator greaterThan22_2 = graalVm22_3Test.trueBranch()) { - - ResultHandle runtimeResourceSupportClass = greaterThan22_2.loadClassFromTCCL(RUNTIME_RESOURCE_SUPPORT); - - greaterThan22_2.assign(resourcesSingleton, greaterThan22_2.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP, - runtimeResourceSupportClass)); - - greaterThan22_2.assign(ignoreResourcesMethod, greaterThan22_2.invokeStaticMethod(LOOKUP_METHOD, - runtimeResourceSupportClass, greaterThan22_2.load("ignoreResources"), resourcesArgTypes)); - greaterThan22_2.assign(addResourcesMethod, greaterThan22_2.invokeStaticMethod(LOOKUP_METHOD, - runtimeResourceSupportClass, greaterThan22_2.load("addResources"), resourcesArgTypes)); - } - - /* GraalVM < 22.3 */ - try (BytecodeCreator smallerThan22_3 = graalVm22_3Test.falseBranch()) { - - ResultHandle resourceRegistryClass = smallerThan22_3 - .loadClassFromTCCL("com.oracle.svm.core.configure.ResourcesRegistry"); - smallerThan22_3.assign(resourcesSingleton, smallerThan22_3.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP, - resourceRegistryClass)); - - smallerThan22_3.assign(ignoreResourcesMethod, smallerThan22_3.invokeStaticMethod(LOOKUP_METHOD, - resourceRegistryClass, smallerThan22_3.load("ignoreResources"), resourcesArgTypes)); - smallerThan22_3.assign(addResourcesMethod, smallerThan22_3.invokeStaticMethod(LOOKUP_METHOD, - resourceRegistryClass, smallerThan22_3.load("addResources"), resourcesArgTypes)); - } - - ResultHandle indexOne = tc.load(1); - - for (NativeImageResourcePatternsBuildItem resourcePatternsItem : resourcePatterns) { - for (String pattern : resourcePatternsItem.getExcludePatterns()) { - tc.writeArrayValue(resourcesArgs, indexOne, tc.load(pattern)); - tc.invokeVirtualMethod(INVOKE, ignoreResourcesMethod, resourcesSingleton, resourcesArgs); - } - for (String pattern : resourcePatternsItem.getIncludePatterns()) { - tc.writeArrayValue(resourcesArgs, indexOne, tc.load(pattern)); - tc.invokeVirtualMethod(INVOKE, addResourcesMethod, resourcesSingleton, resourcesArgs); - } - } - CatchBlockCreator cc = tc.addCatch(Throwable.class); - cc.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), cc.getCaughtException()); - - resourceIncludesExcludes.returnVoid(); - overallCatch.invokeStaticMethod(resourceIncludesExcludes.getMethodDescriptor()); - } - - MethodCreator registerServiceProviders = file - .getMethodCreator("registerServiceProviders", void.class) - .setModifiers(Modifier.PRIVATE | Modifier.STATIC); - for (ServiceProviderBuildItem i : serviceProviderBuildItems) { - registerServiceProviders.invokeStaticMethod( - ofMethod(ResourceHelper.class, "registerResources", void.class, String.class), - registerServiceProviders.load(i.serviceDescriptorFile())); - } - registerServiceProviders.returnVoid(); - overallCatch.invokeStaticMethod(registerServiceProviders.getMethodDescriptor()); - - if (!resourceBundles.isEmpty()) { - MethodCreator registerResourceBundles = file - .getMethodCreator("registerResourceBundles", void.class) - .setModifiers(Modifier.PRIVATE | Modifier.STATIC); - - // Needed to access LOCALIZATION_FEATURE - exports.produce( - new JPMSExportBuildItem("org.graalvm.nativeimage.builder", "com.oracle.svm.core.jdk.localization", - null, GraalVM.Version.VERSION_22_3_0)); - - BranchResult graalVm22_3Test = registerResourceBundles - .ifGreaterEqualZero(registerResourceBundles.invokeVirtualMethod(VERSION_COMPARE_TO, - registerResourceBundles.invokeStaticMethod(VERSION_CURRENT), - registerResourceBundles.marshalAsArray(int.class, registerResourceBundles.load(22), - registerResourceBundles.load(3)))); - /* GraalVM >= 22.3 */ - try (BytecodeCreator greaterThan22_2 = graalVm22_3Test.trueBranch()) { - - MethodDescriptor addResourceBundle = ofMethod("org.graalvm.nativeimage.hosted.RuntimeResourceAccess", - "addResourceBundle", void.class, Module.class, String.class); - - for (NativeImageResourceBundleBuildItem i : resourceBundles) { - TryBlock tc = greaterThan22_2.tryBlock(); - - String moduleName = i.getModuleName(); - ResultHandle moduleNameHandle; - if (moduleName == null) { - moduleNameHandle = tc.loadNull(); - } else { - moduleNameHandle = tc.load(moduleName); - } - ResultHandle module = tc.invokeStaticMethod(FIND_MODULE_METHOD, moduleNameHandle); - tc.invokeStaticMethod(addResourceBundle, module, tc.load(i.getBundleName())); - CatchBlockCreator c = tc.addCatch(Throwable.class); - //c.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), c.getCaughtException()); - } - } - - /* GraalVM < 22.3 */ - try (BytecodeCreator smallerThan22_3 = graalVm22_3Test.falseBranch()) { - - ResultHandle locClass = smallerThan22_3.loadClassFromTCCL(LOCALIZATION_FEATURE); - ResultHandle newParams = smallerThan22_3.marshalAsArray(Class.class, - smallerThan22_3.loadClassFromTCCL(String.class)); - ResultHandle registerMethod = smallerThan22_3.invokeStaticMethod( - LOOKUP_METHOD, - locClass, smallerThan22_3.load("prepareBundle"), newParams); - - ResultHandle locSupport = smallerThan22_3.invokeStaticMethod( - IMAGE_SINGLETONS_LOOKUP, - locClass); - - for (NativeImageResourceBundleBuildItem i : resourceBundles) { - TryBlock et = smallerThan22_3.tryBlock(); - - et.invokeVirtualMethod(ofMethod(Method.class, "invoke", Object.class, Object.class, Object[].class), - registerMethod, locSupport, et.marshalAsArray(Object.class, et.load(i.getBundleName()))); - CatchBlockCreator c = et.addCatch(Throwable.class); - //c.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), c.getCaughtException()); - } - } - - registerResourceBundles.returnVoid(); - overallCatch.invokeStaticMethod(registerResourceBundles.getMethodDescriptor()); - } - CatchBlockCreator print = overallCatch.addCatch(Throwable.class); print.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), print.getCaughtException()); diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageResourceConfigStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageResourceConfigStep.java new file mode 100644 index 00000000000000..84a002343b29e8 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageResourceConfigStep.java @@ -0,0 +1,86 @@ +package io.quarkus.deployment.steps; + +import java.io.IOException; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import io.quarkus.builder.Json; +import io.quarkus.builder.Json.JsonArrayBuilder; +import io.quarkus.builder.Json.JsonObjectBuilder; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.GeneratedResourceBuildItem; +import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; +import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem; +import io.quarkus.deployment.builditem.nativeimage.NativeImageResourcePatternsBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; +import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild; +import io.quarkus.util.GlobUtil; + +public class NativeImageResourceConfigStep { + + @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class) + void generateResourceConfig(BuildProducer resourceConfig, + List resourcePatterns, + List resourceBundles, + List resources, + List serviceProviderBuildItems) { + JsonObjectBuilder root = Json.object(); + + JsonObjectBuilder resourcesJs = Json.object(); + JsonArrayBuilder includes = Json.array(); + JsonArrayBuilder excludes = Json.array(); + + for (NativeImageResourceBuildItem i : resources) { + for (String path : i.getResources()) { + JsonObjectBuilder pat = Json.object(); + pat.put("pattern", GlobUtil.toRegexPattern(path)); + includes.add(pat); + } + addListToJsonArray(includes, i.getResources()); + } + + for (ServiceProviderBuildItem i : serviceProviderBuildItems) { + includes.add(Json.object().put("pattern", GlobUtil.toRegexPattern(i.serviceDescriptorFile()))); + } + + for (NativeImageResourcePatternsBuildItem resourcePatternsItem : resourcePatterns) { + addListToJsonArray(includes, resourcePatternsItem.getIncludePatterns()); + addListToJsonArray(excludes, resourcePatternsItem.getExcludePatterns()); + } + resourcesJs.put("includes", includes); + resourcesJs.put("excludes", excludes); + root.put("resources", resourcesJs); + + JsonArrayBuilder bundles = Json.array(); + for (NativeImageResourceBundleBuildItem i : resourceBundles) { + JsonObjectBuilder bundle = Json.object(); + String moduleName = i.getModuleName(); + StringBuilder sb = new StringBuilder(); + if (moduleName != null) { + sb.append(moduleName).append(":"); + } + sb.append(i.getBundleName().replace("/", ".")); + bundle.put("name", sb.toString()); + bundles.add(bundle); + } + root.put("bundles", bundles); + + try (StringWriter writer = new StringWriter()) { + root.appendTo(writer); + resourceConfig.produce(new GeneratedResourceBuildItem("META-INF/native-image/resource-config.json", + writer.toString().getBytes(StandardCharsets.UTF_8))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void addListToJsonArray(JsonArrayBuilder array, List patterns) { + for (String pattern : patterns) { + JsonObjectBuilder pat = Json.object(); + pat.put("pattern", pattern); + array.add(pat); + } + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/ResourceHelper.java b/core/runtime/src/main/java/io/quarkus/runtime/ResourceHelper.java deleted file mode 100644 index 3d37825a5450ad..00000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/ResourceHelper.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.quarkus.runtime; - -import java.io.InputStream; -import java.lang.reflect.Method; - -import org.graalvm.home.Version; - -import io.quarkus.runtime.util.ClassPathUtils; - -/** - * Helper method that is invoked from generated bytecode during image processing - */ -public class ResourceHelper { - - public static void registerResources(String resource) { - Version currentGraalVmVersion = Version.getCurrent(); - if (currentGraalVmVersion.compareTo(22, 3) >= 0) { - // Use the public API RuntimeResourceAccess with GraalVM >= 22.3 - // TODO: Remove reflective access once support for GraalVM < 22.3 gets dropped and directly invoke - // RuntimeResourceAccess.addResource(ClassLoader.getSystemClassLoader().getUnnamedModule(), resource); - try { - Class runtimeResourceSupportClass = Class.forName("org.graalvm.nativeimage.hosted.RuntimeResourceAccess"); - Method addResource = runtimeResourceSupportClass.getDeclaredMethod("addResource", Module.class, String.class); - addResource.invoke(null, ClassLoader.getSystemClassLoader().getUnnamedModule(), resource); - } catch (Exception e) { - throw new RuntimeException("Failed to load resource " + resource, e); - } - } else { - // Use internal API with GraalVM < 22.3 - try { - Class resourcesClass = Class.forName("com.oracle.svm.core.jdk.Resources"); - Method register = resourcesClass.getDeclaredMethod("registerResource", String.class, InputStream.class); - ClassPathUtils.consumeAsStreams(ResourceHelper.class.getClassLoader(), resource, in -> { - try { - register.invoke(null, resource, in); - } catch (Exception e) { - throw new RuntimeException("Failed to register resource " + resource, e); - } - }); - } catch (Exception e) { - throw new RuntimeException("Failed to load resource " + resource, e); - } - } - } - -} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/graal/ResourcesFeature.java b/core/runtime/src/main/java/io/quarkus/runtime/graal/ResourcesFeature.java deleted file mode 100644 index e1b3be92ef7fb1..00000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/graal/ResourcesFeature.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.quarkus.runtime.graal; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -import org.graalvm.nativeimage.hosted.Feature; - -import io.quarkus.runtime.ResourceHelper; - -public class ResourcesFeature implements Feature { - - public static final String META_INF_QUARKUS_NATIVE_RESOURCES_TXT = "META-INF/quarkus-native-resources.txt"; - - @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(META_INF_QUARKUS_NATIVE_RESOURCES_TXT); - if (resourceAsStream != null) { - try (BufferedReader in = new BufferedReader(new InputStreamReader(resourceAsStream))) { - String line; - while ((line = in.readLine()) != null) { - if (!line.isEmpty()) { - ResourceHelper.registerResources(line); - } - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - @Override - public String getDescription() { - return "Register each line in " + META_INF_QUARKUS_NATIVE_RESOURCES_TXT + " as a resource on Substrate VM"; - } -}