2010-12-09 13 views
10

私は、1つのフィールドが別のフィールドのサブセットであり、スーパーセットクラスのゲッターがすべて(getFoo())という名前のクラスを持っています。 に効率的にのすべての共通フィールドをスーパーセットクラスからサブセットクラスにコピーするか、少なくともそのようにコードを自動生成します。Javaの類似クラス間のフィールドをコピーする

私はそれを注意する必要があります。さまざまな理由

  • を、私はスーパーセットクラスを編集することはできません、また私はただのデータコピーを行うことを避けるために全体にそれらを使用することができます。
  • サブセットクラスで新しいメソッドを作成する可能性がありますが、フィールドを変更することはできません。
  • これらのペアは数多くあり、いくつかのクラスには多くのフィールドがありますので、これを手作業で行うのは難しくありません。
  • 同僚は、Javaリフレクションを使用して2つのクラスを取り、フィールドを文字列として反復し、文字列操作を行ってゲッター名を決定し、それを実行して自動的に設定するジェネリックコピーメソッドを作成する方法を考え出しましたサブセットクラスのフィールド。ひどいですが、うまくいくようです。私は本当に良い方法があることを願っています。

編集:要求された

public class SuperClass { 
    private int foo; 
    private int bar; 
    private float bat; 
    public int getFoo() { return foo; } 
    public int getBar() { return bar; } 
    public float getBat() { return bat; } 
} 

public class SubClass { 
    private int foo; 
    private float bat; 
} 

//wanted 
public static copySuperFieldsToSubMethod(Object super, Object sub) { ??? } 

// also acceptable would be some way to autogenerate all the assignment 
// functions needed 
+0

スーパーセットクラスを編集できる場合は、サブセットクラスを拡張し、すべてのフィールドとメソッドを古典的なOOの方法で継承することができます。なぜあなたはスーパーセットクラスを編集できませんか? – Asaph

+0

@Asaph - 悲しいことに、スーパーセットクラスは、別々に開発された外部ライブラリの一部であり、現在は、この特定のプロジェクト用に作成されたクラスに変換する必要があります。 。 – Dusty

+0

関係を逆さにして、サブセットクラスをスーパーセットクラスから継承させた場合はどうなりますか?空のボディでは必要のないフィールドに関連するメソッドをオーバーライドすることができます。あまりエレガントではありませんが、少なくともコピー/ペースト、リフレクション、コード生成なしでコードを再利用できるようになります。 – Asaph

答えて

12

など、いくつかの簡単なコードはこれを行うには、SpringフレームワークでBeanUtilsクラスを使用することができます。リフレクションベースのテクニックよりも必ずしも効率的であるとは限りませんが、コード作成は簡単です。私はあなたがする必要があるだろう、すべてがあることを期待する:このメソッドの

BeanUtils.copyProperties(source, target); 

のJavadocそれが合わない場合は、SpringフレームワークでBeanWrapper/BeanWrapperImplを使用して検討することもできhttp://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/BeanUtils.html#copyProperties(java.lang.Object,%20java.lang.Object)

でご利用いただけますクラスのプロパティを反復処理します。これは、低レベルのリフレクションAPIを使用するより簡単です。

+1

うわー、それは本質的に私が探しているものですが、この1つの問題だけでSpring Frameworkを引き出すのは実現可能ではないと思います。 – Dusty

+4

Apache Commons BeanUtilsが適しているかもしれませんが、Springよりも軽量です。それは同じ名前のクラスとメソッドを持っていますが、私は決してそれを使用していませんが、疑わしいほど似ています。 http://commons.apache.org/beanutils/ – gutch

+0

を参照してください。春バージョンは、継承を介して関連するクラスでうまく機能します。 – raffian

0

あなたの投稿に記載されているシナリオを示すアプリからのサンプルコードを提供できますか? 現在、リフレクションは、実行時にクラスメンバーを検査することができるので、最良の方法のようです。

+0

サンプルコードを追加しましたが、一般的です(実際のコードを表示することはできません)。 – Dusty

+0

@ gutchのアプローチはあなたの要件に正確に合致しますが、残念ながら使用することはできません。 –

2

タスクを効率的に(ランタイムパフォーマンスに関して)したい場合は、ゲッターとセッターを使用してコピーを手作業でコーディングする方法があります。ゲッターメソッドやセッターメソッドについてファンキーなことがない限り、ボディはインライン展開され、フィールドの割り当てと同じくらい速くなります。

反射的アプローチ(例えば、BeanUtilsのような既存のクラスを使用する)は、コーディングは少なくなりますが、getterとsetterを簡単な方法で呼び出すよりも遅くなるでしょう。これを自分で実装しようとすると、特に反射的なコピークラス/メソッドがオーバーロードされたメソッド、継承、値の変換、ボクシング/ボックス解除などに対処しなければならない場合には、

コード生成のアプローチでは、コード生成の実装の労力と複雑さ(選択した技術を使用します)とコピーメソッドを手作業で作成する作業のバランスをとる必要があります。あなたはたぶんおそらく、おそらくおそらくおそらく、20クラスの前にコード生成のアプローチを破ることはありません...あなたがこの技術に精通していなければ、さらに多くのことがあります。

1

私は、スーパーセットからの共通フィールドでサブセットフィールドを設定できるクラスのソースコードを自動生成する簡単なJavaツールを作成したいと思います。このツールは、リフレクションを使用してゲッターメソッドとセッターメソッドの名前を取得します。残りの部分は、メモリにソースファイルを "書き込んで" *.javaファイルに格納するString操作です(単純な)。この自動生成されたすべてのファイルをコンパイルし、クラスファイルをクラスパスに追加します。

クラスには、次のようになります。最初の答えと同様に

class AClassToBClassPopulator implements Populator { 
    @Overwrite 
    public void populate(Object superSet, Object subSet) { 
     subSet.setFieldA(superSet.getFieldA()); 
     subSet.setFieldB(superSet.getFieldB()); 
     // .. and so on. The method body is created through reflection 
    } 
} 
0

他の人がすでに有効な示唆しているが、多分、ここでは少しヘビー級の解決策だが、これは明らかにJavaのリフレクションのための作業であり、もう一つ:

約1年前、私はBeanPropertyControllerと呼ばれる小さなJavaBeanプロパティ修飾子ライブラリを書きました。私は誰にも特に勧めているわけではありませんが、ライブラリの名前付きクラス(see source)を参考にして、同様の機能をニーズに合わせることができます。簡単な例として、ここでは(ほとんど!)私が行うためにBPCを使用する方法ですあなたが求めているもの:

// somewhere in code... 
SuperClass a = new SuperClass(); 
a.foo = 101; 
a.bar = 102; 
a.bat = 103f; 

SubClass b = new SubClass(); 
b.foo = 201; 
b.bat = 202f; 

BeanPropertyController fromB = BeanPropertyController.of(b, ExtractionDepth.QUESTIMATE); 
BeanPropertyController toA = BeanPropertyController.of(a, ExtractionDepth.QUESTIMATE); 

// This is where the magic happens: 
for (String propertyName : fromB.getPropertyNames()) { 
    toA.mutate(propertyName, fromB.access(propertyName)); 
} 
a = (SuperClass) toA.getObject(); 
b = (SubClass) fromB.getObject(); 

System.out.println("SuperClass' foo="+a.foo+" bar="+a.bar+" bat="+a.bat); 
System.out.println("SubClass' foo="+b.foo+" bat="+b.bat); 

これは、そう

SuperClass' foo=201 bar=102 bat=202.0 
SubClass' foo=201 bat=202.0 

プリントアウトし、私がお勧めすることはあなたが行くということですURLにリンクして、このコードをあなたのニーズに適応させます。私はあなたが含まれているさまざまなインスタンス化メソッド、デフォルト値プロバイダなどを必要としないと確信しています。はい、BPCは廃止予定とみなされます。

関連する問題