ALL,
Lets say I have a JAVA project with the gradle.
In the buidl.gradle file I have a property defined like this:
packageName = "svc.pvtbroker" //name of the package
Is there a simple way I can use this "packageName" inside the Java source code?
TIA!!
You can generate either a java file or a resource and add the generated folder to either the resources or compiled sources.
Eg: let's say we wanted the packageName available via a static method at runtime
task generateJava {
// set inputs/outputs for up to date checks
inputs.property('packageName', project.property('packageName'))
outputs.dir "$buildDir/generated/java"
doLast {
File f = file("$buildDir/generated/java/GradleProperties.java"
f.parentFile.mkdirs()
f.text =
"""
public class GradleProperties {
public static String getPackageName() {
return \"${packageName}\";
}
}
"""
}
}
// add the dir to the java sources
sourceSets.main.java.srcDir "$buildDir/generated/java"
// wire the task into the DAG
compileJava.dependsOn generateJava
Inside .app gradle declare your property like this:
defaultConfig {
...
buildConfigField("String", "API_KEY", "123456789")
}
then import your property in your java source code in this way:
import static yourpackage.BuildConfig.API_KEY;
SUGGEST
I also declare my keys inside gradle.properties
API_KEY_INSIDE_GRADLE_PROPERTIES="123456789"
in this way you can use BuildConfigField like this:
defaultConfig {
...
buildConfigField("String", "API_KEY", API_KEY_INSIDE_GRADLE_PROPERTIES)
}
Hope it helps.
Related
I am new to Gradle and trying to migrate an existing system build from ant to Gradle.
As part of this I need to run a java program on every file in a directory. Directory contains xml files and the java code will parse and convert .xml to .java files (and these Java files would be build to generate class and package in final jar) after performing some business specific transformation.
below is a function I wrote in Gradle
private runJavaFile(String dirPath) {
FileTree tree = fileTree(dir: dirPath, include: '**/*.xml')
tree.each {
def xmlfile = it.path
def javaFile = it.path.replaceFirst(".xml", ".java")
javaexec { //// getting error on this line
classpath configurations.all
main = 'XmlToJavaParser'
args = ["$xmlfile", "$javaFile", 'Java']
}
}
}
I am calling this function from a Gradle task by passing the dir path which contains the xml files to be parsed.
While running the task, I am getting below error:
> Resolving configuration 'apiElements' directly is not allowed
Any help would be appreciated.
Let me know if any more information is needed.
In Gradle, a configuration represents a group of artifacts and their dependencies. You typically have several configurations depending on what you want to do. For instance, you could have one where you declare which dependencies are needed for compilation, which are only needed at runtime, or which are needed for running a particular Java application.
In your case, you are saying that the classpath to the XmlToJavaParser class is "all configurations combined" and that doesn't really make sense. You are also not allowed to do that as some configurations from the Java plugin are not resolvable like this, which is why you get an error.
So to fix it, you should declare your own configuration for XmlToJavaParser. You can then declare dependencies for it like you normally do. Example (using the Groovy DSL):
configurations {
xmlJavaParser {
canBeResolved = true
canBeConsumed = false
}
}
dependencies {
xmlJavaParser "org.example:xml-java-parser:1.0" // or whatever you need
}
private runJavaFile(String dirPath) {
// ...
javaexec {
classpath = configurations.xmlJavaParser // The configuration is referenced here
main = 'XmlToJavaParser'
args = ["$xmlfile", "$javaFile", 'Java']
}
}
There are also other ways to go about it. But the main point is to not use configurations.all as a classpath.
I have a custom task that required to check if the current build is debug or release, and then use the corresponding classpath.
The normal task definition:
task custom_java_task(type: JavaExec) {
classpath "build/intermediates/javac/debug/classes/"
main = "com.testapp.JavaTaskTest"
args "test", "${projectDir}"
}
The task definition needs to check BuildConfig.DEBUG and set the different value for classpath:
task custom_java_task(type: JavaExec) {
classpath BuildConfig.DEBUG ? "build/intermediates/javac/debug/classes/" : "build/intermediates/javac/release/classes/"
main = "com.testapp.JavaTaskTest"
args "test", "${projectDir}"
}
The build will fail with the following error:
Could not get unknown property 'BuildConfig' for task ':app:custom_java_task' of type org.gradle.api.tasks.JavaExec.
Thanks.
BuildConfig is generated set of properties that cannot be used from within gradle scripts. It is actually generated based on your build.gradle
But there are some ways to achieve what you want for example like this:
First in project level build.gradle under buildscript you can define the function / method and name ti however you want (eg. doStuff)
buildscript {
...
ext.doStuff = { buildType ->
// do stuff based on buildType param
}
...
}
Than in your module level build.gradle, simply do
android {
...
buildTypes {
debug {
...
doStuff("debug")
}
release {
...
doStuff("release")
}
}
...
}
Now this is just to give you a hint on the abilities of build.gradle files, you can build further from this.
Cheers
I have a such case. I need to save curent date after every release build with gradle. Is there any possibility to save date to gradle.properties file that I can read it in the next build job?
My files:
gradle.properties:
version=0.0.1
date=
build.gradle:
task changeDate() {
file = new File("changelogs/CHANGELOG_RELEASE_FROM_"+getDate()+".md");
project.setProperty("date",getDate());
}
It dosent work and it doesn't save date variable into gradle.properties.
So I wish that I can have a date from release in my gradle.properties file:
gradle.properties:
version=0.0.1
date=12.04.2019
The methods getProperty, findProperty and setProperty are not directly related to the gradle.properties file. Instead, they provide access to properties in the scope of the Project instance against which the build.gradle gets evaluated. This scope includes a lot of different properties, among them so-called extra properties (coming from the gradle.properties files).
However, Gradle provides a task type for this functionality called WriteProperties. Just specify the target file and define some properties:
task changeDate(type: WriteProperties) {
outputFile = file('gradle.properties')
property 'date', getDate()
}
You can try to do something like:
import java.time.*;
task rel {
doLast {
ant.propertyfile(file: "gradle.properties") {
entry( key: "date", value: LocalDateTime.now())
}
}
}
Suppose, rel is your release task or any other task, which execution means, that you release was made. You have to add to it's configuration a doLast closure to run some code after task is executed. In this closure you are modifying some property in properties file.
LocalDateTime and it's import are added just for example, you can use another method to get current date fo sure.
In your case it could look like:
task changeDate() {
doLast {
ant.propertyfile(file: "gradle.properties") {
entry( key: "date", value: LocalDateTime.now())
}
}
}
But you have to make your changeDate executed somehow, if it's not.
Gradle provides a default App.java java source file and its test class at the time of creation of project.
I created java class under main:
/src/main/java/some/package/algo/Sort.java
I would like to create a test class that corresponds to it.
/test/main/java/some/package/algo/SortTest.java
I can do that manually but is it possible that Gradle or any gradle command does it for me whenever I create a new regular Java Source file.
I am not using IDE and IDE provide such options.
Similarly any gradle command, If I have a test file than Gradle create java source file under main source.
task createTestForSource {
inputs.dir 'src/main/java'
outputs.dir 'src/test/java'
doLast {
fileTree('src/main/java').visit { FileVisitDetails fvd ->
if (!fvd.directory) {
String sourcePath = fvd.relativePath.asPath
String testPath = sourcePath.replace('.java', 'Test.java')
File testFile = file("src/test/java/$testPath")
if (!testFile.exists()) {
testFile.parentFile.mkdirs()
testFile.text = // do your magic here
}
}
}
}
}
I would like to use the Gradle "application" plugin to create startScripts for a second mainClass. Is this possible? Even if the application plugin doesn't have this functionality built in, is it possible to leverage the startScripts task to create a second pair of scripts for a different mainClass?
Add something like this to your root build.gradle:
// Creates scripts for entry points
// Subproject must apply application plugin to be able to call this method.
def createScript(project, mainClass, name) {
project.tasks.create(name: name, type: CreateStartScripts) {
outputDir = new File(project.buildDir, 'scripts')
mainClassName = mainClass
applicationName = name
classpath = project.tasks[JavaPlugin.JAR_TASK_NAME].outputs.files + project.configurations.runtimeClasspath
}
project.tasks[name].dependsOn(project.jar)
project.applicationDistribution.with {
into("bin") {
from(project.tasks[name])
fileMode = 0755
}
}
}
Then call it as follows either from the root or from subprojects:
// The next two lines disable the tasks for the primary main which by default
// generates a script with a name matching the project name.
// You can leave them enabled but if so you'll need to define mainClassName
// And you'll be creating your application scripts two different ways which
// could lead to confusion
startScripts.enabled = false
run.enabled = false
// Call this for each Main class you want to expose with an app script
createScript(project, 'com.foo.MyDriver', 'driver')
I combined parts of both of these answers to arrive at the relatively simple solution:
task otherStartScripts(type: CreateStartScripts) {
description "Creates OS specific scripts to call the 'other' entry point"
classpath = startScripts.classpath
outputDir = startScripts.outputDir
mainClassName = 'some.package.app.Other'
applicationName = 'other'
}
distZip {
baseName = archivesBaseName
classifier = 'app'
//include our extra start script
//this is a bit weird, I'm open to suggestions on how to do this better
into("${baseName}-${version}-${classifier}/bin") {
from otherStartScripts
fileMode = 0755
}
}
startScripts is created when the application plugin is applied.
You can create multiple tasks of type CreateStartScripts and in each task you configure a different mainClassName. for convenience, you can do this in a loop.