running Groovy on JDK9

Jochen Theodorou blackdrag at gmx.org
Mon Apr 11 15:57:29 UTC 2016


On 10.04.2016 21:44, Alan Bateman wrote:
>
> On 10/04/2016 19:29, Jochen Theodorou wrote:
>> Hi all,
>>
>> today I had a few hours spare time and decided to invest that in
>> trying to make the Groovy build compile and run tests. I am not trying
>> to make a module on my own yet.
>>
>> for compilation to work my biggest problem was the direct usage of the
>> javac compiler set through gradle. Which is why I had to add
>>
>> options.forkOptions.jvmArgs << > options.forkOptions.jvmArgs <<
>> "-XaddExports:jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"
>>
>> for compileJava and
>>> groovyOptions.forkOptions.jvmArgs <<
>>> "-XaddExports:jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"
>>
>> for the groovy compiler (which uses internally he compiler set through
>> gradle)
> There have been a few issues with Gradle using JDK-internal APIs and so
> failing with JDK 9. Several issues have been fixed but maybe not all. I
> see the issue you see mentioned at the end of this thread:
>
> https://discuss.gradle.org/t/jdk9-jigsaw-build-problem/13054
>
> It would be good to check if there is any open bugs on this.

yeah, most people I would ask regarding this are away atm. I will do so 
later.

>> This error is caused by not using an URLClassloader anymore in JDK9...
>> I actually would like to know what the jdk9 way of doing this is
>> supposed to be. What I mean is that you had the not really supported
>> option of adding a jar to the highest loader and make its classes
>> available to lower loaders that way. Since that loader is no
>> URLClassloader anymore, this does not work any longer. But is there
>> any way to simulate that? Main usage was for example loading a sql
>> driver jar via Class.forName and the driver then registering itself in
>> the static constructor. How am I supposed to dynamically load database
>> drivers in JDK9 (even if they are not written for JDK9)? Would be one
>> question. But this extends to jars loaded at runtime, not through
>> command line options containing services in general actually.
> The only supported way in JDK 8 and older to extend the class path
> dynamically has been via Instrumentation API.
>
> So for URLClassLoader then were you using setAccessible to get at the
> protected addURL method?
>
> Can you describe the JDBC driver scenario a bit more? Can it be deployed
> as a service provider on the class path? Can it be registered via
> registerDriver?

well 
http://mrhaki.blogspot.de/2010/04/groovy-goodness-configuring-grape-to.html 
explains the scenario a little actually. It cannot be deployed on the 
class path, because that is all this scenario is about actually.

Can it be registered via registerDriver? That actually made me wonder 
why exactly we require the system loader here in the first place.

Part of the problem is DriverManager#getConnection, which is 
@CallerSensitive. So if I want to get a connection from an arbitrary 
loader, it has to be the same loader, that registered the driver, or a 
higher one. Here getConnection is done from library code, with a 
different loader. So it cannot work that way... sigh... not reliably.

Caller sensitive code does not really work for Groovy. Even if the call 
logic is realized through a MethodHandle (which would be ignored for the 
caller sensitive logic for the most part), the first call has to go 
through custom code of the runtime since we need runtime types. 
Subsequent calls use the callsite cache without the custom logic. That 
means the first call and the second call may make different loaders 
visible to getConnection. But even this is simplified. Depending on the 
context, another part of the library may appear in the call logic, and 
caller sensitive code will again see the groovy runtime class loader. I 
really really wish there would be a getConnection with additional 
parameter, which is not caller sensitive

But I wonder if it would work out, if we gave the option to set the 
loader to the same as the groovy runtime. There might be a way around 
then. Still requires to change all the existing scripts though.

And then of course there is the problem of XML parser being loaded 
dynamically. You get effects like this: 
https://bugs.openjdk.java.net/browse/JDK-8015099, and we too had already 
a load of fun with xerces being part of the distribution and the 
violation of classloading constraints. All that gets worse, if you want 
to "download" something like xpp3 from the web in your application and 
then use it directly.

>>> Caused by:
>>> java.lang.IllegalAccessException: access to public member failed:
>>> java.util.Comparator.reversed()Comparator/invokeSpecial, from
>>> java.util.Comparator/2 (module java.base)
>>> at
>>> java.lang.invoke.MemberName.makeAccessException(java.base at 9-ea/MemberName.java:870)
>>> at
>>> java.lang.invoke.MethodHandles$Lookup.checkAccess(java.base at 9-ea/MethodHandles.java:1642)
>>> at
>>> java.lang.invoke.MethodHandles$Lookup.checkMethod(java.base at 9-ea/MethodHandles.java:1582)
>>> at
>>> java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(java.base at 9-ea/MethodHandles.java:1731)
>>> at
>>> java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(java.base at 9-ea/MethodHandles.java:1725)
>>> at
>>> java.lang.invoke.MethodHandles$Lookup.unreflectSpecial(java.base at 9-ea/MethodHandles.java:1336)
>>> at
>>> org.codehaus.groovy.vmplugin.v7.Java7.getInvokeSpecialHandle(Java7.java:96)
>>>
>>> ... 7 more
>>
>> Can somebody explain me what the IllegalAccessException means? Why can
>> I not call unreflectSpecial here?
> Do you know how this Lookup is created? I'm curious how the lookup mode
> could be "2" (PRIVATE). Running with -esa might reveal more.

that would then be:

> org.codehaus.groovy.runtime.InterfaceConversionTest > testDefaultInterfaceMethodCallOnProxy FAILED
>     java.lang.AssertionError: java.util.Comparator/2
>         at java.lang.invoke.MethodHandles$Lookup.toString(java.base at 9-ea/MethodHandles.java:792)
>         at java.lang.String.valueOf(java.base at 9-ea/String.java:2806)
>         at java.lang.StringBuilder.append(java.base at 9-ea/StringBuilder.java:135)
>         at java.lang.invoke.MemberName.makeAccessException(java.base at 9-ea/MemberName.java:867)
>         at java.lang.invoke.MethodHandles$Lookup.checkAccess(java.base at 9-ea/MethodHandles.java:1642)
>         at java.lang.invoke.MethodHandles$Lookup.checkMethod(java.base at 9-ea/MethodHandles.java:1582)
>         at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(java.base at 9-ea/MethodHandles.java:1731)
>         at java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(java.base at 9-ea/MethodHandles.java:1725)
>         at java.lang.invoke.MethodHandles$Lookup.unreflectSpecial(java.base at 9-ea/MethodHandles.java:1336)
>         at org.codehaus.groovy.vmplugin.v7.Java7.getInvokeSpecialHandle(Java7.java:96)
>         at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:109)
>         at com.sun.proxy.$Proxy47.reversed(Unknown Source)
>         at java_util_Comparator$reversed$0.call(Unknown Source)
>         at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
>         at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
>         at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
>         at org.codehaus.groovy.runtime.InterfaceConversionTest.testDefaultInterfaceMethodCallOnProxy(InterfaceConversionTest.groovy:52)

but if I see the trace correctly, this is already due to a failed access 
check and just a secondary error, or wrong?

bye Jochen



More information about the jigsaw-dev mailing list