February 16, 2019
Hot Topics:

More on Custom Ant Tasks

  • October 5, 2006
  • By Rob Lybarger
  • Send Email »
  • More Articles »

Nesting Tasks and Conditions: Task versus ConditionBase

One final wrinkle that might surface is the case of needing to write a task that supports arbitrary condition types. Naturally, single-inheritance being what it is, you cannot subclass both Task and ConditionBase at the same time. On the other hand, a quick view of the documentation for the "if" task (provided in the ant-contrib package) indicates it is doing exactly this feat. A quick peek at the source code for the "if" task, however, indicates that it subclasses ConditionBase (and implements TaskContainer to allow any nested tasks). Yet, it provides an execute() method and functions apparently like any other first-class task. (For that matter, the standard condition task itself is a ConditionBase derivative that behaves like a task.)

The conclusion is that Ant has a little-known (at least little-publicized) secret: Your task doesn't exactly have to subclass ant's own "Task" class to work... simply having the execute() method, plus being taskdef'ed, is enough to work. Still, you do lose out on a bit of functionality that the Task class would provide you if you were to subclass from it, so weigh the effects of this carefully. (The condition and if tasks don't do anything that really requires such functionality.) You can still get and set project-level properties by virtue of ConditionBase also being a subclass of Ant's ProjectComponent class.

However, the general spirit of Ant's design indicates you may want to consider a different approach: Have your main task class subclass from Task to provide the execute() method and then provide a nested condition type which subclasses from ConditionBase to handle the conditions. Example:

<project ...>

   <taskdef name="mytask" ... />
   <typedef name="mycondition" ... />

   <mytask ...>
         <!-- standard conditionals here -->
      <!-- standard or custom tasks nested here -->


What's Left?

Custom selectors

Another special-purpose type that Ant exposes to customizations is the selector type used in, for example, a fileset element. You can write your own logic to determine whether a given file encountered in the filesystem (as a fileset is being populated) should be included in the fileset's entries. To do this, implement the org.apache.tools.ant.types.selectors.FileSelector interface and provide an implementation for isSelected:

public class MyCustomSelector implements FileSelector {
   public boolean isSelected(File basedir,
                             String filename,
                             File file)      { ... }

This is a type, so declare this via a typedef statement. And of course, you may provide for attributes and other nested elements as with any custom type. Although I will not show an example here, the Ant manual shows a quick example of a selector that returns true only if the filename ends in ".java", but the selection logic can be as complex as you need it to be.

Much like the ConditionBase class, there is an analogous org.apache.tools.ant.types.selectors.BaseSelectorContainer class that you might want to look into, should you wish to write a custom task or type that allows arbitrary nested standard selector elements.

XML Namespaces

The more recent versions of Ant (the 1.6 branch) support the concept of XML namespaces. A namespace in XML is conceptually similar to namespaces in programming toolsets (like Java's concept "package"). The standard version of Ant includes the <property> element, so if you also create a custom task or type with that element name, you'll collide against the standard version. With an XML namespace prefix, you could say <acme:property> and get your version instead.

Ant gives you a few different ways to get a namespace prefix to work in your build files, but I will show just this one version that puts the "xmlns" attributes in the root element (that is, the <project> element) where XML geeks are likely to look for them. The only other thing you need to do is to match the value of the URI you mention in the xmlns attribute in a uri attribute in your taskdef and typedef elements:

<project xmlns:acme="http://ant.acme.com/custom" ...>

   <taskdef uri="http://ant.acme.com/custom" ... />
   <typedef uri="http://ant.acme.com/custom" ... />

   <acme:mytask ...>

         <isset property="some_property />

      <delete file="some_file.properties" />

      <acme:mytype ... />



Although many publicly available projects tend to use a web address (URL) as their URI, it can be any string in any format you want... just be sure they match. (If you make your custom ant code available in bid for fame and fortune, pick a stable URI and don't change it.) A URI value of INHOUSE_CODE_BY_TOM_DICK_AND_HARRY is just as functional (to Ant, anyway) as the URI in the above example.

Download the Code

You can download the code file that accompanies the article here.

Next Time

Custom Ant event loggers and Ant in your apps

You also can make use of the built-in Ant task code in your own Java applications and projects without having to invoke Ant on the command line. You also can hijack the default logging facilities to create Ant logging output in any custom format you need. I will cover these two options in a future article. Stay tuned.


About the Author

Rob Lybarger is a software engineer who has been using Java for nearly a decade and using Ant since its earliest days. He has used various versions of Windows, various distributions of Linux, and, most recently, Mac OS X. Although he knows a wide array of software languages, the cross-platform nature of Java and Ant has proven to be a valuable combination for his personal and professional efforts.

Page 4 of 4

Comment and Contribute


(Maximum characters: 1200). You have characters left.



Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date