JUnit 5, Java 9 and Gradle: How to pass --add-modules? - gradle

I want to migrate from Java 8 to Java 9. When running my tests I get a CNFE regarding javax.xml.bind.JAXBContext. Therefore, "--add-modules java.xml.bind" seems to be required. I tried to extend my GRADLE_OPTS env variable, but the error remains. Any hint is appreciated.

You can follow the five basic steps while migrating as stated in the gradle-building java9 modules which are:-
When converting a java-library project to produce a Java 9 module,
there are five changes you should to make to your project.
Add a module-info.java describing the module.
Modify the compileJava task to produce a module.
Modify the compileTestJava task to locally alter the module.
Modify the test task to consume the locally altered module.
(Optional) Add Automatic-Module-Name manifest entries for all other projects.
In your use case, you need to ensure that the
compileTestJava {
inputs.property("moduleName", moduleName)
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'org.junit.jupiter.api', // junit5 automatic module specific
'--add-modules', 'java.xml.bind', // jaxb specific
'--add-reads', "$moduleName=org.junit.jupiter.api", // allow junit to read your module
'--patch-module', "$moduleName=" + files(sourceSets.test.java.srcDirs).asPath, // add test source files to your module
]
classpath = files()
}
}
and then for executing the test, you would need not to udpate the test task as
test {
inputs.property("moduleName", moduleName)
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'ALL-MODULE-PATH', // to resolve all module in the module path to be accessed by gradle test runner
'--add-reads', "$moduleName=org.junit.jupiter.api",
'--patch-module', "$moduleName=" + files(sourceSets.test.java.outputDir).asPath,
]
classpath = files()
}
}
Note: For a long-term solution though I would also suggest you follow the important point mentioned in this answer as well.

According to Alan Bateman, I added the following lines to build.gradle so that gradle bootRun also works:
runtime('org.glassfish.jaxb:jaxb-runtime:2.3.0', 'javax.activation:activation:1.1.1')

Related

Configure plugin in separate file using Kotlin DSL

to differenciate diferent plugins configurations, I use separate files.
For example:
./build.gradle.kts
./detekt.gradle.kts
./settings.gradle.kts
./module1
./module2
...
In the root build.gradle.kts I have this:
plugins {
id("io.gitlab.arturbosch.detekt") version DependencyVersion.Detekt
}
buildscript {
dependencies {
classpath(io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.1.1)
}
}
And to configure it I go to the detekt.gradle.kts and put:
apply(plugin = "io.gitlab.arturbosch.detekt")
detekt {
// configure
}
But detekt lambda is not found. Also tried with:
apply(plugin = "io.gitlab.arturbosch.detekt")
configure<io.gitlab.arturbosch.detekt.Detekt> {
// configure
}
But it doesn't find .Detekt.
With JaCoCo I haven't got any problems using the second approach, but it doesn't work with Detekt or SonarQube.
How can I configure plugins in a separate file?
Thanks.
Try something like below. I have declared a plugin "sonarqube" in my main gradle. I then apply the file sonar.gradle.kts towards the end of the build.gradle.kts file.
build.gradle.kts:
plugins {
id("org.sonarqube") version "2.8" apply false
}
...
apply(from="$rootDir/gradle/includes/sonar.gradle.kts")
gradle/includes/sonar.gradle.kts:
apply(plugin="org.sonarqube")
Using a setup like above, I can then run "gradle sonarqube"
I faced a similar issue. Everything that you need to do is to call
configure<io.gitlab.arturbosch.detekt.extensions.DetektExtension> {
// configure
}
More info, you can find here: https://docs.gradle.org/current/userguide/migrating_from_groovy_to_kotlin_dsl.html#configuring-plugins

Not able to extend a Gradle task

I'm new with Gradle (we're switching from SBT) and using it to build apps made with Play Framework.
I need to add some filtering on the resources before Gradle processes them (I would like to inject some build properties into the configuration to make them available from the code).
I've managed to "extend" the java processResources task, but, for some reason, I cannot do the same with play processPlayBinaryPlayResources.
processPlayBinaryPlayResources {
filter ReplaceTokens, tokens: [
"applicationVersion": version
]
}
Even this doesn't work :
def playVersion = "2.6.20"
def scalaVersion = "2.12"
def javaVersion = "1.8"
apply plugin: "java"
apply plugin: "idea"
apply plugin: "play"
model {
components {
play {
platform play: playVersion, scala: scalaVersion, java: javaVersion
injectedRoutesGenerator = true
}
}
}
processPlayBinaryPlayResources {
doLast {
println("ok")
}
}
dependencies {
compile "io.vavr:vavr:0.9.2"
compile "org.imgscalr:imgscalr-lib:4.2"
compile "com.typesafe.play:play-guice_${scalaVersion}:2.6.20"
compile "com.typesafe.akka:akka-http_${scalaVersion}:10.1.5"
compile "com.typesafe.play:filters-helpers_${scalaVersion}:2.6.20"
compile "ch.qos.logback:logback-classic:1.2.3"
}
It yields :
> Could not find method processPlayBinaryPlayResources() for arguments [build_6grwx7eowye82rdqpu4qlinur$_run_closure2#582d9dbd] on root project 'myproject' of type org.gradle.api.Project.
Any idea why ?
Your assumption of finding a task processPlayBinaryPlayResources is based on that, that the java plugin automatically adds a processResources task for all source set as process<sourceset_name>Resources . This happens only when a source set is added using java pugins sourceSets method which, in this case PlayBinaryPlay is not. The play plugin uses its own DSL to configure source sets.
Therefore when you try extending processPlayBinaryPlayResources it does not happen as no such tasks by that name exists in the first place and hence while delegating it to Project, you end up with this
Could not find method processPlayBinaryPlayResources() for arguments [build_6grwx7eowye82rdqpu4qlinur$_run_closure2#582d9dbd] on root project 'myproject' of type org.gradle.api.Project.
Lastly, I would like to add that the processPlayBinaryPlayResources task is not added by the play plugin.

Gradle Kotlin DSL equivalent for Groovy DSL 'run'?

I am trying to build a simple JavaFX 11 program with Kotlin and Java 11, using Gradle, following the instructions here. However, this page uses Gradle's Groovy DSL, and I am trying to use the Kotlin DSL. Surprisingly, my Google searches have not turned up a document that maps each Groovy construct to its equivalent Kotlin construct or explains in general how to convert Groovy DSL code to equivalent Kotlin DSL code. (This seems like a big oversight in the Gradle documentation!).
In particular, this document contains the following Groovy code:
compileJava {
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'javafx.controls'
]
}
}
run {
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'javafx.controls'
]
}
}
As far as I can tell, the Kotlin equivalent to the first part appears to be:
tasks.withType<JavaCompile> {
options.compilerArgs.addAll(arrayOf(
"--module-path", classpath.asPath,
"--add-modules", "javafx.controls"
))
}
However, I have not been able to figure out what the Kotlin DSL equivalent to the second part is. Note that 'run' is a standard function extension in Kotlin's standard library, so it does not appear that the Kotlin version of this code can use the name 'run' for the same purpose in the Kotlin DSL.
(Note: I considered trying to use a plugin for the JavaFX support (as described by this page, for instance), but the plugin seems quite complicated to use, and I already am having enough problems with the number of complications in this project that I am hesitant to introduce a very-lightly-documented open-source plugin into the mix. I really am trying to produce the simplest possible "Hello, World" program in JavaFX/Gradle at the moment, and this has so far seemed surprisingly difficult.).
Any help would be appreciated.
Using the configuration avoidance APIs, the equivalent to the second block is:
tasks.named<JavaExec>("run") {
doFirst {
jvmArgs = listOf("--module-path", classpath.asPath,"--add-modules", "javafx.controls")
}
}
The key is that run has the JavaExec type, which like any task's type can be discovered by creating a task to print the class of the task that you then run:
tasks.register("getName") {
doFirst {
print("Class name: ${tasks["run"].javaClass}")
}
}
Note that as your JavaFX application grows, you will need to specify additional modules like this:
tasks.named<JavaExec>("run") {
doFirst {
jvmArgs = listOf("--module-path", classpath.asPath,
"--add-modules", "javafx.base,javafx.controls,javafx.graphics")
}
}
Surprisingly, my Google searches have not turned up a document that maps each Groovy construct to its equivalent Kotlin construct or explains in general how to convert Groovy DSL code to equivalent Kotlin DSL code.
Please have a look at https://guides.gradle.org/migrating-build-logic-from-groovy-to-kotlin/ and esp. the Configuring tasks section. According to that, I'd say the Kotlin DSL equivalent is
tasks.named<JavaExec>("run").doFirst {
jvmArgs = listOf('--module-path', classpath.asPath, '--add-modules', 'javafx.controls')
}
With Gradle 5.0 and kotlin-dsl 1.0, tasks that are registered or created by plugins can be statically accessed through the tasks container (TaskContainer. There is this example provided in the release notes:
plugins {
java
}
tasks {
named<Test>("test") {
testLogging.showStacktraces = true
}
}
you can now write:
plugins {
java
}
tasks {
test {
testLogging.showStacktraces = true
}
}
For your example, you are most likely using the application plugin, which registers the run task so you can configure it in a similar matter. One issue to be aware of is that run clashes with the Kotlin stdlib run method so you need to apply some workaround to make sure it gets invoked (see gradle/kotlin-dsl/issues/1175)
tasks {
compileJava {
doFirst {
jvmArgs = listOf("--module-path", classpath.asPath,
"--add-modules", "javafx.base,javafx.controls,javafx.graphics")
}
}
(run) {
doFirst {
jvmArgs = listOf(
"--module-path", classpath.asPath,
"--add-modules", "javafx.controls"
)
}
}
}
The other answers show how you can use the name, type, or combination to query the container for specific tasks.

How to create a custom task in gradle to pack java and kotlin code to a jar?

We have a multi modular setup and we are sharing some tests classes between the modules (mainly Fakes implementations). Our current solution (that you can find below) works just for classes written in Java, but we are looking at supporting also shared kotlin classes.
if (isAndroidLibrary()) {
task compileTestCommonJar(type: JavaCompile) {
classpath = compileDebugUnitTestJavaWithJavac.classpath
source sourceSets.testShared.java.srcDirs
destinationDir = file('build/testCommon')
}
taskToDependOn = compileDebugUnitTestSources
} else {
task compileTestCommonJar(type: JavaCompile) {
classpath = compileTestJava.classpath
source sourceSets.testShared.java.srcDirs
destinationDir = file('build/testCommon')
}
taskToDependOn = testClasses
}
task testJar(type: Jar, dependsOn: taskToDependOn) {
classifier = 'tests'
from compileTestCommonJar.outputs
}
How can I modify the compileTestCommonJar so it supports kotlin?
Here is what we do:
In the module with shared test classes, pack the test source set output into a jar
configurations { tests }
...
task testJar(type: Jar, dependsOn: testClasses) {
baseName = "test-${project.archivesBaseName}"
from sourceSets.test.output
}
artifacts { tests testJar }
In a module that depends on the shared classes
dependencies {
testCompile project(path: ":my-project-with-shared-test-classes", configuration: "tests")
}
PS: Honestly, I would prefer to have a separate Gradle module with common test classes as it's more explicit solution.
The task compileTestCommonJar(type: JavaCompile) compiles .java files only because its the task of JavaCompile type.
There's KotlinCompile task aswell, so you would need to merge it, it basically works similary to JavaCompile but compiles .kt files only.
Said that i wouldn't use task system to share the dependencies across, i would use separate module and work with default compileTestKotlin and compileTestJava task's outputs

Gradle Multi Project with Java 9 and Java 8

I would like to migrate a gradle multi project to java 9. Instead of trying a big bang I would like to go step by step. My idea is to start from top (main module) and then work my way down. This implies, that I will have a main module in Java 9 while others are still in Java 8.
If my info is correct a good approach is to have the modules in java 8 integrated as automatic modules. It works fine with 3rd party libs as jar's, but I do not know how to teach gradle to do it with my own java 8 modules.
Imagine I got a Main Java 9 Module 'java9' and a Java 8 Library Module 'java8'
What I did so far:
'java8' build.gradle
apply plugin: 'java'
ext.moduleName = 'java8module.main'
jar {
inputs.property("moduleName", moduleName)
manifest {
attributes('Automatic-Module-Name': moduleName)
}
}
This gives me a java8 jar with a Module Name I decided for in the MANIFEST.MF
'java9' build.gradle
apply plugin: 'application'
mainClassName = 'com.thoughtblaze.java9.main.Main'
ext.moduleName = 'java9main.main'
compileJava {
inputs.property("moduleName", moduleName)
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
]
classpath = files()
}
}
dependencies {
compile project (':java8')
}
'java9' module-info
module java9main.main {
requires java9module.main ;
requires java8module.main ;
}
The problem now is:
'java9' does not recognize java8 as a required module and therefore I cant access any class of the java8 module.
What do I miss here ?

Resources