How can I specify a Groovy CompilerConfig using Gradle? - groovy

I have a Groovy project, where I would like to enable this CompilerConfig:
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
ast(groovy.transform.TypeChecked)
}
How can I enable this using Gradle?

Beginning from Gradle 2.1 it is possible, see the corresponding release notes.
This is especially useful for working with Groovy on Android, see this presentation. E.g. you could add the #CompileStatic to each class with the following code:
File build.gradle
compileGroovy {
groovyOptions.configurationScript = file("gradle/config.groovy")
}
File gradle/config.groovy
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
}
For more options, see the GroovyCompileOptions and Groovy Customizer Builder.

Gradle's GroovyCompile task doesn't currently support passing a CompilerConfiguration instance or --configscript option. See http://forums.gradle.org/gradle/topics/ability_to_specify_a_compilerconfiguration_instance_for_groovycompile_task for a related discussion.

Related

Is additional context configuration required when upgrading cucumber-jvm from version 4 to version 6?

I am using cucumber-jvm to perform some functional tests in Kotlin.
I have the standard empty runner class:
#RunWith(Cucumber::class)
#CucumberOptions(features=[foo],
glue=[bar],
plugin=[baz],
strict=true,
monochrome=true)
class Whatever
The actual steps are defined in another class with the #ContextConfiguration springframework annotation.
This class also uses other spring features like #Autowire or #Qualifier
#ContextConfiguration(locations=["x/y/z/config.xml"])
class MyClass {
...
#Before
...
#Given("some feature file stuff")
...
// etc
}
This all work fine in cucumber version 4.2.0, however upgrading to version 6.3.0 breaks things. After updating the imports to match the new cucumber project layout the tests now fail with this error:
io.cucumber.core.backend.CucumberBackendException: Please annotate a glue class with some context configuration.
It provides examples of what it means...
For example:
#CucumberContextConfiguration
#SpringBootTest(classes = TestConfig.class)
public class CucumberSpringConfiguration {}
Or:
#CucumberContextConfiguration
#ContextConfiguration( ... )
public class CucumberSpringConfiguration {}
It looks like it's telling me I can just add #CucumberContextConfiguration to MyClass.
But why?
I get the point of #CucumberContextConfiguration, it's explained well here but why do I need it now with version 6 when version 4 got on fine without it? I can't see any feature that was deprecated and replaced by this.
Any help would be appreciated :)
Since the error matches exactly with the error I was getting in running Cucumber tests with Spring Boot, so I am sharing my fix.
One of the probable reason is: Cucumber can't find the CucumberSpringConfiguration
class in the glue path.
Solution 1:
Move the CucumberSpringConfiguration class inside the glue path (which in my case was inside the steps package).
Solution 2:
Add the CucumberSpringConfiguration package path in the glue path.
The below screenshot depicts my project structure.
As you can see that my CucumberSpringConfig class was under configurations package so it was throwing me the error when I tried to run feature file from command prompt (mvn clean test):
"Please annotate a glue class with some context configuration."
So I applied solution 2, i.e added the configurations package in the glue path in my runner class annotation.
And this is the screenshot of the contents of CucumberSpringConfiguration class:
Just an extra info:
To run tests from command prompt we need to include the below plugin in pom.xml
https://github.com/cucumber/cucumber-jvm/pull/1959 removed the context configuration auto-discovery. The author concluded that it hid user errors and removing it would provide more clarity and reduce complexity. It also listed the scenarios where the context configuration auto-discovery used to apply.
Note that it was introduced after https://github.com/cucumber/cucumber-jvm/pull/1911, which you had mentioned.
Had the same error but while running Cucumber tests from Jar with Gradle.
The solution was to add a rule to the jar task to merge all the files with the name "META-INF/services/io.cucumber.core.backend.BackendProviderService" (there could be multiple of them in different Cucumber libs - cucumber-java, cucumber-spring).
For Gradle it is:
shadowJar {
....
transform(AppendingTransformer) {
resource = 'META-INF/services/io.cucumber.core.backend.BackendProviderService'
}
}
For Maven something like this:
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/services/io.cucumber.core.backend.BackendProviderService</resource>
</transformer>
</transformers>
A bit more explanation could be found in this answer

Suppress warning “Access to field exceeds its access rights” in Groovy

I write a Groovy script and I need to access a field that has a private access modifier. This works fine but generates a warning:
Access to <field_name> exceeds its access rights
I want to supress this warning. What value of #SuppressWarnings annotation do I have to use in order to achieve it?
I've tried #SuppressWarnings("all") and it works fine but I would like to have more granular control over suppressions. I've also tried #SuppressWarnings("AccessingNonPublicFieldOfAnotherObject") but it has no effect.
Below how this warning looks in IntelliJ:
Unfortunately automatic hint doesn't suggest any sensible solution:
If you are talking about IntelliJ warning:
then you can hit Alt+Enter on the offender and choose "Suppress for method" as follows:
after which you will see #SuppressWarnings("GroovyAccessibility") over your test method:
I had this "problem" when I had buildSrc folder in Gradle-project which contained Kotlin code for my Gradle build scripts and it was used in Groovy code.
Seems like it was because I was accessing private variable field and not the getter. Kotlin makes field private by default. I solved this by using #JvmField in Kotlin code which makes the variable field public and does not generate getter for that field.
// groovy in gradle build script
compileOptions {
sourceCompatibility(CompileOptions.javaVersion)
}
// kotlin in buildSrc (this gives the warning)
object CompileOptions {
val javaVersion = JavaVersion.VERSION_11
}
// kotlin in buildSrc (this does not give the warning as field is now public)
object CompileOptions {
#JvmField val javaVersion = JavaVersion.VERSION_11
}

Error with Nullable annotation when generating Javadoc using doclava

I am trying to generate a Javadoc for an Android Library using Doclava in Android Studio. The source code uses "Nullable" tag at some point and this causes a crash while generating the javadoc:
In doclet class com.google.doclava.Doclava, method start has thrown an exception java.lang.reflect.InvocationTargetException
com.sun.tools.javac.code.Symbol$CompletionFailure: class file for javax.annotation.Nullable not found
Can I somehow overcome this?
I had to include in Javadoc's classpath, the findbugs:jsr305 library.
So, in my Gradle configuration, I added:
dependencies {
// For Doclava JavaDoc
jaxDoclet("com.google.doclava:doclava:1.0.6")
classpaths files('build/intermediates/classes/release')
classpaths 'com.google.code.findbugs:jsr305:3.0.1'
}
task javadoc(type: Javadoc) {
//.... the rest of the configuration
options {
classpath += configurations.classpaths.files.asType(List)
//.... the rest of the configuration
}
}
For this exception, check here: https://code.google.com/p/android/issues/detail?id=1261
Just add -XDignore.symbol.file to the end of the command, and it may remove this exception.

Gradle plugin for default properties

I am trying (and failing :) ) to create a gradle plugin that has a default set of versions for dependencies and can be overridden in the gradle.build file that is calling my plugin. Ideally something like the sudo-code below
MyDefaultPropertiesPlugin.groovy
project.versions.springBoot="1.0.0-RELEASE"
MyPlugin.groovy
project.apply plugin: MyDefaultPropertiesPlugin
compile("org.springframework.boot:spring-boot-starter-web:${project.versions.springBoot}")
build.gradle
versions.springBoot = "1.1.0-RELEASE"
project.apply plugin "my.plugin"
I attempted to do using extensions but ran into isssue's via the ordering when overriding. (versions doesnt exist)
I would greatly appreciate any advise on this, maven would be easy, but my gradle knowledge is still evolving :)
Thanks in advance for any insight!
Plugins have to defer accessing the build model until after build scripts have been evaluated. Easiest solution is to use project.afterEvaluate {}, but there are others. For more information, see answers to similar questions here or on http://forums.gradle.org.
Came up with a pretty workable if not perfect solution, I will update if i think of anything better, my gradle is at a learning level, so please commend if this can be improved.
This allows me to define a set of versions and clients to overwrite those versions with a simple property
MyDefaultVersionsPlugin.groovy
class MyDefaultVersionsPlugin implements Plugin<Project>{
project.extensions.create('versions', MyVersions, project)
}
class MyVersions{
String spring
String slf4j
public MyVersions (Project project){
spring = setVersion(project,'springVersion', 'x.x.x.x')
slf4j = setVersion(project,'slf4jVersion', 'x.x.x.x')
}
private static String setVersion(Project project, String name, String version){
if(project.hasProperties(name)){
return project.getProperties().get(name)
}
else {
return version
}
}
}
MyPlugin.groovy
project.apply plugin: MyDefaultVersionsPlugin
compile("org.springframework.boot:spring-boot-starter-web:${project.versions.spring}")
build.gradle
buildscript { ext { springVersion = 'x.x.x.x'} }

gradle object in a gradle build script

Consider the following method invokation containing in the gradle build script:
gradle.taskGraph.whenReady{taskGraph ->
println gradle.toString()
println "Ready"
}
It prints
build 'task_graph'
Ready
I thought we work in the scope of Project object, since gradle should be a property of that Project object. But there is neither property nor even method with such name. Why can we use it in the build script?
I may be wrong but I think your confusion is that there exists a getGradle() method on the Project interface but no such public field named gradle. This is a Groovy feature. In Groovy, getter and setter methods can by referenced as properties. For example:
println project.description // same as project.getDescription()
project.description = 'My java project' // same as project.setDescription('My java project')
I'd highly suggest familiarizing yourself with Groovy by checking out their documentation. You'll see a lot of differing syntax in Gradle examples simply because there are many different ways to accomplish the same thing in Groovy.

Resources