Skip to content

Commit 4bd466c

Browse files
committed
[GR-47365] Throw missing registration errors for proxy classes
PullRequest: graal/15056
2 parents 6263e64 + 57101f0 commit 4bd466c

File tree

3 files changed

+26
-14
lines changed

3 files changed

+26
-14
lines changed

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This changelog summarizes major changes to GraalVM Native Image.
1010
* (GR-39406) All classes can now be used at image build time, even when they are not explicitly configured as `--initialize-at-build-time`. Note, however, that still only classes configured as `--initialize-at-build-time` are allowed in the image heap.
1111
* (GR-46392) Add `--parallelism` option to control how many threads are used by the build process.
1212
* (GR-46392) Add build resources section to the build output that shows the memory and thread limits of the build process.
13+
* (GR-47365) Throw `MissingReflectionRegistrationError` when attempting to create a proxy class without having it registered at build-time, instead of a `VMError`.
1314

1415
## Version 23.0.0
1516
* (GR-40187) Report invalid use of SVM specific classes on image class- or module-path as error. As a temporary workaround, `-H:+AllowDeprecatedBuilderClassesOnImageClasspath` allows turning the error into a warning.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/MissingReflectionRegistrationUtils.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import java.lang.reflect.Executable;
3030
import java.lang.reflect.Field;
3131
import java.lang.reflect.Method;
32+
import java.lang.reflect.Proxy;
33+
import java.util.Arrays;
3234
import java.util.Map;
3335
import java.util.Set;
3436
import java.util.StringJoiner;
@@ -110,10 +112,28 @@ public static void forBulkQuery(Class<?> declaringClass, String methodName) {
110112
report(exception);
111113
}
112114

115+
public static void forProxy(Class<?>... interfaces) {
116+
MissingReflectionRegistrationError exception = new MissingReflectionRegistrationError(errorMessage("access the proxy class inheriting",
117+
Arrays.toString(Arrays.stream(interfaces).map(Class::getTypeName).toArray()),
118+
"The order of interfaces used to create proxies matters.", "dynamic-proxy"),
119+
Proxy.class, null, null, interfaces);
120+
report(exception);
121+
/*
122+
* If report doesn't throw, we throw the exception anyway since this is a Native
123+
* Image-specific error that is unrecoverable in any case.
124+
*/
125+
throw exception;
126+
}
127+
113128
private static String errorMessage(String failedAction, String elementDescriptor) {
129+
return errorMessage(failedAction, elementDescriptor, null, "reflection");
130+
}
131+
132+
private static String errorMessage(String failedAction, String elementDescriptor, String note, String helpLink) {
114133
return "The program tried to reflectively " + failedAction + " " + elementDescriptor +
115-
" without it being registered for runtime reflection. Add it to the reflection metadata to solve this problem. " +
116-
"See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.";
134+
" without it being registered for runtime reflection. Add " + elementDescriptor + " to the " + helpLink + " metadata to solve this problem. " +
135+
(note != null ? "Note: " + note + " " : "") +
136+
"See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#" + helpLink + " for help.";
117137
}
118138

119139
private static final int CONTEXT_LINES = 4;
@@ -213,6 +233,7 @@ private static void printLine(StringBuilder sb, Object object) {
213233
"newInstance"),
214234
Method.class.getTypeName(), Set.of("invoke"),
215235
Constructor.class.getTypeName(), Set.of("newInstance"),
236+
Proxy.class.getTypeName(), Set.of("getProxyClass", "newProxyInstance"),
216237
"java.lang.reflect.ReflectAccess", Set.of("newInstance"),
217238
"jdk.internal.access.JavaLangAccess", Set.of("getDeclaredPublicMethods"),
218239
"sun.misc.Unsafe", Set.of("allocateInstance"),

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/proxy/DynamicProxySupport.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,17 @@
3838
import org.graalvm.nativeimage.hosted.RuntimeReflection;
3939

4040
import com.oracle.svm.core.SubstrateUtil;
41-
import com.oracle.svm.core.configure.ConfigurationFiles;
4241
import com.oracle.svm.core.hub.DynamicHub;
4342
import com.oracle.svm.core.hub.PredefinedClassesSupport;
4443
import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry;
45-
import com.oracle.svm.core.option.SubstrateOptionsParser;
44+
import com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils;
4645
import com.oracle.svm.core.util.ImageHeapMap;
47-
import com.oracle.svm.core.util.VMError;
4846
import com.oracle.svm.util.ClassUtil;
4947
import com.oracle.svm.util.LogUtils;
5048
import com.oracle.svm.util.ReflectionUtil;
5149

5250
public class DynamicProxySupport implements DynamicProxyRegistry {
5351

54-
private static final String proxyConfigFilesOption = SubstrateOptionsParser.commandArgument(ConfigurationFiles.Options.DynamicProxyConfigurationFiles, "<comma-separated-config-files>");
55-
private static final String proxyConfigResourcesOption = SubstrateOptionsParser.commandArgument(ConfigurationFiles.Options.DynamicProxyConfigurationResources,
56-
"<comma-separated-config-resources>");
57-
5852
public static final Pattern PROXY_CLASS_NAME_PATTERN = Pattern.compile(".*\\$Proxy[0-9]+");
5953

6054
static final class ProxyCacheKey {
@@ -179,11 +173,7 @@ public Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) {
179173
ProxyCacheKey key = new ProxyCacheKey(interfaces);
180174
Object clazzOrError = proxyCache.get(key);
181175
if (clazzOrError == null) {
182-
throw VMError.unsupportedFeature("Proxy class defined by the following sequence of interfaces " + Arrays.toString(interfaces) + " not found. " +
183-
"Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. " +
184-
"To define proxy classes use " + proxyConfigFilesOption + " and " + proxyConfigResourcesOption + " options. " +
185-
"Note: The order of interfaces used to create proxies matters. " +
186-
"Proxies with the same set of interfaces specified in a different order do not resolve to the same class and thus require individual configuration entries.");
176+
MissingReflectionRegistrationUtils.forProxy(interfaces);
187177
}
188178
if (clazzOrError instanceof Throwable) {
189179
throw new GraalError((Throwable) clazzOrError);

0 commit comments

Comments
 (0)