Sunday, October 9, 2011

Java, Apache Ant and Hello World

Hello World with Java and Ant, Build File
This post discusses the following tasks:

  • Task 1: How to create a simple Hello World Java application and run it from the command line
  • Task 2: How to build a JAR and use the JAR to run the Hello World application
  • Task 3: How to use Apache Ant to create a build file for the Hello World application
  • Task 4: How to build a Hello World application, using an external library (log4j), at the command line
  • Task 5: How to create an Apache Ant build file for a Hello World application that uses an external library
  • Task 6: How to pass arguments into the Hello World application using the build file

We must say that scarcely 4 months ago, this was all Greek to us. And through a recent job change, I was plunged into the world of Ant and Java. We are mostly documenting this because it was amazing how long it took to get these basics straightened out and we want a place to come back to and use as a cheat sheet!

(Once we saw a boat called Hello World in Shilshole Bay Marina. When we asked the owners if they were programmers one said yes, mentioning that not many people get the name.)

So Java is a popular programming language. And Ant is, from the Apache Ant Project site: “…a Java library and command-line tool whose mission is to drive processes described in build files as targets and extension points dependent upon each other. The main known usage of Ant is the build of Java applications.” Using Ant to build a Java application is what we show here. The tasks shown here take their cue from the Hello World with Apache Ant instructions on the Apache Ant web site. We created this post because we felt there was more room for clarification.

Testing environment for this post:

  • Windows 7
  • Java 1.7 for x64 (download)
  • Apache Ant (binaries, install instructions)
  • Environment variables set as follows:
    • JAVA_HOME=C:\Program Files\Java\jdk1.7.0
    • JRE_HOME=C:\Program Files\Java\jdk1.7.0\jre
    • ANT_HOME=C:\tools\apache-ant-1.8.2
    • Path={your full path};C:\tools\apache-ant-1.8.2\bin;C:\Program Files\Java\jdk1.7.0\bin

After you have everything set up, you should be able to you open a command prompt and type

    ant –help

to get the help for Ant.

Task 1: How to create a simple Hello World Java application and run it from the command line

1. Create the following directory structure (where [basedir] is some directory you choose).

[basedir]\src\packagename
[basedir]\build\classes
[basedir]\build\jar

2. Create a file HelloWorld.java and put the following inside of [basedir]\src\packagename directory.

package packagename;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}


3. Compile and run the application using the following commands. Run the commands while in [basedir].

javac -d build\classes src\packagename\HelloWorld.java
java -classpath build\classes packagename.HelloWorld


The second statement runs the application by calling the class file. If you get an "Unsupported major.minor version" check that your java.exe and javac.exe are the same versions. For example, check "java -version" and "javac -version".



Task 2: How to build a JAR and use the JAR to run the Hello World application



It’s more realistic to build a Java Archive (JAR) file which makes it easily to distribute your awesome Hello World application.

1. Create a manifest file. The command below assumes you create the manifest file in [basedir].

    echo Main-Class: packagename.HelloWorld>myManifest

2. Create the JAR. (Don’t miss the “dot” at the end of the command.)

    jar cfm build\jar\HelloWorld.jar myManifest -C build\classes .

3. Run the application using the JAR.

    java -jar build\jar\HelloWorld.jar


Task 3: How to use Apache Ant to create a build file for the Hello World application



The following XML file is a build file. Copy the text below and put into a file called build.xml at the root of the HelloWorld application ([basedidr]). To invoke the build file, type “ant” at the command line. This runs the main target in the build file. A target in the build file is a container for tasks. To run other targets in the build file type “ant targetname” like “ant compile” to compile. Note that the project tag defines the default task as main. The main task in turn depends on the clean and run task. The run task in turns depends on the jar task. Finally, the jar task depends on the compile task. So the cascade of dependencies catches all the targets.

<project name="HelloWorld" basedir="." default="main">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="main-class" value="packagename.HelloWorld"/>

<target name="clean">
<delete dir="${build.dir}"/>
</target>

<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}"/>
</target>

<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
</manifest>
</jar>
</target>

<target name="run" depends="jar">
<java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/>
</target>

<target name="clean-build" depends="clean,jar"/>
<target name="main" depends="clean,run"/>

</project>



Task 4: How to build a Hello World application that takes an input argument and uses an external library (log4j), at the command line



Now let’s jump back to doing everything by hand and let’s suppose we want to introduce an external library, log4j. Log4j is a library that provides a flexible logging framework.


1. Modify the Hello World application as follows:  

package packagename;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

public class HelloWorld {
public static Logger log = Logger.getLogger(HelloWorld.class);
public static void main(String[] args) {
BasicConfigurator.configure();
log.debug("hi there from the logger");
System.out.println("hello world " + args[0]);
}
}

2. Add the log4j-1.2.16.jar (or whatever version you are using) to the \lib folder.

3. Compile and run the application using the following commands.

    javac -d build\classes src\packagename\HelloWorld.java
    Error. We need to specify the path to the log4j JAR.

    javac -classpath lib\* -d build\classes src\packagename\HelloWorld.java
    Successful compile.

    java -classpath build\classes packagename.HelloWorld
    Error. Again, we need to specify the path to the log4j library.

    java -classpath build\classes;lib\* packagename.HelloWorld tester
    Successful run.

The output is "hello world tester" and a logging message "hi there from the logger". Details about the command options for the java and the javac commands are on the Oracle Tool Doc site.


4. The directory should look like this after successful compilation.



[basedir]\build
[basedir]\build\classes
[basedir]\build\classes\packagename
[basedir]\build\classes\packagename\HelloWorld.class
[basedir]\build\jar\HelloWorld.jar
[basedir]\lib\log4j-1.2.16.jar
[basedir]\src
[basedir]\src\packagname
[basedir]\src\packagename\HelloWorld.java

5. Let’s now continue and suppose, like we did in Task 2, that we want to run the program using the .jar. In Task 2 it was easy since we had no external libraries. In this task we do and it adds a wrinkle. As discussed here mindprod.com, if we use "-jar" when using java.exe to invoke the jar,
the -classpath is ignored. In order to run the program using the jar we need to put a Class-Path entry in the manifest file. The Class-Path entry points to the external jar (log4j in this case).



a. Add the Class-Path line to the manifest file. You can reuse the manifest file from Task 2.  Note the “>>” in the echo command below which mean append the line to the manifest file.

echo Class-Path: ../../lib/log4j-1.2.15.jar>>myManifest

b. Create the JAR. (Don’t miss the “dot” at the end of the command.)


jar cfm build\jar\HelloWorld.jar myManifest -C build\classes .


c. Run the application using the JAR. (Don’t forget the input argument!)

java -jar build\jar\HelloWorld.jar tester


Task 5: How to create an Apache Ant build file for a Hello World application that uses an external library


The next tasks is how to modify the Apache Ant build file for the external library we added.

Changes from above:



  • add property name lib.dir


  • add path element for classpath to include jars in lib.dir


  • in the compile target add classpathref to use the classpath which points to the extnernal library JAR. This corresponds to Successful compile above.


  • modify run task (and this is the crux of the matter) so that it refers to both the main-class and finds the project jar and uses the classpath with the JARs in the library. This is very different than just a simple jar with no external libraries.This corresponds to Successful run above.


The revised build file:

<project name="HelloWorld2" basedir="." default="main">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="lib.dir" value="lib"/>
<property name="main-class" value="packagename.HelloWorld"/>

<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
</target>
<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java classname="${main-class}">
<classpath>
<path refid="classpath"/>
<path location="${jar.dir}/${ant.project.name}.jar"/>
</classpath>
</java>
</target>
<target name="clean-build" depends="clean,jar"/>
<target name="main" depends="clean,run"/>
</project>



Details on the Java task page in the Ant documentation. Compare, just a project JAR run task:

<target name="run" depends="jar">
<java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/>
</target>



With a run task using an external library:

<target name="run" depends="jar">
<java classname="${main-class}">
<classpath>
<path refid="classpath"/>
<path location="${jar.dir}/${ant.project.name}.jar"/>
</classpath>
</java>
</target>



Task 6: How to pass arguments into the Hello World application using the build file




Suppose we change the HelloWorld program output line to include a passed in argument:

System.out.println("hello world :" + args[0]);


Compiling and running by the command line:

    javac -classpath lib\* -d build\classes src\packagename\HelloWorld.java
    Success.

    java -classpath build\classes;lib\* packagename.HelloWorld
    Error. We didn’t pass in an argument or catch the exception.

   
java -classpath build\classes;lib\* packagename.HelloWorld "travelmarx"
    Success. We passed in an expected string “travelmarx” to give a value to args[0].

With the build file, we only need to change the run task and add an arg element.

<target name="run" depends="jar">
<java classname="${main-class}" >
<classpath>
<path refid="classpath"/>
<path location="${jar.dir}/${ant.project.name}.jar"/>
</classpath>
<arg value="travelmarx"/>
</java>
</target>


Passing parameters from the the command line to a build file is mentioned in the FAQ on the Apache Ant site.

2 comments:

  1. Thank you, I had been looking for some online reference to be used in my training and your work really helped me.
    Java Training | Java Training | Java Training

    ReplyDelete
  2. This comment has been removed by a blog administrator.

    ReplyDelete