Providing main-class attribute through AntBuilder in a gradle script - java

Is there a way to specify the main-class of the jar in its manifest file as a parameter in Groovy's AntBuilder?
def jAnt = project.createAntBuilder();
jAnt.jar(
basedir: build_dir + "/classes", //I have only one class with the main method in it
destfile: build_dir + "/jar/test-jar.jar"
)
I just want to specify the main class here while creating the jar.

all documentation about ant tasks: https://ant.apache.org/manual/anttaskslist.html
and for jar task there are a lot of examples including Main-Class specification
you just need to create corresponding groovy-builder code
def ant = new AntBuilder()
def build_dir = "/11/git/myprj/build"
ant.jar( basedir: "${build_dir}/classes", destfile: "${build_dir}/test-jar.jar"){
manifest{
attribute(name: "Built-By", value: "me, myself" )
attribute(name: "Main-Class", value: "myPackage.MyClass" )
}
}

Related

Get module path not root path in Java

I have a multi-module Java(Spring) project, which build by Gradle 6.7.1. And I use in Jetbrain IDEA to develop. The file Structure like this:
root
|--orm
| +---hibernates
|
|--web
|--mvc
|--rest
And then, I have tried some codes in my module project like below, what I get all are root path (/home/user/IdeaProjects/root/), not module path (/home/user/IdeaProjects/root/web/mvc). How can I get module path (/home/user/IdeaProjects/root/web/mvc) ?
new File("").getAbsolutePath()
Assuming for instance that your mvc project is setup like this in setting.gradle, in the root folder :
include 'mvc'
project(':mvc').projectDir = new File('./web/mvc')
Then, to get the path /home/user/IdeaProjects/root/web/mvc, just try this :
println project(':mvc').projectDir
Will prints :
/home/user/IdeaProjects/root/web/mvc
based on the answer of #ToYonos. We can do that by this:
settings.gradle gets the project path of every module.
write a key value into the info.properties in every module.
Spring Project read this properties file.
Code
Because struct of my project is:
root
|--orm
| +---mybatis
| +---jpa
| +---...
|--web
+--mvc
+--rest
+--...
So, I should loop twice to get the module name. And I exclude project without build.gradle.
file("${rootDir}").eachDir {
it.eachDirMatch(~/.*/) {
if (it.list().contains("build.gradle")) {
def moduleName = "${it.parentFile.name}:${it.name}"
println " ${moduleName}"
include moduleName
}}}
And then, read and write info.properties.
import java.nio.file.Paths
// read
def project_dir = project(":${moduleName}").projectDir
def propFile = Paths.get("${project_dir}", "src", "main","resources","info.properties").toFile()
propFile.createNewFile()
Properties props = new Properties()
propFile.withInputStream {
props.load(it)
}
// write
props.setProperty("project.dir","$project_dir")
props.store propFile.newWriter(), null

gradle javaexec error "'apiElements' directly is not allowed"- Gradle 5.4.1

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.

How can it be that a file with full file path Can Not be found?

I have a few lines of a Gradle script and with some Groovy methods that I want to use as a base for testing a few ideas around project testing and configuration. There are existing scripts involved that need to use the (Java) construct: File (as opposed to the Gradle file() method).
The script runs perfectly on the command line and in Netbeans as long as I supply the complete Absolute File Path to the Properties.load() call.
Later, when run build (again in Netbeans) using a legal relative path and file name my little function fails to find the the file (at all!). That can happen. But in this case; the Java File.getAbsolutePath() method show the identical string in all cases. Working and the Fail case. I prepared this using Linux. The results are produced on Windows 10.
There must be a reason. I'm blowed if I can see what it could be at this point. The Gradle,
Working with Files section
says relative file paths are OK.
Java - Writing System Properties
System.setProperty()
I myself was a little dubious about using user.dir - However the docs seem to back it up, been there since Java 1.2
It works not only with Gradle; in Java and Groovy too.
Same as -Duser.dir=pathString
Failing output:
============ project ============
Gradle version: 3.4.1
Groovy version: 2.4.7
Java version: 1.8.0_121
Root project: 'try'
project dir: '/home/projects/sandbox/lab/gradle-lab/try-gradle'
cwd: '/home/projects/sandbox/lab/gradle-lab/try-gradle'
===================================
xxxxxxxxxxxxxxxxx[ loadProperties testing ]xxxx
cwd: '/home/projects/sandbox/lab/gradle-lab/try-gradle'
user.dir: '/home/projects/sandbox/lab/gradle-lab/try-gradle' ...
loading: 'common.properties' ...
loading: '/home/projects/sandbox/lab/gradle-lab/try-gradle/common.properties' ...
* No Such File: '/home/projects/sandbox/lab/gradle-lab/try-gradle/common.properties'.
xxxxxxxxxxxxxxxxx[ loadProperties end ]xxxx
Working output:
xxxxxxxxxxxxxxxxx[ loadProperties testing ]xxxx
cwd: '/home/projects/sandbox/lab/gradle-lab/try-gradle'
user.dir: '/home/projects/sandbox/lab/gradle-lab/try-gradle' ...
loading: '/home/projects/sandbox/lab/gradle-lab/try-gradle/common.properties' ...
loading: '/home/projects/sandbox/lab/gradle-lab/try-gradle/common.properties' ...
'ext.zzz' => "ext.zzz"
'zzz' => "zzz"
xxxxxxxxxxxxxxxxx[ loadProperties end ]xxxx
The Gradle build.gradle script is quite simple with a few lines to report on the runtime environment and software versions, etc.
build.gradle script:
import org.gradle.api.artifacts.*
System.setProperty( "user.dir", project.rootDir.toString() )
/****
* try-s project
*****/
println "";
apply plugin: 'base' // To add "clean" task to the root project.
println "\n ============ project ============";
println "Gradle version: "+ gradle.gradleVersion;
println "Groovy version: "+ GroovySystem.version;
println "Java version: "+ System.getProperty("java.version");
println "";
println "Root project: '${project.rootProject.name}'";
// println " root dir: '${project.rootDir}'";
println " project dir: '${project.projectDir}'";
println " cwd: '${(new File(".")).getCanonicalPath()}'";
// println " user dir: '${System.getProperty("user.dir")}'";
println "";
println " ===================================\n";
println " xxxxxxxxxxxxxxxxx[ loadProperties testing ]xxxx"
println ""
// Does Not Work:
// File.exists() --> false
//
loadProperties( "common.properties" );
// Works - fully qualified file path:
// File.exists() --> true
// and then loads properties from the file
//
loadProperties( "/home/projects/sandbox/lab/gradle-lab/try-gradle/common.properties" );
// Works - using project.rootDir property
//
loadProperties( "${project.rootDir}/common.properties" );
// Works - using a path relative to the Netbeans start directory
// Only works when `System.user.dir` has the
// same value as the start directory
// Obviously the path must be relative to
// Netbeans start-up directory -- Likely
// to change for different locations, etc.
//
loadProperties( "../../../sandbox/lab/gradle-lab/try-gradle/common.properties" );
println ""
println " xxxxxxxxxxxxxxxxx[ loadProperties end ]xxxx"
loadProperties() function:
private def loadProperties( String fileName )
{
File propFile = new File( fileName );
Properties fileProps = new Properties( );
// Check current directory
//
println " cwd: '${(new File(".")).getCanonicalPath()}'";
println " user.dir: '${System.getProperty("user.dir")}' ...";
println " loading: '${fileName}' ...";
println " loading: '${propFile.getCanonicalPath()}' ...";
println "";
if( propFile.exists() )
{
InputStream propStream = new FileInputStream( propFile ); // fileName );
fileProps.load( propStream );
fileProps.each { prop, val ->
println " '${prop}' => \"${val}\"";
}
}
else {
println " * No Such File: '${propFile.getAbsolutePath()}'."
}
} //loadProperties
Unfortunately without the if( propFile.exists() ) check Gradle reports an excepton: FileNotFoundException (oddly enough).
Looking at the output of the propFile.getAbsolutePath() and either the Fully Qualified file name string or the rootDir+"common.properties version of events -- All Four scenarios show the identical file-path-name string:
'/home/projects/sandbox/lab/gradle-lab/try-gradle/common.properties'
For me the bottom line is, How May two Identical File Paths be processed and ONE of FOUR, just one valid file pathname is Not Found by the JVM / Gradle partnership.
ps.
I already know the Gradle plugin has a bug concerning Not starting with the project dir as the current directory. By choice (apparently). I fix that with user.dir setting -- Unfortunately commenting that line makes no difference to the results. As long as the paths are correct.
Quite surprising. It is working.
build.gradle:
System.setProperty( "user.dir", project.rootDir.toString() )
apply plugin: 'base' // To add "clean" task to the root project.
println " user dir: ${System.getProperty('user.dir')}"
loadProperties('common.properties')
println "ends"
def loadProperties(file){
def properties = new Properties()
def propertiesFile = new File(file)
if( propertiesFile.exists() ) println 'file exists'
propertiesFile.withInputStream {
properties.load(it)
}
println properties
}
Output is seen as expected
$ gradle
Starting a Gradle Daemon (subsequent builds will be faster)
user dir: /home/rsettine/Documents/gradle
file exists
{abc=1, test=1}
ends
:help
Welcome to Gradle 3.3.
To run a build, run gradle <task> ...
To see a list of available tasks, run gradle tasks
To see a list of command-line options, run gradle --help
To see more detail about a task, run gradle help --task <task>
BUILD SUCCESSFUL
Total time: 8.263 secs

How to execute a main class in a jar from gradle using the 'java' command

I have these files under the <project_root> folder:
./build.gradle
./build/libs/vh-1.0-SNAPSHOT.jar
./libs/groovy-all-2.1.7.jar
./src/main/groovy/vh/Main.groovy
In the build.gradle file, I have this task:
task vh( type:Exec ) {
commandLine 'java -cp libs/groovy-all-2.1.7.jar:build/libs/' +
project.name + '-' + version + '.jar vh.Main'
}
The Main.groovy file is simple:
package vh
class Main {
static void main( String[] args ) {
println 'Hello, World!'
}
}
After plugging in the string values, the command line is:
java -cp libs/groovy-all-2.1.7.jar:build/libs/vh-1.0-SNAPSHOT.jar vh.Main
If I run the command directly from shell, I get correct output. However, if I run gradle vh, it will fail. So, how do I make it work? Thank you very much.
Exec.commandLine expects a list of values: one value for the executable, and another value for each argument. To execute Java code, it's better to use the JavaExec task:
task vh(type: JavaExec) {
main = "vh.Main"
classpath = files("libs/groovy-all-2.1.7.jar", "build/libs/${project.name}-${version}.jar")
}
Typically, you wouldn't have to hardcode the class path like that. For example, if you are using the groovy plugin, and groovy-all is already declared as a compile dependency (and knowing that the second Jar is created from the main sources), you would rather do:
classpath = sourceSets.main.runtimeClasspath
To find out more about the Exec and JavaExec task types, consult the Gradle Build Language Reference.

Is it possible to specify multiple main classes using gradle 'application' plugin

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.

Categories