Gradle Tooling API Introduction
Gradle has developed an API to query the Gradle project artifacts like taskNames, dependencies, etc. It allows users to execute builds programatically. Read on to learn more.
Join the DZone community and get the full member experience.
Join For FreeGradle has developed an API to query the Gradle project artifacts like taskNames, dependencies, etc. It allows users to execute builds programatically.
According to official Gradle Website documentation:
"The Tooling API provides a programmatic interface to Gradle, allowing the execution of builds and querying of the build model"
Features of Tooling API
- You can query Gradle for the details of a build, including: the project hierarchy, the project dependencies, external dependencies (including source and Javadoc jars), source directories, and tasks of each project.
- You can execute a build and listen to stdout and stderr logging and progress (e.g. the stuff shown in the status bar when you run on the command line).
- Tooling API can download and install the appropriate Gradle version, similar to the wrapper. Bear in mind that the tooling API is wrapper aware, so you should not need to configure a Gradle distribution directly.
- The implementation is lightweight, with only a small number of dependencies. It is also a well-behaved library, and makes no assumptions about your classloader structure or logging configuration. This makes the API easy to bundle in your application.
While you can get more details about the theory on the Gradle website this article is about practical implementation of this API. I would also like to discuss the approach I took to learn this API.
I thought it was really simple task to write a sample "Hello World" program, but initially I faced a few issues. I had to find correct dependencies. As one jar has a dependency on another I received lots of this:
ClassNotFoundException
What to Expect From This Article
My aim of writing this article is to provide enough information/examples which will make it easy for you to work with this API successfully.
Gradle Dependencies
You will require a minimum of the below dependencies to start writing your first example.
gradle-base-services-2.1.jar
gradle-core-2.1.jar
gradle-messaging-2.1.jar
gradle-resources-2.1.jar
gradle-tooling-api-2.1.jar
gradle-wrapper-2.1.jar
guava-jdk5-17.0.jar
slf4j-api-1.7.5.jar
Let's write our first progam.
Get the TaskNames defined for project
Assuming build.gradle for project is defined as:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'war'
defaultTasks 'clean', 'build', 'war', 'copyDepJars'
sourceCompatibility = 1.6
repositories {
mavenCentral()
jcenter()
}
dependencies {
compile 'org.springframework:spring-core:4.2.3.RELEASE'
compile 'org.springframework.amqp:spring-rabbit:1.5.2.RELEASE'
}
task copyDepJars(type: Copy) {
from configurations.compile
into 'C:\\Users\\athakur\\Desktop\\lib'
}
This program finds all tasks defined for projects.
public class GradleConnector {
private org.gradle.tooling.GradleConnector connector;
public GradleConnector(String gradleInstallationDir, String projectDir) {
File gradleInstallationDir1 = new File(gradleInstallationDir);
connector = org.gradle.tooling.GradleConnector.newConnector();
connector.useInstallation(gradleInstallationDir1);
connector.forProjectDirectory(new File(projectDir));
}
public String getGradleVersion() {
return GradleVersion.current().getVersion();
}
public List<String> getGradleTaskNames() {
List<String> taskNames = new ArrayList<>();
List<GradleTask> tasks = getGradleTasks();
return tasks.stream().map(task -> task.getName()).collect(Collectors.toList());
}
public List<GradleTask> getGradleTasks() {
List<GradleTask> tasks = new ArrayList<>();
ProjectConnection connection = connector.connect();
try {
GradleProject project = connection.getModel(GradleProject.class);
for (GradleTask task : project.getTasks()) {
tasks.add(task);
}
} finally {
connection.close();
}
return tasks;
}
}
Let's talk about this sample program.
Class GradleVersion gives us the version number of gradle installed. It refers to the directory mentioned in useInstallation() method of GradleConnector class.
connector.useInstallation(gradleInstallationDir)
GradleConnector
This is an important class of tooling API.
connector.forProjectDirectory(new File(projectDir));
This method allows us to set the Gradle project directory for which we need to query using the Gradle API. We can connect to an external project or to the current one. To be able to connect with current project you should use:
connector.forProjectDirectory(".");
I think it's a great feature, enabling you to query/build a current project or any project which is external to your program.
Getting a connection to the project:
ProjectConnection connection = connector.connect();
try {
GradleProject project = connection.getModel(GradleProject.class);
for(GradleTask task : project.getTasks()){
tasks.add(task);
}
} finally {
connection.close();
}
Calling connect() method gives you the connection(ProjectConnection) object .
GradleProject has method getTasks(); which returns to you all the tasks defined for a project.
For example, if you call getGradleTaskNames() Method, you will get list of TaskNames equivalent to:
Arrays.asList("spring-core-4.2.3.RELEASE.jar",
"spring-rabbit-1.5.2.RELEASE.jar","commons-logging-1.2.jar",
"spring-messaging-4.2.2.RELEASE.jar","spring-retry-1.1.2.RELEASE.jar",
"spring-amqp-1.5.2.RELEASE.jar","spring-tx-4.2.2.RELEASE.jar",
"http-client-1.0.0.RELEASE.jar","spring-web-4.2.2.RELEASE.jar",
"amqp-client-3.5.6.jar","spring-context-4.2.2.RELEASE.jar",
"spring-beans-4.2.2.RELEASE.jar","httpclient-4.3.6.jar",
"jackson-databind-2.5.1.jar","spring-aop-4.2.2.RELEASE.jar",
"spring-expression-4.2.2.RELEASE.jar","httpcore-4.3.3.jar",
"commons-codec-1.6.jar","jackson-annotations-2.5.0.jar",
"jackson-core-2.5.1.jar","aopalliance-1.0.jar")
Build a Gradle Project
Add the below method in GradleConnector class to build the project.
public boolean buildProject()
{
ProjectConnection connection = connector.connect();
BuildLauncher build = connection.newBuild();
try {
build.run();
}finally {
connection.close();
}
return true;
}
By default, it will execute all the tasks defined in the build.gradle file.
If you want to execute specific tasks use the method below.
public boolean buildProject(String... tasks) {
ProjectConnection connection = connector.connect();
BuildLauncher build = connection.newBuild();
build.forTasks(tasks);
try {
build.run();
}finally {
connection.close();
}
return true;
}
Note: Dont forget to close the connection.
I have shared the sample working project on Github https://github.com/ShirishkumarBari/LearnGradleToolingApi
Please feel free to download it and provide any suggestions you may have.
I plan on adding more examples and explanations in the next article... until then, stay tuned.
Opinions expressed by DZone contributors are their own.
Comments