自定义Ant类型,引用结果为空类

时间:2012-11-22 14:30:37

标签: java ant customization

我正在使用Apache Ant作为繁琐的数据收集和计算任务的工具,我必须一遍又一遍地做。我已经定义了一些自定义的Ant任务,它们的工作非常好。

但是,现在我想使用<typedef>标记创建新的数据类型。我想在我的build.xml开头定义一些数据,稍后我可以参考,就像我的一个Java项目的常规构建文件中的以下示例一样:

<path id="classpath.build">
    <fileset dir="${dir.lib}">
        <include name="**/*.jar" />
        <exclude name="**/junit*" />
    </fileset>
</path>

所以我创建了一个简单的HelloWorld示例,如下所示:

<sampledata data="LOL" id="someid" />

在自定义ant任务中,我想引用这种数据类型:

<customtask dataref="someid" />

这看似合理简单,因此在深入研究API文档后,我发现我的课程必须扩展org.apache.tools.ant.types.DataType并且必须使用方法setRefid(org.apache.tools.ant.types.Reference r)

我的自定义Ant任务customtask对dataref属性使用以下代码:

public class CustomTask extends Task {

     private SampleData data;

     public void setDataref(Reference r) {
        data = new SampleData(getProject());
        data.setRefid(r);
     }

     public void execute() {
          System.out.println(data.getData());
     }
}

我的SampleData实现如下:

public class SampleData extends DataType {

     private String data;

     public SampleData(Project project) {
         setProject(project);
     }

     public void setData(String data) {
         this.data = data;
     }

     public String getData() {
         return this.data;
     }

     public void setRefid(Reference r) {
          super.setRefid(r);
     }

 }

请注意,这完全基于来自org.apache.tools.ant.types.Path的来源,它显示了我想要的行为。

但是,在使用上面定义的customtask创建目标后,输出为null。因此SampleData被实例化,但引用未正确设置。当我调试时,我发现SampleData在我的ant文件中使用数据LOL正确实例化,甚至refence也设置为someid。此外,CustomTasksetDataref方法确实传递了一个名为someid的引用,所以在setDataref方法中都出错了,但我不知道我有什么并且缺乏手册(或者我缺少一个重要的部分)。

我觉得我没有完全掌握id为自定义数据类型的生命周期。

编辑23-11-2012 9:24:

经过一些更多的摆弄并查看org.apache.tools.ant.types.Path的来源后,我遵循了一些方法并将SampleData.getData更改为以下内容:

public String getData() {
    if(isReference()) {
        return ((SampleData)getCheckedRef()).getData();
    }
    return this.data;
}

我稍微进一步,但现在我在build.xml中收到以下Ant错误:

 /home/arjan/dev/so-demo/build.xml:9: someid doesn't denote a SampleData

但是,当我检查由Reference对象封装的类时,它是正确的类型。 我现在非常厌倦了。还有什么提示吗?

编辑23-11-2012 11:46:

我用一个明确的测试用例创建了一个Gist。我的Ant版本是1.8.4。 希望有人会提供一个解决方案,因为我已经查看了Sonatype Aether Antlib等其他库,并遵循他们的推理方式。

getCheckedRef方法出错,特别是在Ant源文件src\main\org\apache\tools\ant\types\DataType.java:250中:

if (!(requiredClass.isAssignableFrom(o.getClass()))) {
    log("Class " + o.getClass() + " is not a subclass of " + requiredClass,
            Project.MSG_VERBOSE);
    String msg = ref.getRefId() + " doesn\'t denote a " + dataTypeName;
    throw new BuildException(msg);
}

发生了什么事?这是我能想到的简单测试用例。

3 个答案:

答案 0 :(得分:1)

我相信这可能会解决您的问题,我遇到了类似的错误:

您缺少自定义任务和类型的loaderRef指令。请参阅here:如果要定义与多个taskdef或typedef任务共享相同类路径的任务或类型,则相应的类将由不同的Java ClassLoader加载。从Java VM的角度来看,通过不同的ClassLoader加载的两个具有相同名称的类不是同一个类,它们不共享静态变量,并且这些类的实例不能访问由“”定义的实例的私有方法或属性。另一类“同名。它们甚至不属于同一个Java包,也不能访问包私有代码。

因此,当您通过typedef和taskdef定义自定义任务和自定义类型时,请使用loaderRef属性 - 这可以是任何内容(如customTaskLoader),只要它在您的任务和类型定义之间是相同的。

从那里,您可以进一步简化代码:

public class CustomTask extends Task {

 private SampleData data;

 public void execute() {
      System.out.println(data.getData());
 }

}

public class SampleData extends DataType {

 private String data;

 public SampleData(Project project) {
     setProject(project);
 }

 public void setData(String data) {
     this.data = data;
 }

 public String getData() {
     if(isReference()) {
         return ((SampleData)getCheckedRef()).getData();
     }
     return this.data;
 }

}

答案 1 :(得分:0)

我认为问题是你没有为你的班级提供数据的setter ...这对于CustomTask是强制性的......

public class CustomTask extends Task {
    private SampleData data;
     public void setDataref(Reference r) {
        data = new SampleData(getProject());
        data.setRefid(r);
     }
    public void setData(SampleData data){
        this.data = data;
    }
     public void execute() {
          System.out.println(data.getData());
     }
}

希望这会有所帮助..

答案 2 :(得分:0)

我使用上面的要点解决了它!问题是双重的,但我不知道如何解决第二个问题。

问题1

classpathreftypedef标记的taskdef参数不是一种方法。我将它们导向cls目录中的已编译类。

所以我决定将我的所有文件存放起来并将它们放在{ant.home}/lib目录中,如下所示:

<jar basedir="cls" destfile="${ant.home}/lib/demo.jar" />
<delete dir="cls" />

这样我可以删除classpathref个参数。 我认为这可能会解决它...但我错了,但是实际的解决方案(如果你可以称之为)可行。

问题2

Eclipse ...这个程序使用自己的Ant发行版,运行Eclipse时,我自己生成的jar不会添加到类路径中。这会导致以下错误:

typedef class types.DemoType cannot be found

从命令行运行证明没问题。

<强>底线

通过调整我的类型和任务并从命令行运行它来解决问题。将classpathreftypedeftaskdef一起使用会导致someid doesn't denote a SampleData错误。使用Eclipse导致class not found错误。

奇怪的行为我必须说,我想知道如何让Eclipse正常使用自定义任务,因为这必须是可能的。

嗯......这花了我几个小时。