Execute Groovy script from Gradle without compiling Java - java

I have a Java project with Gradle.
Also I use Groovy to generate some class that will be used in Java code. Gradle executes script in separate task below:
task generateClass(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'generatorScript'
}
If I run this task, it first starts Java compilation, and only after that executes script. So if compilation failed, my generator script will not be executed. As it was mentioned, script generates one class, which my Java code is actually depends on, so, if not generated, Java will not be compiled. Vicious circle.
Script itself does not depend on some Java classes and is placed in separate sources directory:
/src
/main
/java
/...(java classes)
/groovy
generatorScript.groovy
It seems like nothing interferes me to execute script separately and independently from Java compilation.
How can I achieve that?

The problem is that you have the generator groovy script in the main sourcesets, and you try to compile this groovy script to use it as classpath for your JavaExec task. This is why compileJava task is executed, I guess.
You could do in another way, using groovy.ui.GroovyMain to execute your script, with following solution based on this link
configurations {
// a dedicated Configuration for Groovy classpath
groovyScript
}
dependencies {
// Set Groovy dependency so groovy.ui.GroovyMain can be found.
groovyScript localGroovy()
}
task generateClass(type: JavaExec) {
// Set class path used for running Groovy command line.
classpath = configurations.groovyScript
// Main class that runs the Groovy command line.
main = 'groovy.ui.GroovyMain'
// Pass your groovy script as argument of the GroovyMain main
// (can be improved)
args 'src/main/groovy/generatorScript.groovy'
}

Related

Use Scala (or java) method in Gradle build script

I have a Gradle build script which has to call a Scala (or Java) method in a Task.
currently, i have src/.../utils/lib.java
this file has a simple class with a static method that I would like to call in the build.gradle script.
but I have no idea how to import this file and use this method.
This really depends on how your gradle script is set up and what you are trying to accomplish. Without seeing it, it is hard to give a concrete all encompassing response. Here are the two most common methods I know of that would allow you to execute code in a gradle script.
1) To directly answer your response, to execute a static java method, it needs to be compiled first. If the rest of your build requires this to be executed, then you would need to structure this as a multi-project build.
https://docs.gradle.org/current/userguide/multi_project_builds.html
Assuming you have
apply plugin: 'java'
You would then be able to create a jar with the class containing your static method, and create a task that you can execute of type Exec or JavaExec that would execute this jar.
2) The easier and less complex approach:
Since gradle allows you to directly execute groovy code, if possible, I would try to move the logic from the static method into the gradle file. You can reference Objects and methods on the org.gradle.api to customize a lot of build actions.
https://docs.gradle.org/current/javadoc/
Here is an example from my build.gradle use to copy resources files after a compile step into the build directory before it is packaged into a jar.
compileJava {
doLast {
def f = file("src/main/java/resources/db/migration")
println "Copying SQL from {$f} to {$buildDir/db/migration}"
copy {
from file(f)
into file("$buildDir/db/migration")
include('*.sql')
}
}
}
This may not be the easy solution that you were looking for but I hope it gives you some good guidance.

Gradle: Multi-project dependency: Tasks of the same name executing together

I have a multi-project dependency in my gradle build, but there's a feature that's somewhat in my way. Whenever I call a task name that exists in both projects, it calls them both. I don't like that.
My directory structure is as follows:
[Root]
---->[projA]
----------->build.gradle
---->[projB]
----------->build.gradle
So I have projB dependent on projA in my code.
Say I have a task run in projB:
task run << {
println 'projB running'
}
And I also have a task run in projA:
task run << {
println 'projA running'
}
By calling gradle run, I would get
:run
projB running
:projA:run
projA running
Is there any way to prevent some of the tasks from having this dependency? Some of them, say clean is fine, but I'd prefer to have specific tasks separate (without having to change the naming scheme).
The equivalent of what I want can be achieved by doing either:
gradle run -x :projA:run
or
gradle :run
I want a solution that is within the build file, though.
Thanks!
That fact that projB declares a project dependency on projA is irrelevant for the behavior you are seeing. If you execute a task from the root project of a multi-project build Gradle will try to find the task in any of its subprojects with the requested name and execute it. This feature is called task execution matching. Given this default behavior there's no way Gradle could know which run task you mean when executing gradle run from the root project. I'd suggest you define what you want to execute on the command line as mentioned in my previous comment.
If you really wanted to add logic to your build script, then you could achieve it with the following code:
def taskRequests = gradle.startParameter.taskRequests
def runTaskRequest = taskRequests.find { it.args.contains('run') }
if (runTaskRequest) {
gradle.startParameter.excludedTaskNames = [':projA:run']
}
The code provided would prevent the execution of the run task for the subproject projA if you execute the command gradle run. Keep in mind that it would also exclude :projA:run if you navigate to the projA subdirectory and run the same command. If you still want to be able to execute the run task from the subdirectory, then you'll have to build in additional logic.

How to execute command line tools with projects built with gradle?

Running a Java application built with Gradle requires adding to the classpath a directory for each individual library, as it stores them in individual directories.
Therefore, when you look at the command to launch the application in IntelliJ you can easily see a whole screen filled with classpath dependencies.
This is fine for IntelliJ because it can figure them out automatically, but I want to be able to run my command line tool in the terminal, writing arguments there instead of editing my run configuration each time I want to change anything. How can I do so without pasting a whole screen of machine-specific JAR dependencies from the IDE?
Is it possible to do it in a development environment without creating a giant JAR file bundling all the libraries?
Take a look at JavaExec task. You can create a custom task as such:
task customRun(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = "fully.qualified.name.of.your.main"
args = ["100", "1000" ...] // the command line options for your tool
jvmArgs = [ ... ] // additional JVM args you might need
}
Then you can invoke it using gradle customRun. If you want to be able to provide the command line arguments, I would suggest using gradle properties:
gradle -PcustomRunArgs="100 1000" customRun
and modifying the task to grab the arguments:
task ... {
...
if (project.hasProperty('customRunArgs')) {
args = customRunArgs.split(' ')
}
...
}

Custom Task needs to be executed when gradle build is executed

I am working on Java/JNI project. Under parent, I have different modules for java and C codebase.Java module needs to generate JNI header file. Since, I couldn't find any existing task/plugin that supported javah, so I wrote my custom task for javah to generate JNI interface. So, when I do
gradle javah
I am getting the desired output.
However, I want that whenever I invoke gradle build, it should also execute javah task once either after classes are generated or build task ends.
Also, is it possible to generate the shared libraries in such a mixed project when I just do gradle build? Currently, I have to do gradle <project-name>SharedLibrary
Part 1: You can use finalizedBy on task1 to execute task2 after task1 completes. For your case, you can try the following:
// 'javah' will be executed after 'classes' task executes.
classes.finalizedBy javah
// Make 'javah' task depend on 'classes' task,
// so that when 'classes' task fails, 'javah' is not executed.
javah.dependsOn classes
// Make 'build' depend on 'javah' task,
// so that executing 'build' task automatically executes 'javah'
build.dependsOn javah
Part 2: You can use dependsOn to wire up the <project-name>SharedLibrary task as follows:
build.dependsOn "${project.name}SharedLibrary"
// Assuming the SharedLibrary task needs to depend on 'javah' task
tasks["${project.name}SharedLibrary"].dependsOn javah
I'm assuming that the the SharedLibarary task name is dynamic, hence using a slightly different syntax for that task.

Clojure and Java source in the same NetBeans project

Has anyone successfully created a NetBeans project that combines Clojure and Java source?
I have projects where the driver program (startup, gui, user prefs, etc.) are in Java, but the logic is in Clojure. At the moment, I compile the Clojure code to a jar in one project and import it as a library in a separate Java project. It would be convenient if all the source could be combined in one single NetBeans project.
Has anyone come up with a method to do this?
One possible solution is to modify your NetBeans Java project's Ant script (build.xml in your root directory) to have it .
By default, NetBeans creates several placeholder Ant targets in the root project directory's build.xml for you to override to automate tasks beyond the standard build process (such as compiling other languages to use their libraries in your current project). By overriding one of the placeholder targets in that build script such as "-pre-compile" you could write a simple target to call the Clojure compilation process using the Ant "exec" task and place all the resulting class files (or JAR) in the appropriate build directory.
If you do this frequently, you could define an Ant extension (via a macro or Ant plugin) so you don't have to modify the build.xml each time.
I use the RT method. I put my Clojure code into a script file that I include and process at startup:
try {
RT.loadResourceScript("com/mydomain/app/clojure_scripts.clj"); // Initialize Clojure script processor with our script
} catch (Exception e) {
Util.logException(e, "Unable to run Clojure initialization script.");
}
Then, since my main logic is in Java and I'm only calling out to Clojure for calculations, I use some glue code to map the calls for me:
/*
* Class to wrap Clojure scripts with Java friendly methods.
*/
public class Clojure {
private static final String ns="com.mydomain.app";
public static double calculate(final double size, final double otherVar) {
Var report=RT.var(ns, "calculate");
return (Double) report.invoke(size, otherVar);
}
};

Categories