From 5fce8057802e81e339d3b1b954430487b2c4a5ac Mon Sep 17 00:00:00 2001 From: Vojin Jovanovic Date: Wed, 21 May 2025 13:05:33 +0200 Subject: [PATCH] Enable serialization in -H:Preserve --- .../hosted/image/PreserveOptionsSupport.java | 4 ++- .../hosted/reflect/ReflectionDataBuilder.java | 26 +++++++++++++------ .../serialize/SerializationFeature.java | 3 +++ .../com/oracle/svm/util/ReflectionUtil.java | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/PreserveOptionsSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/PreserveOptionsSupport.java index 1e0eb80398b2..7dd901d04df6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/PreserveOptionsSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/PreserveOptionsSupport.java @@ -44,6 +44,7 @@ import org.graalvm.nativeimage.impl.RuntimeJNIAccessSupport; import org.graalvm.nativeimage.impl.RuntimeProxyCreationSupport; import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; +import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.svm.core.SubstrateOptions; @@ -152,6 +153,7 @@ public static void registerPreservedClasses(NativeImageClassLoaderSupport classL final RuntimeReflectionSupport reflection = ImageSingletons.lookup(RuntimeReflectionSupport.class); final RuntimeJNIAccessSupport jni = ImageSingletons.lookup(RuntimeJNIAccessSupport.class); final RuntimeProxyCreationSupport proxy = ImageSingletons.lookup(RuntimeProxyCreationSupport.class); + final RuntimeSerializationSupport serialization = RuntimeSerializationSupport.singleton(); final ConfigurationCondition always = ConfigurationCondition.alwaysTrue(); /* @@ -207,7 +209,7 @@ public static void registerPreservedClasses(NativeImageClassLoaderSupport classL classesToPreserve.reversed().forEach(c -> { reflection.registerAllFields(always, c); reflection.registerAllMethodsQuery(always, false, c); - // RuntimeSerialization.register(c); + serialization.register(always, c); }); for (String className : classLoaderSupport.getClassNamesToPreserve()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java index ec098837c07a..4a943e83ab35 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java @@ -554,15 +554,24 @@ public void registerAllDeclaredFields(ConfigurationCondition condition, Class registerAllDeclaredFieldsQuery(condition, false, clazz); } + private record AllDeclaredFieldsQuery(ConfigurationCondition condition, boolean queriedOnly, Class clazz) { + } + + private Set existingAllDeclaredFieldsQuery = ConcurrentHashMap.newKeySet(); + public void registerAllDeclaredFieldsQuery(ConfigurationCondition condition, boolean queriedOnly, Class clazz) { - runConditionalInAnalysisTask(condition, (cnd) -> { - setQueryFlag(clazz, ALL_DECLARED_FIELDS_FLAG); - try { - registerFields(cnd, queriedOnly, clazz.getDeclaredFields()); - } catch (LinkageError e) { - registerLinkageError(clazz, e, fieldLookupExceptions); - } - }); + final var query = new AllDeclaredFieldsQuery(condition, queriedOnly, clazz); + if (!existingAllDeclaredFieldsQuery.contains(query)) { + runConditionalInAnalysisTask(condition, (cnd) -> { + setQueryFlag(clazz, ALL_DECLARED_FIELDS_FLAG); + try { + registerFields(cnd, queriedOnly, clazz.getDeclaredFields()); + } catch (LinkageError e) { + registerLinkageError(clazz, e, fieldLookupExceptions); + } + }); + existingAllDeclaredFieldsQuery.add(query); + } } private void registerFields(ConfigurationCondition cnd, boolean queriedOnly, Field[] reflectFields) { @@ -1137,6 +1146,7 @@ protected void afterAnalysis() { if (!throwMissingRegistrationErrors()) { pendingRecordClasses = null; } + existingAllDeclaredFieldsQuery = null; } @Override 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 e9959b5b76e7..633a3353b579 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 @@ -604,6 +604,9 @@ private Constructor newConstructorForSerialization(Class serializationTarg } else { constructorToCall = customConstructorToCall; } + if (constructorToCall == null) { + return null; + } ConstructorAccessor acc = getConstructorAccessor(serializationTargetClass, constructorToCall); JavaLangReflectAccess langReflectAccess = ReflectionUtil.readField(ReflectionFactory.class, "langReflectAccess", ReflectionFactory.getReflectionFactory()); Method newConstructorWithAccessor = ReflectionUtil.lookupMethod(JavaLangReflectAccess.class, "newConstructorWithAccessor", Constructor.class, ConstructorAccessor.class); diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java index 7d216e2ec700..5be387ad46a6 100644 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java @@ -123,7 +123,7 @@ public static Constructor lookupConstructor(boolean optional, Class de openModule(declaringClass); result.setAccessible(true); return result; - } catch (ReflectiveOperationException | NoClassDefFoundError ex) { + } catch (ReflectiveOperationException | LinkageError ex) { if (optional) { return null; }