2010-11-23 6 views
8

私のプロジェクトでは、ゲッターとセッターだけのDTO、POJOの2つのパッケージがあります。単純なJava Bean(例えば、Apache CXFがWebサービスXSDなどを作成するために使用するなど)は重要ですが、そのようにプログラムするのはひどく誤りがちです。Java Builderジェネレータの問題

Foo foo = new Foo(); 
foo.setBar("baz"); 
foo.setPhleem(123); 
return foo; 

私は流暢なインターフェイスやビルダーオブジェクトを好むので、私は自動的にのDTOのためのビルダーを作成するのmaven/gmavenを使用しています。私も自動的に生成されたビルダーのためのユニットテストを生成

Foo foo = new FooBuilder() 
      .bar("baz") 
      .phleem(123) 
      .build(); 

を:だから、上記のコードのために、FooBuilderは自動的に私はこのように使うことができ、生成されます。単体テストでは、上記のコード(ビルダー・バージョンと非ビルダー・バージョン)の両方が生成され、両方のバージョンがequals()hashcode()という点で同等であると主張します。私が達成できる方法は、すべてのプロパティタイプに対してデフォルトでグローバルにアクセス可能なMapを用意することです。次のようなものがあります。

public final class Defaults{ 
    private Defaults(){} 
    private static final Map<Class<?>, Object> DEFAULT_VALUES = 
     new HashMap<Class<?>, Object>(); 
    static{ 
     DEFAULT_VALUES.put(String.class, "baz"); 
     // argh, autoboxing is necessary :-) 
     DEFAULT_VALUES.put(int.class, 123); 
     // etc. etc. 
    } 
    public static getPropertyValue(Class<?> type){ 
     return DEFAULT_VALUES.get(type); 
    } 
} 

もう1つの重要なことは、時にはコレクションメンバーがあることです。例えば:

foo.setBings(List<Bing> bings) 

が、私のビルダーでは、私がこの場合の二つの方法を生成したいと思います:setメソッドとaddメソッド:私は、カスタムアノテーションを追加することでこれを解決した

fooBuilder.bings(List<Bing> bings); // set method 
fooBuilder.addBing(Bing bing); // add method 

Foo

@ComponentType(Bing.class) 
private List<Bing> bings; 

ビルダービルダー(SIC)でプロパティフィールドは、注釈を読み取って生成する方法の一般的なタイプのような値を使用します。

私たちは今質問に近づいています(申し訳ありませんが、簡潔さは私のメリットの一つではありません:-))。

私は、このビルダーのアプローチが複数のプロジェクトで使用できることに気づいたので、私はそれをmavenプラグインに変換することを考えています。私はMavenプラグインを生成する方法について完全にはっきりしているので、それは質問の一部ではなく(有効なJavaソースコードを生成する方法でもない)私の問題は次のとおりです。どのように私は(プロジェクトとプラグインの間)の任意の共通の依存関係を導入することなく、上記の二つの問題に対処することができます

<Question>

  1. 私はデフォルトクラス(または同様のメカニズム)が必要です生成された単体テストのデフォルト値を取得するためのものです(これは概念の重要な部分ですが、完全にテストされていない場合は自動的に生成されたビルダーを信頼しません)。各プロジェクトが独自のドメインオブジェクトを持っているので、この問題を解決するための良い一般的な方法を考えてください。

  2. ジェネリック型をビルダージェネレータに伝達する一般的な方法が必要です。私が使用している現在のアノテーションベースのバージョンは、プロジェクトとプラグインの両方が同じアノテーションを認識する必要があるため、満足できるものではありません。

</Question>

任意のアイデア?

私は、ビルダーを使用することの本当の重要な点は、オブジェクトを不変にしていることを知っています。標準のJava Beanが必要なので私は変更できませんが、AspectJを使用して、ビルダー以外のコードベースのどこでもset-methodもコンストラクタも呼び出されないようにします。したがって、実際の目的では、 。

また、はい、私は既存のビルダージェネレータIDEプラグインについて認識しています。それは私の目的に合っていません。自動化されたソリューションが必要です。基礎となるコードが変更されたときは常に最新の状態になっています。


マットBはビルダーの生成方法についていくつかの情報を要求しました。私は何をしますか:

私はリフレクションごとにクラスを読んで、Introspector.getBeanInfo(clazz).getPropertyDescriptors()を使ってプロパティ記述子の配列を取得します。私のすべてのビルダーは基本クラスAbstractBuilder<T>を持っています。ここで、はFooになります。ここにはthe code of the Abstract Builder classがあります。 PropertyDescriptor配列内のすべてのプロパティに対して、プロパティの名前でメソッドが生成されます。これはFooBuilder.bar(String)の実装次のようになります。

public FooBuilder bar(String bar){ 
    setProperty("bar", bar); 
    return this; 
} 

AbstractBuilderbuild()メソッドは、オブジェクトをインスタンス化し、それのプロパティマップ内のすべてのプロパティを割り当てます。

+0

コメント:Javaコード(特にユニットテストの巨大なセット)を生成する必要があるときは、grep/sed + pythonを使用します。 – khachik

+0

私は言語を理解する技術を使いたいです。これは、a)リフレクションb)ソースコードパーサc)ASMのようなバイトコードツール –

+0

興味深いことに、MavenプラグインがBuilderクラスを生成するのは何ですか? –

答えて

1

Diezelを見ましたか? ビルダージェネレータです。

  1. それはそれは記述のXMLファイルに基づいて、すべてのインターフェイス、および実装ボイラープレートを生成し、質問2
  2. のためにここに役に立つかもしれませんので、それは、ジェネリック型を処理します。このXMLを生成するためのイントロスペクションを通じて(またはより低いAPIに直接行くこともできます)
  3. これは、Mavenプラグインとしてバンドルされています。
+0

すごくいいですね、ありがとう –

2

POJOは、Java Bean spoecに従わないオブジェクトです。すなわち、セッター/ゲッターはありません。

JavaBeansは設定者を必要とせず、呼び出したくない場合は生成しません。 (あなたのビルダーはパッケージのローカルコンストラクタまたはプライベートコンストラクタを呼び出して不変オブジェクトを作成できます)

+0

これはPOJOではなくBeanです。しかし、私たちが使っているいくつかの外部ツールは(たとえ自分で使っていなくても)セッターに依存しているので、彼らにはセッターが必要です。あなたは別の質問に答えています(私の答えは無効で、私には関係ないと言っているわけではありません)。質問は不変性に関するものではなく、2つの具体的な問題に関するものであり、どちらもあなたの答えによって解決されていません。 –