2

我正在尝试在自定义 Ant 标记中添加嵌套类型,如http://ant.apache.org/manual/develop.html#nested-elements中所述,但我不断收到异常outer doesn't support the nested "innerone" element.

我整个早上都在谷歌上搜索,但我找不到任何示例、教程或任何使用这种模式来解决这个问题的帮助,我开始怀疑它是否已经实现了!

我的构建文件:

<?xml version="1.0"?>
<project name="test" default="tester" basedir="../../..">
  <taskdef name="outer" classname="tester.Outer" classpath="target/classes"/>
  <typedef name="innerone" classname="tester.Outer$InnerOne" classpath="target/classes"/>
  <typedef name="innertwo" classname="tester.Outer$InnerTwo" classpath="target/classes"/>

  <target name="tester">
    <innerone/>
    <innertwo/>
    <outer>
      <innerone/>
      <innertwo/>
    </outer>
  </target>
</project>

Java代码:

public class Outer extends Task
{
  private List<Inner> inners = new ArrayList<Inner>();
  public void add(Inner inner) {
    inners.add(inner);
    System.out.println("Add: ");
  }
  public void addConfigured(Inner inner) {
    inners.add(inner);
    System.out.println("AddConfigured: ");
  }
  public void execute() {
    for (Inner inner : inners) {
      System.out.println("Inner: " + inner.getMsg());
    }
  }

  public interface Inner {
    String getMsg();
  }
  public static class InnerOne implements Inner {
    public String getMsg() {
      return "One";
    }
  }
  public static class InnerTwo implements Inner {
    public String getMsg() {
      return "Two";
    }
  }
}

使用这些方法addInner(Inner inner)并且addConfiguredInner(Inner inner)两者都有效,但我希望能够添加实现 Inner 接口的内部标记,而不必在 Outer 类中为它们显式创建方法。

4

2 回答 2

1

传统上,嵌套元素名称必须在方法名称中指定,例如将嵌套元素定义<inner>addInner(Inner inner) or addConfiguredInner(Inner inner)(正如您所提到的,它可以工作)。

Ant 1.5 引入了DynamicConfigurator接口,它提供了一种动态定义属性和嵌套元素名称的机制。尽管这并不能完全提供您正在寻找的功能,但您可能仍然会发现它很有用。例如,您的Outer任务可以按如下方式实现。

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DynamicConfigurator;
import org.apache.tools.ant.Task;

import java.util.ArrayList;
import java.util.List;

public class Outer extends Task implements DynamicConfigurator
{
  private List<Inner> inners = new ArrayList<Inner>();

  public void setDynamicAttribute(String name, String value)
      throws BuildException {
    throw new BuildException("Attribute " + name + " is not supported");
  }

  public Inner createDynamicElement(String elementName) {
    Inner newInner = null;
    if (elementName.equalsIgnoreCase("innerone")) {
      newInner = new InnerOne();
    } else if (elementName.equalsIgnoreCase("innertwo")) {
      newInner = new InnerTwo();
    } else {
      throw new BuildException("Unsupported nested element: " + elementName);
    }
    inners.add(newInner);
    return newInner;
  }

  public void execute() {
    for (Inner inner : inners) {
      System.out.println("Inner: " + inner.getMsg());
    }
  }

  public interface Inner {
    String getMsg();
  }

  public static class InnerOne implements Inner {
    public String getMsg() {
      return "One";
    }
  }

  public static class InnerTwo implements Inner {
    public String getMsg() {
      return "Two";
    }
  }
}

构建文件(摘录)

<taskdef name="outer" classname="tester.Outer" classpath="target/classes"/>

<target name="outer-test">
  <outer>
    <innerone />
    <innertwo />
  </outer>
</target>

输出

outer-test:
    [outer] Inner: One
    [outer] Inner: Two

BUILD SUCCESSFUL
Total time: 0 seconds
于 2012-10-02T16:45:35.050 回答
1

您的示例与您链接的示例非常相似,来自 ant 手册。它们之间有什么区别,一个有效,另一个无效?这是一段很长的路,但是一步一步地让它们越来越相似,我发现了区别。

typedef里面必须有给定的loaderRef属性,等于classpathtypedef 任务的文档说:

使用它允许使用同一个加载器加载多个任务/类型,以便它们可以相互调用。

可能使用 antlib 会使这个问题不存在,因为它是在一个 ant 脚本行中声明的。

最后答案是:是的,它们确实有效:)

于 2012-10-02T17:54:37.123 回答