Monday 17 September 2012

Ant Contrib Try/Catch magic! How to Print Exception Messages in a Catch Block

Hello Readers!

This post will cover how to print exception messages in ant using means provided by ant-contrib.  Apologies for the terrible code formatting..  Will get around to fixing it!


The following examples assume you have antcontrib imported into your build file etc.  Here's a silly example of where you might want to use a try catch block; you're zipping up a folder and want to handle any problems that might occur in doing so:

<target name="try.catch.test" >
    <sequential> 
        <antc:trycatch>
            <try>
                <zip destfile="testzip.zip" basedir="testzipdir"/>
            </try>
            <catch> </catch>
        </antc:trycatch>
    </sequential>
</target>
If say, the "testzipdir" folder does not exist, the code above will swallow the exception and allow the build file to continue execution.  Perhaps we want to print this exception out instead.  To do this we need to specify the ant object that the exception will be stored in, then reference this exception and print it out in the catch block.  To specify the exception object we can add the "reference" attribute to the trycatch element e.g.
<antc:trycatch reference="exception">.
In the catch block, we can create a property that references this exception object and echo that out, e.g.
<catch>
    <property name="exceptionprop" refid="exception" />
    <echo>Exception: ${exceptionprop}</echo>
</catch>




as the antcontrib trycatch documentation seems to suggest.  However using a property to store exceptions is pretty inflexible.  What if your try/catch block is inside a for loop?  Once a property is set, it can't be set again, so if more than one exception occurs the exception message becomes useless.

Luckily, you can pull out the String value of objects referenced in ant using the ${toString:} syntax.  In our case, "${toString:exception}" would call the toString method of whatever object is referenced by "exception".  Our catch block becomes:

<catch>
    <echo>Exception: ${toString:exception}</echo>
</catch>
Putting this all together, the following example loops through all directories specified by the "dir.list" property, and attempts to zip them up.  If any of the listed directories do not exist, the zipping fails and an exception is echoed out.




<target name="try.catch.test"> 
  <sequential>
   <antc:for list="${dir.list}" param="dir">
    <sequential>
     <antc:trycatch reference="exception">
      <try>
       <zip basedir="@{dir}" destfile="@{dir}.zip">
      </zip></try>
      <catch>
       <echo>Exception: ${toString:exception}</echo>
      </catch>
     </antc:trycatch>
    </sequential>
   </antc:for>
  </sequential>
 </target>






Calling this target using ' ant try.catch.test -Ddir.list="bleh,build,Test" ' where directories "build" and "Test" exist but "bleh" does not, will result in the following output:





try.catch.test:
[echo] Exception: C:\Work\build.xml:118: C:\Work\bleh not found.
[zip] Building zip: C:\Work\build.zip 
[zip] Building zip: C:\Work\Test.zip




Hope you've found this useful!