blog

BeanUtilsプロパティ変換ツールの使用を推奨しない理由

プロパティコピーツールの使用は推奨しない」と申し上げましたが、変換クラスや変換メソッドを直接定義し、IDEAプラグインでget/set関数をオートフィルすることを推奨します。 まず、実際のケースでプロ...

Nov 2, 2020 · 4 min. read
シェア

プロパティコピーツールの使用はお勧めしません」と申し上げた通り、変換クラスと変換メソッドを直接定義し、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 を B の 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のジェネリック型は、実際にはコンパイル時にチェックされ、コンパイル後にジェネリック型によって消去されるため、この結果、実行時には Listも ListもList型であり、普通に代入することができます。このため、多くのプロパティ・マッピング・ツールを使用している場合、コンパイル時には容易にわからないエラーが発生します。

mapstructは、コンパイルの段階でマッピングの両側の一般的な型を読み取ることができる独自の注釈プロセッサを定義し、マッピングを実行します。しかし、この種のマッピングも非常に怖い、時には不注意や他の理由のために間違った型を定義し、自動的に変換を支援し、副作用の多くをもたらすでしょう。

様々な属性マッピングツールの性能を簡単に比較し、その結果を以下に示します:

したがって、プロパティ変換ツールを使用することが賢明ですが、可能であれば、我々は、IDEAのプラグインの自動記入を使用して、カスタム変換クラスをお勧めします、効率はかなり高いです、任意のプロパティの種類の不一致でAまたはB、あるいはプロパティを削除すると、コンパイル段階は、エラーとして報告することができ、直接呼び出しの効率も非常に高いセット取得します。



Read next

高度に向かって:優れたAndroidプログラマは、ネットワークの基本を知っている必要があります知っている必要がある

ネットワーク通信は、Androidプロジェクトでは比較的重要なモジュールとなっている、Androidのオープンソースプロジェクトは、優れたネットワークフレームワークの多くに登場している、ツールやカプセル化クラスを使用するのは簡単のほんの一部の最初から、後のGoogleのオープンソースは、より完璧で豊かなVolleyに、その後、今日のより人気のOkhtに...

Nov 2, 2020 · 16 min read