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.
Related
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
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) {
// ...
}
I have a a Java program which reads a System property
System.getProperty("cassandra.ip");
and I have a Gradle build file that I start with
gradle test -Pcassandra.ip=192.168.33.13
or
gradle test -Dcassandra.ip=192.168.33.13
however System.getProperty will always return null.
The only way I found was to add that in my Gradle build file via
test {
systemProperty "cassandra.ip", "192.168.33.13"
}
How Do I do it via -D
The -P flag is for gradle properties, and the -D flag is for JVM properties. Because the test may be forked in a new JVM, the -D argument passed to gradle will not be propagated to the test - it sounds like that is the behavior you are seeing.
You can use the systemProperty in your test block as you have done but base it on the incoming gradle property by passing it with it -P:
test {
systemProperty "cassandra.ip", project.getProperty("cassandra.ip")
}
or alternatively, if you are passing it in via -D
test {
systemProperty "cassandra.ip", System.getProperty("cassandra.ip")
}
Came across this very much problem, except i don't want to list all properties given on the commandline in the gradle script again. Therefore i send all system properties to my test
task integrationTest(type: Test) {
useTestNG()
options {
systemProperties(System.getProperties())
}
}
I had a case where I needed to pass multiple system properties into the test JVM but not all (didn't want to pass in irrelevant ones). Based on the above answers, and by using subMap to filter the ones I needed, this worked for me:
task integrationTest(type: Test) {
// ... Do stuff here ...
systemProperties System.getProperties().subMap(['PROP1', 'PROP2'])
}
In this example, only PROP1 and PROP2 will be passed in, if they exist in gradle's JVM.
Here's a variant that passes numerous project properties to the test JVM as system properties. I prefer project properties over system properties to increase flexibility.
task intTest(type: Test) {
systemProperties project.properties.subMap(["foo", "bar"])
}
Which may be passed on the command-line:
$ gradle intTest -Pfoo=1 -Pbar=2
And retrieved in your test:
String foo = System.getProperty("foo");
Here is something that worked for me
//in build.gradle file
tasks.withType(Test) {
systemProperties = [
ip: System.getProperty('ip', '192.168.33.13'),
]
}
task integrationTests(type: Test){
useTestNG()
}
Suppose if you are using TestNG, you can add the annotation #Parameters as shown below
public class IpAddress {
#Test
#Parameters("ip")
public void printIpAddress(String ip) {
System.out.println(ip);
}
}
Now you are good to execute a gradlew command
./gradlew clean -Dip="xx.xx.xx.xx" integrationTests --tests "IpAddress"
If you want to use #DataProvider to pass the test data, you can pass it like below and execute the same above gradle command to run the test
public class IpAddress {
#DataProvider(name = "GetIP")
private static Object[][] getIp() {
return new Object[][]{
//if -Dip is not provided in command, then by default it gets the value assigned in build.gradle file i.e.'192.168.33.13'
{System.getProperty("ip")},
};
}
#Test(dataProvider = "GetIP")
public void printIpAddress(String ip) {
System.out.println(ip);
}
}
So I've stumbled on that issue today as well, and what worked for me was the following:
ext.env='prod'
test {
systemProperty 'env', System.properties['env'] ?: "${env}"
println "# test environment: " + systemProperties['env']
...
}
I'm calling my test task using -Penv=dev and I get my 'dev' value in my print, or 'prod' if I do not send any value, which is the expected behavior for me.
Value is also accessible on java side, using System.getProperty("env").
My conclusion on the matter is that input value (parameter) is actually stored under System, making it accessible through either System.properties['env'] or System.getProperty("env"), whereas output (system property) is stored in a systemProperties array, making it readable through systemProperties['env'].
I am trying to get parameter names of class inside my android application. to supply input to a help() method which will print all methods available and its parameter type and names. To get the parameter name, i am trying to use paranamer jar. I added paranamer.jar as a module library and i am able to import and use it. But have no idea on how to plug into gradle in order to generate parameter name data. Anyone any help ?
Java code-
public void help() {
Method[] declaredMethods = myclass.class.getDeclaredMethods();
Paranamer paranamer = new CachingParanamer();
for (Method declaredMethod : declaredMethods) {
String[] parameterNames = paranamer.lookupParameterNames(declaredMethod, false);
//process paranamer.
}
}
Use their Ant task, Ant is neatly integrated in Gradle: https://docs.gradle.org/current/userguide/userguide_single.html#sec:using_custom_ant_tasks
Should be something like
configurations {
paranamer
}
dependencies {
paranamer 'com.thoughtworks.paranamer:paranamer-ant:2.8'
}
compileJava.doLast {
ant.taskdef name: 'paranamer',
classname: 'com.thoughtworks.paranamer.ant.ParanamerTask',
classpath: configurations.paranamer.asPath
ant.paranamer(classdir: destinationDir) {
source.addToAntBuilder ant, 'fileset', FileCollection.AntType.FileSet
}
}
I didn't test this, I don't use paranamer, I just made this up from the docs and source. destinationDir and source are not to be replaced by actual strings, but are the fields of the compile task.
I made this as an additional action to the compileJava task instead of an own task, because it modifies the class files produced by the compile task in-place and with a separate task it would involve copying the class files somewhere, running the paranamer and then caring that the modified files are packaged instead of the original files. If the paranamer task would modify the result of the compileJava task in-place, it would break incremental building, as then the compileJava task would always be out-of-date and run every time. The way I suggest it, it is part of the compileJava task and thus is done before the up-to-date check logic and thus should work flawlessly in this regard.
If you have multiple source sets or custom JavaCompile tasks and want to modify all of them, it would instead something like:
tasks.withType(JavaCompile) {
it.doLast {
...
}
}
I'm need to create an api for what will be a suite of primarily java applications. I need to do this quickly however, and at the moment I'm most comfortable writing in groovy. My question is, can I create this api in groovy, and use it in java applications without any special hoops?
That is, can I create a jar from my groovy classes and methods, and have the java applications use this jar as though it were created in java?
Yes, you can. Just compile using gradle, ant, whatever, to generate a jar. The resulting jar will depend on Groovy runtime jar and modules, if any. Groovy compiles to bytecode, so Java doesn't really know the differente. Only dynamic stuff won't work.
MyLib.groovy:
class MyLib {
def string
MyLib(string) {
this.string = string
}
String yell() {
string.toUpperCase() + "!!!"
}
}
Compiled:
$ groovyc MyLib.groovy
Writing the Java class which uses the Groovy one, TestMyLib.java:
public class TestMyLib {
public static void main(String[] args ) {
MyLib my = new MyLib("john doe");
System.out.println(my.yell()); // prints JOHN DOE!!!
}
}
Compiling:
$ javac TestMyLib.java
And execution:
$ java -cp $GROOVY_HOME/embeddable/groovy-all-2.1.8.jar:. TestMyLib
JOHN DOE!!!