From 9e2c6e7629eeb2a50550be6dea17ec81a2dd09ff Mon Sep 17 00:00:00 2001 From: Loic Ottet Date: Tue, 27 Aug 2024 14:41:50 +0200 Subject: [PATCH] Adapt configuration parser to 23.1 --- .../test/config/OmitPreviousConfigTests.java | 4 +- .../config/ResourceConfigurationTest.java | 4 +- .../svm/configure/ConfigurationBase.java | 7 +- .../config/ConfigurationFileCollection.java | 70 +++++-- .../configure/config/ConfigurationSet.java | 9 +- .../config/ParserConfigurationAdapter.java | 58 +++--- .../PredefinedClassesConfiguration.java | 8 +- .../configure/config/ProxyConfiguration.java | 12 +- .../config/ResourceConfiguration.java | 8 +- .../config/SerializationConfiguration.java | 8 +- .../configure/config/TypeConfiguration.java | 16 +- .../PartialConfigurationWithOrigins.java | 6 +- .../configure/ConditionalRuntimeValue.java | 69 ------ .../ConfigurationConditionResolver.java | 18 +- .../core/configure/ConfigurationFiles.java | 108 +++------- .../core/configure/ConfigurationParser.java | 65 +++--- .../ConfigurationTypeDescriptor.java | 2 +- .../LegacyReflectionConfigurationParser.java | 14 +- .../LegacyResourceConfigurationParser.java | 55 ++++- ...egacySerializationConfigurationParser.java | 31 ++- .../NamedConfigurationTypeDescriptor.java | 2 +- .../configure/ProxyConfigurationParser.java | 28 ++- .../ProxyConfigurationTypeDescriptor.java | 5 +- .../ReflectionConfigurationParser.java | 31 ++- ...ReflectionConfigurationParserDelegate.java | 46 ++-- .../configure/ReflectionMetadataParser.java | 14 +- .../ResourceConfigurationParser.java | 140 ++++++++----- .../configure/ResourceMetadataParser.java | 12 +- .../svm/core/configure/ResourcesRegistry.java | 43 +++- .../core/configure/RuntimeConditionSet.java | 197 ------------------ .../SerializationConfigurationParser.java | 23 +- .../SerializationMetadataParser.java | 8 +- .../ReflectionConfigurationFilesHelp.txt | 2 +- .../SerializationConfigurationFilesHelp.txt | 2 +- .../core/jdk/proxy/DynamicProxyRegistry.java | 2 +- ...java_lang_invoke_MethodHandles_Lookup.java | 7 + .../reflect/proxy/DynamicProxySupport.java | 6 +- .../ConditionalConfigurationRegistry.java | 4 +- .../oracle/svm/hosted/ResourcesFeature.java | 12 +- .../config/ConfigurationParserUtils.java | 14 +- .../config/ReflectionRegistryAdapter.java | 80 +++---- .../svm/hosted/config/RegistryAdapter.java | 153 ++++++++------ .../svm/hosted/jni/JNIAccessFeature.java | 17 +- .../svm/hosted/reflect/ReflectionFeature.java | 14 +- .../reflect/proxy/DynamicProxyFeature.java | 4 +- .../hosted/reflect/proxy/ProxyRegistry.java | 2 +- .../serialize/SerializationFeature.java | 15 +- 47 files changed, 693 insertions(+), 762 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalRuntimeValue.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeConditionSet.java diff --git a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java index 38c5440b0fe..6c70847ea12 100644 --- a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java +++ b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java @@ -229,8 +229,8 @@ class TypeMethodsWithFlagsTest { final Map methodsThatMustExist = new HashMap<>(); final Map methodsThatMustNotExist = new HashMap<>(); - final TypeConfiguration previousConfig = new TypeConfiguration(); - final TypeConfiguration currentConfig = new TypeConfiguration(); + final TypeConfiguration previousConfig = new TypeConfiguration(""); + final TypeConfiguration currentConfig = new TypeConfiguration(""); TypeMethodsWithFlagsTest(ConfigurationMemberDeclaration methodKind) { this.methodKind = methodKind; diff --git a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/ResourceConfigurationTest.java b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/ResourceConfigurationTest.java index 600b21440bb..edb48f64a3b 100644 --- a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/ResourceConfigurationTest.java +++ b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/ResourceConfigurationTest.java @@ -38,9 +38,9 @@ import org.junit.Test; import com.oracle.svm.configure.config.ResourceConfiguration; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ResourceConfigurationParser; import com.oracle.svm.core.configure.ResourcesRegistry; +import com.oracle.svm.core.util.json.JsonWriter; public class ResourceConfigurationTest { @@ -117,7 +117,7 @@ public void addClassBasedResourceBundle(ConfigurationCondition condition, String } }; - ResourceConfigurationParser rcp = new ResourceConfigurationParser(registry, true); + ResourceConfigurationParser rcp = ResourceConfigurationParser.create(false, registry, true); writerThread.start(); rcp.parseAndRegister(pr); diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ConfigurationBase.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ConfigurationBase.java index 26a7c7a596d..25962c52983 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ConfigurationBase.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ConfigurationBase.java @@ -26,10 +26,11 @@ import java.util.function.Consumer; -import com.oracle.svm.core.util.json.JsonPrintable; -import com.oracle.svm.core.configure.ConfigurationParser; import org.graalvm.nativeimage.impl.ConfigurationCondition; +import com.oracle.svm.core.configure.ConfigurationParser; +import com.oracle.svm.core.util.json.JsonPrintable; + public abstract class ConfigurationBase, P> implements JsonPrintable { public abstract boolean isEmpty(); @@ -68,5 +69,5 @@ public T copyAndFilter(P predicate) { return copyAnd(copy -> copy.removeIf(predicate)); } - public abstract ConfigurationParser createParser(); + public abstract ConfigurationParser createParser(boolean strictMetadata); } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationFileCollection.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationFileCollection.java index fbc031bc840..cf2fc9046ad 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationFileCollection.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationFileCollection.java @@ -24,10 +24,14 @@ */ package com.oracle.svm.configure.config; +import static com.oracle.svm.core.configure.ConfigurationParser.JNI_KEY; +import static com.oracle.svm.core.configure.ConfigurationParser.REFLECTION_KEY; + import java.io.IOException; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; @@ -35,13 +39,16 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Collectors; import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationParser; +import com.oracle.svm.core.util.VMError; public class ConfigurationFileCollection { public static final Function FAIL_ON_EXCEPTION = e -> e; + private final Set reachabilityMetadataPaths = new LinkedHashSet<>(); private final Set jniConfigPaths = new LinkedHashSet<>(); private final Set reflectConfigPaths = new LinkedHashSet<>(); private final Set proxyConfigPaths = new LinkedHashSet<>(); @@ -51,6 +58,7 @@ public class ConfigurationFileCollection { private Set lockFilePaths; public void addDirectory(Path path) { + reachabilityMetadataPaths.add(path.resolve(ConfigurationFile.REACHABILITY_METADATA.getFileName()).toUri()); jniConfigPaths.add(path.resolve(ConfigurationFile.JNI.getFileName()).toUri()); reflectConfigPaths.add(path.resolve(ConfigurationFile.REFLECTION.getFileName()).toUri()); proxyConfigPaths.add(path.resolve(ConfigurationFile.DYNAMIC_PROXY.getFileName()).toUri()); @@ -70,24 +78,51 @@ private void detectAgentLock(T location, Predicate exists, Function fileResolver) { - jniConfigPaths.add(fileResolver.apply(ConfigurationFile.JNI.getFileName())); - reflectConfigPaths.add(fileResolver.apply(ConfigurationFile.REFLECTION.getFileName())); - proxyConfigPaths.add(fileResolver.apply(ConfigurationFile.DYNAMIC_PROXY.getFileName())); - resourceConfigPaths.add(fileResolver.apply(ConfigurationFile.RESOURCES.getFileName())); - serializationConfigPaths.add(fileResolver.apply(ConfigurationFile.SERIALIZATION.getFileName())); - predefinedClassesConfigPaths.add(fileResolver.apply(ConfigurationFile.PREDEFINED_CLASSES_NAME.getFileName())); + addFile(reachabilityMetadataPaths, fileResolver, ConfigurationFile.REACHABILITY_METADATA); + addFile(jniConfigPaths, fileResolver, ConfigurationFile.JNI); + addFile(reflectConfigPaths, fileResolver, ConfigurationFile.REFLECTION); + addFile(proxyConfigPaths, fileResolver, ConfigurationFile.DYNAMIC_PROXY); + addFile(resourceConfigPaths, fileResolver, ConfigurationFile.RESOURCES); + addFile(serializationConfigPaths, fileResolver, ConfigurationFile.SERIALIZATION); + addFile(predefinedClassesConfigPaths, fileResolver, ConfigurationFile.PREDEFINED_CLASSES_NAME); detectAgentLock(fileResolver.apply(ConfigurationFile.LOCK_FILE_NAME), Objects::nonNull, Function.identity()); } + private static void addFile(Set metadataPaths, Function fileResolver, ConfigurationFile configurationFile) { + URI uri = fileResolver.apply(configurationFile.getFileName()); + if (uri != null) { + metadataPaths.add(uri); + } + } + public Set getDetectedAgentLockPaths() { return (lockFilePaths != null) ? lockFilePaths : Collections.emptySet(); } public boolean isEmpty() { - return jniConfigPaths.isEmpty() && reflectConfigPaths.isEmpty() && proxyConfigPaths.isEmpty() && + return reachabilityMetadataPaths.isEmpty() && jniConfigPaths.isEmpty() && reflectConfigPaths.isEmpty() && proxyConfigPaths.isEmpty() && resourceConfigPaths.isEmpty() && serializationConfigPaths.isEmpty() && predefinedClassesConfigPaths.isEmpty(); } + public Set getPaths(ConfigurationFile configurationFile) { + Set uris; + switch (configurationFile) { + case REACHABILITY_METADATA -> uris = getReachabilityMetadataPaths(); + case DYNAMIC_PROXY -> uris = getProxyConfigPaths(); + case RESOURCES -> uris = getResourceConfigPaths(); + case JNI -> uris = getJniConfigPaths(); + case REFLECTION -> uris = getReflectConfigPaths(); + case SERIALIZATION -> uris = getSerializationConfigPaths(); + case PREDEFINED_CLASSES_NAME -> uris = getPredefinedClassesConfigPaths(); + default -> throw VMError.shouldNotReachHere("Cannot get paths for configuration file " + configurationFile); + } + return uris.stream().map(Paths::get).collect(Collectors.toSet()); + } + + public Set getReachabilityMetadataPaths() { + return reachabilityMetadataPaths; + } + public Set getJniConfigPaths() { return jniConfigPaths; } @@ -113,35 +148,37 @@ public Set getPredefinedClassesConfigPaths() { } public TypeConfiguration loadJniConfig(Function exceptionHandler) throws Exception { - return loadTypeConfig(jniConfigPaths, exceptionHandler); + return loadTypeConfig(JNI_KEY, jniConfigPaths, exceptionHandler); } public TypeConfiguration loadReflectConfig(Function exceptionHandler) throws Exception { - return loadTypeConfig(reflectConfigPaths, exceptionHandler); + return loadTypeConfig(REFLECTION_KEY, reflectConfigPaths, exceptionHandler); } public ProxyConfiguration loadProxyConfig(Function exceptionHandler) throws Exception { ProxyConfiguration proxyConfiguration = new ProxyConfiguration(); - loadConfig(proxyConfigPaths, proxyConfiguration.createParser(), exceptionHandler); + loadConfig(proxyConfigPaths, proxyConfiguration.createParser(false), exceptionHandler); return proxyConfiguration; } public PredefinedClassesConfiguration loadPredefinedClassesConfig(Path[] classDestinationDirs, Predicate shouldExcludeClassesWithHash, Function exceptionHandler) throws Exception { PredefinedClassesConfiguration predefinedClassesConfiguration = new PredefinedClassesConfiguration(classDestinationDirs, shouldExcludeClassesWithHash); - loadConfig(predefinedClassesConfigPaths, predefinedClassesConfiguration.createParser(), exceptionHandler); + loadConfig(predefinedClassesConfigPaths, predefinedClassesConfiguration.createParser(false), exceptionHandler); return predefinedClassesConfiguration; } public ResourceConfiguration loadResourceConfig(Function exceptionHandler) throws Exception { ResourceConfiguration resourceConfiguration = new ResourceConfiguration(); - loadConfig(resourceConfigPaths, resourceConfiguration.createParser(), exceptionHandler); + loadConfig(reachabilityMetadataPaths, resourceConfiguration.createParser(true), exceptionHandler); + loadConfig(resourceConfigPaths, resourceConfiguration.createParser(false), exceptionHandler); return resourceConfiguration; } public SerializationConfiguration loadSerializationConfig(Function exceptionHandler) throws Exception { SerializationConfiguration serializationConfiguration = new SerializationConfiguration(); - loadConfig(serializationConfigPaths, serializationConfiguration.createParser(), exceptionHandler); + loadConfig(reachabilityMetadataPaths, serializationConfiguration.createParser(true), exceptionHandler); + loadConfig(serializationConfigPaths, serializationConfiguration.createParser(false), exceptionHandler); return serializationConfiguration; } @@ -152,9 +189,10 @@ public ConfigurationSet loadConfigurationSet(Function ex loadPredefinedClassesConfig(predefinedConfigClassDestinationDirs, predefinedConfigClassWithHashExclusionPredicate, exceptionHandler)); } - private static TypeConfiguration loadTypeConfig(Collection uris, Function exceptionHandler) throws Exception { - TypeConfiguration configuration = new TypeConfiguration(); - loadConfig(uris, configuration.createParser(), exceptionHandler); + private TypeConfiguration loadTypeConfig(String combinedFileKey, Collection uris, Function exceptionHandler) throws Exception { + TypeConfiguration configuration = new TypeConfiguration(combinedFileKey); + loadConfig(reachabilityMetadataPaths, configuration.createParser(true), exceptionHandler); + loadConfig(uris, configuration.createParser(false), exceptionHandler); return configuration; } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationSet.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationSet.java index 166eb517974..4397508d5fa 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationSet.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationSet.java @@ -24,6 +24,9 @@ */ package com.oracle.svm.configure.config; +import static com.oracle.svm.core.configure.ConfigurationParser.JNI_KEY; +import static com.oracle.svm.core.configure.ConfigurationParser.REFLECTION_KEY; + import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; @@ -32,10 +35,10 @@ import com.oracle.svm.configure.ConfigurationBase; import com.oracle.svm.configure.config.conditional.ConditionalConfigurationPredicate; -import com.oracle.svm.core.util.json.JsonPrintable; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.util.json.JsonPrintable; +import com.oracle.svm.core.util.json.JsonWriter; public class ConfigurationSet { @FunctionalInterface @@ -66,7 +69,7 @@ public ConfigurationSet(ConfigurationSet other) { } public ConfigurationSet() { - this(new TypeConfiguration(), new TypeConfiguration(), new ResourceConfiguration(), new ProxyConfiguration(), new SerializationConfiguration(), + this(new TypeConfiguration(REFLECTION_KEY), new TypeConfiguration(JNI_KEY), new ResourceConfiguration(), new ProxyConfiguration(), new SerializationConfiguration(), new PredefinedClassesConfiguration(new Path[0], hash -> false)); } 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 62a199c3a15..095ea107b67 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 @@ -31,6 +31,8 @@ import com.oracle.svm.configure.config.ConfigurationMemberInfo.ConfigurationMemberAccessibility; import com.oracle.svm.configure.config.ConfigurationMemberInfo.ConfigurationMemberDeclaration; import com.oracle.svm.core.TypeResult; +import com.oracle.svm.core.configure.ConfigurationTypeDescriptor; +import com.oracle.svm.core.configure.NamedConfigurationTypeDescriptor; import com.oracle.svm.core.configure.ReflectionConfigurationParserDelegate; public class ParserConfigurationAdapter implements ReflectionConfigurationParserDelegate { @@ -42,114 +44,114 @@ public ParserConfigurationAdapter(TypeConfiguration configuration) { } @Override - public TypeResult resolveCondition(String typeName) { - return TypeResult.forType(typeName, ConfigurationCondition.create(typeName)); + public TypeResult resolveType(ConfigurationCondition condition, ConfigurationTypeDescriptor typeDescriptor, boolean allowPrimitives) { + if (typeDescriptor instanceof NamedConfigurationTypeDescriptor namedDescriptor) { + String typeName = namedDescriptor.name(); + ConfigurationType type = configuration.get(condition, typeName); + ConfigurationType result = type != null ? type : new ConfigurationType(condition, typeName); + return TypeResult.forType(typeName, result); + } else { + return TypeResult.forException(typeDescriptor.toString(), null); + } } @Override - public TypeResult resolveType(ConfigurationCondition condition, String typeName, boolean allowPrimitives) { - ConfigurationType type = configuration.get(condition, typeName); - ConfigurationType result = type != null ? type : new ConfigurationType(condition, typeName); - return TypeResult.forType(typeName, result); - } - - @Override - public void registerType(ConfigurationType type) { + public void registerType(ConfigurationCondition condition, ConfigurationType type) { configuration.add(type); } @Override - public void registerField(ConfigurationType type, String fieldName, boolean finalButWritable) { + public void registerField(ConfigurationCondition condition, ConfigurationType type, String fieldName, boolean finalButWritable) { type.addField(fieldName, ConfigurationMemberDeclaration.PRESENT, finalButWritable); } @Override - public boolean registerAllMethodsWithName(boolean queriedOnly, ConfigurationType type, String methodName) { + public boolean registerAllMethodsWithName(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type, String methodName) { type.addMethodsWithName(methodName, ConfigurationMemberDeclaration.PRESENT, queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); return true; } @Override - public boolean registerAllConstructors(boolean queriedOnly, ConfigurationType type) { + public boolean registerAllConstructors(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { type.addMethodsWithName(ConfigurationMethod.CONSTRUCTOR_NAME, ConfigurationMemberDeclaration.PRESENT, queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); return true; } @Override - public void registerUnsafeAllocated(ConfigurationType type) { + public void registerUnsafeAllocated(ConfigurationCondition condition, ConfigurationType type) { type.setUnsafeAllocated(); } @Override - public void registerMethod(boolean queriedOnly, ConfigurationType type, String methodName, List methodParameterTypes) { + public void registerMethod(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type, String methodName, List methodParameterTypes) { type.addMethod(methodName, ConfigurationMethod.toInternalParamsSignature(methodParameterTypes), ConfigurationMemberDeclaration.PRESENT, queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override - public void registerConstructor(boolean queriedOnly, ConfigurationType type, List methodParameterTypes) { + public void registerConstructor(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type, List methodParameterTypes) { type.addMethod(ConfigurationMethod.CONSTRUCTOR_NAME, ConfigurationMethod.toInternalParamsSignature(methodParameterTypes), ConfigurationMemberDeclaration.PRESENT, queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override - public void registerPublicClasses(ConfigurationType type) { + public void registerPublicClasses(ConfigurationCondition condition, ConfigurationType type) { type.setAllPublicClasses(); } @Override - public void registerDeclaredClasses(ConfigurationType type) { + public void registerDeclaredClasses(ConfigurationCondition condition, ConfigurationType type) { type.setAllDeclaredClasses(); } @Override - public void registerRecordComponents(ConfigurationType type) { + public void registerRecordComponents(ConfigurationCondition condition, ConfigurationType type) { type.setAllRecordComponents(); } @Override - public void registerPermittedSubclasses(ConfigurationType type) { + public void registerPermittedSubclasses(ConfigurationCondition condition, ConfigurationType type) { type.setAllPermittedSubclasses(); } @Override - public void registerNestMembers(ConfigurationType type) { + public void registerNestMembers(ConfigurationCondition condition, ConfigurationType type) { type.setAllNestMembers(); } @Override - public void registerSigners(ConfigurationType type) { + public void registerSigners(ConfigurationCondition condition, ConfigurationType type) { type.setAllSigners(); } @Override - public void registerPublicFields(ConfigurationType type) { + public void registerPublicFields(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { type.setAllPublicFields(); } @Override - public void registerDeclaredFields(ConfigurationType type) { + public void registerDeclaredFields(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { type.setAllDeclaredFields(); } @Override - public void registerPublicMethods(boolean queriedOnly, ConfigurationType type) { + public void registerPublicMethods(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { type.setAllPublicMethods(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override - public void registerDeclaredMethods(boolean queriedOnly, ConfigurationType type) { + public void registerDeclaredMethods(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { type.setAllDeclaredMethods(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override - public void registerPublicConstructors(boolean queriedOnly, ConfigurationType type) { + public void registerPublicConstructors(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { type.setAllPublicConstructors(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override - public void registerDeclaredConstructors(boolean queriedOnly, ConfigurationType type) { + public void registerDeclaredConstructors(ConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { type.setAllDeclaredConstructors(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/PredefinedClassesConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/PredefinedClassesConfiguration.java index 40229ed4648..87e86fa0309 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/PredefinedClassesConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/PredefinedClassesConfiguration.java @@ -34,14 +34,15 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import com.oracle.svm.core.configure.ConfigurationParser; import org.graalvm.nativeimage.impl.ConfigurationCondition; import com.oracle.svm.configure.ConfigurationBase; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ConfigurationFile; +import com.oracle.svm.core.configure.ConfigurationParser; import com.oracle.svm.core.configure.PredefinedClassesConfigurationParser; import com.oracle.svm.core.hub.PredefinedClassesSupport; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.util.json.JsonWriter; public final class PredefinedClassesConfiguration extends ConfigurationBase { private final Path[] classDestinationDirs; @@ -164,7 +165,8 @@ public void printJson(JsonWriter writer) throws IOException { } @Override - public ConfigurationParser createParser() { + public ConfigurationParser createParser(boolean strictMetadata) { + VMError.guarantee(!strictMetadata, "Predefined classes configuration is not supported with strict metadata"); return new PredefinedClassesConfigurationParser(this::add, true); } 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 9859a20d9e5..98715fbba05 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 @@ -31,13 +31,14 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import com.oracle.svm.core.configure.ConfigurationParser; -import com.oracle.svm.core.configure.ProxyConfigurationParser; import org.graalvm.nativeimage.impl.ConfigurationCondition; import com.oracle.svm.configure.ConfigurationBase; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ConditionalElement; +import com.oracle.svm.core.configure.ConfigurationParser; +import com.oracle.svm.core.configure.ProxyConfigurationParser; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.util.json.JsonWriter; public final class ProxyConfiguration extends ConfigurationBase { private final Set>> interfaceLists = ConcurrentHashMap.newKeySet(); @@ -129,8 +130,9 @@ public static void printProxyInterfaces(JsonWriter writer, List interfaceLists.add(new ConditionalElement<>(cond, intfs))); } @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 803fbb86fa3..b990bdca9b4 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 @@ -38,13 +38,13 @@ import org.graalvm.nativeimage.impl.ConfigurationCondition; import com.oracle.svm.configure.ConfigurationBase; -import com.oracle.svm.core.util.json.JsonPrinter; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ConditionalElement; import com.oracle.svm.core.configure.ConfigurationParser; import com.oracle.svm.core.configure.ResourceConfigurationParser; import com.oracle.svm.core.configure.ResourcesRegistry; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.util.json.JsonPrinter; +import com.oracle.svm.core.util.json.JsonWriter; public final class ResourceConfiguration extends ConfigurationBase { @@ -249,8 +249,8 @@ public void printJson(JsonWriter writer) throws IOException { } @Override - public ConfigurationParser createParser() { - return new ResourceConfigurationParser(new ResourceConfiguration.ParserAdapter(this), true); + public ConfigurationParser createParser(boolean strictMetadata) { + return ResourceConfigurationParser.create(strictMetadata, new ResourceConfiguration.ParserAdapter(this), true); } private static void printResourceBundle(BundleConfiguration config, JsonWriter writer) throws IOException { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java index 1ed2ed4d756..c59d78976a5 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java @@ -37,11 +37,11 @@ import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; import com.oracle.svm.configure.ConfigurationBase; -import com.oracle.svm.core.util.json.JsonPrintable; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ConditionalElement; import com.oracle.svm.core.configure.ConfigurationParser; import com.oracle.svm.core.configure.SerializationConfigurationParser; +import com.oracle.svm.core.util.json.JsonPrintable; +import com.oracle.svm.core.util.json.JsonWriter; public final class SerializationConfiguration extends ConfigurationBase implements RuntimeSerializationSupport { @@ -123,8 +123,8 @@ public void printJson(JsonWriter writer) throws IOException { } @Override - public ConfigurationParser createParser() { - return new SerializationConfigurationParser(this, true); + public ConfigurationParser createParser(boolean strictMetadata) { + return SerializationConfigurationParser.create(strictMetadata, this, true); } private void printProxies(JsonWriter writer) throws IOException { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/TypeConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/TypeConfiguration.java index b90efed5dfd..32d02920d90 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/TypeConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/TypeConfiguration.java @@ -32,24 +32,28 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import com.oracle.svm.core.configure.ConfigurationParser; -import com.oracle.svm.core.configure.ReflectionConfigurationParser; import org.graalvm.nativeimage.impl.ConfigurationCondition; import com.oracle.svm.configure.ConfigurationBase; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ConditionalElement; +import com.oracle.svm.core.configure.ConfigurationParser; +import com.oracle.svm.core.configure.ReflectionConfigurationParser; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.util.json.JsonWriter; public final class TypeConfiguration extends ConfigurationBase { private final ConcurrentMap, ConfigurationType> types = new ConcurrentHashMap<>(); - public TypeConfiguration() { + private final String combinedFileKey; + + public TypeConfiguration(String combinedFileKey) { + this.combinedFileKey = combinedFileKey; } public TypeConfiguration(TypeConfiguration other) { other.types.forEach((key, value) -> types.put(key, new ConfigurationType(value))); + this.combinedFileKey = other.combinedFileKey; } @Override @@ -142,8 +146,8 @@ public void printJson(JsonWriter writer) throws IOException { } @Override - public ConfigurationParser createParser() { - return new ReflectionConfigurationParser<>(new ParserConfigurationAdapter(this), true, false); + public ConfigurationParser createParser(boolean strictMetadata) { + return ReflectionConfigurationParser.create(combinedFileKey, strictMetadata, new ParserConfigurationAdapter(this), true, false); } @Override diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/conditional/PartialConfigurationWithOrigins.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/conditional/PartialConfigurationWithOrigins.java index e7ee09dd8cc..cb56f8c7c52 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/conditional/PartialConfigurationWithOrigins.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/conditional/PartialConfigurationWithOrigins.java @@ -33,10 +33,10 @@ import org.graalvm.util.json.JSONParserException; import com.oracle.svm.configure.config.ConfigurationSet; -import com.oracle.svm.core.util.json.JsonPrintable; -import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationParser; +import com.oracle.svm.core.util.json.JsonPrintable; +import com.oracle.svm.core.util.json.JsonWriter; public class PartialConfigurationWithOrigins extends ConfigurationParser implements JsonPrintable { private static final ConfigurationSet emptyConfigurationSet = new ConfigurationSet(); @@ -169,7 +169,7 @@ private static void parseConfigurationSet(EconomicMap configJson, Con if (configType == null) { throw new JSONParserException("Invalid configuration type: " + configName); } - configurationSet.getConfiguration(configType).createParser().parseAndRegister(cursor.getValue(), origin); + configurationSet.getConfiguration(configType).createParser(false).parseAndRegister(cursor.getValue(), origin); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalRuntimeValue.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalRuntimeValue.java deleted file mode 100644 index d7853365392..00000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalRuntimeValue.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.configure; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -/** - * A image-heap stored {@link ConditionalRuntimeValue#value} that is guarded by run-time computed - * {@link ConditionalRuntimeValue#conditions}. - *

- * {@link ConditionalRuntimeValue#conditions} are stored as an array to save space in the image - * heap. This is subject to further optimizations. - * - * @param type of the stored value. - */ -public final class ConditionalRuntimeValue { - RuntimeConditionSet conditions; - volatile T value; - - public ConditionalRuntimeValue(RuntimeConditionSet conditions, T value) { - this.conditions = conditions; - this.value = value; - } - - @Platforms(Platform.HOSTED_ONLY.class) - public T getValueUnconditionally() { - return value; - } - - public RuntimeConditionSet getConditions() { - return conditions; - } - - public T getValue() { - if (conditions.satisfied()) { - return value; - } else { - return null; - } - } - - @Platforms(Platform.HOSTED_ONLY.class) - public void updateValue(T newValue) { - this.value = newValue; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationConditionResolver.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationConditionResolver.java index bfbba32b23c..f63e5947d04 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationConditionResolver.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationConditionResolver.java @@ -24,27 +24,27 @@ */ package com.oracle.svm.core.configure; -import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; +import org.graalvm.nativeimage.impl.ConfigurationCondition; import com.oracle.svm.core.TypeResult; -public interface ConfigurationConditionResolver { +public interface ConfigurationConditionResolver { - static ConfigurationConditionResolver identityResolver() { - return new ConfigurationConditionResolver<>() { + static ConfigurationConditionResolver identityResolver() { + return new ConfigurationConditionResolver() { @Override - public TypeResult resolveCondition(UnresolvedConfigurationCondition unresolvedCondition) { + public TypeResult resolveCondition(ConfigurationCondition unresolvedCondition) { return TypeResult.forType(unresolvedCondition.getTypeName(), unresolvedCondition); } @Override - public UnresolvedConfigurationCondition alwaysTrue() { - return UnresolvedConfigurationCondition.alwaysTrue(); + public ConfigurationCondition alwaysTrue() { + return ConfigurationCondition.alwaysTrue(); } }; } - TypeResult resolveCondition(UnresolvedConfigurationCondition unresolvedCondition); + TypeResult resolveCondition(ConfigurationCondition unresolvedCondition); - T alwaysTrue(); + ConfigurationCondition alwaysTrue(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFiles.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFiles.java index 53bfa1a703e..d3258173267 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFiles.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFiles.java @@ -34,16 +34,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionStability; +import org.graalvm.compiler.options.OptionType; + import com.oracle.svm.core.option.BundleMember; import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.core.option.OptionMigrationMessage; +import com.oracle.svm.core.option.LocatableMultiOptionValue; import com.oracle.svm.core.util.UserError; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionStability; -import jdk.graal.compiler.options.OptionType; - /** * Gathers configuration files from specified directories without having to provide each * configuration file individually. @@ -51,118 +50,75 @@ public final class ConfigurationFiles { public static final class Options { - @Option(help = "Directories directly containing configuration files for dynamic features at runtime.", type = OptionType.User, stability = OptionStability.STABLE)// @BundleMember(role = BundleMember.Role.Input)// - static final HostedOptionKey ConfigurationFileDirectories = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); + static final HostedOptionKey ConfigurationFileDirectories = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); @Option(help = "Resource path above configuration resources for dynamic features at runtime.", type = OptionType.User)// - public static final HostedOptionKey ConfigurationResourceRoots = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + public static final HostedOptionKey ConfigurationResourceRoots = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); - @OptionMigrationMessage("Use a reflect-config.json in your META-INF/native-image// directory instead.")// @Option(help = "file:doc-files/ReflectionConfigurationFilesHelp.txt", type = OptionType.User)// @BundleMember(role = BundleMember.Role.Input)// - public static final HostedOptionKey ReflectionConfigurationFiles = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); + public static final HostedOptionKey ReflectionConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); @Option(help = "Resources describing program elements to be made available for reflection (see ReflectionConfigurationFiles).", type = OptionType.User)// - public static final HostedOptionKey ReflectionConfigurationResources = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + public static final HostedOptionKey ReflectionConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); - @OptionMigrationMessage("Use a proxy-config.json in your META-INF/native-image// directory instead.")// - @Option(help = "file:doc-files/ProxyConfigurationFilesHelp.txt", type = OptionType.User, deprecated = true)// + @Option(help = "file:doc-files/ProxyConfigurationFilesHelp.txt", type = OptionType.User)// @BundleMember(role = BundleMember.Role.Input)// - public static final HostedOptionKey DynamicProxyConfigurationFiles = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); - @Option(help = "Resources describing program elements to be made available for reflection (see ProxyConfigurationFiles).", type = OptionType.User, deprecated = true, // - deprecationMessage = "This can be caused by a proxy-config.json file in your META-INF directory. " + - "Consider including proxy configuration in the reflection section of reachability-metadata.md instead.")// - public static final HostedOptionKey DynamicProxyConfigurationResources = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); - - @OptionMigrationMessage("Use a serialization-config.json in your META-INF/native-image// directory instead.")// + public static final HostedOptionKey DynamicProxyConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); + @Option(help = "Resources describing program elements to be made available for reflection (see ProxyConfigurationFiles).", type = OptionType.User)// + public static final HostedOptionKey DynamicProxyConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + @Option(help = "file:doc-files/SerializationConfigurationFilesHelp.txt", type = OptionType.User)// @BundleMember(role = BundleMember.Role.Input)// - public static final HostedOptionKey SerializationConfigurationFiles = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); + public static final HostedOptionKey SerializationConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); @Option(help = "Resources describing program elements to be made available for serialization (see SerializationConfigurationFiles).", type = OptionType.User)// - public static final HostedOptionKey SerializationConfigurationResources = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + public static final HostedOptionKey SerializationConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); - @OptionMigrationMessage("Use a serialization-config.json in your META-INF/native-image// directory instead.")// @Option(help = "file:doc-files/SerializationConfigurationFilesHelp.txt", type = OptionType.User)// @BundleMember(role = BundleMember.Role.Input)// - public static final HostedOptionKey SerializationDenyConfigurationFiles = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); + public static final HostedOptionKey SerializationDenyConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); @Option(help = "Resources describing program elements that must not be made available for serialization.", type = OptionType.User)// - public static final HostedOptionKey SerializationDenyConfigurationResources = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + public static final HostedOptionKey SerializationDenyConfigurationResources = new HostedOptionKey<>( + LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); - @OptionMigrationMessage("Use a resource-config.json in your META-INF/native-image// directory instead.")// @Option(help = "Files describing Java resources to be included in the image according to the schema at " + "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/resource-config-schema-v1.0.0.json", type = OptionType.User)// @BundleMember(role = BundleMember.Role.Input)// - public static final HostedOptionKey ResourceConfigurationFiles = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); + public static final HostedOptionKey ResourceConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); @Option(help = "Resources describing Java resources to be included in the image according to the schema at " + "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/resource-config-schema-v1.0.0.json", type = OptionType.User)// - public static final HostedOptionKey ResourceConfigurationResources = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + public static final HostedOptionKey ResourceConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); - @OptionMigrationMessage("Use a jni-config.json in your META-INF/native-image// directory instead.")// - @Option(help = "Files describing program elements to be made accessible via JNI according to the schema at " + - "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/jni-config-schema-v1.1.0.json", type = OptionType.User)// + @Option(help = "Files describing program elements to be made accessible via JNI (for syntax, see ReflectionConfigurationFiles)", type = OptionType.User)// @BundleMember(role = BundleMember.Role.Input)// - public static final HostedOptionKey JNIConfigurationFiles = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); - @Option(help = "Resources describing program elements to be made accessible via JNI according to the schema at " + - "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/jni-config-schema-v1.1.0.json", type = OptionType.User)// - public static final HostedOptionKey JNIConfigurationResources = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + public static final HostedOptionKey JNIConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); + @Option(help = "Resources describing program elements to be made accessible via JNI (see JNIConfigurationFiles).", type = OptionType.User)// + public static final HostedOptionKey JNIConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); @Option(help = "Resources describing reachability metadata needed for the program " + "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reachability-metadata-schema-v1.0.0.json", type = OptionType.User)// - public static final HostedOptionKey ReachabilityMetadataResources = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + public static final HostedOptionKey ReachabilityMetadataResources = new HostedOptionKey<>( + LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); @Option(help = "Files describing stubs allowing foreign calls.", type = OptionType.User)// @BundleMember(role = BundleMember.Role.Input)// - public static final HostedOptionKey ForeignConfigurationFiles = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); + public static final HostedOptionKey ForeignConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); @Option(help = "Resources describing stubs allowing foreign calls.", type = OptionType.User)// - public static final HostedOptionKey ForeignResources = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + public static final HostedOptionKey ForeignResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); - @OptionMigrationMessage("Use a predefined-classes-config.json in your META-INF/native-image// directory instead.")// @Option(help = "Files describing predefined classes that can be loaded at runtime according to the schema at " + "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/predefined-classes-config-schema-v1.0.0.json", type = OptionType.User)// @BundleMember(role = BundleMember.Role.Input)// - public static final HostedOptionKey PredefinedClassesConfigurationFiles = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); + public static final HostedOptionKey PredefinedClassesConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter()); @Option(help = "Resources describing predefined classes that can be loaded at runtime according to the schema at " + "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/predefined-classes-config-schema-v1.0.0.json", type = OptionType.User)// - public static final HostedOptionKey PredefinedClassesConfigurationResources = new HostedOptionKey<>( - AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + public static final HostedOptionKey PredefinedClassesConfigurationResources = new HostedOptionKey<>( + LocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); @Option(help = "When configuration files do not match their schema, abort the image build instead of emitting a warning.")// public static final HostedOptionKey StrictConfiguration = new HostedOptionKey<>(false); - @Option(help = "Testing flag: the 'typeReachable' condition is treated as typeReached so the semantics of programs can change.")// - public static final HostedOptionKey TreatAllTypeReachableConditionsAsTypeReached = new HostedOptionKey<>(false); - - @Option(help = "Testing flag: the 'name' is treated as 'type' in reflection configuration.")// - public static final HostedOptionKey TreatAllNameEntriesAsType = new HostedOptionKey<>(false); - - @Option(help = "Testing flag: the 'typeReached' condition is always satisfied however it prints the stack trace where it would not be satisfied.")// - public static final HostedOptionKey TrackUnsatisfiedTypeReachedConditions = new HostedOptionKey<>(false); - - @Option(help = "Testing flag: print 'typeReached' conditions that are used on interfaces without default methods at build time.")// - public static final HostedOptionKey TrackTypeReachedOnInterfaces = new HostedOptionKey<>(false); - - @Option(help = "Testing flag: every type is considered as it participates in a typeReachable condition.")// - public static final HostedOptionKey TreatAllUserSpaceTypesAsTrackedForTypeReached = new HostedOptionKey<>(false); - @Option(help = "Warn when reflection and JNI configuration files have elements that could not be found on the classpath or modulepath.", type = OptionType.Expert)// public static final HostedOptionKey WarnAboutMissingReflectionOrJNIMetadataElements = new HostedOptionKey<>(false); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationParser.java index cc28760d089..9333a6955ab 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationParser.java @@ -24,10 +24,6 @@ */ package com.oracle.svm.core.configure; -import static com.oracle.svm.core.configure.ConfigurationFiles.Options.TreatAllTypeReachableConditionsAsTypeReached; -import static org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition.TYPE_REACHABLE_KEY; -import static org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition.TYPE_REACHED_KEY; - import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; @@ -46,16 +42,15 @@ import java.util.Set; import org.graalvm.collections.EconomicMap; -import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; +import org.graalvm.nativeimage.impl.ConfigurationCondition; +import org.graalvm.util.json.JSONParser; +import org.graalvm.util.json.JSONParserException; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.jdk.JavaNetSubstitutions; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.LogUtils; -import jdk.graal.compiler.util.json.JsonParser; -import jdk.graal.compiler.util.json.JsonParserException; - public abstract class ConfigurationParser { public static InputStream openStream(URI uri) throws IOException { URL url = uri.toURL(); @@ -67,6 +62,8 @@ public static InputStream openStream(URI uri) throws IOException { } public static final String CONDITIONAL_KEY = "condition"; + public static final String TYPE_REACHABLE_KEY = "typeReachable"; + public static final String TYPE_REACHED_KEY = "typeReached"; public static final String NAME_KEY = "name"; public static final String TYPE_KEY = "type"; public static final String PROXY_KEY = "proxy"; @@ -76,6 +73,8 @@ public static InputStream openStream(URI uri) throws IOException { public static final String RESOURCES_KEY = "resources"; public static final String BUNDLES_KEY = "bundles"; public static final String GLOBS_KEY = "globs"; + public static final String MODULE_KEY = "module"; + public static final String GLOB_KEY = "glob"; private final Map> seenUnknownAttributesByType = new HashMap<>(); private final boolean strictSchema; @@ -85,7 +84,7 @@ protected ConfigurationParser(boolean strictConfiguration) { public void parseAndRegister(URI uri) throws IOException { try (Reader reader = openReader(uri)) { - parseAndRegister(new JsonParser(reader).parse(), uri); + parseAndRegister(new JSONParser(reader).parse(), uri); } catch (FileNotFoundException e) { /* * Ignore: *-config.json files can be missing when reachability-metadata.json is @@ -99,7 +98,7 @@ protected static BufferedReader openReader(URI uri) throws IOException { } public void parseAndRegister(Reader reader) throws IOException { - parseAndRegister(new JsonParser(reader).parse(), null); + parseAndRegister(new JSONParser(reader).parse(), null); } public abstract void parseAndRegister(Object json, URI origin) throws IOException; @@ -115,7 +114,7 @@ public static List asList(Object data, String errorMessage) { if (data instanceof List) { return (List) data; } - throw new JsonParserException(errorMessage); + throw new JSONParserException(errorMessage); } @SuppressWarnings("unchecked") @@ -123,7 +122,7 @@ public static EconomicMap asMap(Object data, String errorMessage if (data instanceof EconomicMap) { return (EconomicMap) data; } - throw new JsonParserException(errorMessage); + throw new JSONParserException(errorMessage); } protected void checkAttributes(EconomicMap map, String type, Collection requiredAttrs, Collection optionalAttrs) { @@ -132,7 +131,7 @@ protected void checkAttributes(EconomicMap map, String type, Col unseenRequired.remove(key); } if (!unseenRequired.isEmpty()) { - throw new JsonParserException("Missing attribute(s) [" + String.join(", ", unseenRequired) + "] in " + type); + throw new JSONParserException("Missing attribute(s) [" + String.join(", ", unseenRequired) + "] in " + type); } Set unknownAttributes = new HashSet<>(); for (String key : map.getKeys()) { @@ -159,14 +158,14 @@ public static void checkHasExactlyOneAttribute(EconomicMap map, if (alternativeAttributes.contains(key)) { if (attributeFound) { String message = "Exactly one of [" + String.join(", ", alternativeAttributes) + "] must be set in " + type; - throw new JsonParserException(message); + throw new JSONParserException(message); } attributeFound = true; } } if (!attributeFound) { String message = "Exactly one of [" + String.join(", ", alternativeAttributes) + "] must be set in " + type; - throw new JsonParserException(message); + throw new JSONParserException(message); } } @@ -192,14 +191,14 @@ public static String asString(Object value) { if (value instanceof String) { return (String) value; } - throw new JsonParserException("Invalid string value \"" + value + "\"."); + throw new JSONParserException("Invalid string value \"" + value + "\"."); } protected static String asString(Object value, String propertyName) { if (value instanceof String) { return (String) value; } - throw new JsonParserException("Invalid string value \"" + value + "\" for element '" + propertyName + "'"); + throw new JSONParserException("Invalid string value \"" + value + "\" for element '" + propertyName + "'"); } protected static String asNullableString(Object value, String propertyName) { @@ -210,7 +209,7 @@ protected static boolean asBoolean(Object value, String propertyName) { if (value instanceof Boolean) { return (boolean) value; } - throw new JsonParserException("Invalid boolean value '" + value + "' for element '" + propertyName + "'"); + throw new JSONParserException("Invalid boolean value '" + value + "' for element '" + propertyName + "'"); } protected static long asLong(Object value, String propertyName) { @@ -220,15 +219,19 @@ protected static long asLong(Object value, String propertyName) { if (value instanceof Integer) { return (int) value; } - throw new JsonParserException("Invalid long value '" + value + "' for element '" + propertyName + "'"); + throw new JSONParserException("Invalid long value '" + value + "' for element '" + propertyName + "'"); } - protected UnresolvedConfigurationCondition parseCondition(EconomicMap data, boolean runtimeCondition) { + private static boolean alreadyWarned = false; + + protected ConfigurationCondition parseCondition(EconomicMap data, boolean runtimeCondition) { Object conditionData = data.get(CONDITIONAL_KEY); if (conditionData != null) { EconomicMap conditionObject = asMap(conditionData, "Attribute 'condition' must be an object"); if (conditionObject.containsKey(TYPE_REACHABLE_KEY) && conditionObject.containsKey(TYPE_REACHED_KEY)) { failOnSchemaError("condition can not have both '" + TYPE_REACHED_KEY + "' and '" + TYPE_REACHABLE_KEY + "' set."); + } else if (conditionObject.isEmpty()) { + failOnSchemaError("condition can not be empty"); } if (conditionObject.containsKey(TYPE_REACHED_KEY)) { @@ -238,26 +241,34 @@ protected UnresolvedConfigurationCondition parseCondition(EconomicMap extends ReflectionConfigurationParser { +final class LegacyReflectionConfigurationParser extends ReflectionConfigurationParser { private static final List OPTIONAL_REFLECT_CONFIG_OBJECT_ATTRS = Arrays.asList("allDeclaredConstructors", "allPublicConstructors", "allDeclaredMethods", "allPublicMethods", "allDeclaredFields", "allPublicFields", @@ -45,7 +45,7 @@ final class LegacyReflectionConfigurationParser extends ReflectionConfigur private final boolean treatAllNameEntriesAsType; - LegacyReflectionConfigurationParser(ConfigurationConditionResolver conditionResolver, ReflectionConfigurationParserDelegate delegate, boolean strictConfiguration, + LegacyReflectionConfigurationParser(ConfigurationConditionResolver conditionResolver, ReflectionConfigurationParserDelegate delegate, boolean strictConfiguration, boolean printMissingElements, boolean treatAllNameEntriesAsType) { super(conditionResolver, delegate, strictConfiguration, printMissingElements); this.treatAllNameEntriesAsType = treatAllNameEntriesAsType; @@ -72,8 +72,8 @@ protected void parseClass(EconomicMap data) { */ boolean isType = type.get().definedAsType(); - UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, isType); - TypeResult conditionResult = conditionResolver.resolveCondition(unresolvedCondition); + ConfigurationCondition unresolvedCondition = parseCondition(data, isType); + TypeResult conditionResult = conditionResolver.resolveCondition(unresolvedCondition); if (!conditionResult.isPresent()) { return; } @@ -82,14 +82,14 @@ protected void parseClass(EconomicMap data) { * Even if primitives cannot be queried through Class.forName, they can be registered to * allow getDeclaredMethods() and similar bulk queries at run time. */ - C condition = conditionResult.get(); + ConfigurationCondition condition = conditionResult.get(); TypeResult result = delegate.resolveType(condition, typeDescriptor, true); if (!result.isPresent()) { handleMissingElement("Could not resolve " + typeDescriptor + " for reflection configuration.", result.getException()); return; } - C queryCondition = isType ? conditionResolver.alwaysTrue() : condition; + ConfigurationCondition queryCondition = isType ? conditionResolver.alwaysTrue() : condition; T clazz = result.get(); delegate.registerType(conditionResult.get(), clazz); 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 0f680cb4489..525b43cc1d4 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,12 +25,18 @@ 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.ConfigurationCondition; -final class LegacyResourceConfigurationParser extends ResourceConfigurationParser { - LegacyResourceConfigurationParser(ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { +import com.oracle.svm.core.TypeResult; + +final class LegacyResourceConfigurationParser extends ResourceConfigurationParser { + LegacyResourceConfigurationParser(ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { super(conditionResolver, registry, strictConfiguration); } @@ -39,6 +45,11 @@ public void parseAndRegister(Object json, URI origin) { parseTopLevelObject(asMap(json, "first level of document must be an object")); } + @Override + protected ConfigurationCondition parseCondition(EconomicMap data) { + return parseCondition(data, false); + } + private void parseTopLevelObject(EconomicMap obj) { Object resourcesObject = null; Object bundlesObject = null; @@ -64,4 +75,44 @@ private void parseTopLevelObject(EconomicMap obj) { parseGlobsObject(globsObject); } } + + @SuppressWarnings("unchecked") + private void parseResourcesObject(Object resourcesObject) { + 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, registry::addResources, "'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, registry::addResources, "'resources' list"); + } + } + } + + 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); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacySerializationConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacySerializationConfigurationParser.java index 46c92f8b389..b94f83b3812 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacySerializationConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacySerializationConfigurationParser.java @@ -30,22 +30,21 @@ import java.util.List; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; -import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; +import org.graalvm.util.json.JSONParserException; -import jdk.graal.compiler.util.json.JsonParserException; - -final class LegacySerializationConfigurationParser extends SerializationConfigurationParser { +final class LegacySerializationConfigurationParser extends SerializationConfigurationParser { private static final String SERIALIZATION_TYPES_KEY = "types"; private static final String LAMBDA_CAPTURING_SERIALIZATION_TYPES_KEY = "lambdaCapturingTypes"; private static final String PROXY_SERIALIZATION_TYPES_KEY = "proxies"; - private final ProxyConfigurationParser proxyConfigurationParser; + private final ProxyConfigurationParser proxyConfigurationParser; - LegacySerializationConfigurationParser(ConfigurationConditionResolver conditionResolver, RuntimeSerializationSupport serializationSupport, boolean strictConfiguration) { + LegacySerializationConfigurationParser(ConfigurationConditionResolver conditionResolver, RuntimeSerializationSupport serializationSupport, boolean strictConfiguration) { super(conditionResolver, serializationSupport, strictConfiguration); - this.proxyConfigurationParser = new ProxyConfigurationParser<>(conditionResolver, strictConfiguration, serializationSupport::registerProxyClass); + this.proxyConfigurationParser = new ProxyConfigurationParser(strictConfiguration, serializationSupport::registerProxyClass); } @Override @@ -55,7 +54,7 @@ public void parseAndRegister(Object json, URI origin) { } else if (json instanceof EconomicMap) { parseNewConfiguration(asMap(json, "First-level of document must be a map of serialization types")); } else { - throw new JsonParserException("First-level of document must either be an array of serialization lists or a map of serialization types"); + throw new JSONParserException("First-level of document must either be an array of serialization lists or a map of serialization types"); } } @@ -65,7 +64,7 @@ private void parseOldConfiguration(List listOfSerializationConfiguration private void parseNewConfiguration(EconomicMap listOfSerializationConfigurationObjects) { if (!listOfSerializationConfigurationObjects.containsKey(SERIALIZATION_TYPES_KEY) || !listOfSerializationConfigurationObjects.containsKey(LAMBDA_CAPTURING_SERIALIZATION_TYPES_KEY)) { - throw new JsonParserException("Second-level of document must be arrays of serialization descriptor objects"); + throw new JSONParserException("Second-level of document must be arrays of serialization descriptor objects"); } parseSerializationTypes(asList(listOfSerializationConfigurationObjects.get(SERIALIZATION_TYPES_KEY), "The types property must be an array of serialization descriptor objects"), false); @@ -87,26 +86,20 @@ protected void parseSerializationDescriptorObject(EconomicMap da checkAttributes(data, "serialization descriptor object", Collections.singleton(NAME_KEY), Arrays.asList(CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY, CONDITIONAL_KEY)); } - ConfigurationTypeDescriptor targetSerializationClass = new NamedConfigurationTypeDescriptor(asString(data.get(NAME_KEY))); - UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, false); + NamedConfigurationTypeDescriptor targetSerializationClass = new NamedConfigurationTypeDescriptor(asString(data.get(NAME_KEY))); + ConfigurationCondition unresolvedCondition = parseCondition(data, false); var condition = conditionResolver.resolveCondition(unresolvedCondition); if (!condition.isPresent()) { return; } if (lambdaCapturingType) { - String className = ((NamedConfigurationTypeDescriptor) targetSerializationClass).name(); + String className = targetSerializationClass.name(); serializationSupport.registerLambdaCapturingClass(condition.get(), className); } else { Object optionalCustomCtorValue = data.get(CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY); String customTargetConstructorClass = optionalCustomCtorValue != null ? asString(optionalCustomCtorValue) : null; - if (targetSerializationClass instanceof NamedConfigurationTypeDescriptor namedClass) { - serializationSupport.registerWithTargetConstructorClass(condition.get(), namedClass.name(), customTargetConstructorClass); - } else if (targetSerializationClass instanceof ProxyConfigurationTypeDescriptor proxyClass) { - serializationSupport.registerProxyClass(condition.get(), proxyClass.interfaceNames()); - } else { - throw new JsonParserException("Unknown configuration type descriptor: %s".formatted(targetSerializationClass.toString())); - } + serializationSupport.registerWithTargetConstructorClass(condition.get(), targetSerializationClass.name(), customTargetConstructorClass); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/NamedConfigurationTypeDescriptor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/NamedConfigurationTypeDescriptor.java index 5a498583481..86b33152bf4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/NamedConfigurationTypeDescriptor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/NamedConfigurationTypeDescriptor.java @@ -28,7 +28,7 @@ import java.util.Collection; import java.util.Collections; -import jdk.graal.compiler.util.json.JsonWriter; +import com.oracle.svm.core.util.json.JsonWriter; public record NamedConfigurationTypeDescriptor(String name) implements ConfigurationTypeDescriptor { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationParser.java index 048db3ef2e0..816cd15b922 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationParser.java @@ -31,27 +31,25 @@ import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; -import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; +import org.graalvm.nativeimage.impl.ConfigurationCondition; +import org.graalvm.util.json.JSONParserException; import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry; -import jdk.graal.compiler.util.json.JsonParserException; - /** * Parses JSON describing lists of interfaces and register them in the {@link DynamicProxyRegistry}. */ -public final class ProxyConfigurationParser extends ConfigurationParser { +public final class ProxyConfigurationParser extends ConfigurationParser { - private final ConfigurationConditionResolver conditionResolver; + private final ConfigurationConditionResolver conditionResolver; - private final BiConsumer> proxyConfigConsumer; + private final BiConsumer> proxyConfigConsumer; - public ProxyConfigurationParser(ConfigurationConditionResolver conditionResolver, boolean strictConfiguration, - BiConsumer> proxyConfigConsumer) { + public ProxyConfigurationParser(boolean strictConfiguration, BiConsumer> proxyConfigConsumer) { super(strictConfiguration); this.proxyConfigConsumer = proxyConfigConsumer; - this.conditionResolver = conditionResolver; + this.conditionResolver = ConfigurationConditionResolver.identityResolver(); } @Override @@ -70,28 +68,28 @@ private void parseTopLevelArray(List proxyConfiguration) { foundProxyConfigurationObjects = true; parseWithConditionalConfig(asMap(proxyConfigurationObject, "")); } else { - throw new JsonParserException("Second-level must be composed of either interface lists or proxy configuration objects"); + throw new JSONParserException("Second-level must be composed of either interface lists or proxy configuration objects"); } if (foundInterfaceLists && foundProxyConfigurationObjects) { - throw new JsonParserException("Second-level can only be populated of either interface lists or proxy configuration objects, but these cannot be mixed"); + throw new JSONParserException("Second-level can only be populated of either interface lists or proxy configuration objects, but these cannot be mixed"); } } } - private void parseInterfaceList(C condition, List data) { + private void parseInterfaceList(ConfigurationCondition condition, List data) { List interfaces = data.stream().map(ConfigurationParser::asString).collect(Collectors.toList()); try { proxyConfigConsumer.accept(condition, interfaces); } catch (Exception e) { - throw new JsonParserException(e.toString()); + throw new JSONParserException(e.toString()); } } private void parseWithConditionalConfig(EconomicMap proxyConfigObject) { checkAttributes(proxyConfigObject, "proxy descriptor object", Collections.singleton("interfaces"), Collections.singletonList(CONDITIONAL_KEY)); - UnresolvedConfigurationCondition condition = parseCondition(proxyConfigObject, false); - TypeResult resolvedCondition = conditionResolver.resolveCondition(condition); + ConfigurationCondition condition = parseCondition(proxyConfigObject, false); + TypeResult resolvedCondition = conditionResolver.resolveCondition(condition); if (resolvedCondition.isPresent()) { parseInterfaceList(resolvedCondition.get(), asList(proxyConfigObject.get("interfaces"), "The interfaces property must be an array of fully qualified interface names")); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationTypeDescriptor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationTypeDescriptor.java index c60f589852c..a085ae2ab25 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationTypeDescriptor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationTypeDescriptor.java @@ -30,9 +30,8 @@ import java.util.List; import com.oracle.svm.core.reflect.proxy.DynamicProxySupport; - -import jdk.graal.compiler.util.json.JsonPrinter; -import jdk.graal.compiler.util.json.JsonWriter; +import com.oracle.svm.core.util.json.JsonPrinter; +import com.oracle.svm.core.util.json.JsonWriter; public record ProxyConfigurationTypeDescriptor(List interfaceNames) implements ConfigurationTypeDescriptor { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java index 349f586ff5f..202b6c3c266 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java @@ -31,24 +31,24 @@ import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.ConfigurationCondition; +import org.graalvm.util.json.JSONParserException; import com.oracle.svm.core.TypeResult; import com.oracle.svm.util.LogUtils; -import jdk.graal.compiler.util.json.JsonParserException; - /** * Parses JSON describing classes, methods and fields and delegates their registration to a * {@link ReflectionConfigurationParserDelegate}. */ -public abstract class ReflectionConfigurationParser extends ConfigurationParser { +public abstract class ReflectionConfigurationParser extends ConfigurationParser { private static final String CONSTRUCTOR_NAME = ""; - protected final ConfigurationConditionResolver conditionResolver; - protected final ReflectionConfigurationParserDelegate delegate; + protected final ConfigurationConditionResolver conditionResolver; + protected final ReflectionConfigurationParserDelegate delegate; private final boolean printMissingElements; - public ReflectionConfigurationParser(ConfigurationConditionResolver conditionResolver, ReflectionConfigurationParserDelegate delegate, boolean strictConfiguration, + public ReflectionConfigurationParser(ConfigurationConditionResolver conditionResolver, ReflectionConfigurationParserDelegate delegate, boolean strictConfiguration, boolean printMissingElements) { super(strictConfiguration); this.conditionResolver = conditionResolver; @@ -56,13 +56,12 @@ public ReflectionConfigurationParser(ConfigurationConditionResolver condition this.delegate = delegate; } - public static ReflectionConfigurationParser create(String combinedFileKey, boolean strictMetadata, - ConfigurationConditionResolver conditionResolver, ReflectionConfigurationParserDelegate delegate, - boolean strictConfiguration, boolean printMissingElements, boolean treatAllEntriesAsType) { + public static ReflectionConfigurationParser create(String combinedFileKey, boolean strictMetadata, ReflectionConfigurationParserDelegate delegate, boolean strictConfiguration, + boolean printMissingElements) { if (strictMetadata) { - return new ReflectionMetadataParser<>(combinedFileKey, conditionResolver, delegate, strictConfiguration, printMissingElements); + return new ReflectionMetadataParser<>(combinedFileKey, ConfigurationConditionResolver.identityResolver(), delegate, strictConfiguration, printMissingElements); } else { - return new LegacyReflectionConfigurationParser<>(conditionResolver, delegate, strictConfiguration, printMissingElements, treatAllEntriesAsType); + return new LegacyReflectionConfigurationParser<>(ConfigurationConditionResolver.identityResolver(), delegate, strictConfiguration, printMissingElements, false); } } @@ -84,13 +83,13 @@ protected void registerIfNotDefault(EconomicMap data, boolean de } } - protected void parseFields(C condition, List fields, T clazz) { + protected void parseFields(ConfigurationCondition condition, List fields, T clazz) { for (Object field : fields) { parseField(condition, asMap(field, "Elements of 'fields' array must be field descriptor objects"), clazz); } } - private void parseField(C condition, EconomicMap data, T clazz) { + private void parseField(ConfigurationCondition condition, EconomicMap data, T clazz) { checkAttributes(data, "reflection field descriptor object", Collections.singleton("name"), Arrays.asList("allowWrite", "allowUnsafeAccess")); String fieldName = asString(data.get("name"), "name"); boolean allowWrite = data.containsKey("allowWrite") && asBoolean(data.get("allowWrite"), "allowWrite"); @@ -104,13 +103,13 @@ private void parseField(C condition, EconomicMap data, T clazz) } } - protected void parseMethods(C condition, boolean queriedOnly, List methods, T clazz) { + protected void parseMethods(ConfigurationCondition condition, boolean queriedOnly, List methods, T clazz) { for (Object method : methods) { parseMethod(condition, queriedOnly, asMap(method, "Elements of 'methods' array must be method descriptor objects"), clazz); } } - private void parseMethod(C condition, boolean queriedOnly, EconomicMap data, T clazz) { + private void parseMethod(ConfigurationCondition condition, boolean queriedOnly, EconomicMap data, T clazz) { checkAttributes(data, "reflection method descriptor object", Collections.singleton("name"), Collections.singleton("parameterTypes")); String methodName = asString(data.get("name"), "name"); List methodParameterTypes = null; @@ -144,7 +143,7 @@ private void parseMethod(C condition, boolean queriedOnly, EconomicMap { +public interface ReflectionConfigurationParserDelegate { - TypeResult resolveType(C condition, ConfigurationTypeDescriptor typeDescriptor, boolean allowPrimitives); + TypeResult resolveType(ConfigurationCondition condition, ConfigurationTypeDescriptor typeDescriptor, boolean allowPrimitives); - void registerType(C condition, T type); + void registerType(ConfigurationCondition condition, T type); - void registerPublicClasses(C condition, T type); + void registerPublicClasses(ConfigurationCondition condition, T type); - void registerDeclaredClasses(C condition, T type); + void registerDeclaredClasses(ConfigurationCondition condition, T type); - void registerRecordComponents(C condition, T type); + void registerRecordComponents(ConfigurationCondition condition, T type); - void registerPermittedSubclasses(C condition, T type); + void registerPermittedSubclasses(ConfigurationCondition condition, T type); - void registerNestMembers(C condition, T type); + void registerNestMembers(ConfigurationCondition condition, T type); - void registerSigners(C condition, T type); + void registerSigners(ConfigurationCondition condition, T type); - void registerPublicFields(C condition, boolean queriedOnly, T type); + void registerPublicFields(ConfigurationCondition condition, boolean queriedOnly, T type); - void registerDeclaredFields(C condition, boolean queriedOnly, T type); + void registerDeclaredFields(ConfigurationCondition condition, boolean queriedOnly, T type); - void registerPublicMethods(C condition, boolean queriedOnly, T type); + void registerPublicMethods(ConfigurationCondition condition, boolean queriedOnly, T type); - void registerDeclaredMethods(C condition, boolean queriedOnly, T type); + void registerDeclaredMethods(ConfigurationCondition condition, boolean queriedOnly, T type); - void registerPublicConstructors(C condition, boolean queriedOnly, T type); + void registerPublicConstructors(ConfigurationCondition condition, boolean queriedOnly, T type); - void registerDeclaredConstructors(C condition, boolean queriedOnly, T type); + void registerDeclaredConstructors(ConfigurationCondition condition, boolean queriedOnly, T type); - void registerField(C condition, T type, String fieldName, boolean allowWrite) throws NoSuchFieldException; + void registerField(ConfigurationCondition condition, T type, String fieldName, boolean allowWrite) throws NoSuchFieldException; - boolean registerAllMethodsWithName(C condition, boolean queriedOnly, T type, String methodName); + boolean registerAllMethodsWithName(ConfigurationCondition condition, boolean queriedOnly, T type, String methodName); - void registerMethod(C condition, boolean queriedOnly, T type, String methodName, List methodParameterTypes) throws NoSuchMethodException; + void registerMethod(ConfigurationCondition condition, boolean queriedOnly, T type, String methodName, List methodParameterTypes) throws NoSuchMethodException; - void registerConstructor(C condition, boolean queriedOnly, T type, List methodParameterTypes) throws NoSuchMethodException; + void registerConstructor(ConfigurationCondition condition, boolean queriedOnly, T type, List methodParameterTypes) throws NoSuchMethodException; - boolean registerAllConstructors(C condition, boolean queriedOnly, T type); + boolean registerAllConstructors(ConfigurationCondition condition, boolean queriedOnly, T type); - void registerUnsafeAllocated(C condition, T clazz); + void registerUnsafeAllocated(ConfigurationCondition condition, T clazz); String getTypeName(T type); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionMetadataParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionMetadataParser.java index 33bd0028be6..7b4fa47a453 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionMetadataParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionMetadataParser.java @@ -31,18 +31,18 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.MapCursor; -import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; +import org.graalvm.nativeimage.impl.ConfigurationCondition; import com.oracle.svm.core.TypeResult; -class ReflectionMetadataParser extends ReflectionConfigurationParser { +class ReflectionMetadataParser extends ReflectionConfigurationParser { private static final List OPTIONAL_REFLECT_METADATA_ATTRS = Arrays.asList(CONDITIONAL_KEY, "allDeclaredConstructors", "allPublicConstructors", "allDeclaredMethods", "allPublicMethods", "allDeclaredFields", "allPublicFields", "methods", "fields", "unsafeAllocated"); private final String combinedFileKey; - ReflectionMetadataParser(String combinedFileKey, ConfigurationConditionResolver conditionResolver, ReflectionConfigurationParserDelegate delegate, boolean strictConfiguration, + ReflectionMetadataParser(String combinedFileKey, ConfigurationConditionResolver conditionResolver, ReflectionConfigurationParserDelegate delegate, boolean strictConfiguration, boolean printMissingElements) { super(conditionResolver, delegate, strictConfiguration, printMissingElements); this.combinedFileKey = combinedFileKey; @@ -65,12 +65,12 @@ protected void parseClass(EconomicMap data) { return; } - UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, true); - TypeResult conditionResult = conditionResolver.resolveCondition(unresolvedCondition); + ConfigurationCondition unresolvedCondition = parseCondition(data, true); + TypeResult conditionResult = conditionResolver.resolveCondition(unresolvedCondition); if (!conditionResult.isPresent()) { return; } - C condition = conditionResult.get(); + ConfigurationCondition condition = conditionResult.get(); /* * Even if primitives cannot be queried through Class.forName, they can be registered to @@ -82,7 +82,7 @@ protected void parseClass(EconomicMap data) { return; } - C queryCondition = conditionResolver.alwaysTrue(); + ConfigurationCondition queryCondition = conditionResolver.alwaysTrue(); T clazz = result.get(); delegate.registerType(conditionResult.get(), clazz); 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 8242237d6a6..237d9e964c1 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,35 +28,37 @@ import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.function.BiConsumer; +import java.util.regex.Pattern; import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.ConfigurationCondition; +import org.graalvm.util.json.JSONParserException; import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.jdk.localization.LocalizationSupport; -import jdk.graal.compiler.util.json.JsonParserException; +public abstract class ResourceConfigurationParser extends ConfigurationParser { + protected final ResourcesRegistry registry; -public abstract class ResourceConfigurationParser extends ConfigurationParser { - protected final ResourcesRegistry registry; + protected final ConfigurationConditionResolver conditionResolver; - protected final ConfigurationConditionResolver conditionResolver; - - public static ResourceConfigurationParser create(boolean strictMetadata, ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { + public static ResourceConfigurationParser create(boolean strictMetadata, ResourcesRegistry registry, boolean strictConfiguration) { if (strictMetadata) { - return new ResourceMetadataParser<>(conditionResolver, registry, strictConfiguration); + return new ResourceMetadataParser(ConfigurationConditionResolver.identityResolver(), registry, strictConfiguration); } else { - return new LegacyResourceConfigurationParser<>(conditionResolver, registry, strictConfiguration); + return new LegacyResourceConfigurationParser(ConfigurationConditionResolver.identityResolver(), registry, strictConfiguration); } } - protected ResourceConfigurationParser(ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { + protected ResourceConfigurationParser(ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { super(strictConfiguration); this.registry = registry; this.conditionResolver = conditionResolver; } + protected abstract ConfigurationCondition parseCondition(EconomicMap data); + protected void parseBundlesObject(Object bundlesObject) { List bundles = asList(bundlesObject, "Attribute 'bundles' must be a list of bundles"); for (Object bundle : bundles) { @@ -64,38 +66,11 @@ protected void parseBundlesObject(Object bundlesObject) { } } - @SuppressWarnings("unchecked") - protected void parseResourcesObject(Object resourcesObject) { - 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, registry::addResources, "'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, registry::addResources, "'resources' list"); - } - } - } - 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; } @@ -128,28 +103,91 @@ private static Locale parseLocale(Object input) { String localeTag = asString(input); Locale locale = LocalizationSupport.parseLocaleFromTag(localeTag); if (locale == null) { - throw new JsonParserException(localeTag + " is not a valid locale tag"); + throw new JSONParserException(localeTag + " is not a valid locale tag"); } 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; + public static String globToRegex(String module, String glob) { + return (module == null || module.isEmpty() ? "" : module + ":") + globToRegex(glob); + } + + private static String globToRegex(String glob) { + /* this char will trigger last wildcard dump if the glob ends with the wildcard */ + String tmpGlob = glob + '#'; + StringBuilder sb = new StringBuilder(); + + int quoteStartIndex = 0; + Wildcard previousWildcard = Wildcard.START; + for (int i = 0; i < tmpGlob.length(); i++) { + char c = tmpGlob.charAt(i); + Wildcard currentWildcard = previousWildcard.next(c); + + boolean wildcardStart = previousWildcard == Wildcard.START && currentWildcard != Wildcard.START; + if (wildcardStart && quoteStartIndex != i) { + /* start of the new wildcard => quote previous content */ + sb.append(Pattern.quote(tmpGlob.substring(quoteStartIndex, i))); + } + + boolean consecutiveWildcards = previousWildcard == Wildcard.DOUBLE_STAR_SLASH && currentWildcard != Wildcard.START; + boolean wildcardEnd = previousWildcard != Wildcard.START && currentWildcard == Wildcard.START; + if (wildcardEnd || consecutiveWildcards) { + /* end of the wildcard => append regex and move start of next quote after it */ + sb.append(previousWildcard.regex); + quoteStartIndex = i; + } + previousWildcard = currentWildcard; + } + /* remove the last char we added artificially */ + tmpGlob = tmpGlob.substring(0, tmpGlob.length() - 1); + if (quoteStartIndex < tmpGlob.length()) { + sb.append(Pattern.quote(tmpGlob.substring(quoteStartIndex))); + } + return sb.toString(); + } + + /** + * This enum acts like a state machine that helps to identify glob wildcards. + */ + private enum Wildcard { + START("") { + @Override + public Wildcard next(char c) { + return c == '*' ? STAR : START; + } + }, + STAR("[^/]*") { + @Override + public Wildcard next(char c) { + return c == '*' ? DOUBLE_STAR : START; + } + }, + DOUBLE_STAR(".*") { + @Override + public Wildcard next(char c) { + return c == '/' ? DOUBLE_STAR_SLASH : START; + } + }, + DOUBLE_STAR_SLASH("([^/]*(/|$))*") { + @Override + public Wildcard next(char c) { + return c == '*' ? STAR : START; + } + }; + + final String regex; + + Wildcard(String val) { + regex = val; } - Object valueObject = resource.get("pattern"); - String value = asString(valueObject, "pattern"); - resourceRegistry.accept(resolvedConfigurationCondition.get(), value); + public abstract Wildcard next(char c); } protected void parseGlobsObject(Object globsObject) { List globs = asList(globsObject, "Attribute 'globs' must be a list of glob patterns"); for (Object object : globs) { - parseGlobEntry(object, registry::addGlob); + parseGlobEntry(object, (condition, module, resource) -> registry.addResources(condition, globToRegex(module, resource))); } } @@ -157,10 +195,10 @@ private interface GlobPatternConsumer { void accept(T a, String b, String c); } - private void parseGlobEntry(Object data, GlobPatternConsumer resourceRegistry) { + 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 2e1b4720ed4..caa09ce98cf 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,8 +26,11 @@ import java.net.URI; -final class ResourceMetadataParser extends ResourceConfigurationParser { - ResourceMetadataParser(ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { +import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.ConfigurationCondition; + +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 ConfigurationCondition parseCondition(EconomicMap data) { + return parseCondition(data, true); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourcesRegistry.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourcesRegistry.java index 89ce92951e1..323feb31e89 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourcesRegistry.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourcesRegistry.java @@ -31,14 +31,43 @@ import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.RuntimeResourceSupport; -public interface ResourcesRegistry extends RuntimeResourceSupport { +public interface ResourcesRegistry extends RuntimeResourceSupport { @SuppressWarnings("unchecked") - static ResourcesRegistry singleton() { + static ResourcesRegistry singleton() { return ImageSingletons.lookup(ResourcesRegistry.class); } - void addClassBasedResourceBundle(C condition, String basename, String className); + /** + * @deprecated Use {@link RuntimeResourceSupport#addResources(ConfigurationCondition, String)} + * instead. + */ + @Deprecated + default void addResources(String pattern) { + addResources(ConfigurationCondition.alwaysTrue(), pattern); + } + + /** + * @deprecated Use + * {@link RuntimeResourceSupport#ignoreResources(ConfigurationCondition, String)} + * instead. + */ + @Deprecated + default void ignoreResources(String pattern) { + ignoreResources(ConfigurationCondition.alwaysTrue(), pattern); + } + + /** + * @deprecated Use + * {@link RuntimeResourceSupport#addResourceBundles(ConfigurationCondition, String)} + * instead. + */ + @Deprecated + default void addResourceBundles(String name) { + addResourceBundles(ConfigurationCondition.alwaysTrue(), name); + } + + void addClassBasedResourceBundle(ConfigurationCondition condition, String basename, String className); /** * Although the interface-methods below are already defined in the super-interface @@ -46,14 +75,14 @@ static ResourcesRegistry singleton() { * reflectively. */ @Override - void addResources(C condition, String pattern); + void addResources(ConfigurationCondition condition, String pattern); @Override - void ignoreResources(C condition, String pattern); + void ignoreResources(ConfigurationCondition condition, String pattern); @Override - void addResourceBundles(C condition, String name); + void addResourceBundles(ConfigurationCondition condition, String name); @Override - void addResourceBundles(C condition, String basename, Collection locales); + void addResourceBundles(ConfigurationCondition condition, String basename, Collection locales); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeConditionSet.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeConditionSet.java deleted file mode 100644 index d403da2152b..00000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeConditionSet.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.svm.core.configure; - -import static com.oracle.svm.core.configure.ConfigurationFiles.Options.TrackUnsatisfiedTypeReachedConditions; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.impl.ConfigurationCondition; - -import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.LogUtils; - -/** - * Represents a group of {@link #conditions} that guard a value. The conditions are encoded - *

- * If any of the {@link #conditions} is satisfied then the whole set becomes also - * {@link #satisfied}. {@link RuntimeConditionSet}s can be created at build time - * {@link #createHosted(ConfigurationCondition)} and stored to the image heap, or it can be encoded - * ({@link #getTypesForEncoding()} and later decoded at run time ({@link #createDecoded(Object[])}. - * The current implementation does not cache {@link #conditions}, although this will be implemented - * in the future (GR-49526) - */ -public class RuntimeConditionSet { - - private Object[] conditions; - private boolean satisfied; - - @Platforms(Platform.HOSTED_ONLY.class) - public static RuntimeConditionSet emptySet() { - return new RuntimeConditionSet(new Object[0]); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public static RuntimeConditionSet createHosted(ConfigurationCondition condition) { - var conditionSet = new RuntimeConditionSet(new Object[0]); - conditionSet.addCondition(condition); - return conditionSet; - } - - @Platforms(Platform.HOSTED_ONLY.class) - public synchronized void addCondition(ConfigurationCondition cnd) { - VMError.guarantee(cnd.isRuntimeChecked(), "Only runtime conditions can be added to the ConditionalRuntimeValue."); - if (satisfied) { - return; - } else if (cnd.isAlwaysTrue()) { - conditions = null; - satisfied = true; - return; - } - - Object newRuntimeCondition = createRuntimeCondition(cnd); - Set existingConditions = conditions == null ? new HashSet<>() : new HashSet<>(Arrays.asList(conditions)); - existingConditions.add(newRuntimeCondition); - setConditions(existingConditions.toArray()); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public Set> getTypesForEncoding() { - if (conditions == null) { - return Set.of(); - } else { - Set> types = new HashSet<>(); - for (Object condition : conditions) { - types.addAll(getTypesForEncoding(condition)); - } - return types; - } - } - - public static RuntimeConditionSet unmodifiableEmptySet() { - return UnmodifiableRuntimeConditionSet.UNMODIFIABLE_EMPTY_SET; - } - - public static RuntimeConditionSet createDecoded(Object[] conditions) { - return new RuntimeConditionSet(conditions); - } - - /** - * Checks if any of the conditions has been satisfied. It caches the value in satisfied. This - * code can be concurrently executed, however there are no concurrency primitives used. The - * implementation relies on the fact that checking if a condition is satisfied is an idempotent - * operation. - * - * @return true if any of the elements is satisfied. - */ - public boolean satisfied() { - var result = false; - if (satisfied) { - result = true; - } else { - final var localConditions = conditions; - if (localConditions == null) { - result = true; - } else { - for (Object condition : localConditions) { - if (isSatisfied(condition)) { - conditions = null; - satisfied = result = true; - break; - } - } - } - } - - if (TrackUnsatisfiedTypeReachedConditions.getValue() && !result) { - LogUtils.info("Unsatisfied runtime conditions reachable at build-time: " + Arrays.toString(conditions)); - new Exception().printStackTrace(System.out); - return true; - } - - return result; - } - - @Override - public String toString() { - String conditionsString = this.conditions == null ? "[]" : Arrays.toString(this.conditions); - return conditionsString + " = " + satisfied; - } - - private RuntimeConditionSet(Object[] conditions) { - setConditions(conditions); - } - - private void setConditions(Object[] conditions) { - if (conditions.length == 0) { - this.conditions = null; - } else { - this.conditions = conditions; - } - satisfied = false; - } - - private static Object createRuntimeCondition(ConfigurationCondition cnd) { - if (cnd.isAlwaysTrue() || !cnd.isRuntimeChecked()) { - throw VMError.shouldNotReachHere("We should never create run-time conditions from conditions that are always true at build time. Condition: " + cnd); - } - return cnd.getType(); - } - - private static boolean isSatisfied(Object condition) { - if (condition instanceof Class typeReachedCondition) { - return DynamicHub.fromClass(typeReachedCondition).isReached(); - } else { - throw VMError.shouldNotReachHere("Only typeReached condition is supported."); - } - } - - private static Set> getTypesForEncoding(Object condition) { - if (condition instanceof Class res) { - return Set.of(res); - } else { - throw VMError.shouldNotReachHere("Only typeReached condition is supported."); - } - } - - public static final class UnmodifiableRuntimeConditionSet extends RuntimeConditionSet { - private static final RuntimeConditionSet UNMODIFIABLE_EMPTY_SET = new UnmodifiableRuntimeConditionSet(new Object[0]); - - private UnmodifiableRuntimeConditionSet(Object[] conditions) { - super(conditions); - } - - @Override - public synchronized void addCondition(ConfigurationCondition cnd) { - throw new UnsupportedOperationException("Can't add conditions to an unmodifiable set of conditions."); - } - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java index e34d651a303..1f26a9e072a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java @@ -28,27 +28,26 @@ import java.util.List; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; +import org.graalvm.util.json.JSONParserException; -import jdk.graal.compiler.util.json.JsonParserException; - -public abstract class SerializationConfigurationParser extends ConfigurationParser { +public abstract class SerializationConfigurationParser extends ConfigurationParser { public static final String CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY = "customTargetConstructorClass"; - protected final ConfigurationConditionResolver conditionResolver; - protected final RuntimeSerializationSupport serializationSupport; + protected final ConfigurationConditionResolver conditionResolver; + protected final RuntimeSerializationSupport serializationSupport; - public static SerializationConfigurationParser create(boolean strictMetadata, ConfigurationConditionResolver conditionResolver, RuntimeSerializationSupport serializationSupport, - boolean strictConfiguration) { + public static SerializationConfigurationParser create(boolean strictMetadata, RuntimeSerializationSupport serializationSupport, boolean strictConfiguration) { if (strictMetadata) { - return new SerializationMetadataParser<>(conditionResolver, serializationSupport, strictConfiguration); + return new SerializationMetadataParser<>(ConfigurationConditionResolver.identityResolver(), serializationSupport, strictConfiguration); } else { - return new LegacySerializationConfigurationParser<>(conditionResolver, serializationSupport, strictConfiguration); + return new LegacySerializationConfigurationParser(ConfigurationConditionResolver.identityResolver(), serializationSupport, strictConfiguration); } } - public SerializationConfigurationParser(ConfigurationConditionResolver conditionResolver, RuntimeSerializationSupport serializationSupport, boolean strictConfiguration) { + public SerializationConfigurationParser(ConfigurationConditionResolver conditionResolver, RuntimeSerializationSupport serializationSupport, boolean strictConfiguration) { super(strictConfiguration); this.serializationSupport = serializationSupport; this.conditionResolver = conditionResolver; @@ -62,14 +61,14 @@ protected void parseSerializationTypes(List listOfSerializationTypes, bo protected abstract void parseSerializationDescriptorObject(EconomicMap data, boolean lambdaCapturingType); - protected void registerType(ConfigurationTypeDescriptor targetSerializationClass, C condition, Object optionalCustomCtorValue) { + protected void registerType(ConfigurationTypeDescriptor targetSerializationClass, ConfigurationCondition condition, Object optionalCustomCtorValue) { String customTargetConstructorClass = optionalCustomCtorValue != null ? asString(optionalCustomCtorValue) : null; if (targetSerializationClass instanceof NamedConfigurationTypeDescriptor namedClass) { serializationSupport.registerWithTargetConstructorClass(condition, namedClass.name(), customTargetConstructorClass); } else if (targetSerializationClass instanceof ProxyConfigurationTypeDescriptor proxyClass) { serializationSupport.registerProxyClass(condition, proxyClass.interfaceNames()); } else { - throw new JsonParserException("Unknown configuration type descriptor: %s".formatted(targetSerializationClass.toString())); + throw new JSONParserException("Unknown configuration type descriptor: %s".formatted(targetSerializationClass.toString())); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationMetadataParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationMetadataParser.java index 9b74ed81124..86d81982df3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationMetadataParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationMetadataParser.java @@ -29,12 +29,12 @@ import java.util.Optional; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; -import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; -final class SerializationMetadataParser extends SerializationConfigurationParser { +final class SerializationMetadataParser extends SerializationConfigurationParser { - SerializationMetadataParser(ConfigurationConditionResolver conditionResolver, RuntimeSerializationSupport serializationSupport, boolean strictConfiguration) { + SerializationMetadataParser(ConfigurationConditionResolver conditionResolver, RuntimeSerializationSupport serializationSupport, boolean strictConfiguration) { super(conditionResolver, serializationSupport, strictConfiguration); } @@ -55,7 +55,7 @@ protected void parseSerializationDescriptorObject(EconomicMap da return; } - UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, true); + ConfigurationCondition unresolvedCondition = parseCondition(data, true); var condition = conditionResolver.resolveCondition(unresolvedCondition); if (!condition.isPresent()) { return; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/doc-files/ReflectionConfigurationFilesHelp.txt b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/doc-files/ReflectionConfigurationFilesHelp.txt index cc20fd1e7d7..ff4c16a974f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/doc-files/ReflectionConfigurationFilesHelp.txt +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/doc-files/ReflectionConfigurationFilesHelp.txt @@ -2,7 +2,7 @@ One or several (comma-separated) paths to JSON files that specify which program The JSON object schema is described at: - https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reflect-config-schema-v1.1.0.json + https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reflect-config-schema-v1.0.0.json Example: diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/doc-files/SerializationConfigurationFilesHelp.txt b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/doc-files/SerializationConfigurationFilesHelp.txt index e606e1ede89..aecd04f4547 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/doc-files/SerializationConfigurationFilesHelp.txt +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/doc-files/SerializationConfigurationFilesHelp.txt @@ -2,7 +2,7 @@ One or several (comma-separated) paths to JSON files that specify lists of seria The structure is described in the following schema: - https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/serialization-config-schema-v1.1.0.json + https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/serialization-config-schema-v1.0.0.json Example: diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/proxy/DynamicProxyRegistry.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/proxy/DynamicProxyRegistry.java index d57bd01e0b5..e5749235490 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/proxy/DynamicProxyRegistry.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/proxy/DynamicProxyRegistry.java @@ -35,5 +35,5 @@ public interface DynamicProxyRegistry extends RuntimeProxyCreationSupport { boolean isProxyClass(Class clazz); @Platforms(Platform.HOSTED_ONLY.class) - Class createProxyClassForSerialization(Class... interfaces); + Class getProxyClassHosted(Class... interfaces); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java index 5f28bed354b..773038bc8e8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java @@ -28,9 +28,11 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.util.concurrent.ConcurrentHashMap; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; @@ -39,6 +41,11 @@ @TargetClass(value = MethodHandles.class, innerClass = "Lookup") final class Target_java_lang_invoke_MethodHandles_Lookup { + // Checkstyle: stop + @Delete // + static ConcurrentHashMap LOOKASIDE_TABLE; + // Checkstyle: resume + @SuppressWarnings("static-method") @Substitute public Class defineClass(@SuppressWarnings("unused") byte[] bytes) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/proxy/DynamicProxySupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/proxy/DynamicProxySupport.java index b1a3d5f075a..8961f347adb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/proxy/DynamicProxySupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/proxy/DynamicProxySupport.java @@ -145,7 +145,7 @@ private Object createProxyClass(Class[] interfaces) { @Override @Platforms(Platform.HOSTED_ONLY.class) - public Class createProxyClassForSerialization(Class... interfaces) { + public Class getProxyClassHosted(Class... interfaces) { final Class[] intfs = interfaces.clone(); return createProxyClassFromImplementedInterfaces(intfs); } @@ -244,4 +244,8 @@ private synchronized boolean isHostedProxyClass(Class clazz) { public static Class getJdkProxyClass(ClassLoader loader, Class... interfaces) { return java.lang.reflect.Proxy.getProxyClass(loader, interfaces); } + + public static String proxyTypeDescriptor(String... interfaceNames) { + return "Proxy[" + String.join(", ", interfaceNames) + "]"; + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ConditionalConfigurationRegistry.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ConditionalConfigurationRegistry.java index 8af9e717078..33e2a65289d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ConditionalConfigurationRegistry.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ConditionalConfigurationRegistry.java @@ -53,7 +53,9 @@ protected void registerConditionalConfiguration(ConfigurationCondition condition public void flushConditionalConfiguration(Feature.BeforeAnalysisAccess b) { for (Map.Entry> reachabilityEntry : pendingReachabilityHandlers.entrySet()) { TypeResult> typeResult = ((FeatureImpl.BeforeAnalysisAccessImpl) b).getImageClassLoader().findClass(reachabilityEntry.getKey()); - b.registerReachabilityHandler(access -> reachabilityEntry.getValue().forEach(Runnable::run), typeResult.get()); + if (typeResult.isPresent()) { + b.registerReachabilityHandler(access -> reachabilityEntry.getValue().forEach(Runnable::run), typeResult.get()); + } } pendingReachabilityHandlers.clear(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java index 5ce7637a13a..ee51025bdb0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java @@ -213,10 +213,14 @@ private static ResourcesRegistryImpl resourceRegistryImpl() { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { - ResourceConfigurationParser parser = new ResourceConfigurationParser(ImageSingletons.lookup(ResourcesRegistry.class), ConfigurationFiles.Options.StrictConfiguration.getValue()); - loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurations(parser, imageClassLoader, "resource", - ConfigurationFiles.Options.ResourceConfigurationFiles, ConfigurationFiles.Options.ResourceConfigurationResources, - ConfigurationFile.RESOURCES.getFileName()); + ResourceConfigurationParser parser = ResourceConfigurationParser.create(true, ResourcesRegistry.singleton(), + ConfigurationFiles.Options.StrictConfiguration.getValue()); + loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurationsFromCombinedFile(parser, imageClassLoader, "resource"); + + ResourceConfigurationParser legacyParser = ResourceConfigurationParser.create(false, ResourcesRegistry.singleton(), + ConfigurationFiles.Options.StrictConfiguration.getValue()); + loadedConfigurations += ConfigurationParserUtils.parseAndRegisterConfigurations(legacyParser, imageClassLoader, "resource", ConfigurationFiles.Options.ResourceConfigurationFiles, + ConfigurationFiles.Options.ResourceConfigurationResources, ConfigurationFile.RESOURCES.getFileName()); resourcePatternWorkSet.addAll(Options.IncludeResources.getValue().values()); excludedResourcePatterns.addAll(Options.ExcludeResources.getValue().values()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java index fde6041471e..98e01b52b72 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java @@ -30,6 +30,7 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Spliterator; @@ -41,7 +42,7 @@ import org.graalvm.nativeimage.impl.ReflectionRegistry; import org.graalvm.util.json.JSONParserException; -import com.oracle.svm.core.configure.ConditionalElement; +import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationFiles; import com.oracle.svm.core.configure.ConfigurationParser; import com.oracle.svm.core.configure.ReflectionConfigurationParser; @@ -52,10 +53,9 @@ public final class ConfigurationParserUtils { - public static ReflectionConfigurationParser>> create(ReflectionRegistry registry, ImageClassLoader imageClassLoader) { - return new ReflectionConfigurationParser<>(RegistryAdapter.create(registry, imageClassLoader), - ConfigurationFiles.Options.StrictConfiguration.getValue(), - ConfigurationFiles.Options.WarnAboutMissingReflectionOrJNIMetadataElements.getValue()); + public static ReflectionConfigurationParser> create(String combinedFileKey, boolean strictMetadata, ReflectionRegistry registry, ImageClassLoader imageClassLoader) { + return ReflectionConfigurationParser.create(combinedFileKey, strictMetadata, RegistryAdapter.create(registry, imageClassLoader), + ConfigurationFiles.Options.StrictConfiguration.getValue(), ConfigurationFiles.Options.WarnAboutMissingReflectionOrJNIMetadataElements.getValue()); } /** @@ -75,6 +75,10 @@ public static int parseAndRegisterConfigurations(ConfigurationParser parser, Ima return parseAndRegisterConfigurations(parser, classLoader, featureName, directoryFileName, paths, resourceValues); } + public static int parseAndRegisterConfigurationsFromCombinedFile(ConfigurationParser parser, ImageClassLoader classLoader, String featureName) { + return parseAndRegisterConfigurations(parser, classLoader, featureName, ConfigurationFile.REACHABILITY_METADATA.getFileName(), Collections.emptyList(), Collections.emptyList()); + } + public static int parseAndRegisterConfigurations(ConfigurationParser parser, ImageClassLoader classLoader, String featureName, String directoryFileName, List paths, diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ReflectionRegistryAdapter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ReflectionRegistryAdapter.java index 6b763eb4e8b..1d815eb71c0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ReflectionRegistryAdapter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ReflectionRegistryAdapter.java @@ -32,7 +32,7 @@ import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; import com.oracle.svm.core.TypeResult; -import com.oracle.svm.core.configure.ConditionalElement; +import com.oracle.svm.core.configure.ConfigurationTypeDescriptor; import com.oracle.svm.hosted.ImageClassLoader; public class ReflectionRegistryAdapter extends RegistryAdapter { @@ -44,86 +44,90 @@ public class ReflectionRegistryAdapter extends RegistryAdapter { } @Override - public TypeResult>> resolveType(ConfigurationCondition condition, String typeName, boolean allowPrimitives) { - TypeResult>> result = super.resolveType(condition, typeName, allowPrimitives); + public TypeResult> resolveType(ConfigurationCondition condition, ConfigurationTypeDescriptor typeDescriptor, boolean allowPrimitives) { + TypeResult> result = super.resolveType(condition, typeDescriptor, allowPrimitives); if (!result.isPresent()) { Throwable classLookupException = result.getException(); if (classLookupException instanceof LinkageError) { - reflectionSupport.registerClassLookupException(condition, typeName, classLookupException); + reflectionSupport.registerClassLookupException(condition, typeDescriptor.toString(), classLookupException); } else if (throwMissingRegistrationErrors() && classLookupException instanceof ClassNotFoundException) { - reflectionSupport.registerClassLookup(condition, typeName); + reflectionSupport.registerClassLookup(condition, typeDescriptor.toString()); } } return result; } @Override - public void registerPublicClasses(ConditionalElement> type) { - reflectionSupport.registerAllClassesQuery(type.getCondition(), type.getElement()); + public void registerPublicClasses(ConfigurationCondition condition, Class type) { + reflectionSupport.registerAllClassesQuery(condition, type); } @Override - public void registerDeclaredClasses(ConditionalElement> type) { - reflectionSupport.registerAllDeclaredClassesQuery(type.getCondition(), type.getElement()); + public void registerDeclaredClasses(ConfigurationCondition condition, Class type) { + reflectionSupport.registerAllDeclaredClassesQuery(condition, type); } @Override - public void registerRecordComponents(ConditionalElement> type) { - reflectionSupport.registerAllRecordComponentsQuery(type.getCondition(), type.getElement()); + public void registerRecordComponents(ConfigurationCondition condition, Class type) { + reflectionSupport.registerAllRecordComponentsQuery(condition, type); } @Override - public void registerPermittedSubclasses(ConditionalElement> type) { - reflectionSupport.registerAllPermittedSubclassesQuery(type.getCondition(), type.getElement()); + public void registerPermittedSubclasses(ConfigurationCondition condition, Class type) { + reflectionSupport.registerAllPermittedSubclassesQuery(condition, type); } @Override - public void registerNestMembers(ConditionalElement> type) { - reflectionSupport.registerAllNestMembersQuery(type.getCondition(), type.getElement()); + public void registerNestMembers(ConfigurationCondition condition, Class type) { + reflectionSupport.registerAllNestMembersQuery(condition, type); } @Override - public void registerSigners(ConditionalElement> type) { - reflectionSupport.registerAllSignersQuery(type.getCondition(), type.getElement()); + public void registerSigners(ConfigurationCondition condition, Class type) { + reflectionSupport.registerAllSignersQuery(condition, type); } @Override - public void registerPublicFields(ConditionalElement> type) { - reflectionSupport.registerAllFieldsQuery(type.getCondition(), type.getElement()); + public void registerPublicFields(ConfigurationCondition condition, boolean queriedOnly, Class type) { + if (!queriedOnly) { + reflectionSupport.registerAllFieldsQuery(condition, type); + } } @Override - public void registerDeclaredFields(ConditionalElement> type) { - reflectionSupport.registerAllDeclaredFieldsQuery(type.getCondition(), type.getElement()); + public void registerDeclaredFields(ConfigurationCondition condition, boolean queriedOnly, Class type) { + if (!queriedOnly) { + reflectionSupport.registerAllDeclaredFieldsQuery(condition, type); + } } @Override - public void registerPublicMethods(boolean queriedOnly, ConditionalElement> type) { - reflectionSupport.registerAllMethodsQuery(type.getCondition(), queriedOnly, type.getElement()); + public void registerPublicMethods(ConfigurationCondition condition, boolean queriedOnly, Class type) { + reflectionSupport.registerAllMethodsQuery(condition, queriedOnly, type); } @Override - public void registerDeclaredMethods(boolean queriedOnly, ConditionalElement> type) { - reflectionSupport.registerAllDeclaredMethodsQuery(type.getCondition(), queriedOnly, type.getElement()); + public void registerDeclaredMethods(ConfigurationCondition condition, boolean queriedOnly, Class type) { + reflectionSupport.registerAllDeclaredMethodsQuery(condition, queriedOnly, type); } @Override - public void registerPublicConstructors(boolean queriedOnly, ConditionalElement> type) { - reflectionSupport.registerAllConstructorsQuery(type.getCondition(), queriedOnly, type.getElement()); + public void registerPublicConstructors(ConfigurationCondition condition, boolean queriedOnly, Class type) { + reflectionSupport.registerAllConstructorsQuery(condition, queriedOnly, type); } @Override - public void registerDeclaredConstructors(boolean queriedOnly, ConditionalElement> type) { - reflectionSupport.registerAllDeclaredConstructorsQuery(type.getCondition(), queriedOnly, type.getElement()); + public void registerDeclaredConstructors(ConfigurationCondition condition, boolean queriedOnly, Class type) { + reflectionSupport.registerAllDeclaredConstructorsQuery(condition, queriedOnly, type); } @Override - public void registerField(ConditionalElement> type, String fieldName, boolean allowWrite) throws NoSuchFieldException { + public void registerField(ConfigurationCondition condition, Class type, String fieldName, boolean allowWrite) throws NoSuchFieldException { try { - super.registerField(type, fieldName, allowWrite); + super.registerField(condition, type, fieldName, allowWrite); } catch (NoSuchFieldException e) { if (throwMissingRegistrationErrors()) { - reflectionSupport.registerFieldLookup(type.getCondition(), type.getElement(), fieldName); + reflectionSupport.registerFieldLookup(condition, type, fieldName); } else { throw e; } @@ -131,12 +135,12 @@ public void registerField(ConditionalElement> type, String fieldName, b } @Override - public void registerMethod(boolean queriedOnly, ConditionalElement> type, String methodName, List>> methodParameterTypes) throws NoSuchMethodException { + public void registerMethod(ConfigurationCondition condition, boolean queriedOnly, Class type, String methodName, List> methodParameterTypes) throws NoSuchMethodException { try { - super.registerMethod(queriedOnly, type, methodName, methodParameterTypes); + super.registerMethod(condition, queriedOnly, type, methodName, methodParameterTypes); } catch (NoSuchMethodException e) { if (throwMissingRegistrationErrors()) { - reflectionSupport.registerMethodLookup(type.getCondition(), type.getElement(), methodName, getParameterTypes(methodParameterTypes)); + reflectionSupport.registerMethodLookup(condition, type, methodName, getParameterTypes(methodParameterTypes)); } else { throw e; } @@ -144,12 +148,12 @@ public void registerMethod(boolean queriedOnly, ConditionalElement> typ } @Override - public void registerConstructor(boolean queriedOnly, ConditionalElement> type, List>> methodParameterTypes) throws NoSuchMethodException { + public void registerConstructor(ConfigurationCondition condition, boolean queriedOnly, Class type, List> methodParameterTypes) throws NoSuchMethodException { try { - super.registerConstructor(queriedOnly, type, methodParameterTypes); + super.registerConstructor(condition, queriedOnly, type, methodParameterTypes); } catch (NoSuchMethodException e) { if (throwMissingRegistrationErrors()) { - reflectionSupport.registerConstructorLookup(type.getCondition(), type.getElement(), getParameterTypes(methodParameterTypes)); + reflectionSupport.registerConstructorLookup(condition, type, getParameterTypes(methodParameterTypes)); } else { throw e; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/RegistryAdapter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/RegistryAdapter.java index 1725a1cc775..73a12c2d838 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/RegistryAdapter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/RegistryAdapter.java @@ -27,21 +27,25 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.List; +import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.ReflectionRegistry; import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; import com.oracle.svm.core.TypeResult; -import com.oracle.svm.core.configure.ConditionalElement; +import com.oracle.svm.core.configure.ConfigurationTypeDescriptor; +import com.oracle.svm.core.configure.NamedConfigurationTypeDescriptor; +import com.oracle.svm.core.configure.ProxyConfigurationTypeDescriptor; import com.oracle.svm.core.configure.ReflectionConfigurationParserDelegate; +import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.util.ClassUtil; -import jdk.vm.ci.meta.MetaUtil; - -public class RegistryAdapter implements ReflectionConfigurationParserDelegate>> { +public class RegistryAdapter implements ReflectionConfigurationParserDelegate> { private final ReflectionRegistry registry; private final ImageClassLoader classLoader; @@ -59,102 +63,116 @@ public static RegistryAdapter create(ReflectionRegistry registry, ImageClassLoad } @Override - public void registerType(ConditionalElement> type) { - registry.register(type.getCondition(), type.getElement()); - } - - @Override - public TypeResult resolveCondition(String typeName) { - String canonicalizedName = canonicalizeTypeName(typeName); - TypeResult> clazz = classLoader.findClass(canonicalizedName); - return clazz.map(Class::getTypeName) - .map(ConfigurationCondition::create); + public void registerType(ConfigurationCondition condition, Class type) { + registry.register(condition, type); } @Override - public TypeResult>> resolveType(ConfigurationCondition condition, String typeName, boolean allowPrimitives) { - String name = canonicalizeTypeName(typeName); - TypeResult> clazz = classLoader.findClass(name, allowPrimitives); - return clazz.map(c -> new ConditionalElement<>(condition, c)); + public TypeResult> resolveType(ConfigurationCondition condition, ConfigurationTypeDescriptor typeDescriptor, boolean allowPrimitives) { + switch (typeDescriptor.getDescriptorType()) { + case NAMED -> { + NamedConfigurationTypeDescriptor namedDescriptor = (NamedConfigurationTypeDescriptor) typeDescriptor; + return classLoader.findClass(namedDescriptor.name(), allowPrimitives); + } + case PROXY -> { + return resolveProxyType((ProxyConfigurationTypeDescriptor) typeDescriptor); + } + default -> { + throw VMError.shouldNotReachHere("Unknown type descriptor kind: %s", typeDescriptor.getDescriptorType()); + } + } } - private static String canonicalizeTypeName(String typeName) { - String name = typeName; - if (name.indexOf('[') != -1) { - /* accept "int[][]", "java.lang.String[]" */ - name = MetaUtil.internalNameToJava(MetaUtil.toInternalName(name), true, true); + private TypeResult> resolveProxyType(ProxyConfigurationTypeDescriptor typeDescriptor) { + String typeName = typeDescriptor.toString(); + List>> interfaceResults = typeDescriptor.interfaceNames().stream().map(name -> { + NamedConfigurationTypeDescriptor typeDescriptor1 = new NamedConfigurationTypeDescriptor(name); + return classLoader.findClass(typeDescriptor1.name(), false); + }).toList(); + List> interfaces = new ArrayList<>(); + for (TypeResult> intf : interfaceResults) { + if (!intf.isPresent()) { + return TypeResult.forException(typeName, intf.getException()); + } + interfaces.add(intf.get()); + } + try { + DynamicProxyRegistry proxyRegistry = ImageSingletons.lookup(DynamicProxyRegistry.class); + Class proxyClass = proxyRegistry.getProxyClassHosted(interfaces.toArray(Class[]::new)); + return TypeResult.forType(typeName, proxyClass); + } catch (Throwable t) { + return TypeResult.forException(typeName, t); } - return name; } @Override - public void registerPublicClasses(ConditionalElement> type) { - registry.register(type.getCondition(), type.getElement().getClasses()); + public void registerPublicClasses(ConfigurationCondition condition, Class type) { + registry.register(condition, type.getClasses()); } @Override - public void registerDeclaredClasses(ConditionalElement> type) { - registry.register(type.getCondition(), type.getElement().getDeclaredClasses()); + public void registerDeclaredClasses(ConfigurationCondition condition, Class type) { + registry.register(condition, type.getDeclaredClasses()); } @Override - public void registerRecordComponents(ConditionalElement> type) { + public void registerRecordComponents(ConfigurationCondition condition, Class type) { } @Override - public void registerPermittedSubclasses(ConditionalElement> type) { + public void registerPermittedSubclasses(ConfigurationCondition condition, Class type) { } @Override - public void registerNestMembers(ConditionalElement> type) { + public void registerNestMembers(ConfigurationCondition condition, Class type) { } @Override - public void registerSigners(ConditionalElement> type) { + public void registerSigners(ConfigurationCondition condition, Class type) { } @Override - public void registerPublicFields(ConditionalElement> type) { - registry.register(type.getCondition(), false, type.getElement().getFields()); + public void registerPublicFields(ConfigurationCondition condition, boolean queriedOnly, Class type) { + registry.register(condition, false, type.getFields()); } @Override - public void registerDeclaredFields(ConditionalElement> type) { - registry.register(type.getCondition(), false, type.getElement().getDeclaredFields()); + public void registerDeclaredFields(ConfigurationCondition condition, boolean queriedOnly, Class type) { + registry.register(condition, false, type.getDeclaredFields()); } @Override - public void registerPublicMethods(boolean queriedOnly, ConditionalElement> type) { - registry.register(type.getCondition(), queriedOnly, type.getElement().getMethods()); + public void registerPublicMethods(ConfigurationCondition condition, boolean queriedOnly, Class type) { + registry.register(condition, queriedOnly, type.getMethods()); } @Override - public void registerDeclaredMethods(boolean queriedOnly, ConditionalElement> type) { - registry.register(type.getCondition(), queriedOnly, type.getElement().getDeclaredMethods()); + public void registerDeclaredMethods(ConfigurationCondition condition, boolean queriedOnly, Class type) { + registry.register(condition, queriedOnly, type.getDeclaredMethods()); } @Override - public void registerPublicConstructors(boolean queriedOnly, ConditionalElement> type) { - registry.register(type.getCondition(), queriedOnly, type.getElement().getConstructors()); + public void registerPublicConstructors(ConfigurationCondition condition, boolean queriedOnly, Class type) { + registry.register(condition, queriedOnly, type.getConstructors()); } @Override - public void registerDeclaredConstructors(boolean queriedOnly, ConditionalElement> type) { - registry.register(type.getCondition(), queriedOnly, type.getElement().getDeclaredConstructors()); + public void registerDeclaredConstructors(ConfigurationCondition condition, boolean queriedOnly, Class type) { + registry.register(condition, queriedOnly, type.getDeclaredConstructors()); } @Override - public void registerField(ConditionalElement> type, String fieldName, boolean allowWrite) throws NoSuchFieldException { - registry.register(type.getCondition(), allowWrite, type.getElement().getDeclaredField(fieldName)); + public void registerField(ConfigurationCondition condition, Class type, String fieldName, boolean allowWrite) throws NoSuchFieldException { + registry.register(condition, allowWrite, type.getDeclaredField(fieldName)); } @Override - public boolean registerAllMethodsWithName(boolean queriedOnly, ConditionalElement> type, String methodName) { + public boolean registerAllMethodsWithName(ConfigurationCondition condition, boolean queriedOnly, Class type, String methodName) { boolean found = false; - Executable[] methods = type.getElement().getDeclaredMethods(); + Executable[] methods = type.getDeclaredMethods(); for (Executable method : methods) { if (method.getName().equals(methodName)) { - registerExecutable(type.getCondition(), queriedOnly, method); + registerExecutable(condition, queriedOnly, method); found = true; } } @@ -162,17 +180,16 @@ public boolean registerAllMethodsWithName(boolean queriedOnly, ConditionalElemen } @Override - public boolean registerAllConstructors(boolean queriedOnly, ConditionalElement> type) { - Executable[] methods = type.getElement().getDeclaredConstructors(); - registerExecutable(type.getCondition(), queriedOnly, methods); + public boolean registerAllConstructors(ConfigurationCondition condition, boolean queriedOnly, Class type) { + Executable[] methods = type.getDeclaredConstructors(); + registerExecutable(condition, queriedOnly, methods); return methods.length > 0; } @Override - public void registerUnsafeAllocated(ConditionalElement> clazz) { - Class type = clazz.getElement(); + public void registerUnsafeAllocated(ConfigurationCondition condition, Class type) { if (!type.isArray() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) { - registry.register(clazz.getCondition(), true, clazz.getElement()); + registry.register(condition, true, type); /* * Ignore otherwise as the implementation of allocateInstance will anyhow throw an * exception. @@ -181,11 +198,11 @@ public void registerUnsafeAllocated(ConditionalElement> clazz) { } @Override - public void registerMethod(boolean queriedOnly, ConditionalElement> type, String methodName, List>> methodParameterTypes) throws NoSuchMethodException { + public void registerMethod(ConfigurationCondition condition, boolean queriedOnly, Class type, String methodName, List> methodParameterTypes) throws NoSuchMethodException { Class[] parameterTypesArray = getParameterTypes(methodParameterTypes); Method method; try { - method = type.getElement().getDeclaredMethod(methodName, parameterTypesArray); + method = type.getDeclaredMethod(methodName, parameterTypesArray); } catch (NoClassDefFoundError e) { /* * getDeclaredMethod() builds a set of all the declared methods, which can fail when a @@ -196,24 +213,22 @@ public void registerMethod(boolean queriedOnly, ConditionalElement> typ * precisely because the application used getMethod() instead of getDeclaredMethod(). */ try { - method = type.getElement().getMethod(methodName, parameterTypesArray); + method = type.getMethod(methodName, parameterTypesArray); } catch (Throwable ignored) { throw e; } } - registerExecutable(type.getCondition(), queriedOnly, method); + registerExecutable(condition, queriedOnly, method); } @Override - public void registerConstructor(boolean queriedOnly, ConditionalElement> type, List>> methodParameterTypes) throws NoSuchMethodException { + public void registerConstructor(ConfigurationCondition condition, boolean queriedOnly, Class type, List> methodParameterTypes) throws NoSuchMethodException { Class[] parameterTypesArray = getParameterTypes(methodParameterTypes); - registerExecutable(type.getCondition(), queriedOnly, type.getElement().getDeclaredConstructor(parameterTypesArray)); + registerExecutable(condition, queriedOnly, type.getDeclaredConstructor(parameterTypesArray)); } - static Class[] getParameterTypes(List>> methodParameterTypes) { - return methodParameterTypes.stream() - .map(ConditionalElement::getElement) - .toArray(Class[]::new); + static Class[] getParameterTypes(List> methodParameterTypes) { + return methodParameterTypes.toArray(Class[]::new); } private void registerExecutable(ConfigurationCondition condition, boolean queriedOnly, Executable... executable) { @@ -221,12 +236,12 @@ private void registerExecutable(ConfigurationCondition condition, boolean querie } @Override - public String getTypeName(ConditionalElement> type) { - return type.getElement().getTypeName(); + public String getTypeName(Class type) { + return type.getTypeName(); } @Override - public String getSimpleName(ConditionalElement> type) { - return ClassUtil.getUnqualifiedName(type.getElement()); + public String getSimpleName(Class type) { + return ClassUtil.getUnqualifiedName(type); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java index 37bf159f74b..328a6557702 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.jni; +import static com.oracle.svm.core.configure.ConfigurationParser.JNI_KEY; + import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -61,7 +63,6 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.core.config.ObjectLayout; -import com.oracle.svm.core.configure.ConditionalElement; import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationFiles; import com.oracle.svm.core.configure.ReflectionConfigurationParser; @@ -192,9 +193,13 @@ public void afterRegistration(AfterRegistrationAccess arg) { runtimeSupport = new JNIRuntimeAccessibilitySupportImpl(); ImageSingletons.add(RuntimeJNIAccessSupport.class, runtimeSupport); - ReflectionConfigurationParser>> parser = ConfigurationParserUtils.create(runtimeSupport, access.getImageClassLoader()); - loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurations(parser, access.getImageClassLoader(), "JNI", - ConfigurationFiles.Options.JNIConfigurationFiles, ConfigurationFiles.Options.JNIConfigurationResources, ConfigurationFile.JNI.getFileName()); + ReflectionConfigurationParser> parser = ConfigurationParserUtils.create(JNI_KEY, true, runtimeSupport, + access.getImageClassLoader()); + loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurationsFromCombinedFile(parser, access.getImageClassLoader(), "JNI"); + ReflectionConfigurationParser> legacyParser = ConfigurationParserUtils.create(null, false, runtimeSupport, + access.getImageClassLoader()); + loadedConfigurations += ConfigurationParserUtils.parseAndRegisterConfigurations(legacyParser, access.getImageClassLoader(), "JNI", ConfigurationFiles.Options.JNIConfigurationFiles, + ConfigurationFiles.Options.JNIConfigurationResources, ConfigurationFile.JNI.getFileName()); } private class JNIRuntimeAccessibilitySupportImpl extends ConditionalConfigurationRegistry @@ -212,7 +217,9 @@ public void register(ConfigurationCondition condition, boolean unsafeAllocated, public void register(ConfigurationCondition condition, boolean queriedOnly, Executable... methods) { requireNonNull(methods, "methods"); abortIfSealed(); - registerConditionalConfiguration(condition, () -> newMethods.addAll(Arrays.asList(methods))); + if (!queriedOnly) { + registerConditionalConfiguration(condition, () -> newMethods.addAll(Arrays.asList(methods))); + } } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java index 372d1e53316..ddf7d4ce88e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.reflect; +import static com.oracle.svm.core.configure.ConfigurationParser.REFLECTION_KEY; + import java.lang.invoke.MethodHandle; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; @@ -52,7 +54,6 @@ import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Delete; -import com.oracle.svm.core.configure.ConditionalElement; import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationFiles; import com.oracle.svm.core.configure.ReflectionConfigurationParser; @@ -261,10 +262,13 @@ public void duringSetup(DuringSetupAccess a) { aUniverse = access.getUniverse(); reflectionData.duringSetup(access.getMetaAccess(), aUniverse); - ReflectionConfigurationParser>> parser = ConfigurationParserUtils.create(reflectionData, access.getImageClassLoader()); - loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurations(parser, access.getImageClassLoader(), "reflection", - ConfigurationFiles.Options.ReflectionConfigurationFiles, ConfigurationFiles.Options.ReflectionConfigurationResources, - ConfigurationFile.REFLECTION.getFileName()); + ReflectionConfigurationParser> parser = ConfigurationParserUtils.create(REFLECTION_KEY, true, reflectionData, + access.getImageClassLoader()); + loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurationsFromCombinedFile(parser, access.getImageClassLoader(), "reflection"); + ReflectionConfigurationParser> legacyParser = ConfigurationParserUtils.create(null, false, reflectionData, + access.getImageClassLoader()); + loadedConfigurations += ConfigurationParserUtils.parseAndRegisterConfigurations(legacyParser, access.getImageClassLoader(), "reflection", + ConfigurationFiles.Options.ReflectionConfigurationFiles, ConfigurationFiles.Options.ReflectionConfigurationResources, ConfigurationFile.REFLECTION.getFileName()); loader = access.getImageClassLoader(); annotationSubstitutions = ((Inflation) access.getBigBang()).getAnnotationSubstitutionProcessor(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/DynamicProxyFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/DynamicProxyFeature.java index 3caa69ae79f..f311da09d87 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/DynamicProxyFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/DynamicProxyFeature.java @@ -32,6 +32,7 @@ import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.impl.RuntimeProxyCreationSupport; +import com.oracle.svm.core.configure.ConditionalElement; import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationFiles; import com.oracle.svm.core.configure.ProxyConfigurationParser; @@ -68,7 +69,8 @@ public void duringSetup(DuringSetupAccess a) { ConfigurationTypeResolver typeResolver = new ConfigurationTypeResolver("resource configuration", imageClassLoader); ProxyRegistry proxyRegistry = new ProxyRegistry(typeResolver, dynamicProxySupport, imageClassLoader); ImageSingletons.add(ProxyRegistry.class, proxyRegistry); - ProxyConfigurationParser parser = new ProxyConfigurationParser(proxyRegistry, ConfigurationFiles.Options.StrictConfiguration.getValue()); + ProxyConfigurationParser parser = new ProxyConfigurationParser(ConfigurationFiles.Options.StrictConfiguration.getValue(), + (cond, intfs) -> proxyRegistry.accept(new ConditionalElement<>(cond, intfs))); loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurations(parser, imageClassLoader, "dynamic proxy", ConfigurationFiles.Options.DynamicProxyConfigurationFiles, ConfigurationFiles.Options.DynamicProxyConfigurationResources, ConfigurationFile.DYNAMIC_PROXY.getFileName()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/ProxyRegistry.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/ProxyRegistry.java index 82794c408f1..086bb379b18 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/ProxyRegistry.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/ProxyRegistry.java @@ -59,7 +59,7 @@ public void accept(ConditionalElement> proxies) { public Class createProxyClassForSerialization(ConditionalElement> proxies) { Class[] interfaces = checkIfInterfacesAreValid(proxies); if (interfaces != null) { - return dynamicProxySupport.createProxyClassForSerialization(interfaces); + return dynamicProxySupport.getProxyClassHosted(interfaces); } return null; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java index 32a4813ca80..2e9eecc2a00 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java @@ -122,14 +122,23 @@ public void duringSetup(DuringSetupAccess a) { SerializationDenyRegistry serializationDenyRegistry = new SerializationDenyRegistry(typeResolver); serializationBuilder = new SerializationBuilder(serializationDenyRegistry, access, typeResolver, ImageSingletons.lookup(ProxyRegistry.class)); ImageSingletons.add(RuntimeSerializationSupport.class, serializationBuilder); - SerializationConfigurationParser denyCollectorParser = new SerializationConfigurationParser(serializationDenyRegistry, ConfigurationFiles.Options.StrictConfiguration.getValue()); + + Boolean strictConfiguration = ConfigurationFiles.Options.StrictConfiguration.getValue(); + + SerializationConfigurationParser parser = SerializationConfigurationParser.create(true, serializationBuilder, + strictConfiguration); + loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurationsFromCombinedFile(parser, imageClassLoader, "serialization"); + + SerializationConfigurationParser denyCollectorParser = SerializationConfigurationParser.create(false, serializationDenyRegistry, + strictConfiguration); ConfigurationParserUtils.parseAndRegisterConfigurations(denyCollectorParser, imageClassLoader, "serialization", ConfigurationFiles.Options.SerializationDenyConfigurationFiles, ConfigurationFiles.Options.SerializationDenyConfigurationResources, ConfigurationFile.SERIALIZATION_DENY.getFileName()); - SerializationConfigurationParser parser = new SerializationConfigurationParser(serializationBuilder, ConfigurationFiles.Options.StrictConfiguration.getValue()); - loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurations(parser, imageClassLoader, "serialization", + SerializationConfigurationParser legacyParser = SerializationConfigurationParser.create(false, serializationBuilder, + strictConfiguration); + loadedConfigurations += ConfigurationParserUtils.parseAndRegisterConfigurations(legacyParser, imageClassLoader, "serialization", ConfigurationFiles.Options.SerializationConfigurationFiles, ConfigurationFiles.Options.SerializationConfigurationResources, ConfigurationFile.SERIALIZATION.getFileName());