diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index efb21d961880..8fbc207571bf 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -36,6 +36,8 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-49770) Add support for glob patterns in resource-config files in addition to regexp. The Tracing Agent now prints entries in the glob format. * (GR-46386) Throw missing registration errors for JNI queries when the query was not included in the reachability metadata. * (GR-51479) Implement cgroup support in native code. See the [README](src/com.oracle.svm.native.libcontainer/README.md) and the [PR description](https://github.com/oracle/graal/pull/8989). +* (GR-54241) Streamline Native Image reachability metadata into a single `reachability-metadata.json`. The formerly-used individual metadata files (`reflection-config.json`, `resource-config.json`, etc.) are now deprecated, but will still be accepted. + Native Image will only output `reachability-metadata.json` files, and those will be readable on the previous LTS versions of GraalVM. See the [documentation](../docs/reference-manual/native-image/ReachabilityMetadata.md). ## GraalVM for JDK 22 (Internal Version 24.0.0) * (GR-48304) Red Hat added support for the JFR event ThreadAllocationStatistics. diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 56af591175d5..32ed90c7be35 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -1285,7 +1285,9 @@ def _native_image_launcher_extra_jvm_args(): build_args=driver_build_args + [ '--features=com.oracle.svm.agent.NativeImageAgent$RegistrationFeature', '--enable-url-protocols=jar', - ], + ] + svm_experimental_options([ + '-H:+TreatAllTypeReachableConditionsAsTypeReached', + ]), headers=False, home_finder=False, ), @@ -1574,6 +1576,7 @@ def _native_image_configure_extra_jvm_args(): main_class='com.oracle.svm.configure.ConfigurationTool', build_args=svm_experimental_options([ '-H:-ParseRuntimeOptions', + '-H:+TreatAllTypeReachableConditionsAsTypeReached', ]), extra_jvm_args=_native_image_configure_extra_jvm_args(), home_finder=False, diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationConditionPrintable.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationConditionPrintable.java index d9a4eda47730..0344046c7736 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationConditionPrintable.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationConditionPrintable.java @@ -35,10 +35,14 @@ import jdk.graal.compiler.util.json.JsonWriter; final class ConfigurationConditionPrintable { - static void printConditionAttribute(UnresolvedConfigurationCondition condition, JsonWriter writer) throws IOException { + static void printConditionAttribute(UnresolvedConfigurationCondition condition, JsonWriter writer, boolean combinedFile) throws IOException { if (!condition.isAlwaysTrue()) { writer.quote(CONDITIONAL_KEY).appendFieldSeparator().appendObjectStart(); - writer.quote(condition.isRuntimeChecked() ? TYPE_REACHED_KEY : TYPE_REACHABLE_KEY).appendFieldSeparator().quote(condition.getTypeName()); + /* + * typeReachable conditions are emitted as typeReached in reachability-metadata.json. + * typeReached conditions are emitted as typeReachable in resource-config.json + */ + writer.quote(combinedFile ? TYPE_REACHED_KEY : TYPE_REACHABLE_KEY).appendFieldSeparator().quote(condition.getTypeName()); writer.appendObjectEnd().appendSeparator(); } } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java index 7284a8120bf9..39d0bcf00ca1 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java @@ -460,7 +460,7 @@ public synchronized void setAllPublicConstructors(ConfigurationMemberAccessibili @Override public synchronized void printJson(JsonWriter writer) throws IOException { writer.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(condition, writer); + ConfigurationConditionPrintable.printConditionAttribute(condition, writer, true); writer.quote("type").appendFieldSeparator(); typeDescriptor.printJson(writer); diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ParserConfigurationAdapter.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ParserConfigurationAdapter.java index c653e9206892..39657123cec2 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ParserConfigurationAdapter.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ParserConfigurationAdapter.java @@ -103,73 +103,73 @@ public void registerConstructor(UnresolvedConfigurationCondition condition, bool @Override public void registerPublicClasses(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPublicClasses(); } @Override public void registerDeclaredClasses(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllDeclaredClasses(); } @Override public void registerRecordComponents(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllRecordComponents(); } @Override public void registerPermittedSubclasses(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPermittedSubclasses(); } @Override public void registerNestMembers(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllNestMembers(); } @Override public void registerSigners(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllSigners(); } @Override public void registerPublicFields(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPublicFields(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerDeclaredFields(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllDeclaredFields(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerPublicMethods(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPublicMethods(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerDeclaredMethods(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllDeclaredMethods(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerPublicConstructors(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPublicConstructors(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerDeclaredConstructors(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllDeclaredConstructors(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java index 73fc92121bd2..64296045273d 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java @@ -110,25 +110,30 @@ public void printJson(JsonWriter writer) throws IOException { public static void printProxyInterfaces(JsonWriter writer, List>> lists) throws IOException { lists.sort(ConditionalElement.comparator(ProxyConfiguration::compareList)); - writer.append('['); - writer.indent(); - String prefix = ""; + writer.appendArrayStart(); + boolean firstProxy = true; for (ConditionalElement> list : lists) { - writer.append(prefix).newline(); - writer.append('{').indent().newline(); - ConfigurationConditionPrintable.printConditionAttribute(list.condition(), writer); - writer.quote("interfaces").append(":").append('['); - String typePrefix = ""; + if (firstProxy) { + firstProxy = false; + } else { + writer.appendSeparator(); + } + writer.appendObjectStart(); + ConfigurationConditionPrintable.printConditionAttribute(list.condition(), writer, false); + writer.quote("interfaces").appendFieldSeparator().appendArrayStart(); + boolean firstType = true; for (String type : list.element()) { - writer.append(typePrefix).quote(type); - typePrefix = ","; + if (firstType) { + firstType = false; + } else { + writer.appendSeparator(); + } + writer.quote(type); } - writer.append(']').unindent().newline(); - writer.append('}'); - prefix = ","; + writer.appendArrayEnd(); + writer.appendObjectEnd(); } - writer.unindent().newline(); - writer.append(']'); + writer.appendArrayEnd(); } @Override diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java index eb409453bf04..982d4a5e1f77 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java @@ -342,19 +342,19 @@ public boolean anyBundleMatches(UnresolvedConfigurationCondition condition, Stri @Override public void printJson(JsonWriter writer) throws IOException { printGlobsJson(writer, true); - writer.appendSeparator().newline(); - printBundlesJson(writer); + writer.appendSeparator(); + printBundlesJson(writer, true); } @Override public void printLegacyJson(JsonWriter writer) throws IOException { - writer.appendObjectStart().indent().newline(); + writer.appendObjectStart(); printResourcesJson(writer); - writer.appendSeparator().newline(); - printBundlesJson(writer); - writer.appendSeparator().newline(); + writer.appendSeparator(); + printBundlesJson(writer, false); + writer.appendSeparator(); printGlobsJson(writer, false); - writer.unindent().newline().appendObjectEnd(); + writer.appendObjectEnd(); } void printResourcesJson(JsonWriter writer) throws IOException { @@ -369,14 +369,14 @@ void printResourcesJson(JsonWriter writer) throws IOException { writer.appendObjectEnd(); } - void printBundlesJson(JsonWriter writer) throws IOException { + void printBundlesJson(JsonWriter writer, boolean combinedFile) throws IOException { writer.quote(BUNDLES_KEY).appendFieldSeparator(); - JsonPrinter.printCollection(writer, bundles.keySet(), ConditionalElement.comparator(), (p, w) -> printResourceBundle(bundles.get(p), w)); + JsonPrinter.printCollection(writer, bundles.keySet(), ConditionalElement.comparator(), (p, w) -> printResourceBundle(bundles.get(p), w, combinedFile)); } - void printGlobsJson(JsonWriter writer, boolean useResourcesFieldName) throws IOException { - writer.quote(useResourcesFieldName ? RESOURCES_KEY : GLOBS_KEY).appendFieldSeparator(); - JsonPrinter.printCollection(writer, addedGlobs, ConditionalElement.comparator(ResourceEntry.comparator()), ResourceConfiguration::conditionalGlobElementJson); + void printGlobsJson(JsonWriter writer, boolean combinedFile) throws IOException { + writer.quote(combinedFile ? RESOURCES_KEY : GLOBS_KEY).appendFieldSeparator(); + JsonPrinter.printCollection(writer, addedGlobs, ConditionalElement.comparator(ResourceEntry.comparator()), (p, w) -> conditionalGlobElementJson(p, w, combinedFile)); } @Override @@ -384,9 +384,9 @@ public ConfigurationParser createParser(boolean strictMetadata) { return ResourceConfigurationParser.create(strictMetadata, ConfigurationConditionResolver.identityResolver(), new ResourceConfiguration.ParserAdapter(this), true); } - private static void printResourceBundle(BundleConfiguration config, JsonWriter writer) throws IOException { + private static void printResourceBundle(BundleConfiguration config, JsonWriter writer, boolean combinedFile) throws IOException { writer.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(config.condition, writer); + ConfigurationConditionPrintable.printConditionAttribute(config.condition, writer, combinedFile); writer.quote("name").appendFieldSeparator().quote(config.baseName); if (!config.locales.isEmpty()) { writer.appendSeparator().quote("locales").appendFieldSeparator(); @@ -417,11 +417,11 @@ public boolean supportsCombinedFile() { return true; } - private static void conditionalGlobElementJson(ConditionalElement p, JsonWriter w) throws IOException { + private static void conditionalGlobElementJson(ConditionalElement p, JsonWriter w, boolean combinedFile) throws IOException { String pattern = p.element().pattern(); String module = p.element().module(); w.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(p.condition(), w); + ConfigurationConditionPrintable.printConditionAttribute(p.condition(), w, combinedFile); if (module != null) { w.quote("module").appendFieldSeparator().quote(module).appendSeparator(); } @@ -431,7 +431,7 @@ private static void conditionalGlobElementJson(ConditionalElement private static void conditionalRegexElementJson(ConditionalElement p, JsonWriter w) throws IOException { w.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(p.condition(), w); + ConfigurationConditionPrintable.printConditionAttribute(p.condition(), w, false); w.quote("pattern").appendFieldSeparator().quote(p.element()); w.appendObjectEnd(); } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationLambdaCapturingType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationLambdaCapturingType.java index 0e7798618d1e..d797cdd42e58 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationLambdaCapturingType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationLambdaCapturingType.java @@ -57,7 +57,7 @@ public String getQualifiedJavaName() { @Override public void printJson(JsonWriter writer) throws IOException { writer.append('{').indent().newline(); - ConfigurationConditionPrintable.printConditionAttribute(condition, writer); + ConfigurationConditionPrintable.printConditionAttribute(condition, writer, false); writer.quote(SerializationConfigurationParser.NAME_KEY).append(":").quote(qualifiedJavaName); writer.unindent().newline().append('}'); diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java index 21a96a62368f..bc6bc8fcadb0 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java @@ -35,6 +35,9 @@ import jdk.graal.compiler.util.json.JsonPrintable; import jdk.graal.compiler.util.json.JsonWriter; +import static com.oracle.svm.core.configure.ConfigurationParser.NAME_KEY; +import static com.oracle.svm.core.configure.ConfigurationParser.TYPE_KEY; + public class SerializationConfigurationType implements JsonPrintable, Comparable { private final UnresolvedConfigurationCondition condition; private final String qualifiedJavaName; @@ -66,17 +69,17 @@ public UnresolvedConfigurationCondition getCondition() { @Override public void printJson(JsonWriter writer) throws IOException { - printJson(writer, SerializationConfigurationParser.TYPE_KEY); + printJson(writer, true); } public void printLegacyJson(JsonWriter writer) throws IOException { - printJson(writer, SerializationConfigurationParser.NAME_KEY); + printJson(writer, false); } - private void printJson(JsonWriter writer, String key) throws IOException { + private void printJson(JsonWriter writer, boolean combinedFile) throws IOException { writer.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(condition, writer); - writer.quote(key).appendFieldSeparator().quote(qualifiedJavaName); + ConfigurationConditionPrintable.printConditionAttribute(condition, writer, combinedFile); + writer.quote(combinedFile ? TYPE_KEY : NAME_KEY).appendFieldSeparator().quote(qualifiedJavaName); if (qualifiedCustomTargetConstructorJavaName != null) { writer.appendSeparator(); writer.quote(SerializationConfigurationParser.CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY).appendFieldSeparator() diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyResourceConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyResourceConfigurationParser.java index ef4979778352..25487904cc63 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyResourceConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyResourceConfigurationParser.java @@ -25,9 +25,16 @@ package com.oracle.svm.core.configure; import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.function.BiConsumer; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.MapCursor; +import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; + +import com.oracle.svm.core.TypeResult; +import com.oracle.svm.core.jdk.resources.CompressedGlobTrie.CompressedGlobTrie; final class LegacyResourceConfigurationParser extends ResourceConfigurationParser { LegacyResourceConfigurationParser(ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { @@ -64,4 +71,61 @@ private void parseTopLevelObject(EconomicMap obj, Object origin) parseGlobsObject(globsObject, origin); } } + + @Override + protected UnresolvedConfigurationCondition parseCondition(EconomicMap condition) { + return parseCondition(condition, false); + } + + @SuppressWarnings("unchecked") + private void parseResourcesObject(Object resourcesObject, Object origin) { + if (resourcesObject instanceof EconomicMap) { // New format + EconomicMap resourcesObjectMap = (EconomicMap) resourcesObject; + checkAttributes(resourcesObjectMap, "resource descriptor object", Collections.singleton("includes"), Collections.singleton("excludes")); + Object includesObject = resourcesObjectMap.get("includes"); + Object excludesObject = resourcesObjectMap.get("excludes"); + + List includes = asList(includesObject, "Attribute 'includes' must be a list of resources"); + for (Object object : includes) { + parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern, origin), + (condition, module, glob) -> registry.addGlob(condition, module, glob, origin), "'includes' list"); + } + + if (excludesObject != null) { + List excludes = asList(excludesObject, "Attribute 'excludes' must be a list of resources"); + for (Object object : excludes) { + parsePatternEntry(object, registry::ignoreResources, null, "'excludes' list"); + } + } + } else { // Old format: may be deprecated in future versions + List resources = asList(resourcesObject, "Attribute 'resources' must be a list of resources"); + for (Object object : resources) { + parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern, origin), + (condition, module, glob) -> registry.addGlob(condition, module, glob, origin), "'resources' list"); + } + } + } + + private void parsePatternEntry(Object data, BiConsumer resourceRegistry, GlobPatternConsumer globRegistry, String parentType) { + EconomicMap resource = asMap(data, "Elements of " + parentType + " must be a resource descriptor object"); + checkAttributes(resource, "regex resource descriptor object", Collections.singletonList("pattern"), Collections.singletonList(CONDITIONAL_KEY)); + TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource, false)); + if (!resolvedConfigurationCondition.isPresent()) { + return; + } + + Object valueObject = resource.get("pattern"); + String value = asString(valueObject, "pattern"); + + /* Parse fully literal regex as globs */ + if (value.startsWith("\\Q") && value.endsWith("\\E") && value.indexOf("\\E") == value.lastIndexOf("\\E")) { + String globValue = value.substring("\\Q".length(), value.length() - "\\E".length()); + if (CompressedGlobTrie.validatePattern(globValue).isEmpty()) { + globRegistry.accept(resolvedConfigurationCondition.get(), null, globValue); + return; + } + } + + resourceRegistry.accept(resolvedConfigurationCondition.get(), value); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceConfigurationParser.java index 3389995ed577..01ec3fae048d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceConfigurationParser.java @@ -28,10 +28,10 @@ import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.function.BiConsumer; import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.jdk.localization.LocalizationSupport; @@ -64,38 +64,13 @@ protected void parseBundlesObject(Object bundlesObject) { } } - @SuppressWarnings("unchecked") - protected void parseResourcesObject(Object resourcesObject, Object origin) { - if (resourcesObject instanceof EconomicMap) { // New format - EconomicMap resourcesObjectMap = (EconomicMap) resourcesObject; - checkAttributes(resourcesObjectMap, "resource descriptor object", Collections.singleton("includes"), Collections.singleton("excludes")); - Object includesObject = resourcesObjectMap.get("includes"); - Object excludesObject = resourcesObjectMap.get("excludes"); - - List includes = asList(includesObject, "Attribute 'includes' must be a list of resources"); - for (Object object : includes) { - parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern, origin), "'includes' list"); - } - - if (excludesObject != null) { - List excludes = asList(excludesObject, "Attribute 'excludes' must be a list of resources"); - for (Object object : excludes) { - parsePatternEntry(object, registry::ignoreResources, "'excludes' list"); - } - } - } else { // Old format: may be deprecated in future versions - List resources = asList(resourcesObject, "Attribute 'resources' must be a list of resources"); - for (Object object : resources) { - parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern, origin), "'resources' list"); - } - } - } + protected abstract UnresolvedConfigurationCondition parseCondition(EconomicMap condition); private void parseBundle(Object bundle) { EconomicMap resource = asMap(bundle, "Elements of 'bundles' list must be a bundle descriptor object"); checkAttributes(resource, "bundle descriptor object", Collections.singletonList("name"), Arrays.asList("locales", "classNames", "condition")); String basename = asString(resource.get("name")); - TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource, false)); + TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource)); if (!resolvedConfigurationCondition.isPresent()) { return; } @@ -133,19 +108,6 @@ private static Locale parseLocale(Object input) { return locale; } - private void parsePatternEntry(Object data, BiConsumer resourceRegistry, String parentType) { - EconomicMap resource = asMap(data, "Elements of " + parentType + " must be a resource descriptor object"); - checkAttributes(resource, "regex resource descriptor object", Collections.singletonList("pattern"), Collections.singletonList(CONDITIONAL_KEY)); - TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource, false)); - if (!resolvedConfigurationCondition.isPresent()) { - return; - } - - Object valueObject = resource.get("pattern"); - String value = asString(valueObject, "pattern"); - resourceRegistry.accept(resolvedConfigurationCondition.get(), value); - } - protected void parseGlobsObject(Object globsObject, Object origin) { List globs = asList(globsObject, "Attribute 'globs' must be a list of glob patterns"); for (Object object : globs) { @@ -153,14 +115,14 @@ protected void parseGlobsObject(Object globsObject, Object origin) { } } - private interface GlobPatternConsumer { + protected interface GlobPatternConsumer { void accept(T a, String b, String c); } private void parseGlobEntry(Object data, GlobPatternConsumer resourceRegistry) { EconomicMap globObject = asMap(data, "Elements of 'globs' list must be a glob descriptor objects"); checkAttributes(globObject, "glob resource descriptor object", Collections.singletonList(GLOB_KEY), List.of(CONDITIONAL_KEY, MODULE_KEY)); - TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(globObject, false)); + TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(globObject)); if (!resolvedConfigurationCondition.isPresent()) { return; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceMetadataParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceMetadataParser.java index 279ecb9f8039..a5e593f7f469 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceMetadataParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceMetadataParser.java @@ -26,6 +26,9 @@ import java.net.URI; +import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; + final class ResourceMetadataParser extends ResourceConfigurationParser { ResourceMetadataParser(ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { super(conditionResolver, registry, strictConfiguration); @@ -42,4 +45,9 @@ public void parseAndRegister(Object json, URI origin) { parseBundlesObject(bundlesJson); } } + + @Override + protected UnresolvedConfigurationCondition parseCondition(EconomicMap condition) { + return parseCondition(condition, true); + } }