You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

tutorial-HelloWorldWithAnt.html 19 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. <!DOCTYPE html>
  2. <!--
  3. Licensed to the Apache Software Foundation (ASF) under one or more
  4. contributor license agreements. See the NOTICE file distributed with
  5. this work for additional information regarding copyright ownership.
  6. The ASF licenses this file to You under the Apache License, Version 2.0
  7. (the "License"); you may not use this file except in compliance with
  8. the License. You may obtain a copy of the License at
  9. https://www.apache.org/licenses/LICENSE-2.0
  10. Unless required by applicable law or agreed to in writing, software
  11. distributed under the License is distributed on an "AS IS" BASIS,
  12. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. See the License for the specific language governing permissions and
  14. limitations under the License.
  15. -->
  16. <html lang="en">
  17. <head>
  18. <title>Tutorial: Hello World with Apache Ant</title>
  19. <link rel="stylesheet" type="text/css" href="stylesheets/style.css">
  20. </head>
  21. <body>
  22. <h1>Tutorial: Hello World with Apache Ant</h1>
  23. <p>This document provides a step by step tutorial for starting Java programming with Apache Ant. It
  24. does <strong>not</strong> contain deeper knowledge about Java or Ant. This tutorial has the goal to let you see, how to
  25. do the easiest steps in Ant.</p>
  26. <h2>Content</h2>
  27. <ul>
  28. <li><a href="#prepare">Preparing the project</a></li>
  29. <li><a href="#four-steps">Four steps to a running application</a></li>
  30. <li><a href="#enhance">Enhance the build file</a></li>
  31. <li><a href="#ext-libs">Using external libraries</a></li>
  32. <li><a href="#resources">Resources</a></li>
  33. </ul>
  34. <h2 id="prepare">Preparing the project</h2>
  35. <p>We want to separate the source from the generated files, so our Java source files will be in <samp>src</samp>
  36. folder. All generated files should be under <samp>build</samp>, and there split into several subdirectories for the
  37. individual steps: <samp>classes</samp> for our compiled files and <samp>jar</samp> for our own JAR-file.</p>
  38. <p>We have to create only the <samp>src</samp> directory. (Because I am working on Windows, here is the Windows
  39. syntax&mdash;translate to your shell):</p>
  40. <pre class="input">md src</pre>
  41. <p>The following simple Java class just prints a fixed message out to STDOUT, so just write this code
  42. into <samp>src\oata\HelloWorld.java</samp>.</p>
  43. <pre>
  44. package oata;
  45. public class HelloWorld {
  46. public static void main(String[] args) {
  47. System.out.println("Hello World");
  48. }
  49. }</pre>
  50. <p>Now just try to compile and run that:</p>
  51. <pre class="input">
  52. md build\classes
  53. javac -sourcepath src -d build\classes src\oata\HelloWorld.java
  54. java -cp build\classes oata.HelloWorld</pre>
  55. which will result in
  56. <pre class="output">Hello World</pre>
  57. <p>Creating a jar-file is not very difficult. But creating a <em>startable</em> jar-file needs more steps: create a
  58. manifest-file containing the start class, creating the target directory and archiving the files.</p>
  59. <pre class="input">
  60. echo Main-Class: oata.HelloWorld&gt;myManifest
  61. md build\jar
  62. jar cfm build\jar\HelloWorld.jar myManifest -C build\classes .
  63. java -jar build\jar\HelloWorld.jar</pre>
  64. <p><strong>Note</strong>: Do not have blanks around the &gt;-sign in the <kbd>echo Main-Class</kbd> instruction because
  65. it would falsify it!</p>
  66. <h2 id="four-steps">Four steps to a running application</h2>
  67. <p>After finishing the Java-only step we have to think about our build process. We <em>have</em> to compile our code,
  68. otherwise we couldn't start the program. Oh&mdash;<q>start</q>&mdash;yes, we could provide a target for
  69. that. We <em>should</em> package our application. Now it's only one class&mdash;but if you want to provide a download,
  70. no one would download several hundreds files ... (think about a complex Swing GUI&mdash;so let us create a jar file. A
  71. startable jar file would be nice ... And it's a good practise to have a <q>clean</q> target, which deletes all the
  72. generated stuff. Many failures could be solved just by a "clean build".</p>
  73. <p>By default Ant uses <samp>build.xml</samp> as the name for a buildfile, so our <samp>.\build.xml</samp> would be:</p>
  74. <pre>
  75. &lt;project&gt;
  76. &lt;target name="clean"&gt;
  77. &lt;delete dir="build"/&gt;
  78. &lt;/target&gt;
  79. &lt;target name="compile"&gt;
  80. &lt;mkdir dir="build/classes"/&gt;
  81. &lt;javac srcdir="src" destdir="build/classes"/&gt;
  82. &lt;/target&gt;
  83. &lt;target name="jar"&gt;
  84. &lt;mkdir dir="build/jar"/&gt;
  85. &lt;jar destfile="build/jar/HelloWorld.jar" basedir="build/classes"&gt;
  86. &lt;manifest&gt;
  87. &lt;attribute name="Main-Class" value="oata.HelloWorld"/&gt;
  88. &lt;/manifest&gt;
  89. &lt;/jar&gt;
  90. &lt;/target&gt;
  91. &lt;target name="run"&gt;
  92. &lt;java jar="build/jar/HelloWorld.jar" fork="true"/&gt;
  93. &lt;/target&gt;
  94. &lt;/project&gt;</pre>
  95. <p>Now you can compile, package and run the application via</p>
  96. <pre class="input">
  97. ant compile
  98. ant jar
  99. ant run</pre>
  100. <p>Or shorter with</p>
  101. <pre class="input">ant compile jar run</pre>
  102. <p>While having a look at the buildfile, we will see some similar steps between Ant and the Java-only commands:</p>
  103. <table>
  104. <tr>
  105. <th scope="col">Java-only</th>
  106. <th scope="col">Ant</th>
  107. </tr>
  108. <tr>
  109. <td><pre class="input">
  110. md build\classes
  111. javac
  112. -sourcepath src
  113. -d build\classes
  114. src\oata\HelloWorld.java
  115. echo Main-Class: oata.HelloWorld>mf
  116. md build\jar
  117. jar cfm
  118. build\jar\HelloWorld.jar
  119. mf
  120. -C build\classes
  121. .
  122. java -jar build\jar\HelloWorld.jar</pre></td>
  123. <td><pre>
  124. &lt;mkdir dir="build/classes"/&gt;
  125. &lt;javac
  126. srcdir="src"
  127. destdir="build/classes"/&gt;
  128. <em>&lt;!-- automatically detected --&gt;</em>
  129. <em>&lt;!-- obsolete; done via manifest tag --&gt;</em>
  130. &lt;mkdir dir="build/jar"/&gt;
  131. &lt;jar
  132. destfile="build/jar/HelloWorld.jar"
  133. basedir="build/classes"&gt;
  134. &lt;manifest&gt;
  135. &lt;attribute name="Main-Class" value="oata.HelloWorld"/&gt;
  136. &lt;/manifest&gt;
  137. &lt;/jar&gt;
  138. &lt;java jar="build/jar/HelloWorld.jar" fork="true"/&gt;</pre></td>
  139. </tr>
  140. </table>
  141. <h2 id="enhance">Enhance the build file</h2>
  142. <p>Now that we have a working buildfile, we could do some enhancements: many times you are referencing the same
  143. directories, main-class and jar-name are hardcoded, and while invoking you have to remember the right order of build
  144. steps.</p>
  145. <p>The first and second point would be addressed with <em>properties</em>, the third with a special property&mdash;an
  146. attribute of the <code>&lt;project&gt;</code> tag and the fourth problem can be solved using dependencies.</p>
  147. <pre>
  148. &lt;project name="HelloWorld" basedir="." default="main"&gt;
  149. &lt;property name="src.dir" value="src"/&gt;
  150. &lt;property name="build.dir" value="build"/&gt;
  151. &lt;property name="classes.dir" value="${build.dir}/classes"/&gt;
  152. &lt;property name="jar.dir" value="${build.dir}/jar"/&gt;
  153. &lt;property name="main-class" value="oata.HelloWorld"/&gt;
  154. &lt;target name="clean"&gt;
  155. &lt;delete dir="${build.dir}"/&gt;
  156. &lt;/target&gt;
  157. &lt;target name="compile"&gt;
  158. &lt;mkdir dir="${classes.dir}"/&gt;
  159. &lt;javac srcdir="${src.dir}" destdir="${classes.dir}"/&gt;
  160. &lt;/target&gt;
  161. &lt;target name="jar" depends="compile"&gt;
  162. &lt;mkdir dir="${jar.dir}"/&gt;
  163. &lt;jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"&gt;
  164. &lt;manifest&gt;
  165. &lt;attribute name="Main-Class" value="${main-class}"/&gt;
  166. &lt;/manifest&gt;
  167. &lt;/jar&gt;
  168. &lt;/target&gt;
  169. &lt;target name="run" depends="jar"&gt;
  170. &lt;java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/&gt;
  171. &lt;/target&gt;
  172. &lt;target name="clean-build" depends="clean,jar"/&gt;
  173. &lt;target name="main" depends="clean,run"/&gt;
  174. &lt;/project&gt;</pre>
  175. <p>Now it's easier, just do a <kbd>ant</kbd> and you will get</p>
  176. <pre class="output">
  177. Buildfile: build.xml
  178. clean:
  179. compile:
  180. [mkdir] Created dir: C:\...\build\classes
  181. [javac] Compiling 1 source file to C:\...\build\classes
  182. jar:
  183. [mkdir] Created dir: C:\...\build\jar
  184. [jar] Building jar: C:\...\build\jar\HelloWorld.jar
  185. run:
  186. [java] Hello World
  187. main:
  188. BUILD SUCCESSFUL</pre>
  189. <h2 id="ext-libs">Using external libraries</h2>
  190. <p>Somebody told us not to use <code>System</code>-statements. For output, we should use a Logging
  191. API&mdash;customizable to a high degree (including switching off during usual life (= not development) execution). We
  192. use Log4J for that, because</p>
  193. <ul>
  194. <li>it is not part of the JDK and we want to show how to use external libs</li>
  195. <li>it's highly configurable</li>
  196. <li>it's from Apache ;-)</li>
  197. </ul>
  198. <p>We store our external libraries in a new directory <samp>lib</samp>. Log4J can
  199. be <a href="https://archive.apache.org/dist/logging/log4j/1.2.17/log4j-1.2.17.zip" target="_top">downloaded
  200. [1]</a> from Logging's Homepage. Create the <samp>lib</samp> directory and extract the <samp>log4j-1.2.17.jar</samp>
  201. into that directory. After that we have to modify our Java source file to use that library and our buildfile so that
  202. this library could be accessed during compilation and run.</p>
  203. <p>Working with Log4J is documented inside its manual. Here we use the <samp>MyApp</samp>-example from
  204. the <a href="https://logging.apache.org/log4j/1.2/manual.html" target="_top">Short Manual [2]</a>. First we have to
  205. modify the java source to use the logging framework:</p>
  206. <pre>
  207. package oata;
  208. <b>import org.apache.log4j.Logger;</b>
  209. <b>import org.apache.log4j.BasicConfigurator;</b>
  210. public class HelloWorld {
  211. <b>static Logger logger = Logger.getLogger(HelloWorld.class);</b>
  212. public static void main(String[] args) {
  213. <b>BasicConfigurator.configure();</b>
  214. <span style="color:blue"><b>logger.info("Hello World");</b></span> // the old SysO-statement
  215. }
  216. }</pre>
  217. <p>Most of the modifications are "framework overhead" which has to be done once. The blue line is our "old System-out"
  218. statement.</p>
  219. <p>Don't try to run <kbd>ant</kbd>&mdash;you will only get lot of compiler errors. Log4J is not on the classpath so we
  220. have to do a little work here. But do not change the <code>CLASSPATH</code> environment variable! This is only for this
  221. project and maybe you would break other environments (this is one of the most famous mistakes when working with Ant). We
  222. introduce Log4J (or to be more precise: all libraries (jar-files) which are somewhere under <samp>.\lib</samp>) into our
  223. buildfile:</p>
  224. <pre>
  225. &lt;project name="HelloWorld" basedir="." default="main"&gt;
  226. ...
  227. <b>&lt;property name="lib.dir" value="lib"/&gt;</b>
  228. <b>&lt;path id="classpath"&gt;</b>
  229. <b>&lt;fileset dir="${lib.dir}" includes="**/*.jar"/&gt;</b>
  230. <b>&lt;/path&gt;</b>
  231. ...
  232. &lt;target name="compile"&gt;
  233. &lt;mkdir dir="${classes.dir}"/&gt;
  234. &lt;javac srcdir="${src.dir}" destdir="${classes.dir}" <b>classpathref="classpath"</b>/&gt;
  235. &lt;/target&gt;
  236. &lt;target name="run" depends="jar"&gt;
  237. &lt;java fork="true" <b>classname="${main-class}"</b>&gt;
  238. <b>&lt;classpath&gt;</b>
  239. <b>&lt;path refid="classpath"/&gt;</b>
  240. <span style="color:red"><b>&lt;path location="${jar.dir}/${ant.project.name}.jar"/&gt;</b></span>
  241. <b>&lt;/classpath&gt;</b>
  242. &lt;/java&gt;
  243. &lt;/target&gt;
  244. ...
  245. &lt;/project&gt;</pre>
  246. <p>In this example we start our application not via its <code>Main-Class</code> manifest-attribute, because we could not
  247. 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
  248. usual. Running <kbd>ant</kbd> would give (after the usual compile stuff):</p>
  249. <pre class="output">[java] 0 [main] INFO oata.HelloWorld - Hello World</pre>
  250. <p>What's that?</p>
  251. <ul>
  252. <li><code>[java]</code> Ant task running at the moment</li>
  253. <li><code>0</code> <small>sorry, don't know&mdash;some Log4J stuff</small></li>
  254. <li><code>[main]</code> the running thread from our application</li>
  255. <li><code>INFO</code> log level of that statement</li>
  256. <li><code>oata.HelloWorld</code> source of that statement</li>
  257. <li><code>-</code> separator</li>
  258. <li><code>Hello World</code> the message</li>
  259. </ul>
  260. <p>For another layout ... have a look inside Log4J's documentation about using other PatternLayouts.</p>
  261. <h2 id="config-files">Configuration files</h2>
  262. <p>Why we have used Log4J? "It's highly configurable"? No&mdash;all is hardcoded! But that is not the fault of
  263. Log4J&mdash;it's ours. We had coded <code class="code">BasicConfigurator.configure();</code> which implies a simple, but
  264. hardcoded configuration. More comfortable would be using a property file. In the Java source file, delete
  265. the <code class="code">BasicConfiguration</code> line from the <code class="code">main()</code> method (and the
  266. related <code>import</code> statement). Log4J will search then for a configuration as described in its manual. Then
  267. create a new file <samp>src/log4j.properties</samp>. That's the default name for Log4J's configuration and using that
  268. name would make life easier&mdash;not only the framework knows what is inside, you too!</p>
  269. <pre>
  270. log4j.rootLogger=DEBUG, <b>stdout</b>
  271. log4j.appender.<b>stdout</b>=org.apache.log4j.ConsoleAppender
  272. log4j.appender.<b>stdout</b>.layout=org.apache.log4j.PatternLayout
  273. log4j.appender.<b>stdout</b>.layout.ConversionPattern=<span style="color:blue"><b>%m%n</b></span>
  274. </pre>
  275. <p>This configuration creates an output channel (<q>Appender</q>) to console named as <code>stdout</code> which prints
  276. the message (<q>%m</q>) followed by a line feed (<q>%n</q>)&mdash;same as the
  277. earlier <code class="code">System.out.println()</code> :-) Oooh kay&mdash;but we haven't finished yet. We should deliver
  278. the configuration file, too. So we change the buildfile:</p>
  279. <pre>
  280. ...
  281. &lt;target name="compile"&gt;
  282. &lt;mkdir dir="${classes.dir}"/&gt;
  283. &lt;javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/&gt;
  284. <b>&lt;copy todir="${classes.dir}"&gt;</b>
  285. <b>&lt;fileset dir="${src.dir}" excludes="**/*.java"/&gt;</b>
  286. <b>&lt;/copy&gt;</b>
  287. &lt;/target&gt;
  288. ...</pre>
  289. <p>This copies all resources (as long as they haven't the suffix <samp>.java</samp>) to the build directory, so we could
  290. start the application from that directory and these files will included into the jar.</p>
  291. <h2 id="junit">Testing the class</h2>
  292. <p>In this step we will introduce the usage of the JUnit [3] test framework in combination with Ant. Because Ant has a
  293. built-in JUnit 4.13.1 you could start directly using it. Write a test class
  294. in <samp>src\oata\HelloWorldTest.java</samp>:</p>
  295. <pre>
  296. package oata;
  297. import org.junit.Test;
  298. import static org.junit.Assert.fail;
  299. public class HelloWorldTest {
  300. @Test
  301. public void testNothing() {
  302. }
  303. @Test
  304. public void testWillAlwaysFail() {
  305. fail("An error message");
  306. }
  307. }</pre>
  308. <p>Because we don't have real business logic to test, this test class is very small: just showing how to start. For
  309. further information see the JUnit documentation [3] and the manual of <a href="Tasks/junit.html">junit</a> task. Now we
  310. add a <code>junit</code> instruction to our buildfile:</p>
  311. <pre>
  312. ...
  313. &lt;path <b>id="application"</b> location="${jar.dir}/${ant.project.name}.jar"/&gt;
  314. &lt;target name="run" depends="jar"&gt;
  315. &lt;java fork="true" classname="${main-class}"&gt;
  316. &lt;classpath&gt;
  317. &lt;path refid="classpath"/&gt;
  318. <b>&lt;path refid="application"/&gt;</b>
  319. &lt;/classpath&gt;
  320. &lt;/java&gt;
  321. &lt;/target&gt;
  322. <b>&lt;target name="junit" depends="jar"&gt;
  323. &lt;junit printsummary="yes"&gt;
  324. &lt;classpath&gt;
  325. &lt;path refid="classpath"/&gt;
  326. &lt;path refid="application"/&gt;
  327. &lt;/classpath&gt;
  328. &lt;batchtest fork="yes"&gt;
  329. &lt;fileset dir="${src.dir}" includes="**/*Test.java"/&gt;
  330. &lt;/batchtest&gt;
  331. &lt;/junit&gt;
  332. &lt;/target&gt;</b>
  333. ...</pre>
  334. <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
  335. globally available. The <var>printsummary</var>=<q>yes</q> lets us see more detailed information than just a "FAILED"
  336. or "PASSED" message. How much tests failed? Some errors? <var>printsummary</var> lets us know. The classpath is set up
  337. to find our classes. To run tests the <code>batchtest</code> here is used, so you could easily add more test classes in
  338. the future just by naming them <code>*Test.java</code>. This is a common naming scheme.</p>
  339. <p>After a <kbd>ant junit</kbd> you'll get:</p>
  340. <pre class="output">
  341. ...
  342. junit:
  343. [junit] Running oata.HelloWorldTest
  344. [junit] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0,01 sec
  345. [junit] Test oata.HelloWorldTest FAILED
  346. BUILD SUCCESSFUL
  347. ...</pre>
  348. <p>We can also produce a report. Something that you (and others) could read after closing the shell ... There are two
  349. steps: 1. let <code>&lt;junit&gt;</code> log the information and 2. convert these log files to something readable
  350. (browsable).<p>
  351. <pre>
  352. ...
  353. <b>&lt;property name="report.dir" value="${build.dir}/junitreport"/&gt;</b>
  354. ...
  355. &lt;target name="junit" depends="jar"&gt;
  356. <b>&lt;mkdir dir="${report.dir}"/&gt;</b>
  357. &lt;junit printsummary="yes"&gt;
  358. &lt;classpath&gt;
  359. &lt;path refid="classpath"/&gt;
  360. &lt;path refid="application"/&gt;
  361. &lt;/classpath&gt;
  362. <b>&lt;formatter type="xml"/&gt;</b>
  363. &lt;batchtest fork="yes" <b>todir="${report.dir}"</b>&gt;
  364. &lt;fileset dir="${src.dir}" includes="**/*Test.java"/&gt;
  365. &lt;/batchtest&gt;
  366. &lt;/junit&gt;
  367. &lt;/target&gt;
  368. <b>&lt;target name="junitreport"&gt;
  369. &lt;junitreport todir="${report.dir}"&gt;
  370. &lt;fileset dir="${report.dir}" includes="TEST-*.xml"/&gt;
  371. &lt;report todir="${report.dir}"/&gt;
  372. &lt;/junitreport&gt;
  373. &lt;/target&gt;</b></pre>
  374. <p>Because we would produce a lot of files and these files would be written to the current directory by default, we
  375. define a report directory, create it before running the <q>junit</q> and redirect the logging to it. The log format is
  376. XML so <q>junitreport</q> could parse it. In a second target <q>junitreport</q> should create a browsable HTML report
  377. for all generated XML log files in the report directory. Now you can open the <samp>${report.dir}\index.html</samp> and
  378. see the result (looks something like JavaDoc).<br/> Personally I use two different targets
  379. for <code>&lt;junit&gt;</code> and <code>&lt;junitreport&gt;</code>. Generating the HTML report needs some time and you
  380. 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>
  381. <h2 id="resources">Resources</h2>
  382. <ol class="refs">
  383. <li><a href="https://archive.apache.org/dist/logging/log4j/1.2.17/log4j-1.2.17.zip"
  384. target="_top">https://archive.apache.org/dist/logging/log4j/1.2.17/log4j-1.2.17.zip</a></li>
  385. <li><a href="https://logging.apache.org/log4j/1.2/manual.html"
  386. target="_top">https://logging.apache.org/log4j/1.2/manual.html</a></li>
  387. <li><a href="https://junit.org/junit4" target="_top">https://junit.org/junit4</a></li>
  388. </ol>
  389. </body>
  390. </html>