Skip to content

Commit

Permalink
[GR-47365] Throw missing registration errors for proxy classes
Browse files Browse the repository at this point in the history
PullRequest: graal/15056
  • Loading branch information
loicottet committed Aug 1, 2023
2 parents 6263e64 + 57101f0 commit 4bd466c
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 14 deletions.
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This changelog summarizes major changes to GraalVM Native Image.
* (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.
* (GR-46392) Add `--parallelism` option to control how many threads are used by the build process.
* (GR-46392) Add build resources section to the build output that shows the memory and thread limits of the build process.
* (GR-47365) Throw `MissingReflectionRegistrationError` when attempting to create a proxy class without having it registered at build-time, instead of a `VMError`.

## Version 23.0.0
* (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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
Expand Down Expand Up @@ -110,10 +112,28 @@ public static void forBulkQuery(Class<?> declaringClass, String methodName) {
report(exception);
}

public static void forProxy(Class<?>... interfaces) {
MissingReflectionRegistrationError exception = new MissingReflectionRegistrationError(errorMessage("access the proxy class inheriting",
Arrays.toString(Arrays.stream(interfaces).map(Class::getTypeName).toArray()),
"The order of interfaces used to create proxies matters.", "dynamic-proxy"),
Proxy.class, null, null, interfaces);
report(exception);
/*
* If report doesn't throw, we throw the exception anyway since this is a Native
* Image-specific error that is unrecoverable in any case.
*/
throw exception;
}

private static String errorMessage(String failedAction, String elementDescriptor) {
return errorMessage(failedAction, elementDescriptor, null, "reflection");
}

private static String errorMessage(String failedAction, String elementDescriptor, String note, String helpLink) {
return "The program tried to reflectively " + failedAction + " " + elementDescriptor +
" without it being registered for runtime reflection. Add it to the reflection metadata to solve this problem. " +
"See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.";
" without it being registered for runtime reflection. Add " + elementDescriptor + " to the " + helpLink + " metadata to solve this problem. " +
(note != null ? "Note: " + note + " " : "") +
"See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#" + helpLink + " for help.";
}

private static final int CONTEXT_LINES = 4;
Expand Down Expand Up @@ -213,6 +233,7 @@ private static void printLine(StringBuilder sb, Object object) {
"newInstance"),
Method.class.getTypeName(), Set.of("invoke"),
Constructor.class.getTypeName(), Set.of("newInstance"),
Proxy.class.getTypeName(), Set.of("getProxyClass", "newProxyInstance"),
"java.lang.reflect.ReflectAccess", Set.of("newInstance"),
"jdk.internal.access.JavaLangAccess", Set.of("getDeclaredPublicMethods"),
"sun.misc.Unsafe", Set.of("allocateInstance"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,17 @@
import org.graalvm.nativeimage.hosted.RuntimeReflection;

import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.configure.ConfigurationFiles;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.PredefinedClassesSupport;
import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry;
import com.oracle.svm.core.option.SubstrateOptionsParser;
import com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils;
import com.oracle.svm.core.util.ImageHeapMap;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.ClassUtil;
import com.oracle.svm.util.LogUtils;
import com.oracle.svm.util.ReflectionUtil;

public class DynamicProxySupport implements DynamicProxyRegistry {

private static final String proxyConfigFilesOption = SubstrateOptionsParser.commandArgument(ConfigurationFiles.Options.DynamicProxyConfigurationFiles, "<comma-separated-config-files>");
private static final String proxyConfigResourcesOption = SubstrateOptionsParser.commandArgument(ConfigurationFiles.Options.DynamicProxyConfigurationResources,
"<comma-separated-config-resources>");

public static final Pattern PROXY_CLASS_NAME_PATTERN = Pattern.compile(".*\\$Proxy[0-9]+");

static final class ProxyCacheKey {
Expand Down Expand Up @@ -179,11 +173,7 @@ public Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) {
ProxyCacheKey key = new ProxyCacheKey(interfaces);
Object clazzOrError = proxyCache.get(key);
if (clazzOrError == null) {
throw VMError.unsupportedFeature("Proxy class defined by the following sequence of interfaces " + Arrays.toString(interfaces) + " not found. " +
"Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. " +
"To define proxy classes use " + proxyConfigFilesOption + " and " + proxyConfigResourcesOption + " options. " +
"Note: The order of interfaces used to create proxies matters. " +
"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.");
MissingReflectionRegistrationUtils.forProxy(interfaces);
}
if (clazzOrError instanceof Throwable) {
throw new GraalError((Throwable) clazzOrError);
Expand Down

0 comments on commit 4bd466c

Please sign in to comment.