Gradle - Groovy and Java class dependency - Compile - java

My project has both Java (N files) and Groovy code (1 file only). Java compile depends upon this single Groovy file's class file for Java compilation (compileJava task to succeed).
When I don't use src/java as one of the srcDir within main>groovy> sourceSet section, then I get an error saying class/symbol not found which is in the groovy file/class. In ANT, it's easy that we are calling compile-groovy target first, before calling compile-java target but the same in Gradle is what I'm trying to find.
I read some posts and found that if I make main>java section NULL and specify srcDir for main>java which is src/java inside main>groovy sourceSet section, then it compiles fine.
My ?s:
1. Is there any other way to do? for ex, the following should work:
compileJava {
dependsOn compileGroovy
}
though, this goes to an infinte loop.
OR
what about using doFirst for compileJava task:
compileJava {
doFirst {
compileGroovy
}
}
this doesn't work either.
build.gradle This works, but compileJava in one sense becomes useless here even though the source code has N no. of java files in the src/java or src/java-test etc tree. I know this build script is working but logically it might bring some confusion to the developer if s/he is not familiar why sourceSet for Groovy MUST have "src/java" as its srcDir value.
apply plugin: 'java'
apply plugin: 'groovy'
sourceSets {
main {
groovy {
srcDir 'src/groovy'
srcDir 'src/java'
}
java {
//The following needs to be commented out OR Gradle will always pick compileJava before compileGroovy
//srcDir 'src/java'
//srcDir 'src/java-test'
}
}
test {
groovy {
srcDir 'test/groovy'
}
java {
srcDir 'test/java'
}
resources {
srcDir 'test/resources'
srcDir 'conf'
}
}
integrationTest {
groovy {
srcDir 'src/groovy-test'
}
java {
srcDir 'src/java-test'
}
resources {
srcDir 'test/resources'
srcDir 'conf'
}
}
}
Other links:
How to make Gradle compile Groovy tests before Java tests

The Groovy (base) plugin makes GroovyCompile tasks depend on the corresponding JavaCompile tasks because it's more common to call from Groovy into Java than the other way around. If you need it the other way around (or both ways), joint compilation is a good solution. Here is a somewhat improved (over your version) joint compilation setup:
sourceSets {
main {
groovy {
// override the default locations, rather than adding additional ones
srcDirs = ['src/groovy', 'src/java']
}
java {
srcDirs = [] // don't compile Java code twice
}
}
}
If you prefer separate compilation with Java->Groovy dependencies only, something like the following should work:
// since you aren't using the default locations
sourceSets {
main {
groovy {
srcDirs = ['src/groovy']
}
java {
srcDirs = ['src/java']
}
}
}
// remove GroovyCompile->JavaCompile task dependencies
tasks.withType(GroovyCompile) {
dependsOn = []
}
// add JavaCompile->GroovyCompile task dependencies
tasks.withType(JavaCompile) { task ->
dependsOn task.name.replace("Java", "Groovy")
}
Because a JavaCompile task and its corresponding GroovyCompile task write to the same output directory, Java compilation will now have the compiled Groovy code on its compile class path.
PS: Calling a task from another task is not supported, and bad things can happen if you try. Instead, you should always work with task relationships (dependsOn, finalizedBy, mustRunAfter, shouldRunAfter).

Related

Split default test sourceset into more specific test sourcesets

i'm currently setting up a new project using java, gradle and spring boot. I'm struggling to create my planned test setup. My goal is to have separate test commands and directories located IN the test package.
What I have
I have looked into gradle sourceSets and was able to create two new sourceSets for unit and component tests. The problem I face is that I don't know if there is any way to defined the path of the sourcesets so they are inside the test directory.
src
-- main
-- test
-- unit
-- component
What I want
I just want the default test sourceSet to behave like a normal directory which itself contains my two testing sourceSets like this:
src
-- main
-- test
---- unit
---- component
Is this possible and also would this be 'against the convention' or something like that?
Any pointers are appreciated!
Basically, you should be able to set paths to your source sets any way you want to. Something like this should work:
sourceSets {
test {
java {
srcDirs = ['test/unit']
}
resources {
srcDirs = ['test/unit']
}
}
testComponent {
java {
srcDirs = ['test/component']
}
resources {
srcDirs = ['test/component']
}
}
}
Unfortunately I'm not sure if you can change the names of default source sets.
Keep in mind that you will have to provide more configuration for your new source set, e.g. create new Test task:
task testComponent(type: Test) {
testClassesDirs = sourceSets.testComponent.output
classpath += sourceSets.main.output
}
And also manage its dependencies separately or extend them from already existing configuration:
configurations {
testComponentCompile.extendsFrom(testCompile)
testComponentRuntime.extendsFrom(testRuntime)
}
As for the convention: it's best to stick to provided defaults, but if you have the need for different structure then it's also fine. Most common case for test separation is probably when you want split unit and integration test in order to be able to run them individually.

Kotlin Gradle Plugin: How to access `Project` extensions such as `sourceSets`?

In a regular build script you can easily use extensions on Project like Project.sourceSets, for example build.gradle.kts:
sourceSets {
main {
...
}
}
But when I am developing a Gradle plugin in my buildSrc module, I cannot access these. For example:
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.*
class ExamplePlugin : Plugin<Project> {
override fun apply(target: Project) {
target.sourceSets { // error because `sourceSets` can't be resolved.
}
}
}
This is happening despite including the kotlin-gradle-plugin module in my buildSrc dependencies:
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31")
}
So, how can I access these extensions from within my Gradle plugin?
class ExamplePlugin : Plugin<Project> {
override fun apply(target: Project) {
target.configure<JavaPluginExtension> {
sourceSets {
println(names)
}
}
}
}
See additional notes here: https://docs.gradle.org/current/userguide/kotlin_dsl.html#project_extensions_and_conventions
Basically for plugins, or other times when the plugins applied are not known, the accessors (sourceSets, configurations, etc) of extensions added by other plugins will need to go through a method call which sort of 'retrieves' that scope or object. Further down the link there is also an example of how to get tasks created by other plugins:
val test by target.tasks.existing(Test::class)
test.configure { useJUnitPlatform() }
// or
val test by target.tasks.existing(Test::class) {
useJUnitPlatform()
}
note that if the 'sourceSet' object does not exist on the project (because the java plugin was not applied), an exception will be thrown .
tested with gradle version 7.2, kotlin-dsl version 2.1.6

why new sourceset resources not in buildDir in gradle

I have declared
sourceSets {
micro {
resources.srcDir file('src/micro/resources')
}
}
but
micro/resources
not copied to ${buildDir}/resources/micro.
I want to add micro sourceSet to classpath. Thereby I can run from eclipse or from gradleConsole.
What am I missing here?
It looks like you might not be using the correct syntax: How do I add a new sourceset to Gradle?
Maybe you could try like this:
sourceSets {
micro{
resources {
srcDir 'src/micro/resources'
}
}
}

Gradle test log4j.xml

Sorry, if this isn't enough information, new to gradle, let me know if more is needed.
I have a log4j2.xml in a config folder that I define in a gradle.properties file.
project.ext.logConfigFile="./config/log4j2.xml"
The structure of my project
project
src
test
lib
config
log4j2.xml
Now when I run gradle test, it says that it can't find the log4j2 configuration.
This is what my build.gradle file looks like..
sourceSets {
test {
java {
srcDirs = ["test"]
}
}
main {
java {
srcDirs = ["src"]
}
}
}
test {
testLogging {
outputs.upToDateWhen {false}
showStandardStreams = true
events "PASSED", "STARTED", "FAILED", "SKIPPED"
afterSuite { desc, result ->
if (!desc.parent) { // will match the outermost suite
println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
}
}
}
}
Been dinking around with things I found on the internet, that's why all those statements in the "testLogging" part. But basically, I have LOGGER.info() statements that aren't coming up because it defaults to errors only.
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.
Can I tell gradle test exactly where to go for my log4j2.xml? Something like this? Though I don't think this works....
tasks.withType(Test) {
systemProperty 'log4j.configuration', logConfigFile
}
A little stuck right now. Thanks!
Just put it in src/test/resources. That comes first on the classpath during testing. Then configure log4j to load from classpath, not a file path; I think that’s the default behavior anyway
Believe I solved the problem, you just define where the resources are in the sourceSets also. It will look there for the log4j2.xml.
sourceSets {
test {
java {
srcDirs = ["test"]
}
resources {
srcDirs = ["config"]
}
}
main {
java {
srcDirs = ["src"]
}
}
}

Where is the 'main' method of 'sourceSets' defined?

I'm going through some simple Gradle examples, and trying to get my head around the syntax. According to Gradle syntax, there must be a method called 'main' somewhere on 'sourceSets' (which is a SourceSetContainer) that takes a Closure. I figured that I would be able to find it by browsing around the Gradle javadocs, but I can't find it. Can someone point me to where 'main' is defined in this example?
apply plugin: 'java'
sourceSets {
main {
java {
srcDirs = ['src']
}
}
}
sourceSets is a container of named source sets. The java plugin adds a source set named main (and another named test) to that container. As such, there is no physical method or property called main. sourceSets.main { ... } could also be written as sourceSets.getByName("main") { ... }.

Categories

Resources