0
votes

i was writing a custom task for ant in java and my idea was that i can give someone the .jar which contains the java files like the classes and the libraries and the build.xml for ant and he can use it.

If i export my java project the .jar (antTask.jar) contains : a folder for the compiled classes, one for the libraries, meta-inf folder and .classpath .project files

The ant build.xml looks like this:

<?xml version="1.0" ?>
<project name="repair" basedir="." default="repairTask">    
<taskdef name="antTask" classpath="antTask.jar" classname="def.RepairTask"/>
<target....

i don't really understand all this classpath stuff, so can someone tell me what i have to add in my build file so it will work only with this .jar file without the java code sources?

right now i am getting an error that ant can't find one of the libraries i use in the java code with this error (but the antTask.jar contains this lib as another .jar):

taskdef A class needed by class def.RepairTask cannot be found: org/apache/commons/...      
using the classloader AntClassLoader[C:...\AntTask\antTask.jar]

i am trying for hours but i just can't figure out how i have to edit my build.xml so i just have to point to this single .jar file and it works..

Thank you guys

1
Can you post the entire error message from Ant? I suspect that you are referencing a third party JAR (like Apache StringUtils) to which you may not have a reference in the subsequent project in which you're using your custom Ant task. - J Steven Perry
taskdef A class needed by class def.RepairTask cannot be found: org/apache/commons/io/input/BOMInputStream using the classloader AntClassLoader[C:...\antTask.jar]. yes it is a third party lib. but it is contained in the resulting antTask.jar and also everything is working when i use eclipse to run a the ant build.xml (i edit the run configuration and add the missing apache jar) but i really want to now how i can write this down into the build.xml so it will work without eclipse - yaay

1 Answers

0
votes

All a taskdef does is associate a task name to a classfile that contains the code to execute that task. However, in order to find that classfile, you need to tell <taskdef/> where to find the jar that contains it. That's all classpath does is.

You don't have to define a classpath with the <taskdef/> task. Ant by default looks for all jars that contain code for the <taskdef/> tasks in $ANT_HOME/lib. If you copy your jar to that folder, you could simply define that task this way:

<taskdef name="antTask" classname="def.RepairTask"/>

No need for the classpath. However, I actually don't recommend doing that. Instead, I recommend putting that jar file into your project, so other developers can use your project without having to install that task jar into their $ANT_HOME/lib folder:

<taskdef name='antTask' classname="def.RepairTask">
    <classpath>
        <fileset dir="${basedir}/antlib/antjar"/>
    </classpath>
</taskdef>

Now, when a developer checks out the project that requires the optional task jar, that task jar comes with the project, so they can simply do their build.

There are two ways to define tasks. One is to give a task a name, and then tell <taskdef/> what classfile is associated with that jar as you did above. However, you can also define a resource that also will associate task names with their classes. Here's a common way to include the Ant-Contrib ant tasks:

<taskdef resource="net/sf/antcontrib/antcontrib.properties">
    <classpath>
        <fileset dir="${basedir}/antlib/antcontrib"/>
    </classpath>
</taskdef>

If I expand the antcontrib jar, I'll see it contains a net/sf/antcontrib/antcontrib.properties1 file inside the jar. That file looks something like this:

...
# Logic tasks
if=net.sf.antcontrib.logic.IfTask
foreach=net.sf.antcontrib.logic.ForEach
throw=net.sf.antcontrib.logic.Throw
trycatch=net.sf.antcontrib.logic.TryCatchTask
switch=net.sf.antcontrib.logic.Switch
outofdate=net.sf.antcontrib.logic.OutOfDate
runtarget=net.sf.antcontrib.logic.RunTargetTask
timestampselector=net.sf.antcontrib.logic.TimestampSelector
antcallback=net.sf.antcontrib.logic.AntCallBack
antfetch=net.sf.antcontrib.logic.AntFetch
assert=net.sf.antcontrib.logic.Assert
relentless=net.sf.antcontrib.logic.Relentless

# Math Tasks
math=net.sf.antcontrib.math.MathTask
...

All it does is define each task with a classfile for that task. I would recommend you do something similar with your custom ant task. This way, if you decide to include other tasks, you can simply modify this one file, and developers won't have to change their <taskdef/> definition in their jars, or add in multiple ones.

By the way, you should make good and sure that your class doesn't clash with another class that someone else may use. You might want to give your classname a full path that includes a unique prefix:

<taskdef name='antTask' classname="com.vegicorp.anttasks.RepairTask">

Assuming you work for VegiCorp...


1 Ant contrib tasks contain two such files. One is XML format and the other is in properties format. I always use the XML format, and that's what your suppose to use when you define Ant Task resources. I used the properties file because it's a simpler format and easier to see what's going on.