Java8 incompatibility due to use of older version of ASM

I have a number of tests that are failing only when executed by gradle. These tests run normally when executed from the IDE (using a gradle generated idea project). I have upgraded to 2.5 to confirm the bug is still present.

The stacktrace is as follows

16:07:55.295 [DEBUG] [TestEventLogger] ci-suite > Gradle test > com.mycompany.MyTest.someTest FAILED
16:07:55.295 [DEBUG] [TestEventLogger]     java.lang.ArrayIndexOutOfBoundsException: 1
16:07:55.296 [DEBUG] [TestEventLogger]         at com.mycompany.SomeCode$GoesHere.byName(Criteria.java:34)
16:07:55.296 [DEBUG] [TestEventLogger]         at com.mycompany.MyTest.someTest(MyTest.java:354)
16:07:55.296 [DEBUG] [TestEventLogger]         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
16:07:55.297 [DEBUG] [TestEventLogger]         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
16:07:55.297 [DEBUG] [TestEventLogger]         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
16:07:55.297 [DEBUG] [TestEventLogger]         at java.lang.reflect.Method.invoke(Method.java:497)
16:07:55.297 [DEBUG] [TestEventLogger]         at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
16:07:55.298 [DEBUG] [TestEventLogger]         at org.testng.internal.Invoker.invokeMethod(Invoker.java:639)
16:07:55.298 [DEBUG] [TestEventLogger]         at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:821)
16:07:55.298 [DEBUG] [TestEventLogger]         at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1131)
16:07:55.299 [DEBUG] [TestEventLogger]         at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:124)
16:07:55.299 [DEBUG] [TestEventLogger]         at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108)
16:07:55.299 [DEBUG] [TestEventLogger]         at org.testng.TestRunner.privateRun(TestRunner.java:773)
16:07:55.300 [DEBUG] [TestEventLogger]         at org.testng.TestRunner.run(TestRunner.java:623)
16:07:55.300 [DEBUG] [TestEventLogger]         at org.testng.SuiteRunner.runTest(SuiteRunner.java:357)
16:07:55.300 [DEBUG] [TestEventLogger]         at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:352)
16:07:55.300 [DEBUG] [TestEventLogger]         at org.testng.SuiteRunner.privateRun(SuiteRunner.java:310)
16:07:55.301 [DEBUG] [TestEventLogger]         at org.testng.SuiteRunner.run(SuiteRunner.java:259)
16:07:55.319 [DEBUG] [TestEventLogger]         at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
16:07:55.320 [DEBUG] [TestEventLogger]         at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
16:07:55.411 [DEBUG] [TestEventLogger]         at org.testng.TestNG.runSuitesSequentially(TestNG.java:1185)
16:07:55.412 [DEBUG] [TestEventLogger]         at org.testng.TestNG.runSuitesLocally(TestNG.java:1110)
16:07:55.414 [DEBUG] [TestEventLogger]         at org.testng.TestNG.run(TestNG.java:1018)

The line that throws the exception is

    static Consumer<Foo> byName(String name) {
        return it -> it.setName(name);
    }

i.e it’s just some method that returns a java8 Consumer which calls some setter. Clearly there is no array in sight here.

Google indicates that this sort of exception is commonly associated with older versions of ASM (e.g. http://stackoverflow.com/questions/22917462/java-8-lambda-expression-within-rest-service-not-working) which has led to a whole bunch of libraries upgrading to use ASM 5.0.3. I have completed that upgrade cycle in my build and confirmed that nothing older than asm-5.0.3 is appearing on my classpath.

However I see

16:07:14.096 [DEBUG] [org.gradle.process.internal.DefaultWorkerProcessFactory] Using implementation classpath ...... v long list of jars here ......  file:/C:/apps/libs/gradle-2.5/lib/reflectasm-1.07-shaded.jar, ..... more jars

The reflectasm github project recently merged this PR - https://github.com/EsotericSoftware/reflectasm/pull/33 - which upgrades it to ASM 5.0.3 “for full java8 compatibility”

Therefore I suspect you’re going to have to upgrade to at least reflectasm 1.10.1 before you can declare complete compatibility with java8.

This is a critical bug IMO and should be fixed ASAP otherwise gradle is currently broken for some unknown subset of java8 projects.

Further investigation suggests this is pulled in by the use of kryo 2.20 in gradle-messaging

Unfortunately kryo only updates to the newer reflectasm in 3.0.1 (https://github.com/EsotericSoftware/kryo/blob/master/CHANGES.md) and the 3.x release is not compatible with 2.x at either the binary or source level.

I fail to see how kryo would be involved here, hence how Gradle could interfere with the code compiled by javac. Do you happen to use a code coverage tool? In that case, it might be possible that the bytecode is instrumented, and I would put this as the first candidate for the error.

1 Like

good call, I didn’t spot that dependency in there. It seems the version of jacoco I was using was not completely java8 compatible & moving to 0.7.5 solves the problem.