0

我使用 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显示我想要的行为的来源。

但是,在使用上述自定义任务创建目标后,输出为null. 因此 SampleData 已实例化,但引用设置不正确。当我调试时,我发现 SampleData 在我的 ant 文件中正确实例化了数据LOL,甚至参考设置为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;
}

我更进一步,但是现在我在我的中收到以下 Ant 错误build.xml

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

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

编辑 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);
}

到底是怎么回事?这是我能想出的简单测试用例。

4

3 回答 3

1

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

您缺少自定义任务和类型的 loaderRef 指令。请参见此处:如果您正在定义与多个 taskdef 或 typedef 任务共享相同类路径的任务或类型,则相应的类将由不同的 Java 类加载器加载。从 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;
 }

}

于 2013-07-12T15:56:21.013 回答
0

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

问题 1

不知何故,和标签的classpathref论点不是要走的路。我将它们引导到目录中我编译的类。typedeftaskdefcls

所以我决定将我所有的文件打包并放在{ant.home}/lib如下目录中:

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

这样我可以删除classpathref论点。我认为这可能会解决它......但我错了,但它是有效的实际解决方案(如果你可以这样称呼它)。

问题 2

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

typedef class types.DemoType cannot be found

从命令行运行被证明是没有问题的。

底线

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

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

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

于 2012-11-23T11:15:34.757 回答
0

我认为问题是你没有在你的班级中为 Data 提供 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());
     }
}

希望这可以帮助..

于 2012-11-23T05:50:28.893 回答