This page looks best with JavaScript enabled

Running Spock with unsupported Groovy version (Gradle + Maven)

 ·   ·  ☕ 11 min read

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:

  1. 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) Spock 1.3-groovy-2.5-SNAPSHOT works fine with Groovy 3.0.x.

  2. 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

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:

1
2
3
test {
    systemProperty "spock.iKnowWhatImDoing.disableGroovyVersionCheck", "true"   //doesn't work
}

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?

1
2
3
tasks.withType(Test).configureEach {
    systemProperty "spock.iKnowWhatImDoing.disableGroovyVersionCheck", "true"   //doesn't work either
}

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:

1
2
3
tasks.withType(GroovyCompile).configureEach {
    options.forkOptions.jvmArgs << '-Dspock.iKnowWhatImDoing.disableGroovyVersionCheck=true'    //it works! But be aware that "options" not "groovyOptions"!
}

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

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:

1
2
3
4
5
6
7
8
<project>
...
  <properties>
     <!-- doesn't work -->
     <spock.iKnowWhatImDoing.disableGroovyVersionCheck>true</spock.iKnowWhatImDoing.disableGroovyVersionCheck>
  </properties>
...
</project>

It fails. Next, I added the following to the compiler parameters:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
    <!-- ... -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <!-- doesn't work -->
                    <compilerArgs>
                        <arg>-v</arg>
                        <arg>-Dspock.iKnowWhatImDoing.disableGroovyVersionCheck=true</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            <!-- ... -->
        </plugins>
    </build>
    <!-- ... -->

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>properties-maven-plugin</artifactId>
        <version>1.0.0</version>
        <executions>
            <execution>
                <goals>
                    <goal>set-system-properties</goal>
                </goals>
                <configuration>
                    <properties>
                        <!-- works fine -->
                        <property>
                            <name>spock.iKnowWhatImDoing.disableGroovyVersionCheck</name>
                            <value>true</value>
                        </property>
                    </properties>
                </configuration>
            </execution>
        </executions>
    </plugin>

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.

Lead photo by geralt, published in Pixabay, Pixabay License.
Share on

Marcin Zajączkowski
WRITTEN BY
Marcin Zajączkowski
Software Craftsman & Software Architect
An experienced architect aiming for high quality solutions. Very engaged in evangelising Software Craftsmanship, Clean Code and Test-Driven Development as a conference speaker and a trainer. A specialist in Continuous Delivery and Continuous Inspection of Code Quality. An enthusiast of Reactive Systems and broadly defined concurrency.

Besides, open source author and contributor, a proud Linux user.


Don't want to use the Utterance bot? Comments can be also placed directly on GitHub.
What's on this Page