| <!DOCTYPE html> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| https://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <html lang="en"> |
| <head> |
| <title>Tutorial: Hello World with Apache Ant</title> |
| <link rel="stylesheet" type="text/css" href="stylesheets/style.css"> |
| </head> |
| <body> |
| <h1>Tutorial: Hello World with Apache Ant</h1> |
| |
| <p>This document provides a step by step tutorial for starting Java programming with Apache Ant. It |
| does <strong>not</strong> contain deeper knowledge about Java or Ant. This tutorial has the goal to let you see, how to |
| do the easiest steps in Ant.</p> |
| |
| <h2>Content</h2> |
| <ul> |
| <li><a href="#prepare">Preparing the project</a></li> |
| <li><a href="#four-steps">Four steps to a running application</a></li> |
| <li><a href="#enhance">Enhance the build file</a></li> |
| <li><a href="#ext-libs">Using external libraries</a></li> |
| <li><a href="#resources">Resources</a></li> |
| </ul> |
| |
| <h2 id="prepare">Preparing the project</h2> |
| <p>We want to separate the source from the generated files, so our Java source files will be in <samp>src</samp> |
| folder. All generated files should be under <samp>build</samp>, and there split into several subdirectories for the |
| individual steps: <samp>classes</samp> for our compiled files and <samp>jar</samp> for our own JAR-file.</p> |
| |
| <p>We have to create only the <samp>src</samp> directory. (Because I am working on Windows, here is the Windows |
| syntax—translate to your shell):</p> |
| |
| <pre class="input">md src</pre> |
| |
| <p>The following simple Java class just prints a fixed message out to STDOUT, so just write this code |
| into <samp>src\oata\HelloWorld.java</samp>.</p> |
| |
| <pre> |
| package oata; |
| |
| public class HelloWorld { |
| public static void main(String[] args) { |
| System.out.println("Hello World"); |
| } |
| }</pre> |
| |
| <p>Now just try to compile and run that:</p> |
| <pre class="input"> |
| md build\classes |
| javac -sourcepath src -d build\classes src\oata\HelloWorld.java |
| java -cp build\classes oata.HelloWorld</pre> |
| which will result in |
| <pre class="output">Hello World</pre> |
| |
| <p>Creating a jar-file is not very difficult. But creating a <em>startable</em> jar-file needs more steps: create a |
| manifest-file containing the start class, creating the target directory and archiving the files.</p> |
| <pre class="input"> |
| echo Main-Class: oata.HelloWorld>myManifest |
| md build\jar |
| jar cfm build\jar\HelloWorld.jar myManifest -C build\classes . |
| java -jar build\jar\HelloWorld.jar</pre> |
| |
| <p><strong>Note</strong>: Do not have blanks around the >-sign in the <kbd>echo Main-Class</kbd> instruction because |
| it would falsify it!</p> |
| |
| <h2 id="four-steps">Four steps to a running application</h2> |
| <p>After finishing the Java-only step we have to think about our build process. We <em>have</em> to compile our code, |
| otherwise we couldn't start the program. Oh—<q>start</q>—yes, we could provide a target for |
| that. We <em>should</em> package our application. Now it's only one class—but if you want to provide a download, |
| no one would download several hundreds files ... (think about a complex Swing GUI—so let us create a jar file. A |
| startable jar file would be nice ... And it's a good practise to have a <q>clean</q> target, which deletes all the |
| generated stuff. Many failures could be solved just by a "clean build".</p> |
| |
| <p>By default Ant uses <samp>build.xml</samp> as the name for a buildfile, so our <samp>.\build.xml</samp> would be:</p> |
| <pre> |
| <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/HelloWorld.jar" basedir="build/classes"> |
| <manifest> |
| <attribute name="Main-Class" value="oata.HelloWorld"/> |
| </manifest> |
| </jar> |
| </target> |
| |
| <target name="run"> |
| <java jar="build/jar/HelloWorld.jar" fork="true"/> |
| </target> |
| |
| </project></pre> |
| |
| <p>Now you can compile, package and run the application via</p> |
| <pre class="input"> |
| ant compile |
| ant jar |
| ant run</pre> |
| <p>Or shorter with</p> |
| <pre class="input">ant compile jar run</pre> |
| |
| <p>While having a look at the buildfile, we will see some similar steps between Ant and the Java-only commands:</p> |
| <table> |
| <tr> |
| <th scope="col">Java-only</th> |
| <th scope="col">Ant</th> |
| </tr> |
| <tr> |
| <td><pre class="input"> |
| md build\classes |
| javac |
| -sourcepath src |
| -d build\classes |
| src\oata\HelloWorld.java |
| echo Main-Class: oata.HelloWorld>mf |
| md build\jar |
| jar cfm |
| build\jar\HelloWorld.jar |
| mf |
| -C build\classes |
| . |
| |
| |
| |
| java -jar build\jar\HelloWorld.jar</pre></td> |
| <td><pre> |
| <mkdir dir="build/classes"/> |
| <javac |
| srcdir="src" |
| destdir="build/classes"/> |
| <em><!-- automatically detected --></em> |
| <em><!-- obsolete; done via manifest tag --></em> |
| <mkdir dir="build/jar"/> |
| <jar |
| destfile="build/jar/HelloWorld.jar" |
| |
| basedir="build/classes"> |
| <manifest> |
| <attribute name="Main-Class" value="oata.HelloWorld"/> |
| </manifest> |
| </jar> |
| <java jar="build/jar/HelloWorld.jar" fork="true"/></pre></td> |
| </tr> |
| </table> |
| |
| <h2 id="enhance">Enhance the build file</h2> |
| <p>Now that we have a working buildfile, we could do some enhancements: many times you are referencing the same |
| directories, main-class and jar-name are hardcoded, and while invoking you have to remember the right order of build |
| steps.</p> |
| <p>The first and second point would be addressed with <em>properties</em>, the third with a special property—an |
| attribute of the <code><project></code> tag and the fourth problem can be solved using dependencies.</p> |
| |
| <pre> |
| <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="oata.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></pre> |
| |
| <p>Now it's easier, just do a <kbd>ant</kbd> and you will get</p> |
| <pre class="output"> |
| Buildfile: build.xml |
| |
| clean: |
| |
| compile: |
| [mkdir] Created dir: C:\...\build\classes |
| [javac] Compiling 1 source file to C:\...\build\classes |
| |
| jar: |
| [mkdir] Created dir: C:\...\build\jar |
| [jar] Building jar: C:\...\build\jar\HelloWorld.jar |
| |
| run: |
| [java] Hello World |
| |
| main: |
| |
| BUILD SUCCESSFUL</pre> |
| |
| <h2 id="ext-libs">Using external libraries</h2> |
| <p>Somebody told us not to use <code>System</code>-statements. For output, we should use a Logging |
| API—customizable to a high degree (including switching off during usual life (= not development) execution). We |
| use Log4J for that, because</p> |
| <ul> |
| <li>it is not part of the JDK (1.4+) and we want to show how to use external libs</li> |
| <li>it can run under JDK 1.2 (as Ant)</li> |
| <li>it's highly configurable</li> |
| <li>it's from Apache ;-)</li> |
| </ul> |
| <p>We store our external libraries in a new directory <samp>lib</samp>. Log4J can |
| be <a href="https://archive.apache.org/dist/logging/log4j/1.2.17/log4j-1.2.17.zip" target="_top">downloaded |
| [1]</a> from Logging's Homepage. Create the <samp>lib</samp> directory and extract the <samp>log4j-1.2.17.jar</samp> |
| into that directory. After that we have to modify our Java source file to use that library and our buildfile so that |
| this library could be accessed during compilation and run.</p> |
| <p>Working with Log4J is documented inside its manual. Here we use the <samp>MyApp</samp>-example from |
| the <a href="https://logging.apache.org/log4j/1.2/manual.html" target="_top">Short Manual [2]</a>. First we have to |
| modify the java source to use the logging framework:</p> |
| |
| <pre> |
| package oata; |
| |
| <b>import org.apache.log4j.Logger;</b> |
| <b>import org.apache.log4j.BasicConfigurator;</b> |
| |
| public class HelloWorld { |
| <b>static Logger logger = Logger.getLogger(HelloWorld.class);</b> |
| |
| public static void main(String[] args) { |
| <b>BasicConfigurator.configure();</b> |
| <span style="color:blue"><b>logger.info("Hello World");</b></span> // the old SysO-statement |
| } |
| }</pre> |
| |
| <p>Most of the modifications are "framework overhead" which has to be done once. The blue line is our "old System-out" |
| statement.</p> |
| <p>Don't try to run <kbd>ant</kbd>—you will only get lot of compiler errors. Log4J is not on the classpath so we |
| have to do a little work here. But do not change the <code>CLASSPATH</code> environment variable! This is only for this |
| project and maybe you would break other environments (this is one of the most famous mistakes when working with Ant). We |
| introduce Log4J (or to be more precise: all libraries (jar-files) which are somewhere under <samp>.\lib</samp>) into our |
| buildfile:</p> |
| |
| <pre> |
| <project name="HelloWorld" basedir="." default="main"> |
| ... |
| <b><property name="lib.dir" value="lib"/></b> |
| |
| <b><path id="classpath"></b> |
| <b><fileset dir="${lib.dir}" includes="**/*.jar"/></b> |
| <b></path></b> |
| |
| ... |
| |
| <target name="compile"> |
| <mkdir dir="${classes.dir}"/> |
| <javac srcdir="${src.dir}" destdir="${classes.dir}" <b>classpathref="classpath"</b>/> |
| </target> |
| |
| <target name="run" depends="jar"> |
| <java fork="true" <b>classname="${main-class}"</b>> |
| <b><classpath></b> |
| <b><path refid="classpath"/></b> |
| <span style="color:red"><b><path location="${jar.dir}/${ant.project.name}.jar"/></b></span> |
| <b></classpath></b> |
| </java> |
| </target> |
| |
| ... |
| |
| </project></pre> |
| |
| <p>In this example we start our application not via its <code>Main-Class</code> manifest-attribute, because we could not |
| provide a jar-name <em>and</em> a classpath. So add our class in the red line to the already defined path and start as |
| usual. Running <kbd>ant</kbd> would give (after the usual compile stuff):</p> |
| |
| <pre class="output">[java] 0 [main] INFO oata.HelloWorld - Hello World</pre> |
| |
| <p>What's that?</p> |
| <ul> |
| <li><code>[java]</code> Ant task running at the moment</li> |
| <li><code>0</code> <small>sorry, don't know—some Log4J stuff</small></li> |
| <li><code>[main]</code> the running thread from our application</li> |
| <li><code>INFO</code> log level of that statement</li> |
| <li><code>oata.HelloWorld</code> source of that statement</li> |
| <li><code>-</code> separator</li> |
| <li><code>Hello World</code> the message</li> |
| </ul> |
| <p>For another layout ... have a look inside Log4J's documentation about using other PatternLayouts.</p> |
| |
| <h2 id="config-files">Configuration files</h2> |
| <p>Why we have used Log4J? "It's highly configurable"? No—all is hardcoded! But that is not the fault of |
| Log4J—it's ours. We had coded <code class="code">BasicConfigurator.configure();</code> which implies a simple, but |
| hardcoded configuration. More comfortable would be using a property file. In the Java source file, delete |
| the <code class="code">BasicConfiguration</code> line from the <code class="code">main()</code> method (and the |
| related <code>import</code> statement). Log4J will search then for a configuration as described in its manual. Then |
| create a new file <samp>src/log4j.properties</samp>. That's the default name for Log4J's configuration and using that |
| name would make life easier—not only the framework knows what is inside, you too!</p> |
| |
| <pre> |
| log4j.rootLogger=DEBUG, <b>stdout</b> |
| |
| log4j.appender.<b>stdout</b>=org.apache.log4j.ConsoleAppender |
| |
| log4j.appender.<b>stdout</b>.layout=org.apache.log4j.PatternLayout |
| log4j.appender.<b>stdout</b>.layout.ConversionPattern=<span style="color:blue"><b>%m%n</b></span> |
| </pre> |
| |
| <p>This configuration creates an output channel (<q>Appender</q>) to console named as <code>stdout</code> which prints |
| the message (<q>%m</q>) followed by a line feed (<q>%n</q>)—same as the |
| earlier <code class="code">System.out.println()</code> :-) Oooh kay—but we haven't finished yet. We should deliver |
| the configuration file, too. So we change the buildfile:</p> |
| |
| <pre> |
| ... |
| <target name="compile"> |
| <mkdir dir="${classes.dir}"/> |
| <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/> |
| <b><copy todir="${classes.dir}"></b> |
| <b><fileset dir="${src.dir}" excludes="**/*.java"/></b> |
| <b></copy></b> |
| </target> |
| ...</pre> |
| |
| <p>This copies all resources (as long as they haven't the suffix <samp>.java</samp>) to the build directory, so we could |
| start the application from that directory and these files will included into the jar.</p> |
| |
| <h2 id="junit">Testing the class</h2> |
| <p>In this step we will introduce the usage of the JUnit [3] test framework in combination with Ant. Because Ant has a |
| built-in JUnit 4.13 you could start directly using it. Write a test class |
| in <samp>src\oata\HelloWorldTest.java</samp>:</p> |
| |
| <pre> |
| package oata; |
| |
| import org.junit.Test; |
| |
| import static org.junit.Assert.fail; |
| |
| public class HelloWorldTest { |
| |
| @Test |
| public void testNothing() { |
| } |
| |
| @Test |
| public void testWillAlwaysFail() { |
| fail("An error message"); |
| } |
| |
| }</pre> |
| |
| <p>Because we don't have real business logic to test, this test class is very small: just showing how to start. For |
| further information see the JUnit documentation [3] and the manual of <a href="Tasks/junit.html">junit</a> task. Now we |
| add a <code>junit</code> instruction to our buildfile:</p> |
| |
| <pre> |
| ... |
| |
| <path <b>id="application"</b> location="${jar.dir}/${ant.project.name}.jar"/> |
| |
| <target name="run" depends="jar"> |
| <java fork="true" classname="${main-class}"> |
| <classpath> |
| <path refid="classpath"/> |
| <b><path refid="application"/></b> |
| </classpath> |
| </java> |
| </target> |
| |
| <b><target name="junit" depends="jar"> |
| <junit printsummary="yes"> |
| <classpath> |
| <path refid="classpath"/> |
| <path refid="application"/> |
| </classpath> |
| |
| <batchtest fork="yes"> |
| <fileset dir="${src.dir}" includes="**/*Test.java"/> |
| </batchtest> |
| </junit> |
| </target></b> |
| |
| ...</pre> |
| |
| <p>We reuse the path to our own jar file as defined in <q>run</q>-target by giving it an <var>id</var> and making it |
| globally available. The <var>printsummary</var>=<q>yes</q> lets us see more detailed information than just a "FAILED" |
| or "PASSED" message. How much tests failed? Some errors? <var>printsummary</var> lets us know. The classpath is set up |
| to find our classes. To run tests the <code>batchtest</code> here is used, so you could easily add more test classes in |
| the future just by naming them <code>*Test.java</code>. This is a common naming scheme.</p> |
| |
| <p>After a <kbd>ant junit</kbd> you'll get:</p> |
| |
| <pre class="output"> |
| ... |
| junit: |
| [junit] Running oata.HelloWorldTest |
| [junit] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0,01 sec |
| [junit] Test oata.HelloWorldTest FAILED |
| |
| BUILD SUCCESSFUL |
| ...</pre> |
| |
| <p>We can also produce a report. Something that you (and others) could read after closing the shell ... There are two |
| steps: 1. let <code><junit></code> log the information and 2. convert these log files to something readable |
| (browsable).<p> |
| |
| <pre> |
| ... |
| <b><property name="report.dir" value="${build.dir}/junitreport"/></b> |
| ... |
| <target name="junit" depends="jar"> |
| <b><mkdir dir="${report.dir}"/></b> |
| <junit printsummary="yes"> |
| <classpath> |
| <path refid="classpath"/> |
| <path refid="application"/> |
| </classpath> |
| |
| <b><formatter type="xml"/></b> |
| |
| <batchtest fork="yes" <b>todir="${report.dir}"</b>> |
| <fileset dir="${src.dir}" includes="**/*Test.java"/> |
| </batchtest> |
| </junit> |
| </target> |
| |
| <b><target name="junitreport"> |
| <junitreport todir="${report.dir}"> |
| <fileset dir="${report.dir}" includes="TEST-*.xml"/> |
| <report todir="${report.dir}"/> |
| </junitreport> |
| </target></b></pre> |
| |
| <p>Because we would produce a lot of files and these files would be written to the current directory by default, we |
| define a report directory, create it before running the <q>junit</q> and redirect the logging to it. The log format is |
| XML so <q>junitreport</q> could parse it. In a second target <q>junitreport</q> should create a browsable HTML report |
| for all generated XML log files in the report directory. Now you can open the <samp>${report.dir}\index.html</samp> and |
| see the result (looks something like JavaDoc).<br/> Personally I use two different targets |
| for <code><junit></code> and <code><junitreport></code>. Generating the HTML report needs some time and you |
| don't need the HTML report just for testing, e.g. if you are fixing an error or a integration server is doing a job.</p> |
| |
| <h2 id="resources">Resources</h2> |
| <ol class="refs"> |
| <li><a href="https://archive.apache.org/dist/logging/log4j/1.2.17/log4j-1.2.17.zip" |
| target="_top">https://archive.apache.org/dist/logging/log4j/1.2.17/log4j-1.2.17.zip</a></li> |
| <li><a href="https://logging.apache.org/log4j/1.2/manual.html" |
| target="_top">https://logging.apache.org/log4j/1.2/manual.html</a></li> |
| <li><a href="https://junit.org/junit4" target="_top">https://junit.org/junit4</a></li> |
| </ol> |
| |
| </body> |
| </html> |