Gradle eclipse task not including all sourcesets - java

I have a java project in gradle where I include sourceSets from another location in addition to sourceSets included in this project. The build and test tasks run all appropiate unittests from both src directories, but the eclipse task is missing sourceSets from one or the other. test sourceset is included from one and the main is the sourceSet from another. How do I make the eclipse task include both sourceSets?
sourceSets {
main {
java {
srcDir '../CommonSource/src/main/java'
}
}
test {
java {
srcDir '../CommonSource/src/test/java'
}
}
}
//I also have the implied src in the current project under the gradle convention src/main/java, and src/main/java.

Related

Gradle (java): test task should use generated .jar and not the .class files in classpath

Gradle with apply plugin: 'java' in build.gradle. The file will create a .jar file and the test task is running junit tests:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.12'
}
This is working. But to make sure the public API tests are working with the generated .jar file I want that the 'test' task is running the test with the generated .jar file from the build/libs folder in classpath and not with the generate .class files from folder build/classes in in classpath.
Not working because the sourceSets is set global:
tasks.withType(Test) {
sourceSets {
main {
java {
exclude '**'
}
}
}
}
Partly working: multiproject (test and jar separated in two gradle projects):
dependencies {
compile project(":jar_project")
testCompile 'junit:junit:4.12'
}
in this case jar_project.jar is used but package private test are also executed without an error.
Do somebody have an idea how to run the tests with the .jar as dependency and ignoring the .class files?
Thank you, pulp
The problem is that the test task does not depend on the jar task, which sort of makes sense because the jar is supposed to package the classes, so there should be no reason for tests to depend on that jar.
You can force the dependency by:
test {
dependsOn jar
doFirst {
classpath += jar.outputs.files
}
}
Now the jar will be on the test classpath

Gradle running Spock integration test from a different module

I have my integration-test in a different module, however I have single gradle.build file.
When I'm running gradle clean integrationTest I get the following error
Task :integrationTest NO-SOURCE
Skipping task ':integrationTest' as it has no source files and no previous output files.
In the logs I see the following:
file or directory '<MyPath>/MyService/src/integrationTest/groovy'', not found
However the path should be <MyPath>/MyService/integrationTest/src/test/groovy
my gradle.build file have the following:
sourceSets {
integrationTest {
groovy {
srcDir 'integration-test/src/test/groovy'
}
resources {
srcDir 'integration-test/src/test/resources'
}
}
}
task integrationTest(type: Test) {
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
The form srcDir(<path>) appends another source path. So Gradle will still search in src/integrationTest/groovy, which is the conventional path.
If you want to replace the convention, use
sourceSets {
integrationTest {
groovy {
srcDirs = [file('integration-test/src/test/groovy')] as Set
}
resources {
srcDirs = [file('integration-test/src/test/resources')] as Set
}
}
}
However, there's no need to remove the conventional path. I wonder whether your path is correct, because you say in your post that the path should include 'integrationTest', but you're specifying 'integration-test' in the example code.

How do you create then run an executable jar with dependencies in Intellij IDEs, specifically Android Studio?

I'm trying to create and run an executable jar through gradle. This is what my current gradle looks like:
task jarTask(type: Jar) {
baseName = 'my-main-class'
from 'build/classes/main'
}
task createJarWithDependencies(type: Jar) {
manifest {
attributes 'Implementation-Title': 'Sample Jar',
'Implementation-Version': 1,
'Main-Class':'com.example.MyMainClass'
}
baseName = "my-main-class-with-dependencies"
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
with jarTask
}
configurations {
jarConfiguration
}
artifacts {
jarConfiguration jarTask
}
// This is the task that I call with ./gradlew to execute my jar
task runMyJar(type: JavaExec) {
classpath files('build/libs/my-main-class-with-dependencies.jar')
main 'com.example.MyMainClass'
args = ["param1","param2"]
outputs.upToDateWhen { false }
}
runMyJar.dependsOn(createJarWithDependencies, build)
I got these approach from the following stack overflow answers/references below:
Android Studio export jar with dependencies
Android studio - How to use an executable jar file from gradle
However when I run ./gradlew clean runMyJar (or even just ./gradlew runMyJar, I get the following error message:
Error: Could not find or load main class com.example.MyMainClass
Can anyone point out the reason why my executable jar is not finding the main method inside my class? Is there anything I'm missing?
Since I haven't had much luck with this solution, I managed to get around this problem by doing the following instead:
task deleteJar(type: Delete) {
delete 'libs/my-main-class.jar'
}
task createJar(type: Copy) {
from('build/intermediates/bundles/debug/')
into('libs/')
include('classes.jar')
rename('classes.jar', 'my-main-class.jar')
}
// This is the task that I call with ./gradlew to execute my jar
task runMyJar(type: JavaExec) {
classpath files('libs/my-main-class.jar')
classpath files('libs/common-util.jar')
main 'com.example.MyMainClass'
args = ["param1","param2"]
outputs.upToDateWhen { false }
}
createJar.dependsOn(deleteJar, build)
runMyJar.dependsOn(createJar, build)
This is not the solution that I want though, since this approach doesn't pull in the dependencies from other modules referenced by this module, which is what I was trying to solve. In order to do that, what I end up doing is copy/paste this same approach on those "other" modules and generate a lib for that module, and then copy that lib over to the libs folder of this module. OR I can move those dependent code in this same module so I don't have to deal with it. For a simple application that's not too bad (which, luckily, is my situation), but for a complex one, I'm not sure how to go about that.
As an added reference here is my dependencies section:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':common-util')
// common-util is an Android module, which references other Android
// methods such as Log.d, android.util class methods, etc.
}
By the way, I'm using the Android Studio IntelliJ IDE for this (which was the original motivation of my post). My hope was to not have to create separate jars from other modules to include it to this module but instead do it all in one go ...

Add another java source directory to gradle script

I hava an example java project package
package com.example.testing;
with such file tree
app
|
src->com->example->testing->Main.java
and a gradle script:
apply plugin: 'java'
apply plugin: 'application'
sourceSets {
main {
java {
srcDirs 'src'
}
}
}
sourceSets.main.output.classesDir = file("classes")
mainClassName = 'com.example.testing.Main'
defaultTasks 'compileJava', 'run'
Now I want to add some module to this project and my folders will be something like this
app
|
src1->com->example->testing->Main.java
src2->com->another_example->another_testing->Library.java
How do I add new source code to gradle script?
I agree with #JB Nizet about respecting standard conventions. If you still insist on being an Anarchist though:
You already have src declared in your sourceset, why not add src1 and src2 as well? You can add them to the same sourceset, or define a sourceset per module if you want.
sourceSets {
main {
java {
srcDirs 'src'
srcDirs 'src1'
srcDirs 'src2'
}
}
}
To reference files outside the project, see this answer.
The question is about "Adding"; the question of the text is describing a more concrete scenario. If one just wants to add an existing directory, this is the way to add:
sourceSets.main.java.srcDirs += ['src/gen/java']
An example full build.gradle is as follows:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
implementation 'com.squareup:javapoet:1.12.1'
}
sourceSets.main.java.srcDirs += ['src/gen/java']
JavaPoet s a Java API for generating .java source files. It is just used as example library for the build.gradle file.
I have a slightly different approach with a Gradle 4.6:
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir 'build/swagger-code-dummy/src/main/java'
}
}
}
as you can see, I had to specify the directories with the "/main/java" subdirectories as well, otherwise gradle/intellij was not setting the right path.
Maybe this helps someone else too :)
A slightly different solution:
sourceSets.main.java.srcDirs = ['build/jasper', 'src/main/java']

Gradle multiple jars from single source folder

As for now we have a project structure with single source folder named src, which contains source code for three modules. What I want to do is:
1) Compile source code. This is easily done with sourceSets definition:
sourceSets {
main {
java {
srcDir 'src'
}
}
}
2) Put compilation results into three jars. I am doing this via three 'jar' type tasks:
I am doing this now via three separate tasks:
util.jar
task utilJar(type: Jar) {
from(sourceSets.main.output) {
include "my/util/package/**"
}
}
client.jar
task clientJar(type: Jar) {
from(sourceSets.main.output) {
include "my/client/package/**"
}
}
server.jar
task serverJar(type: Jar) {
from(sourceSets.main.output) {
include "**"
}
excludes.addAll(utilJar.includes)
excludes.addAll(clientJar.includes)
}
The thing is that server.jar should contain all classes that are not contained within client.jar and util.jar. In ant build script we solve this problem by using difference ant task. How this can be done in gradle (my current approach doesn't work)?
Maybe my approach is completely wrong. Please advice.
P.S. as for now we CAN NOT change the project source code folder structure.
I will post my working solution here as an answer (I've got a hint on gradle's forum).
The scopes in gradle are very strange thing :) I thought that every task definition creates an object of some 'Task' class, which is something like 'JarTask' in this particular case. Then I can access any property of the class from anywhere in my build.gradle script. However, I found the only place where I can see the patterns, which are included in jar file - inside a from block of a task. So my working solution for now is to:
1) Define a project-level collection to contain patterns to be excluded from server.jar
2) Exclude all patterns in from block of serverJar task.
Please see final version below
sourceSets {
main {
java {
srcDir 'src'
}
}
}
// holds classes included into client.jar and util.jar, so they are to be excluded from server.jar
ext.serverExcludes = []
// util.jar
task utilJar(type: Jar) {
from(sourceSets.main.output) {
include "my/util/package/**"
project.ext.serverExcludes.addAll(includes)
}
}
// client.jar
task clientJar(type: Jar) {
from(sourceSets.main.output) {
include "my/client/package/**"
project.ext.serverExcludes.addAll(includes)
}
}
// server.jar
task serverJar(type: Jar) {
from(sourceSets.main.output) {
exclude project.ext.serverExcludes
}
}
I think the approach is wrong. I recommend making a project with 3 sub projects.
project
- util
- server (depends on util)
- client (depends on util)
If for some reason you cannot change the class structure use this kind of build files:
settings.gradle
include 'util', 'client', 'server'
build.gradle
subprojects {
apply plugin: 'java'
}
project(':util') {
sourceSets {
main {
java {
srcDir '../src'
include 'util/**'
}
}
}
}
project(':server') {
sourceSets {
main {
java {
srcDir '../src'
include 'server/**'
}
}
}
dependencies {
compile project(':util')
}
}
project(':client') {
sourceSets {
main {
java {
srcDir '../src'
include 'client/**'
}
}
}
dependencies {
compile project(':util')
}
}
You still need directories for subprojects but the sources are in one place as you wanted.
When you run gradle assemble you will have 3 jars with separate set of classes. The advantage of this solution is that we make a proper Gradle multi module project with correct dependencies, not just tasks for building jars.
Please read Multi-Project Builds.
We have the same problem at my company, ie. legacy code that is difficult to migrate into a "good" project structure, and the need to build several jars from the same codebase. We decided to define different sourceSets and build each of the sourceSets using standard Gradle.
We then use iterators to add jar- and javadoc-tasks for each sourceSet:
sourceSets.all { SourceSet sourceSet ->
Task jarTask = tasks.create("jar" + sourceSet.name, Jar.class)
jarTask.from(sourceSet.output)
// Configure other jar task properties: group, description, manifest etc
Task javadocTask = tasks.create("javadoc" + sourceSet.name, Javadoc.class)
javadocTask.setClasspath(sourceSet.output + sourceSet.compileClasspath)
javadocTask.setSource(sourceSet.allJava)
// Extra config for the javadoc task: group, description etc
Task javadocJarTask = tasks.create("javadocJar" + sourceSet.name, Jar.class)
javadocJarTask.setClassifier("javadoc") // adds "-javadoc" to the name of the jar
javadocJarTask.from(javadocTask.outputs)
// Add extra config: group, description, manifest etc
}
I agree in principal with the accepted answer too.
I found a project where the client requires two JAR essentially of the same file except the Manifest is different only by the Class-Path key.
jar {
manifest {
attributes(
"Main-Class": platformMainClass,
"Implementation-Title": platformDisplayName,
"Implementation-Description": platformDescription,
"Platform-Version": platformVersion,
"Implementation-Version": version,
"Build-Assembly-User": System.getProperty("user.name"),
"Build-Assembly-Date": new java.util.Date().toString(),
"Class-Path": configurations.compile.collect { "lib/"+it.getName() }.join(' ')
)
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
exclude( [ 'log4j*.properties', 'uk/gov/acme/secret/product/server/**' ])
}
The same manifest and the source code then is:
task applicationClientJar(type: Jar, description: "Creates the Application Client JAR file.") {
dependsOn compileJava
manifest {
attributes(
"Main-Class": platformMainClass,
"Implementation-Title": platformDisplayName,
"Implementation-Description": platformDescription,
"Platform-Version": platformVersion,
"Implementation-Version": version,
"Assembly-Date": new java.util.Date().toString()
)
}
archiveName = "acme-client-${platformVersion}.jar"
destinationDir = file("${buildDir}/libs")
from sourceSets.main.output
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
exclude( [ 'log4j*.properties', 'uk/gov/acme/secret/product/server/**' }
So Grzegorz notation is correct, because the Gradle should know there are two different JAR with GAVs. Multi-module is the preferred option.
compile "uk.gov.acme.secret:acme:1.0" // CORE
compile "uk.gov.acme.secret:acme-client:1.0"
The only way to configure for this is to use the Multi-Module Gradle project and then add a compile and/or deploy dependency to the core / main project.
project(':common:acme-micro-service-webapp') {
dependencies {
compile project(':common:acme-core')
}
}
Inside the 'acme-micro-service-webapp' project, this ensures that the dependent 'common:acme-core' is compiled first.
PS: I am still trying to figure out a better solution.
PS PS: If you are using Maven as well as, it may be possible to hook on the `install' task.

Categories