Setting up class path in ANT build - java

Situation:
I am new to making ant builds and I have managed to write one that builds the JAR and moves necessary files (Such as images and libraries) into an output folder.
Problem:
When I try to run the new JAR it complains that it cant find the main method (I have it specified in the manifest tag in the ANT script). I have done some research and I think its because I need to define a class-path for the compiled class' to go to but I haven't been able to get it working.
build.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project name="formula_manager" default="rebuild">
<property name="out" value="${basedir}/out/FormulaManager"/>
<target name="clean">
<delete dir="${out}"/>
<mkdir dir="${out}"/>
</target>
<target name="build" description="Build all artifacts">
<property name="tmp" value="${out}/temp"/>
<mkdir dir="${tmp}"/>
<property name="tmpJar" value="${tmp}/Formula Manager.jar"/>
<property name="tmpFolder" value="${tmp}/FormulaManager"/>
<jar destfile="${tmpJar}" duplicate="preserve" filesetmanifest="mergewithoutmain">
<zipfileset dir="${out}"/>
<zipfileset src="${basedir}/resources/pdfbox-app-1.8.10.jar"/>
<zipfileset src="${basedir}/resources/ftp4j-1.7.2.jar"/>
<manifest>
<attribute name="Main-Class" value="com.zakscode.FormulaManager.Main"/>
</manifest>
</jar>
<copy file="${tmpJar}" tofile="${tmp}/Formula Manager.jar"/>
<mkdir dir="${out}"/>
<copy todir="${out}">
<fileset dir="${tmp}"/>
</copy>
<copy file="icon.png" todir="${out}" />
<copy file="splash.png" todir="${out}" />
<copy file="logo.png" todir="${out}" />
<copy file="configuration.properties" todir="${out}" />
<mkdir dir="${out}/resources" />
<copydir src="resources" dest="${out}/resources" />
<!-- Delete temporary files -->
<delete dir="${tmp}"/>
</target>
<target name="rebuild" depends="clean, build"/>
</project>
Output:
$ java -jar "Formula Manager.jar"
Error: Could not find or load main class com.zakscode.FormulaManager.Main
Edit:
I opened up the JAR in 7zip and none of the class files are there which is why the main method cant be loaded. So how do I fix this in my build.xml?

Setting
Main-Class = "com.zakscode.FormulaManager.Main"
assumes that you have the following message defined:
public static void main(String[] args)
in a class named com.zakscode.FormulaManager.Main (method has to be "main", not "Main"). When defining Main-Class, you don't include the main method name, you specify the class that contains main, so if your main method is in FormulaManager, then you set Main-Class as follows:
Main-Class = "com.zakscode.FormulaManager"

Related

Using Ant to build dependencies of the current build target

Say I have a library and a binary target, let's call them MyLib and MyBin,
MyBin depends on MyLib.
I'm trying to create an Ant buildfile for MyBin that first builds MyLib and then includes it in the classpath when building MyBin.
I've tried using Ant tasks as in Building other, dependent projects with Ant .
However, it's not working, and from ant -v I think the MyBin build-deps target is not even building MyLib. Seems like it's confusing MyBin and MyLib properties? I'm not sure how to prevent this though.
I'm dumping only MyBin/build.xml below, but the MyLib is almost identical, except it does not have the build-deps target.
<project name="MyBin" default="main" basedir=".">
<property name="projectName" value="MyBin" />
<property name="src.dir" location="src" />
<property name="build.dir" location="bin" />
<property name="dist.dir" location="dist" />
<property name="dist.lib.dir" location="dist/lib" />
<property name="lib.dir" value="lib" />
<target name="build-deps" depends="init">
<!-- MyLib main target does clean -> build -> jar to dist folder -->
<!-- Its build.xml uses many of the same property values as above -->
<ant antfile="../MyLib/build.xml" target="main"/>
</target>
<path id="classpath">
<fileset dir="${basedir}/">
<include name="../MyLib/dist/**/*.jar" />
</fileset>
</path>
<!-- Need classpath to run this -->
<target name="compile" depends="build-deps" description="compile the source ">
<javac includeantruntime="false" srcdir="${src.dir}"
destdir="${build.dir}" classpathref="classpath" />
</target>
<!-- Group all dependencies into a big dependency-all.jar -->
<target name="copy-dependencies">
<mkdir dir="${dist.lib.dir}" />
<jar jarfile="${dist.lib.dir}/dependencies-all.jar">
<zipgroupfileset dir="${lib.dir}">
<include name="**/*.jar" />
</zipgroupfileset>
</jar>
</target>
<!-- jar it, extract above dependency-all.jar and zip it with project files -->
<target name="jar" depends="compile, copy-dependencies"
description="package, output to JAR">
<mkdir dir="${dist.dir}" />
<mkdir dir="${dist.lib.dir}" />
<jar jarfile="${dist.dir}/${projectName}.jar" basedir="${build.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}" />
</manifest>
<zipfileset src="${dist.lib.dir}/dependencies-all.jar"
excludes="META-INF/*.SF" />
</jar>
</target>
<target name="clean" description="clean up">
<delete dir="${build.dir}" />
<delete dir="${dist.dir}" />
</target>
<!-- Default, run this -->
<target name="main" depends="clean, compile, jar" />
</project>
What I see with ant -v in MyBin is something along the lines of:
build-deps:
Project base dir set to: /MyBin
[ant] calling target(s) [main] in build file /MyLib/build.xml
parsing buildfile /MyLib/build.xml with URI = file:/MyLib/build.xml
Project base dir set to: /MyBin
Override ignored for property "projectName"
Override ignored for property "build.dir"
Override ignored for property "dist.dir"
Override ignored for property "dist.lib.dir"
Override ignored for property "lib.dir"
[pathconvert] Set property classpath.name =
[ant] Entering /MyLib/build.xml...
Build sequence for target(s) `main' is [clean, init, copy-dependencies, jar, main]
Complete build sequence is [clean, init, copy-dependencies, jar, main, ]
clean:
[delete] Deleting directory /MyBin/bin
[delete] Deleting directory /MyBin/bin
init:
[mkdir] Created dir: /MyBin/bin
copy-dependencies:
[ant] Exiting /MyLib/build.xml.
On your specific question:
seems like it's confusing MyBin and MyLib properties? I'm not sure how
to prevent this though.
You are using this to invoke the MyLib build:
<ant antfile="../MyLib/build.xml" target="main" />
A build invoked via the <ant> task this way by default inherits all properties from the caller, including basedir, hence the build is run in the wrong place.
Instead you could use, for example:
<ant dir="../MyLib" />
That will run build.xml in the specified directory, set the basedir property, and call the default target, which should be main if you are using a very similar buildfile for the library as you say. If you don't want to inherit properties from MyBin when executing the MyLib task, specify inheritAll=false in the task.
From the <ant> task docs for the dir attribute:
the directory to use as a basedir for the new Ant project (unless
useNativeBasedir is set to true). Defaults to the current project's
basedir, unless inheritall has been set to false, in which case it
doesn't have a default value. This will override the basedir setting
of the called project. Also serves as the directory to resolve the
antfile and output attribute's values (if any).

Deployed jar can't find the main class while using Apache Ant

I built a jar file using the following build.xml below:
<project name="sampleproject">
<!--Source Directory-->
<property name="src.dir" value="src" />
<property name="deploy.name" value="samplejar.jar" />
<property name="lib.dir" value="./lib" />
<property name="deploy.dir" value="target" />
<property name="compile.dir" value="target/classes" />
<!--Define directory name for third party libraries-->
<property name="jar-all" location="${lib.dir}" />
<!--Fileset is a group of files, here **/* matches all jar files across all directory levels-->
<fileset id="jars" dir="${jar-all}">
</fileset>
<!--Setting the classpath-->
<path id="classpath">
<fileset refid="jars" />
<pathelement location="." />
<pathelement location="${src.dir}" />
<pathelement location="${compile.dir}" />
</path>
<path id="cp">
<fileset refid="jars" />
</path>
<pathconvert property="classpath.path" refid="cp" pathsep=" " dirsep="/">
<map from="${jar-all}" to="lib" />
</pathconvert>
<echo>${classpath}</echo>
<!--Clean-->
<target name="clean">
<delete dir="${deploy.dir}" />
</target>
<!--Jar-->
<target name="jar" depends="compile">
<jar destfile="${deploy.dir}/${deploy.name}.jar" basedir="${compile.dir}">
<manifest>
<attribute name="Main-Class" value="main.java.Main" />
<attribute name="Class-Path" value="${classpath.path}" />
</manifest>
<include name="${src.dir}/META-INF/persistence.xml" />
<restrict>
<not>
<or>
<name name="**/*.RSA" />
<name name="**/*.SF" />
<name name="**/*.DSA" />
</or>
</not>
<archives>
<zips>
<fileset dir="lib" includes="**/*.jar" />
</zips>
</archives>
</restrict>
</jar>
</target>
<!--Compile-->
<target name="compile">
<mkdir dir="${compile.dir}" />
<javac includeantruntime="false" srcdir="${src.dir}" destdir="${compile.dir}">
<classpath refid="classpath" />
</javac>
</target>
</project>
My folder structure is like this:
.
./.settings
./bin
./bin/main
./bin/main/java
./bin/META-INF
./lib
./lib/aws
./lib/hibernate
./src
./src/main
./src/main/java
./src/META-INF
./target
./target/classes
./target/classes/main
./target/classes/main/java
My MANIFEST.MF
Created-By: 1.8.0_45-b14 (Oracle Corporation)
Built-Date: ${TODAY}
Main-Class: main.java.Main
Class-Path: lib/activation.jar lib/aws/aws-java-sdk-1.3.2.jar lib/aws/
httpclient-4.1.1.jar lib/aws/httpcore-4.4.1.jar lib/aws/mail-1.4.3.ja
r lib/aws/stax-1.2.0.jar lib/aws/stax-api-1.0.1.jar lib/commons-beanu
tils-1.8.3.jar lib/commons-codec-1.4.jar lib/commons-configuration-1.
8.jar lib/commons-httpclient-3.0.1.jar lib/commons-io-2.1.jar lib/com
mons-lang-2.4.jar lib/commons-logging-1.1.1.jar lib/hibernate/antlr-2
.7.7.jar lib/hibernate/c3p0-0.9.1.jar lib/hibernate/commons-collectio
ns-3.2.1.jar lib/hibernate/dom4j-1.6.1.jar lib/hibernate/hibernate-c3
p0-4.0.1.Final.jar lib/hibernate/hibernate-commons-annotations-4.0.1.
Final.jar lib/hibernate/hibernate-core-4.0.1.Final.jar lib/hibernate/
hibernate-entitymanager-4.0.1.Final.jar lib/hibernate/hibernate-jpa-2
.0-api-1.0.1.Final.jar lib/hibernate/javassist-3.15.0-GA.jar lib/hibe
rnate/jboss-logging-3.1.0.CR2.jar lib/hibernate/jboss-transaction-api
_1.1_spec-1.0.0.Final.jar lib/jackson-all-1.9.5.jar lib/log4j-1.2.16.
jar lib/mail.jar lib/mongo-2.8.0.jar lib/morphia-0.99.jar lib/mysql-c
onnector-java-5.1.12-bin.jar lib/mysql-connector-java-5.1.25-bin.jar
lib/org.json.jar lib/ymmi-utilities-2.0.jar
Whenever I run the jar produced it gives me, Error: Could not find or load main class main.java.Main.
Also, I want to include lib folder & it's subfolders as well since it contains the libraries required to run the jar.
Before it gave me, No Persistence provider for EntityManager named but I solved that by using <include name="${src.dir}/META-INF/persistence.xml" />. Any where I am might wrong?
Your problem is the <include> element in the jar task.
I executed your script and the Main.class file is not added to the jar.
Replace the
<include
by
<fileset dir="${src.dir}" includes="META-INF/persistence.xml" />
This way it will still add all files located in your ${compile.dir}.
Are you new to java ? Normally you put your source files in src/main/java and resources in src/main/resources.
These folders are the root folder of your classpath meaning: If your project classes would be in package org.myproject, than you would put the Main.java file in src/main/java/org/myproject/Main.java
In your build script you than set the property "src.dir" to "src/main/java".
With all resources (=files which do not need to be compiled but must be available in the jar) in src/main/resources the fileset element in the jar task could just be:
<fileset dir="scr/main/resources"/>
This way all resource files you plan to add to your project will automatically added to your jar.
Why do I tell you this ? If one day you would think of using maven instead of ant, maven expects the sources to be in src/main/java and resources in src/main/resources. (https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html)
Regarding you other dependant jars:
Now you include all jars twice: you add the content of them using the <archives> element within the jar and you define them in the Class-Path attribute of the manifest.mf file.
If you really like to build a single jar containing all dependant files, you don't need to specify the manifest attribute Class-Path.
If you want your jar file containing only your files and deliver the dependant jars separately: remove the <archives> element within the jar task.

Ant does not include generated class files to packaged jar, until I do a Project->Clean in Eclipse

I ran into some strange behaviour that seems to be connected to Eclipse and it's way to refresh the workspace.
I'm using an Ant build file to create my class-files and to create a package from that class-file. This functionality is working fine.
This is the target doing the work:
<target name="package" depends="compile,javaDoc">
<jar destfile="${dist.dir}/MyApplication.jar" basedir="${build.dir}" includes="**/*.class">
<zipgroupfileset dir="${lib.dir}" includes="*.jar" />
<manifest>
<attribute name="Main-Class" value="MyApplication" />
</manifest>
</jar>
</target>
Now I want to add functionality to first clean the directories where the class-files and the jar file are beeing generated.
This is the target code:
<target name="clean" description="Removes all *.class and *.jar files. Also deletes the java doc files.">
<delete dir="${build.dir}" />
<delete dir="${dist.dir}" /></target>
This target also works fine.
Now I would like the package target dependent on the clean target, so that the folders are first cleaned before the packaging is beeing done.
This would look like this:
<target name="package" depends="clean,compile,javaDoc">
<jar destfile="${dist.dir}/MyApplication.jar" basedir="${build.dir}" includes="**/*.class">
<zipgroupfileset dir="${lib.dir}" includes="*.jar" />
<manifest>
<attribute name="Main-Class" value="MyApplication" />
</manifest>
</jar>
</target>
The problem is, that this target does not include the generated class files into the jar. Even on the file system the generated class files are not displayed. Only after I go to Project->Clean in Eclipse and clean the project the class files become visible on the filesystem.
Any help is appreciated.
My compile target looks like this:
<target name="compile" depends="init" description="Compiles the source file to the created directory.">
<javac classpathref="classpath" srcdir="${dist.dir}" destdir="${build.dir}" includeantruntime="false" />
</target>
fixing the error in the compile target worked.
That is the working version:
<target name="compile" depends="init" description="Compiles the source file to the created directory.">
<javac classpathref="classpath" srcdir="${src.dir}" destdir="${build.dir}" includeantruntime="false" /></target>

How to include an external jar lib in my Ant build

I have the following build.xml:
<project>
<target name="clean">
<delete dir="./build"/>
</target>
<target name="compile">
<mkdir dir="./build/classes"/>
<javac srcdir="./src" destdir="./build/classes"/>
</target>
<target name="jar">
<mkdir dir="./build/jar"/>
<jar destfile="./build/jar/DependencyFinder.jar" basedir="./build/classes">
<manifest>
<attribute name="DependencyFinder" value="main"/>
</manifest>
</jar>
</target>
<target name="run">
<java jar="./build/jar/DependencyFinder.jar" classname="${main-class}" fork="true"/>
</target>
</project>
Here is my directory structure:
/build
/lib
/MagicFolder
/Src
/build.xml
Folder src contains .java files.
Path to MagicFolder should be an input parameter.
lib has external .jar library which should be included in my build.
build folder which will have compiled .jar and.class` files
QUESTION:
How should I change my build.xml? My build.xml should:
Add external lib ./lib/jbl.jar
When I run my application put 2 input parametrs for my application
If you need to add a jar to classpath to compile the code (sorry, it isn't quite clear what you're asking for), then you need to change <javac> task to look like this:
<javac srcdir="./src" destdir="./build/classes">
<classpath>
<pathelement path="lib/jbl.jar"/>
</classpath>
</javac>
Or if you need to add contents of jbl.jar to the jar you are creating, then you need to change your <jar> task to look like this:
<jar destfile="./build/jar/DependencyFinder.jar" basedir="./build/classes>
<zipgroupfileset dir="lib" includes="jbl.jar" />
<manifest>
<attribute name="DependencyFinder" value="main"/>
<attribute name="Main-Class" value="org.ivanovpavel.YourMainClass"/>
</manifest>
</jar>
To add arguments to <java> call, use nested <arg> elements:
<target name="run">
<java jar="./build/jar/DependencyFinder.jar:lib/jbl.jar" classname="dependencyfinder.DependencyFinder">
<arg value="Alexander Rosenbaum"/>
<arg value="Dmitry Malikov"/>
</java>
</target>
There are two ways to run a java program. Using the "jar" option is the most convenient and is called an executable jar, however in order to make it work you need to specify both the Main class and classpath in the manifest file as follows:
<jar destfile="${jar.file}" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${jar.main.class}" />
<attribute name="Class-Path" value="${jar.classpath}" />
</manifest>
</jar>
For a more detailed answer on how to do this see:
Execute Java programs in a consistent environment
try with this:
<target name="jar" depends="clean,compile" >
<jar destfile="./build/jar/DependencyFinder.jar">
<fileset dir="./lib" includes="jbl.jar,mysql*.jar" />
<fileset dir="./build/classes" excludes="**/form/*.class,**/orm/*.class,**/org/w3/xmldsig/*.class"/>
</jar>
</target>

Eclipse Ant Builder problem

I made a custom ant script to automatically create a jar file each time I do a build.
This is how it looks like:
<?xml version="1.0" encoding="UTF-8"?>
<project name="TestProj" basedir="." default="jar">
<property name="dist" value="dist" />
<property name="build" value="bin/test/testproj" />
<target name="jar">
<jar destfile="${dist}/TestProj.jar">
<manifest>
<attribute name="Main-Class" value="test.testproj.TestProj" />
</manifest>
<fileset dir="${build}" />
</jar>
</target>
</project>
I added it by Right clicking my project > properties > builders > clicked new > Ant builder > then I specified the location of the above xml file.
However, when I run it by doing:
java -jar TestProj.jar
I get a NoClassDefFoundError test/testproj/TestProj
I'm using Eclipse in Ubuntu. TestProj is the name of the class and it's in package test.testproj
I'm pretty sure there's something wrong with the manifest and probably the location of the xml file as well but I'm not sure how to fix this. Any ideas?
Did you try with:
<property name="build" value="bin" /> <!-- instead of bin/test/testproj -->
<target name="jar">
<jar destfile="${dist}/TestProj.jar">
<manifest>
<attribute name="Main-Class" value="test.testproj.TestProj" />
</manifest>
<fileset dir="${build}" />
</jar>
</target>
just to see if it solves the issue?
The Ant Task mentions:
This task forms an implicit FileSet and supports most attributes of <fileset> (dir becomes basedir)
That means you are trying to jar any class within the root bin/test/testproj (so TestProj get included), instead of referencing all classes within root bin (which would include test.testproj.TestProj)

Categories

Resources