Stuck with the ‘The Spock compiler plugin cannot execute because Spock 1.3-groovy-2.5 (3.0) is not compatible with Groovy 3.0 (4.0)’ error message? Find out what can be done about that (using Gradle and Maven).
Historical background
In the dim and distance past, when Groovy 1.x occasionally had some unpleasant (also runtime) backward compatibility issues, Spock had started to be built for the particular Groovy version individually. There were spock-0.5-groovy-1.6
, spock-0.5-groovy-1.7
and spock-0.5-groovy-1.8
for instance. To help people choose the right Spock and the Groovy versions, the runtime check was added to fail the compilation (at the AST transformation level) with the meaningful error message, in the situation Spock was compiled with the different Groovy version that is available at runtime, e.g.:
The Spock compiler plugin refused to run because Spock 1.3-groovy-2.5 is not compatible with Groovy 3.0.4. For more information,
see http://versioncheck.spockframework.org Spock location: .../spock-1.3-groovy-2.5.jar, Groovy location: .../groovy-3.0.4.jar
The error message is very clear. The reasoning behind this decision is good, and definitely it can help developers to detect problems with the dependencies. However, it can also greatly complicate development, especially taking into account rather rarely released new Spock versions.
If you are here, because of that error visible in your build, jump to the proper section to see what can be done about the problem.
Possible options
Spock 1.3 and Groovy 3.0
Unfortunately, you are out of luck. If you stuck with Spock 1.3 (e.g. migration to Spock 2.0 is blocked for some reasons) there are two (mediocre) options:
-
Switch to
Spock 1.3-SNAPSHOT
. The version compatibility check is relaxed in the SNAPSHOT builds of Spock 1.3. What’s more, there were multiple reports that (in the majority of cases - some corner cases remains) Spock1.3-groovy-2.5-SNAPSHOT
works fine with Groovy3.0.x
. -
There are no plans to release any new maintenance release of Spock 1.x. However, you can still create a new issue on GitHub and try to convince The Spock Developers to make 1.3.1 with that change :-).
Spock 2.0+ and Groovy 3.0
The Spock compiler plugin refused to run because Spock 2.0-groovy-2.5 is not compatible with Groovy 3.0.9.
For more information (including enforce mode), see http://docs.spockframework.org (section 'Known Issues').
Spock location: .../spock-2.0-groovy-2.5.jar
Groovy location: .../groovy-3.0.9.jar
That a trivial case. Just change Spock version from 2.0-groovy-2.5 to 2.0-groovy-3.0, and you are set.
Spock 2.0/2.1 and Groovy 4.0
The Spock compiler plugin refused to run because Spock 2.0-groovy-3.0 is not compatible with Groovy 4.0.0-beta-2.
For more information (including enforce mode), see http://docs.spockframework.org (section 'Known Issues').
Spock location: .../spock-2.0-groovy-3.0.jar
Groovy location: .../groovy-4.0.0-beta-2.jar
This variant assumes that you use Groovy 4 (SNAPSHOT, beta or a regular version) and Spock 2.0-groovy-3.0 (or 2.1). The error message is even more precise than in Spock 1.3, suggesting the ‘Known Issues’
section in the Spock documentation. We can leverage a brand-new system property spock.iKnowWhatImDoing.disableGroovyVersionCheck
, introduced right in Spock 2.0-M3, which allows to disable the version check - of course, at your own risk :-).
Btw, if you in a hurry (e.g. just to test something), it is also possible just to switch Spock to SNAPSHOT version which accepts (almost) any Groovy version.
Btw2, if you prefer to just jump into code, there is a code repository with working examples for Gradle and Maven.
Gradle
As Groovy 4 changed its groupId
from org.codehaus.groovy
to org.apache.groovy
it is required to add implicit exclusion for spock-2.0-groovy-3.0 transitive dependencies:
testImplementation("org.spockframework:spock-core:2.0-groovy-3.0") {
exclude group: 'org.codehaus.groovy'
}
to avoid conflicting Groovy versions on a classpath (it’s nice that Gradle is able to detect that!):
> Task :compileTestGroovy FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileTestGroovy'.
> Could not resolve all files for configuration ':testCompileClasspath'.
> Could not resolve org.apache.groovy:groovy:4.0.0-beta-2.
Required by:
project :
project : > org.apache.groovy:groovy:4.0.0-beta-2 > org.apache.groovy:groovy-bom:4.0.0-beta-2
> Module 'org.apache.groovy:groovy' has been rejected:
Cannot select module with conflict on capability 'org.codehaus.groovy:groovy:4.0.0-beta-2' also provided by [org.codehaus.groovy:groovy:3.0.8(compile)]
> Could not resolve org.codehaus.groovy:groovy:3.0.8.
Required by:
project : > org.spockframework:spock-core:2.0-groovy-3.0
> Module 'org.codehaus.groovy:groovy' has been rejected:
Cannot select module with conflict on capability 'org.codehaus.groovy:groovy:3.0.8' also provided by [org.apache.groovy:groovy:4.0.0-beta-2(groovyApiElements)]
It won’t be required for Spock 2.0-groovy-4.0, once available.
To be able use Groovy 4, Gradle 6.7+ is required.
With earlier Gradle version you might got some misleading errors about not resolvable dependency to org.codehaus.groovy:groovy:4.0.0-beta-2
, even though you configured org.apache.groovy:groovy:4.0.0-beta-2
with the correct, changed group id.
Execution failed for task ':compileTestGroovy'.
> Could not resolve all files for configuration ':detachedConfiguration1'.
> Could not find org.codehaus.groovy:groovy:4.0.0-beta-2.
The obvious way to add system properties to the Gradle execution itself is:
./gradlew check -Dspock.iKnowWhatImDoing.disableGroovyVersionCheck=true //wrong way
Unfortunately it doesn’t work:
> Task :compileTestGroovy FAILED
startup failed:
Could not instantiate global transform class org.spockframework.compiler.SpockTransform specified at jar:file:/home/foobar/.m2/repository/org/spockframework/spock-core/2.0-groovy-3.0/spock-core-2.0-groovy-3.0.jar!/META-INF/services/org.codehaus.groovy.transform.ASTTransformation because of exception org.spockframework.util.IncompatibleGroovyVersionException: The Spock compiler plugin cannot execute because Spock 2.0-groovy-3.0 is not compatible with Groovy 4.0.0-beta-2. For more information (including enforce mode), see http://docs.spockframework.org (section 'Known Issues').
Spock artifact: file:/home/foobar/.m2/repository/org/spockframework/spock-core/2.0-groovy-3.0/.../spock-core-2.0-groovy-3.0.jar
Groovy artifact: file:/home/foobar/.gradle/caches/modules-2/files-2.1/org.apache.groovy/groovy/4.0.0-beta-2/.../groovy-4.0.0-beta-2.jar
1 error
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileTestGroovy'.
> Compilation failed; see the compiler error output for details.
After some searching on the Internet, we can find out that tests in Gradle are (by default) executed in a separate JVM, to it is required to pass the aforementioned system property to the test
task:
|
|
However, it still fails:
> Task :compileTestGroovy FAILED
startup failed:
Could not instantiate global transform class org.spockframework.compiler.SpockTransform specified at ...
Hmm, maybe it would be better to refer the Gradle test task by type?
|
|
It fails with the same error message :-/. What is wrong?
The key difference - quite easy to miss - is the fact the exception is thrown not during the test execution, but during the compilation phrase. Then, the main Spock AST transformation checks if it could be applied:
> Task :compileTestGroovy FAILED <--------- :compileTestGroovy not :test !
startup failed:
...
It is definitely less popular case, and I had a problem to find any sensible source of wisdom proposing a complete solution. One of the possible option (which I talk about deeper in the article about enabling preview features
of the new Java versions) is CompileOptions
(e.g. options.compilerArgs.add('--enable-preview')
in the GroovyCompile
task. The second might be GroovyCompileOptions
also in GroovyCompile
. However, it does not bring expected result. After some digging, I was able to find out, that as the Groovy compilation is performed in the forked JVM and the right way to achieve the goal is:
|
|
And it works as expected:
> Task :compileTestGroovy
Executing Spock 2.0-groovy-3.0 with NOT compatible Groovy version 4.0.0-beta-2 due to set spock.iKnowWhatImDoing.disableGroovyVersionCheck system property set. This is unsupported and may result in weird runtime errors!
> Task :test
...
displaying a nice disclaimer :). Spock 2.0-groovy-3.0 is used together with Groovy 4.
Btw, if you see just not very helpful error message:
Could not instantiate global transform class org.spockframework.compiler.SpockTransform specified at
jar:file:/.../spock-core-.../org.codehaus.groovy.transform.ASTTransformation
because of exception java.lang.reflect.InvocationTargetException
it is caused by GROOVY-9469 which affects Groovy 3 and was fixed in 3.0.3. Upgrade Groovy to see more verbose error message.
Maven
As Groovy 4 changed its groupId
from org.codehaus.groovy
to org.apache.groovy
it is required to add implicit exclusion for spock-2.0-groovy-3.0 transitive dependencies:
<dependencies>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>${spock.version}</version>
<scope>test</scope>
<exclusions>
<!-- to do not have conflicting Groovy versions - Groovy 4 changed groupId from "org.codehaus.groovy" to "org.apache.groovy" -->
<exclusion>
<groupId>org.codehaus.groovy</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
<version>4.0.0-beta-2</version>
</dependency>
</dependencies>
to have your tests executed with Groovy 4 instead of (silently) with Groovy 3, taken from a transitive dependency of Spock 2.0-groovy-3.0!
[INFO] --- gmavenplus-plugin:1.13.0:compileTests (default) @ spock2-groovy4-maven ---
[INFO] Using isolated classloader, without GMavenPlus classpath.
[INFO] Using Groovy 3.0.8 to perform compileTests. <---- Without exclusion, it is executed "silently" with old Groovy!
[INFO] Parallel parsing disabled.
[INFO] Compiled 1 file.
It won’t be required for Spock 2.0-groovy-4.0, once available.
Writing my Spock, Groovy and modern Java related tutorials, I try to cover also the Maven users, which still is quite popular build tool :-). Usually, it takes much more (XML) lines to achieve the same in Maven in comparison to Gradle, however, sometimes it just works flawlessly without any additional effort. Unfortunately, it was not the case this time.
The build with Spock-2.0-groovy-3.0 and Groovy 4.0.0 by default fails with:
[ERROR] Failed to execute goal org.codehaus.gmavenplus:gmavenplus-plugin:1.8.1:compileTests (default) on project spock2-migration-maven: Error occurred while calling a method on a Groovy class from classpath. InvocationTargetException: startup failed:
[ERROR] Could not instantiate global transform class org.spockframework.compiler.SpockTransform specified at jar:file:/home/foobar/.m2/repository/org/spockframework/spock-core/2.0-groovy-3.0/spock-core-2.0-groovy-3.0.jar!/META-INF/services/org.codehaus.groovy.transform.ASTTransformation because of exception org.spockframework.util.IncompatibleGroovyVersionException: The Spock compiler plugin cannot execute because Spock 2.0-groovy-3.0 is not compatible with Groovy 4.0.0-beta-2. For more information (including enforce mode), see http://docs.spockframework.org (section 'Known Issues').
[ERROR] Spock artifact: file:/home/foobar/.m2/repository/org/spockframework/spock-core/2.0-groovy-3.0/spock-core-2.0-groovy-3.0.jar
[ERROR] Groovy artifact: file:/home/foobar/.m2/repository/org/apache/groovy/groovy/4.0.0-beta-2/groovy-4.0.0-beta-2.jar
[ERROR]
[ERROR] 1 error
[ERROR] -> [Help 1]
To make the long story short, I started with the plain Maven properties:
|
|
It fails. Next, I added the following to the compiler parameters:
|
|
however, it doesn’t affect Groovy compilation itself. I even took a look at the gmavenplus
plugin parameters and Groovy’s CompilerConfiguration
, but without any effect. In the end, I was able to achieve that with another plugin properties-maven
:
|
|
resulting in:
[INFO] --- gmavenplus-plugin:1.8.1:compileTests (default) @ spock2-migration-maven ---
[INFO] Using isolated classloader, without GMavenPlus classpath.
[INFO] Using Groovy 4.0.0-beta-2 to perform compileTests.
Executing Spock 2.0-groovy-3.0 with NOT compatible Groovy version 4.0.0-beta-2 due to set spock.iKnowWhatImDoing.disableGroovyVersionCheck system property set. This is unsupported and may result in weird runtime errors!
[INFO] Compiled 10 files.
[INFO]
[INFO] --- maven-surefire-plugin:3.0.0-M4:test (default-test) @ spock2-migration-maven ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
...
It turned out to be quite easy (if you know what to use :-) ), but - unless I missed something - it is somehow not much covered in the existing tutorials or documentation.
Potential issue in IntelliJ IDEA
Even though, having your up-and-running Maven project configured as above, you might still encounter the incompatibility error after importing it in Idea:
Groovyc: While compiling [tests of spock2-groovy4-gradle.test]: Could not instantiate global transform class org.spockframework.compiler.SpockTransform specified at jar:file:/home/…/spock-core-2.0-groovy-3.0.jar!/META-INF/services/org.codehaus.groovy.transform.ASTTransformation because of exception java.lang.NullPointerException: Cannot invoke “java.net.URL.toString()” because the return value of “java.security.CodeSource.getLocation()” is null
The problem is caused by a limitation of Idea (IDEA-287642
), which does not allow providing custom system properties for groovyc compilation (just for javac). You might want to vote for that issue. In fact, as Paul King
pointed out, there is a way to set that property for all the compilers used in the project with Settings → Compiler → Shared build process VM options
. In the context of Spock, it should be enough.
The error itself is not very meaningful (NullPointerException
) which in turn is caused by an unexpected behavior of Idea, reported as IDEA-287643
.
It is worth to mention, the same problem might occur also with Gradle, once “Build and run” is manually set to “Idea” (instead of “Gradle” - default behavior, but not the fastest one).
Summary
The main reason, I implemented that feature in Spock was development of Groovy 4. I didn’t feel comfortable seeing The Groovy Team to be forced to use the Spock snapshot version in the master (Groovy 4.x) builds. With Spock-2.0-M3 it was simplified . The same construction can be used in your project while playing with Groovy 4 (in beta as of XI 2021), in the way I precised for Gradle and Maven (which in turn can be really confusing on their own way which motivated me to write this short post :-) ). There is a plan to add the official support for Groovy 4 in Spock, once it is closer to Groovy 4.0.0-final.
Btw, there is a code repository with working examples for Gradle and Maven.
P.S. If you bumped into that topic during Spock 1.3 -> 2.0 migration, there is a dedicated migration guide article .
Updated 2021-01-31. Added section about potential issue with IntelliJ IDEA.
Updated 2021-02-02. Add workaround suggested by Paul King
about the potential issue with IntelliJ IDEA.