0

私は Apache Ant を、何度も繰り返さなければならない退屈なデータ収集と計算タスクのツールとして使用しています。カスタム Ant タスクをいくつか定義しましたが、それらは非常にうまく機能します。

<typedef>ただし、タグを使用して新しいデータ型を作成したいと考えています。build.xml私のJavaプロジェクトの1つからの通常のビルドファイルからの次の例のように、後で参照できるように、myの最初にいくつかのデータを定義したいと思います。

<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。また、CustomTaskクラスsetDatarefメソッドには実際に という名前の参照が渡される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 エラーが my に表示されます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 sourcefileですべてがうまくいきません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 ClassLoader によってロードされます。異なる ClassLoader を介してロードされた同じ名前の 2 つのクラスは、Java VM の観点からは同じクラスではありません。それらは静的変数を共有せず、これらのクラスのインスタンスはプライベート メソッドまたは "同じ名前の他のクラス」。それらは同じ 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

問題は、クラスのデータにセッターを提供していないことだと思います...これは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 に答える
0

上記のGistを使用して解決しました!問題は 2 つありますが、2 番目の問題を解決する方法がわかりません。

問題1

どういうわけか、タグとタグのclasspathref引数は適切ではありません。ディレクトリ内のコンパイル済みクラスにそれらを誘導しています。typedeftaskdefcls

そこで、すべてのファイルを jar して、{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

コマンドラインからの実行は問題ないことが証明されました。

ボトムライン

この問題は、タイプとタスクを並べ替えてコマンドラインから実行することで解決されます。またはを使用classpathrefすると、エラーが発生しました。Eclipse を使用すると、エラーが発生しました。typedeftaskdefsomeid doesn't denote a SampleDataclass not found

私が言わなければならない奇妙な動作と、Eclipse をカスタムタスクで適切に動作させる方法を知りたいです。それは可能でなければならないからです。

ええと...それは私に数時間を費やしました。

于 2012-11-23T11:15:34.757 に答える