5
votes

I wrote two different custom Ant tasks. They are trying to share data through a static member in a base class. This is not working for me.

I assume I am using static members correctly within Java. I think this is a dynamic loading issue with the Java VM. However, I am a relative newbie with Java.

Since Ant custom tasks are mapped at runtime using the taskdef task, the Ant build engine must dynamically load this code via java.lang.reflect.Constructor.newInstance().

Is there a trick to make this work?

Note: This works fine in "regular" Java code... it is the dynamic loading of Ant that is the issue.

Example classes:

import org.apache.tools.ant.Task;

public class AntCustomTaskShared extends Task {
    private static Integer _static_bigdata = null;
    public Integer get_bigdata() {
        if (_static_bigdata == null) {
            log("alloc");  // from ant Task class
            _static_bigdata = new Integer(0);
        }
        return _static_bigdata;
    }
}
import org.apache.tools.ant.BuildException;

public class AntCustomTask1 extends AntCustomTaskShared {
    public void execute() throws BuildException {
        Integer big_data = get_bigdata();  // "alloc" is printed
        // do stuff with big_data
        log("I'm doing big stuff");
    }
}
import org.apache.tools.ant.BuildException;

public class AntCustomTask2 extends AntCustomTaskShared {
    public void execute() throws BuildException {
        Integer big_data = get_bigdata();  // "alloc" is printed (again)
        // do stuff with big_data
        log("I'm doing big stuff again");
    }
}

Example Ant build.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project name="MyTask" basedir="." default="init">
   <target name="init"
           description="test the custom task"
   >
      <taskdef name="CustomTask1"
               classname="AntCustomTask1"
               classpath="C:\my_custom_ant_task_class_files"
      />
      <taskdef name="CustomTask2"
               classname="AntCustomTask2"
               classpath="C:\my_custom_ant_task_class_files"
      />
      <CustomTask1/>
      <CustomTask2/>
   </target>
</project>

Do all of the above and you will see "alloc" logged twice. I cannot get these two custom tasks to share the "big data".

I am running ant 1.8.1 on Windows with these two env vars:

  • JAVA_HOME=C:\Program Files\Java\jdk1.6.0_21
  • CLASSPATH=(empty)

Hint: If you want to step into this custom task from an Ant (1.8) process, set your breakpoints here:

  • org.apache.tools.ant.launch.Launcher.main()
  • org.apache.tools.ant.UnknownElement.execute()
2
could you post a simple build that illustrates this? I've tried this locally and it appears to work for me - no second alloc is printed.martin clayton
Using your sample build I don't get two calls to the BigData constructor. Do see two allocs now though: one from println, and one from logger. I've got all the classes in one directory fwiw.martin clayton

2 Answers

1
votes

The solution is simple, but poorly (or not?) documented on the Ant website. (I will commit a patch to the Ant docs to correct this situation!)

I needed to use the attribute loaderref on taskdef nodes. The token is used to reference the ClassLoader (and share it). After, static members are shared between custom tasks correctly.

Corrected Ant build.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project name="MyTask" basedir="." default="init">
   <target name="init"
           description="test the custom task"
   >
      <taskdef name="CustomTask1"
               classname="AntCustomTask1"
               classpath="C:\my_custom_ant_task_class_files"
               loaderref="my_shared_class_loader"
      />
      <taskdef name="CustomTask2"
               classname="AntCustomTask2"
               classpath="C:\my_custom_ant_task_class_files"
               loaderref="my_shared_class_loader"
      />
      <CustomTask1/>
      <CustomTask2/>
   </target>
</project>
0
votes

This is less elegant, but you could try sharing the information via the System.setProperty and System.getProperty calls. The ANT class loading is definitely different then a normal Java application.