diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java index 1a82086747df..9a77f30d2d05 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java @@ -104,6 +104,7 @@ static ConfigurationType copyAndMerge(ConfigurationType type, ConfigurationType private ConfigurationMemberAccessibility allPublicMethodsAccess = ConfigurationMemberAccessibility.NONE; private ConfigurationMemberAccessibility allDeclaredConstructorsAccess = ConfigurationMemberAccessibility.NONE; private ConfigurationMemberAccessibility allPublicConstructorsAccess = ConfigurationMemberAccessibility.NONE; + private boolean serializable = false; public ConfigurationType(UnresolvedConfigurationCondition condition, ConfigurationTypeDescriptor typeDescriptor, boolean includeAllElements) { this.condition = condition; @@ -284,6 +285,7 @@ private void setFlagsFromOther(ConfigurationType other, BiPredicate entry, ConfigurationSet configurationSe String function = (String) entry.get("function"); List args = (List) entry.get("args"); SerializationConfiguration serializationConfiguration = configurationSet.getSerializationConfiguration(); + TypeConfiguration reflectionConfiguration = configurationSet.getReflectionConfiguration(); if ("ObjectStreamClass.".equals(function) || "ObjectInputStream.readClassDescriptor".equals(function)) { expectSize(args, 1); @@ -68,7 +71,7 @@ void processEntry(EconomicMap entry, ConfigurationSet configurationSe if (className.contains(LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING)) { serializationConfiguration.registerLambdaCapturingClass(condition, className); } else { - serializationConfiguration.register(condition, className); + reflectionConfiguration.get(condition, new NamedConfigurationTypeDescriptor(className)).setSerializable(); } } else if ("SerializedLambda.readResolve".equals(function)) { expectSize(args, 1); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyReflectionConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyReflectionConfigurationParser.java index c919fa61018d..eabaabb5bd9e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyReflectionConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyReflectionConfigurationParser.java @@ -42,7 +42,7 @@ final class LegacyReflectionConfigurationParser extends ReflectionConfigur "allDeclaredMethods", "allPublicMethods", "allDeclaredFields", "allPublicFields", "allDeclaredClasses", "allRecordComponents", "allPermittedSubclasses", "allNestMembers", "allSigners", "allPublicClasses", "methods", "queriedMethods", "fields", CONDITIONAL_KEY, - "queryAllDeclaredConstructors", "queryAllPublicConstructors", "queryAllDeclaredMethods", "queryAllPublicMethods", "unsafeAllocated"); + "queryAllDeclaredConstructors", "queryAllPublicConstructors", "queryAllDeclaredMethods", "queryAllPublicMethods", "unsafeAllocated", "serializable"); private final boolean treatAllNameEntriesAsType; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParserDelegate.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParserDelegate.java index 78cac38bd80c..4328af2c8e8b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParserDelegate.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParserDelegate.java @@ -68,6 +68,8 @@ public interface ReflectionConfigurationParserDelegate { boolean registerAllConstructors(C condition, boolean queriedOnly, T type); + void registerAsSerializable(C condition, T clazz); + String getTypeName(T type); String getSimpleName(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 ae1f30e3e23e..54483d3cbd8f 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 @@ -39,7 +39,7 @@ 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"); + "methods", "fields", "unsafeAllocated", "serializable"); private final String combinedFileKey; @@ -113,6 +113,8 @@ protected void parseClass(EconomicMap data) { registerIfNotDefault(data, false, clazz, "allDeclaredFields", () -> delegate.registerDeclaredFields(condition, false, clazz)); registerIfNotDefault(data, false, clazz, "allPublicFields", () -> delegate.registerPublicFields(condition, false, clazz)); + registerIfNotDefault(data, false, clazz, "serializable", () -> delegate.registerAsSerializable(condition, clazz)); + MapCursor cursor = data.getEntries(); while (cursor.advance()) { String name = cursor.getKey(); 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 1d04ab086955..c1af19efa6ff 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 @@ -57,13 +57,15 @@ import com.oracle.svm.hosted.reflect.proxy.ProxyRegistry; import jdk.graal.compiler.util.json.JsonParserException; +import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; public final class ConfigurationParserUtils { public static ReflectionConfigurationParser> create(String combinedFileKey, boolean strictMetadata, - ConfigurationConditionResolver conditionResolver, ReflectionRegistry registry, ProxyRegistry proxyRegistry, ImageClassLoader imageClassLoader) { + ConfigurationConditionResolver conditionResolver, ReflectionRegistry registry, ProxyRegistry proxyRegistry, + RuntimeSerializationSupport serializationSupport, ImageClassLoader imageClassLoader) { return ReflectionConfigurationParser.create(combinedFileKey, strictMetadata, conditionResolver, - RegistryAdapter.create(registry, proxyRegistry, imageClassLoader), + RegistryAdapter.create(registry, proxyRegistry, serializationSupport, imageClassLoader), ConfigurationFiles.Options.StrictConfiguration.getValue(), ConfigurationFiles.Options.WarnAboutMissingReflectionOrJNIMetadataElements.getValue(), TreatAllNameEntriesAsType.getValue()); } 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 c2b13640d2f6..d368d87735fc 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 @@ -27,24 +27,27 @@ import java.lang.reflect.Proxy; import java.util.Arrays; -import com.oracle.svm.hosted.reflect.ReflectionDataBuilder; import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; +import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.configure.ConfigurationTypeDescriptor; import com.oracle.svm.core.configure.NamedConfigurationTypeDescriptor; import com.oracle.svm.hosted.ImageClassLoader; +import com.oracle.svm.hosted.reflect.ReflectionDataBuilder; import com.oracle.svm.hosted.reflect.proxy.ProxyRegistry; public class ReflectionRegistryAdapter extends RegistryAdapter { private final RuntimeReflectionSupport reflectionSupport; private final ProxyRegistry proxyRegistry; + private final RuntimeSerializationSupport serializationSupport; - ReflectionRegistryAdapter(RuntimeReflectionSupport reflectionSupport, ProxyRegistry proxyRegistry, ImageClassLoader classLoader) { + ReflectionRegistryAdapter(RuntimeReflectionSupport reflectionSupport, ProxyRegistry proxyRegistry, RuntimeSerializationSupport serializationSupport, ImageClassLoader classLoader) { super(reflectionSupport, classLoader); this.reflectionSupport = reflectionSupport; this.proxyRegistry = proxyRegistry; + this.serializationSupport = serializationSupport; } @Override @@ -126,4 +129,9 @@ public void registerPublicConstructors(ConfigurationCondition condition, boolean public void registerDeclaredConstructors(ConfigurationCondition condition, boolean queriedOnly, Class type) { reflectionSupport.registerAllDeclaredConstructorsQuery(condition, queriedOnly, type); } + + @Override + public void registerAsSerializable(ConfigurationCondition condition, Class clazz) { + serializationSupport.register(condition, clazz); + } } 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 72ac0f18d279..975d6c0cf123 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 @@ -35,6 +35,7 @@ import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.ReflectionRegistry; import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; +import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.configure.ConfigurationTypeDescriptor; @@ -51,9 +52,9 @@ public class RegistryAdapter implements ReflectionConfigurationParserDelegate serializationSupport, ImageClassLoader classLoader) { if (registry instanceof RuntimeReflectionSupport) { - return new ReflectionRegistryAdapter((RuntimeReflectionSupport) registry, proxyRegistry, classLoader); + return new ReflectionRegistryAdapter((RuntimeReflectionSupport) registry, proxyRegistry, serializationSupport, classLoader); } else { return new RegistryAdapter(registry, classLoader); } @@ -277,6 +278,10 @@ private void registerExecutable(ConfigurationCondition condition, boolean querie registry.register(condition, queriedOnly, executable); } + @Override + public void registerAsSerializable(ConfigurationCondition condition, Class clazz) { + } + @Override public String getTypeName(Class type) { return type.getTypeName(); 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 287b6692e8b5..70c41d3f2534 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 @@ -207,9 +207,10 @@ public void afterRegistration(AfterRegistrationAccess arg) { ConfigurationConditionResolver conditionResolver = new NativeImageConditionResolver(access.getImageClassLoader(), ClassInitializationSupport.singleton()); - ReflectionConfigurationParser> parser = ConfigurationParserUtils.create(JNI_KEY, true, conditionResolver, runtimeSupport, null, access.getImageClassLoader()); + ReflectionConfigurationParser> parser = ConfigurationParserUtils.create(JNI_KEY, true, conditionResolver, runtimeSupport, null, null, + access.getImageClassLoader()); loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurationsFromCombinedFile(parser, access.getImageClassLoader(), "JNI"); - ReflectionConfigurationParser> legacyParser = ConfigurationParserUtils.create(null, false, conditionResolver, runtimeSupport, null, + ReflectionConfigurationParser> legacyParser = ConfigurationParserUtils.create(null, false, conditionResolver, runtimeSupport, null, null, access.getImageClassLoader()); loadedConfigurations += ConfigurationParserUtils.parseAndRegisterConfigurations(legacyParser, access.getImageClassLoader(), "JNI", ConfigurationFiles.Options.JNIConfigurationFiles, ConfigurationFiles.Options.JNIConfigurationResources, ConfigurationFile.JNI.getFileName()); 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 c4bd43670b13..0d788afc7dad 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 @@ -46,6 +46,7 @@ import org.graalvm.nativeimage.impl.AnnotationExtractor; import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; +import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; @@ -292,11 +293,12 @@ public void duringSetup(DuringSetupAccess a) { var conditionResolver = new NativeImageConditionResolver(access.getImageClassLoader(), ClassInitializationSupport.singleton()); reflectionData.duringSetup(access.getMetaAccess(), aUniverse); ProxyRegistry proxyRegistry = ImageSingletons.lookup(ProxyRegistry.class); + RuntimeSerializationSupport serializationSupport = RuntimeSerializationSupport.singleton(); ReflectionConfigurationParser> parser = ConfigurationParserUtils.create(REFLECTION_KEY, true, conditionResolver, reflectionData, proxyRegistry, - access.getImageClassLoader()); + serializationSupport, access.getImageClassLoader()); loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurationsFromCombinedFile(parser, access.getImageClassLoader(), "reflection"); ReflectionConfigurationParser> legacyParser = ConfigurationParserUtils.create(null, false, conditionResolver, reflectionData, proxyRegistry, - access.getImageClassLoader()); + serializationSupport, access.getImageClassLoader()); loadedConfigurations += ConfigurationParserUtils.parseAndRegisterConfigurations(legacyParser, access.getImageClassLoader(), "reflection", ConfigurationFiles.Options.ReflectionConfigurationFiles, ConfigurationFiles.Options.ReflectionConfigurationResources, ConfigurationFile.REFLECTION.getFileName()); 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 b8367d0ffe59..7085d3230159 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 @@ -39,6 +39,7 @@ import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry; import com.oracle.svm.core.reflect.proxy.DynamicProxySupport; import com.oracle.svm.hosted.FallbackFeature; +import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.ImageClassLoader; @@ -50,18 +51,25 @@ public final class DynamicProxyFeature implements InternalFeature { private int loadedConfigurations; private Field proxyCacheField; + private ProxyRegistry proxyRegistry; @Override - public void duringSetup(DuringSetupAccess a) { - DuringSetupAccessImpl access = (DuringSetupAccessImpl) a; - + public void afterRegistration(AfterRegistrationAccess a) { + FeatureImpl.AfterRegistrationAccessImpl access = (FeatureImpl.AfterRegistrationAccessImpl) a; ImageClassLoader imageClassLoader = access.getImageClassLoader(); - ConfigurationConditionResolver conditionResolver = new NativeImageConditionResolver(imageClassLoader, ClassInitializationSupport.singleton()); DynamicProxySupport dynamicProxySupport = new DynamicProxySupport(); ImageSingletons.add(DynamicProxyRegistry.class, dynamicProxySupport); ImageSingletons.add(RuntimeProxyCreationSupport.class, dynamicProxySupport); - ProxyRegistry proxyRegistry = new ProxyRegistry(dynamicProxySupport, imageClassLoader); + proxyRegistry = new ProxyRegistry(dynamicProxySupport, imageClassLoader); ImageSingletons.add(ProxyRegistry.class, proxyRegistry); + } + + @Override + public void duringSetup(DuringSetupAccess a) { + DuringSetupAccessImpl access = (DuringSetupAccessImpl) a; + ImageClassLoader imageClassLoader = access.getImageClassLoader(); + ConfigurationConditionResolver conditionResolver = new NativeImageConditionResolver(imageClassLoader, ClassInitializationSupport.singleton()); + ProxyConfigurationParser parser = new ProxyConfigurationParser<>(conditionResolver, ConfigurationFiles.Options.StrictConfiguration.getValue(), proxyRegistry); loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurations(parser, imageClassLoader, "dynamic proxy", ConfigurationFiles.Options.DynamicProxyConfigurationFiles, ConfigurationFiles.Options.DynamicProxyConfigurationResources, 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 c878db324403..618774e2463c 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 @@ -103,6 +103,7 @@ public class SerializationFeature implements InternalFeature { final Set> capturingClasses = ConcurrentHashMap.newKeySet(); private SerializationBuilder serializationBuilder; + private SerializationDenyRegistry serializationDenyRegistry; private int loadedConfigurations; @Override @@ -111,15 +112,20 @@ public List> getRequiredFeatures() { } @Override - public void duringSetup(DuringSetupAccess a) { - FeatureImpl.DuringSetupAccessImpl access = (FeatureImpl.DuringSetupAccessImpl) a; + public void afterRegistration(AfterRegistrationAccess a) { + FeatureImpl.AfterRegistrationAccessImpl access = (FeatureImpl.AfterRegistrationAccessImpl) a; ImageClassLoader imageClassLoader = access.getImageClassLoader(); - ConfigurationConditionResolver conditionResolver = new NativeImageConditionResolver(imageClassLoader, ClassInitializationSupport.singleton()); ConfigurationTypeResolver typeResolver = new ConfigurationTypeResolver("serialization configuration", imageClassLoader); - SerializationDenyRegistry serializationDenyRegistry = new SerializationDenyRegistry(typeResolver); + serializationDenyRegistry = new SerializationDenyRegistry(typeResolver); serializationBuilder = new SerializationBuilder(serializationDenyRegistry, access, typeResolver, ImageSingletons.lookup(ProxyRegistry.class)); ImageSingletons.add(RuntimeSerializationSupport.class, serializationBuilder); + } + @Override + public void duringSetup(DuringSetupAccess a) { + FeatureImpl.DuringSetupAccessImpl access = (FeatureImpl.DuringSetupAccessImpl) a; + ImageClassLoader imageClassLoader = access.getImageClassLoader(); + ConfigurationConditionResolver conditionResolver = new NativeImageConditionResolver(imageClassLoader, ClassInitializationSupport.singleton()); Boolean strictConfiguration = ConfigurationFiles.Options.StrictConfiguration.getValue(); SerializationConfigurationParser parser = SerializationConfigurationParser.create(true, conditionResolver, serializationBuilder, @@ -270,7 +276,7 @@ final class SerializationBuilder extends ConditionalConfigurationRegistry implem final SerializationSupport serializationSupport; private final SerializationDenyRegistry denyRegistry; private final ConfigurationTypeResolver typeResolver; - private final FeatureImpl.DuringSetupAccessImpl access; + private final FeatureImpl.AfterRegistrationAccessImpl access; private final Method disableSerialConstructorChecks; private final Method superHasAccessibleConstructor; private final Method packageEquals; @@ -278,7 +284,7 @@ final class SerializationBuilder extends ConditionalConfigurationRegistry implem private final ProxyRegistry proxyRegistry; private List pendingConstructorRegistrations; - SerializationBuilder(SerializationDenyRegistry serializationDenyRegistry, FeatureImpl.DuringSetupAccessImpl access, ConfigurationTypeResolver typeResolver, ProxyRegistry proxyRegistry) { + SerializationBuilder(SerializationDenyRegistry serializationDenyRegistry, FeatureImpl.AfterRegistrationAccessImpl access, ConfigurationTypeResolver typeResolver, ProxyRegistry proxyRegistry) { this.access = access; Class classDataSlotClazz = access.findClassByName("java.io.ObjectStreamClass$ClassDataSlot"); this.descField = ReflectionUtil.lookupField(classDataSlotClazz, "desc");