diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionSubstitutionSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionSubstitutionSupport.java index 7fff16c01154..d9c07a5da80b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionSubstitutionSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionSubstitutionSupport.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.reflect.target; +import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Field; @@ -52,4 +53,6 @@ static ReflectionSubstitutionSupport singleton() { * deleted. */ String getDeletionReason(Field field); + + boolean isCustomSerializationConstructor(Constructor reflectConstructor); } 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 513e0a887e9d..4417d017fe2c 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 @@ -40,6 +40,7 @@ import static com.oracle.svm.core.configure.ConfigurationFiles.Options.TreatAllTypeReachableConditionsAsTypeReached; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; @@ -87,6 +88,7 @@ import com.oracle.svm.core.hub.ClassForNameSupport; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.reflect.SubstrateAccessor; +import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ClassLoaderFeature; import com.oracle.svm.hosted.ConditionalConfigurationRegistry; @@ -1243,6 +1245,15 @@ public void registerHeapReflectionField(Field reflectField, ScanReason reason) { @Override public void registerHeapReflectionExecutable(Executable reflectExecutable, ScanReason reason) { + if (reflectExecutable instanceof Constructor reflectConstructor && ReflectionSubstitutionSupport.singleton().isCustomSerializationConstructor(reflectConstructor)) { + /* + * Constructors created by Constructor.newWithAccessor are indistinguishable from an + * equivalent constructor with a "correct" accessor, and as such could hide this + * constructor from reflection queries. We therefore exclude such constructors from the + * internal reflection metadata. + */ + return; + } AnalysisMethod analysisMethod = metaAccess.lookupJavaMethod(reflectExecutable); if (heapMethods.put(analysisMethod, reflectExecutable) == null) { if (sealed) { 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 13f195ecffe1..4fb9c890dda4 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 @@ -50,6 +50,7 @@ import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.configure.ConfigurationFile; @@ -270,6 +271,16 @@ private MethodPointer asMethodPointer(ResolvedJavaMethod method) { return new MethodPointer(aMethod); } + @Override + public boolean isCustomSerializationConstructor(Constructor reflectConstructor) { + if (ReflectionUtil.readField(Constructor.class, "constructorAccessor", reflectConstructor) instanceof SubstrateConstructorAccessor accessor) { + AnalysisMetaAccess analysisMetaAccess = analysisAccess.getMetaAccess(); + AnalysisMethod analysisConstructor = analysisMetaAccess.lookupJavaMethod(reflectConstructor); + return !accessor.getFactoryMethod().equals(FactoryMethodSupport.singleton().lookup(analysisMetaAccess, analysisConstructor, analysisConstructor.getDeclaringClass(), false)); + } + return false; + } + @Override public List> getRequiredFeatures() { return List.of(ClassForNameSupportFeature.class, DynamicProxyFeature.class);