Gradle name-bound task types - java

When creating a task with the name jar, Gradle automatically knows that the class of the task is org.gradle.api.tasks.bundling.Jar. How can I replicate this with my custom task?
i.e. I have the following class:
class MyTaskType extends DefaultTask {
#Input String name
// Options
#TaskAction
def generateImage() {
// Stuff
}
}
Up until now I've been doing the following:
task veryCoolTaskName(type:MyTaskType) {
name 'some-name'
}
And I want to be able to define a task of this type by writing:
myTaskType {
name 'some-name'
}
Just like with jar {...}. How can I do that?

This is not how Gradle works.
When writing jar { ... }, you don't actually create a new task. Instead, you are refererring to an existing task jar that was created by a plugin (e.g. the Java plugin):
plugins {
id 'java'
}
jar {
// This works because the task was created by the plugin
}
Without any plugin applied, the same excerpt will fail, as a task named jar does not exist:
jar {
// This fails, because the task `jar` does not exist
}
Instead, you need to create the task to configure it:
task jar(type: Jar)
jar {
// This works because the task was created beforehand
}
Of course, the creation and the configuration of the task may be combined:
task jar(type: Jar) {
// ...
}

Related

How execute annotation processing in gradle separatly from build task

I want to run QueryDsl Q-type generation in a separate task. I want that Q-type classes not to be created in a regular compileJava task, but the compiler sees the AnnotationProcessor in the classpath and creates them itself. I tried nulling the annotationProcessorPath, but then I couldn't restore its configuration in a separate task.
May be is it possible to exclude somehow dependencies of subtasks from the classpath?
compileJava {
options.annotationProcessorPath = null
}
tasks.register('generateQTypes'){
group 'build'
description 'Generate Q-Type classes with QueryDsl library'
dependencies {
annotationProcessor(
'com.querydsl:querydsl-apt:4.1.4:jpa',
'javax.persistence:javax.persistence-api:2.2',
'javax.annotation:javax.annotation-api:1.3.1')
}
compileJava {
options.annotationProcessorPath = classpath
}
}
What is the best way to solve this problem?Thanks in advance!
I made the following solution
class QTypeGenerator extends DefaultTask {
#TaskAction
addDependencies() {
project.dependencies {
annotationProcessor(
'com.querydsl:querydsl-apt:4.1.4:jpa',
'javax.persistence:javax.persistence-api:2.2',
'javax.annotation:javax.annotation-api:1.3.1')
}
}
}
tasks.register("generateQTypeClasses", QTypeGenerator) {
group('build')
description('Generate Q-type classes by queryDsl in build directory with default path')
finalizedBy('compileJava')
doLast {
println("Q-types classes will gererated and stored in ${compileJava.options.annotationProcessorGeneratedSourcesDirectory}")
}
}

Getting the resource path of the java project from a custom gradle plugin

Trying to create a custom gradle plugin in java, how do i get the resources path from inside the task class?
public class MyCustomPlugin implements Plugin<Project> {
#Override
public void apply(Project project) {
project.getTasks().register("doStuff", CustomTask.class);
}
}
public class CustomTask extends DefaultTask {
// How do I get java project resources dir from here?
#Inject
public CustomTask(ProjectLayout projectLayout) {
directoryProperty = projectLayout.getBuildDirectory();
}
#TaskAction
public void execute() {
...
}
}
I would recommend to not get the directory inside the task, because the plugin that provides it might not be applied. Instead I would do it from within your plugin that registers the task, this way you can also ensure that the necessary plugin is actually applied. Gradle will display an error if the task is used without a value being assigned to the input that explains that nothing was assigned.
With the kotlin-dsl:
#CacheableTask
abstract class CustomTask : DefaultTask() {
#get:InputFiles
abstract val resources: FileCollection
//...
}
I cannot answer if #InputFiles is the right annotation for your use case, because I don't know what you want to do with the resource. Refer to the Gradle documentation for more information on the available annotations, and what they do.
plugins {
java
}
tasks.register<CustomTask>("customTask") {
resources.set(sourceSets.main.map { it.resources })
}
Notice the map {} which ensures that our task has a dependency on the processResources task, this is done automatically for us because we stick to the provider API of Gradle for everything.
Note that the resources are by default in one directory, but they don't have to be. This is why the resources are defined as SourceDirectorySet and not as Provider<Directory>. The same is true for anything that originates from the SourceSetContainer. It is easier to explain with Java source code: imagine you have Java and Kotlin, then you will have src/main/java and src/main/kotlin, hence, 2 directories. The former will have a **/*.java include filter, whereas the latter has a **/*.kt includes filter. If we just want to get all sources then we use sourceSets.main.map { it.java.sourceDirectories }, and if we want to get one of both it gets complicated. 😝
First, you'd have to ensure this is a Java project: either applying the "java" plugin from your plugin (project.getPluginManager().apply("java")), or only registering the task when the "java" plugin has been applied by the user (project.getPluginManager().withPlugin("java", ignored -> { project.getTasks().register(…); });).
You could then get the resources from the main source set:
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
// Use named() instead of get() if you prefer/need to use providers
SourceSet mainSourceSet = sourceSets.get(SourceSet.MAIN_SOURCE_SET_NAME);
SourceDirectorySet resources = mainSourceSet.getResources();
BTW, the best practice is to have tasks only declare their inputs and outputs (e.g. I need a set of directories, or files, as inputs, and my outputs will be one single file, or in one single directory) and have the actual wiring with default values be done by the plugin.
You could have the plugin unconditionally register the task, then conditionally when the "java" plugin is applied configure its inputs to the project resources; or conditionally register the task or unconditionally apply the "java" plugin, as I showed above.
You can access the sources through the project.sourceSets.
#Inject
public CustomTask(Project project) {
directoryProperty = project.projectLayout.getBuildDirectory();
sourceSet = project.sourceSets.main
}
See also the reference documentation here: https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_project_layout

how to run a groovy method from gradle task?

I am using
Gradle version 2.14
Groovy version 2.4.4
JVM: 1.8.0_121
I want to run a specific groovy method from a groovy class. How do I make associations with a groovy class from a gradle task ?
my task looks somewhat like this
task someTask << {
// Do something
// Call method, which returns a java.io.File
// Do something else
}
and my groovy class/method
File getSomeFile(String parameter) {
// Do something
// return an instance of java.io.File or maybe null, depending
}
So how do I call the method which takes a parameter and returns java.io.File ?
(hope this is not a dublicate, i looked around, not finding exactly what I need)
class Foo {
void bar() { println 'bar'; }
}
task someTask {
doLast {
new Foo().bar();
}
}
Gradle scripts ARE Groovy scripts, just do it as in any other Groovy script. Just make sure your class is in the classpath, e. g. by depending on the library that includes the file in builscript { dependencies {} }, or by stuffing the file into the buildSrc project of your Gradle project.

Running a task within a custom task in Gradle

I'm trying to write a custom Gradle plugin using Java. One of the things I'll need to do within this plugin is copy all the defined dependencies into a folder. I've found out how you can do this using a task in the build.gradle file:
task copyDeps(type: Copy) {
from configurations.runtime
into 'build/lib'
}
However, I'm struggling to figure out how I would run this task from within my own custom task. I've tried doing this:
public class MyTask extends DefaultTask {
#TaskAction
public void executeTask() {
Copy copyTask = new Copy();
copyTask.into(libFolder).from(getProject().getConfigurations().getByName("runtime").execute();
}
}
However, when I run this I get the exception:
Task of type 'org.gradle.api.tasks.Copy' has been instantiated directly which is not supported. Tasks can only be created using the DSL.
I understand what it is trying to say, but I haven't been able to find out I would be able to execute this task using the DSL from within Java.
You can't create tasks within tasks in Gradle. If you want to write a custom plugin with a task as you have described, the way to go is to write a custom plugin class and within that plugin class you declare a task of type Copy that does what you want to do. This could look like this:
class MyCustomPlugin extends Plugin<Project> {
void apply(Project project) {
project.tasks.create("copyDeps", Copy.class) {
from configurations.runtime
into 'build/lib'
}
}
}
Now, if you apply this plugin within your buildscript:
apply plugin:MyCustomPlugin
you automatically have a task named "copyDeps" of type Copy in your build.
One more thing:
Sometimes it can be convenient to do a simple copy operation in a custom task. This can be done using the project.copy util method. A task like this would look this
public class MyTask extends DefaultTask {
#TaskAction
public void executeTask() {
project.copy {
into(libFolder)
from(project.configurations.runtime)
}
}
}
With plain java it would look like this:
public class MyTask extends DefaultTask {
#TaskAction
public void executeTask() {
project.copy(new Action<CopySpec>() {
#Override
void execute(CopySpec copySpec) {
copySpec.into(libFolder);
copySpec.from(getProject().getConfigurations().getByName("runtime"));
}
});
}
}
One last thing:
You should never call Task#execute() your own. This method is considered to be internal API in Gradle and executing it directly causes unexpected behaviour. (for example it breaks Gradles' incremental build feature)

How to call a task separately in gradle

My build.gradle file looks like below.
apply plugin: 'java'
repositories {
maven {
mavenCentral()
}
dependencies {
compile "commons-logging:commons-logging:1.0.4",
"commons-codec:commons-codec:1.3"
}
jar {
manifest{
attributes ("Product-Name" : project.name, "${manifestSectionName}")
attributes ("Product-Display-Name" : project.description, "${manifestSectionName}")
}
}
task build1 {
sourceSets {
main {
java {
srcDirs = ['src/java/com/abc/xyz/dir1']
}
}
}
buildDir = 'op'
jar{
archiveName = 'build1.jar'
}
}
task build2 {
sourceSets {
main {
java {
srcDirs = ['src/java/com/abc/xyz/dir2']
}
}
}
buildDir = 'op'
jar{
archiveName = 'build2.jar'
}
}
So now I want to call individual task to build individual jar, the way we invoke individual targets in Ant.
So when I am calling it like : gw clean build build2
its building build2.jar in correct way, but when I am running it like: gw clean build build1, its still building build2.jar only.
I am very new to gradle, so not sure about this.
Its still building build2.jar only, I am not sure why its happening .. can someone help me here?
Note that both tasks are independent of each other.
When configuring build1 and build2, you're configuring the unique, shared, main sourceSet and the unique, shared, jar task. Since build2 is configured after build1, it overrides the configuration set by build1.
What you want instead is two additional tasks in the build, which both create a jar with a different content:
task build1(type: Jar) {
dependsOn classes
archiveName = 'build1.jar'
from(sourceSets.main.output) {
include '**/package1/**/*'
}
}
task build2(type: Jar) {
dependsOn classes
archiveName = 'build2.jar'
from(sourceSets.main.output) {
include '**/package2/**/*'
}
}
But that looks to me like bad design. If you want to generate different jars, then you should probably have several subprojects, all using the java plugin and not needing any configuration.

Categories