プロパティコピーツールの使用はお勧めしません」と申し上げた通り、変換クラスと変換メソッドを直接定義し、IDEAプラグインを使用してget/set関数を自動入力することをお勧めします。
お勧めしない主な理由は
- プロパティのコピーツールの中には、ちょっとお行儀の悪いものもあります
- 物件コピーツールには「バグ」があります。
- 物件コピーツールの使用には、いくつかの落とし穴があります。
まず第一に、同社は、プロパティのコピーのBeanUtilsのコモンズパッケージに遭遇している実際のケースのパフォーマンスが低下し、その後、同僚がSpringのBeanUtilsのパフォーマンスに変更され、はるかに優れている、あなたが比較するパフォーマンステストフレームワークやベンチマークフレームワークを使用することができますに興味を持って、ここでは比較されません。
SpringのBeanUtilsプロパティのコピーの何が問題なのかを見てみましょう:
import lombok.Data;import java.util.List;@Datapublic class A { private String name; private List<Integer> ids;}
@Datapublic class B { private String name; private List<String> ids;}
import org."スプリングフレームワーク.beans.BeanUtils;import java.util.Arrays;public class BeanUtilDemo { public static void main(String[] args) { A first = new A(); first.setName("demo"); first.setIds(Arrays.asList(1, 2, 3)); B second = new B(); BeanUtils.copyProperties(first, second); for (String each : second.getIds()) {// 型変換の例外 System.out.println(each); } }}
上記の例を実行すると、型変換例外が発生します。
ブレークポイントからわかるように、B型の2番目のオブジェクトのidは、プロパティコピー後もIntegerのままです:
文字列に変換せずに直接印刷した場合、エラーは報告されません。
コンバータを定義していないCGlibでも同様の問題が発生します:
import org.easymock.cglib.beans.BeanCopier;import java.util.Arrays;public class BeanUtilDemo { public static void main(String[] args) { A first = new A(); first.setName("demo"); first.setIds(Arrays.asList(1, 2, 3)); B second = new B(); final BeanCopier beanCopier = BeanCopier.create(A.class, B.class, false); beanCopier.copy(first,second,null); for (String each : second.getIds()) {// 型変換の例外 System.out.println(each); } }}
繰り返しますが、問題は実行時に露呈します。
次にmapstructを見てください:
import org.mapstruct.Mapper;import org.mapstruct.factory.Mappers;@Mapperpublic interface Converter { Converter INSTANCE = Mappers.getMapper(Converter.class); B aToB(A car);}
import java.util.Arrays;public class BeanUtilDemo { public static void main(String[] args) { A first = new A(); first.setName("demo"); first.setIds(Arrays.asList(1, 2, 3)); B second = Converter.INSTANCE.aToB(first); for (String each : second.getIds()) {// System.out.println(each); } }}
A の List
出来上がったConverterの実装クラスを見てみましょう:
import java.util.ArrayList;import java.util.List;import javax.annotation.Generated;import org."スプリングフレームワーク.stereotype.Component;@Generated( value = "org.mapstruct.ap.MappingProcessor", comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_202 (Oracle Corporation)")@Componentpublic class ConverterImpl implements Converter { @Override public B aToB(A car) { if ( car == null ) { return null; } B b = new B(); b.setName( car.getName() ); b.setIds( integerListToStringList( car.getIds() ) ); return b; } protected List<String> integerListToStringList(List<Integer> list) { if ( list == null ) { return null; } List<String> list1 = new ArrayList<String>( list.size() ); for ( Integer integer : list ) { list1.add( String.valueOf( integer ) ); } return list1; }}
自動ヘルプが変換を行い、型が一貫していないことに気づかなかったのかもしれません。
@Override public B aToB(A car) { if ( car == null ) { return null; } B b = new B(); b.setName( car.getName() ); if ( car.getNumber() != null ) { // ここに問題がある。 b.setNumber( Long.parseLong( car.getNumber() ) ); } b.setIds( integerListToStringList( car.getIds() ) ); return b; }
cglibでは、number属性はデフォルトではマッピングされず、Bのnumberはnullになります。
コンバータが手動で定義されている場合は、IDEAプラグインを使用して自動的に変換します:
public final class A2BConverter { public static B from(A first) { B b = new B(); b.setName(first.getName()); b.setIds(first.getIds()); return b; }}
これはコーディングの段階ではっきりわかります:
Javaのジェネリック型は、実際にはコンパイル時にチェックされ、コンパイル後にジェネリック型によって消去されるため、この結果、実行時には
mapstructは、コンパイルの段階でマッピングの両側の一般的な型を読み取ることができる独自の注釈プロセッサを定義し、マッピングを実行します。しかし、この種のマッピングも非常に怖い、時には不注意や他の理由のために間違った型を定義し、自動的に変換を支援し、副作用の多くをもたらすでしょう。
様々な属性マッピングツールの性能を簡単に比較し、その結果を以下に示します:
したがって、プロパティ変換ツールを使用することが賢明ですが、可能であれば、我々は、IDEAのプラグインの自動記入を使用して、カスタム変換クラスをお勧めします、効率はかなり高いです、任意のプロパティの種類の不一致でAまたはB、あるいはプロパティを削除すると、コンパイル段階は、エラーとして報告することができ、直接呼び出しの効率も非常に高いセット取得します。