Describe the bug
java.net.URL is not supported by GraalVM 20.2.0. Packaging a Quarkus native image is not possible and produces the following error:
Error: com.oracle.svm.hosted.substitute.DeletedElementException: Unsupported field java.net.URL.handlers is reachable
This seems to be a GraalVM limitation/decision as described in this issue .
Having URL data is common place. Is there any standard recommandation, workaround for Quarkus users?
Expected behavior
mvn package -Pnative
working with java.net.URL data
Actual behavior
mvn package -Pnative
not working with java.net.URL data
To Reproduce
This simple GitHub project reproduces this issue.
Configuration
# Add your application.properties here, if applicable.
quarkus.native.additional-build-args=--initialize-at-run-time=io.smallrye.graphql.cdi.validation.ValidationService
Environment (please complete the following information):
uname -a or ver: Darwin MBP-de-powerj 17.7.0 Darwin Kernel Version 17.7.0: Mon Aug 31 22:11:23 PDT 2020; root:xnu-4570.71.82.6~1/RELEASE_X86_64 x86_64java -version: openjdk version "11.0.7" 2020-04-14mvnw --version or gradlew --version): Maven home: /Users/powerj/.m2/wrapper/dists/apache-maven-3.6.3-bin/1iopthnavndlasol9gbrbg6bf2/apache-maven-3.6.3Additional context
java.net.URL is supported in JVM mode.
@jefrajames - not sure how to fix this one. Asking on Zulip.
Just to clarify, that error doesn't mean that you can't use URL, it means you can't use its handlers field.
The code will need to be refactored a bit to avoid using the handlers field. Hopefully that's possible?
It's not really clear what is causing the failure; we need to determine how that deleted field was considered reachable.
I looked into this a bit and what seems to be happening is that this appears to be triggering a potential bug in GraalVM. The call tree with that reproducer application (the one linked in this issue) is extremely large so it isn't easy to copy/paste here. I was however able to easily narrow this down to a simple application which when built as a native-image runs into this same issue. Here's the trivial Java code:
import javax.enterprise.util.AnnotationLiteral;
import java.net.URL;
public class URLProxyTest {
public static void main(final String[] args) throws Exception {
final AnnotationLiteral dummy = new AnnotationLiteral() {
};
final URL url = new URL("file://ignore");
System.out.println("Just here to keep this reachable " + dummy + " " + url.getPath());
}
}
and then (importantly) add java.net.URL as marked for reflection, using this reflection.json file:
[
{
"name" : "java.net.URL",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"allDeclaredClasses" : true,
"allPublicClasses" : true
}
]
Run the native-image generation command:
$GRAALVM_HOME/bin/native-image -classpath lib/cdi-api-1.0.jar:. URLProxyTest --no-server -H:+ReportExceptionStackTraces --no-fallback -H:ReflectionConfigurationFiles=reflection.json -H:+PrintAnalysisCallTree
(make sure you have cdi-api jar in the lib directory)
and you should see this same exception:
Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: com.oracle.svm.hosted.substitute.DeletedElementException: Unsupported field java.net.URL.handlers is reachable
To diagnose the issue, you can add the option --report-unsupported-elements-at-runtime. The unsupported element is then reported at run time when it is accessed the first time.
Detailed message:
Trace:
at parsing java.net.URL.setURLStreamHandlerFactory(URL.java:1213)
Call path from entry point to java.net.URL.setURLStreamHandlerFactory(URLStreamHandlerFactory):
at java.net.URL.setURLStreamHandlerFactory(URL.java:1205)
at com.oracle.svm.reflect.URL_setURLStreamHandlerFactory_8b4d2aa28c41f22bcb499464d696277608a31df4_24.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Method.java:566)
at javax.enterprise.util.AnnotationLiteral.invoke(AnnotationLiteral.java:333)
at javax.enterprise.util.AnnotationLiteral.toString(AnnotationLiteral.java:134)
at java.lang.String.valueOf(String.java:2951)
at java.io.PrintStream.print(PrintStream.java:745)
at java.io.PrintStream.println(PrintStream.java:882)
at com.oracle.svm.jni.functions.JNIFunctions.ExceptionDescribe(JNIFunctions.java:759)
at com.oracle.svm.core.code.IsolateEnterStub.JNIFunctions_ExceptionDescribe_b5412f7570bccae90b000bc37855f00408b2ad73(generated:0)
at com.oracle.graal.pointsto.constraints.UnsupportedFeatures.report(UnsupportedFeatures.java:126)
at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:750)
... 8 more
The AnnotationLiteral in combination with marking URL for reflective access seems to trigger this issue. The root cause is this (IMO, incomplete subsititution) https://github.com/oracle/graal/blob/master/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaNetSubstitutions.java#L59. It marks handlers field as deleted and then substitutes getURLStreamHandler (one of the methods that would have used this handlers) but it doesn't substitute or @Delete the setURLStreamHandlerFactory[1] which too uses this handlers field.
The reason why it shows up in the user's Quarkus application, I guess is because of this endpoint:
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("url")
public URL quarkusURL() throws MalformedURLException {
return new URL("http://quarkus.io");
}
The return type gets marked for reflection from what I remember.
[1] https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/net/URL.java#L1181
I've opened a PR in graal repo with a potential fix for this https://github.com/oracle/graal/pull/2889. Given how URL protocols need special handling in native image[1], AFAIK, URL.setURLStreamHandlerFactory isn't supported at runtime anyway. So I think that PR should be OK.
I've given that change a try both against my trivial reproducer as well as the linked Quarkus application reproducer. Both of them pass with this change.
[1] https://github.com/oracle/graal/blob/master/substratevm/URLProtocols.md
Most helpful comment
I've opened a PR in graal repo with a potential fix for this https://github.com/oracle/graal/pull/2889. Given how URL protocols need special handling in native image[1], AFAIK,
URL.setURLStreamHandlerFactoryisn't supported at runtime anyway. So I think that PR should be OK.I've given that change a try both against my trivial reproducer as well as the linked Quarkus application reproducer. Both of them pass with this change.
[1] https://github.com/oracle/graal/blob/master/substratevm/URLProtocols.md