2.4-rc-1 Regression: JNA path conflicts in test execution JVM

I have a project where the unit tests fail with Gradle 2.4.-rc-1 but pass with Gradle 2.3

I’m going to try to narrow it down further but the errors I’m getting suggest classloader issues. I get one java.lang.UnsatisfiedLinkError and several java.lang.NoClassDefFoundError

I should add that not all the unit test fail. 33 completed 11 failed.

Is it a project you can share or reduce to a reproducible example?

No, I can’t share the project. I will try to isolate as much info as I can. I may be able to make a reproducible example, but the current project is complex so that might not be easy.

Could you post a stacktrace? That might give us some hints to ask for more info.

The unsatisfied link error is JNA releated (I believe we’ve seen this happen before in other contexts)… Our project uses JNA and apparently so does Gradle.

java.lang.UnsatisfiedLinkError: Unable to load library ‘shell32’: com.sun.jna.Native.open(Ljava/lang/String;)J
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:166)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:239)
at com.sun.jna.Library$Handler.(Library.java:140)
at com.sun.jna.Native.loadLibrary(Native.java:393)
at com.sun.jna.platform.win32.Shell32.(Shell32.java:30)
at my.code.is.here.Utility.getUserAppDataDir(Utility.java:82)

All of the NoClassDefFoundErrors refer to the initialization of one particular class:
java.lang.NoClassDefFoundError: Could not initialize class my.code.here.SomeUtilityClass

The static initialization in that class happens to call the same code that is getting the UnsatisfiedLinkError, but that error seems to get lost as the cause.

So it boils down to a problem with JNA loading the native library for com.sun.jna.platform.win32.Shell32

I recalled hitting something like this in one of our gradle scripts before… This is what we had to do to work around it, perhaps this can be built-in to Gradle so it doesn’t mess up the environment for user code:

def savedProp = System.getProperty('jna.boot.library.path')
System.clearProperty('jna.boot.library.path')
// Call Java code that uses JNA
SomeClass.doSomethingThatNeedsJNA()
if (savedProp != null) {
    System.setProperty('jna.boot.library.path', savedProp)
}

Basically our code uses a different version of JNA and the wrong JNA native library is used because Gradle has specified jna.boot.library.path

Thanks, we had cases where we weren’t setting the jna.boot.library.path when we needed it. It looks like we might have gone too far the other way.

@ghhale

I created https://issues.gradle.org/browse/GRADLE-3288 to track.

Can you post how your Test task is configured? Are you setting jna.boot.library.path there?

How was the jna.boot.library.path being set in Gradle 2.3?

In this case we are never setting jna.boot.library.path.

The code snippet I posted above was from a different failure we encountered with an earlier Gradle version that seems to have the same root cause. In that case we were calling a class that triggered similar JNA access directly from the Gradle script. This case is different, as the JNA calls are happening within our Java test cases. So there is likely an earlier regression for the call from within the scrip case that I failed to report, sorry.

There is no special configuration of the test code. The Gradle ‘java’ plugin is applied, we have JUnit tests in /src/test/ some of them fail because somewhere along the line a static variable is initialized in one of the classes that gets loaded with a method that makes a JNA call.

@swpalmer Thanks for reporting this. I’ve been able to reproduce the problem and have a tentative fix. I’ll let you know when there is something you can try out.

Great to hear! … or read!

I was unable to use 2.3 (due to issues that are already resolved) so I am looking forward to jumping ahead to 2.4.

This should be fixed in 2.4-rc-2.