モデルマッパーを使用したカスケードプロパティマップ
-
27-10-2019 - |
質問
6つのPojoクラスを検討してください:3 DAOと3つのDTO。
DAOS:「A」、「B」、「C」
DTO:「1つ」、「2」、「3」
public class A {
private int idOfA;
private String name;
private List<B> b;
// getters, setters, etc...
}
public class B {
private int idOfB;
private String name;
private List<C> c;
// getters, setters, etc...
}
public class C {
private int idOfC;
private String name;
// getters, setters, etc...
}
public class One {
private int id;
private String name;
private List<Two> two;
// getters, setters, etc...
}
public class Two {
private int id;
private String name;
private List<Three> Three;
// getters, setters, etc...
}
public class Three {
private int id;
private String name;
// getters, setters, etc...
}
「A」には「B」のリストが含まれています。 「B」には「C」のリストが含まれています。
「1つ」には、「2つの」sのリストが含まれています。 「2」には、「3」のリストが含まれています。
「a2one」を介して「1つ」をマップします。 「B」を「B2TWO」経由で「2」にマップします。 「c」は「c2three」を介して3にマップします。
public class A2One extends PropertyMap<A, One> {
@Override
protected void configure() {
map().setId(source.getIdOfA());
map().setName(source.getName());
when(Conditions.isNotNull()).using(new BListConverter()).map(source.getBs()).setTwos(null);
}
}
public class BListConverter extends AbstractConverter<List<B>, List<Two>> {
@Override
protected List<Two> convert(List<B> source) {
List<Two> twos = new ArrayList<Two>(source.size());
for(B b : source) {
Two t = new Two();
t.setId(b.getId());
t.setName(b.getName());
// Ignore list of Cs contained in B for now
twos.add(t);
}
return twos;
}
}
public class B2Two extends PropertyMap<B, Two> {
@Override
protected void configure() {
map().setId(source.getIdOfB());
map().setName(source.getName());
when(Conditions.isNotNull()).using(new CListConverter()).map(source.getCs()).setThrees(null);
}
}
B2TWOとC2THREは、A2ONと非常によく似たコードを持っています。
だからここに私の質問があります:
現在、「A」と「One」に含まれるリスト間の変換は、カスタムコンバーター(および機能する)を介して行われますが、B2TWOが実行するはずの操作と同じ操作を繰り返しています(BSからTWOSのマッピング)。
プロパティマップをマッピングする場合、プロパティマップをマッピングする場合、プロパティマップ(a2one-> b2two-> c2three)をカスケードする方法はありますか?
代替1: :ジェネリックを使用してカスタムタイプマップを作成します List, List
正しいプロパティ/タイプマップに転送します。
代替2: :a2oneでは、リストに次のものを使用します
mapper.addMappings(new BList2TwoList());
when(Conditions.isNotNull()).withProvider(listProvider).map().setTwos(mapper.map(source.getBs(), List.class));
listProviderがextend abstractProviderを拡張しますnew arrayList()を返します
代替3: ???
何か案は?より複雑なマッピングの問題に関するドキュメントは、ウェブサイトで非常に貧弱であり、私は必ずしも代替フレームワークを探しているわけではありません。代替品が提供されている場合、簡単にリファクタリングする必要があります(DozerとOrikaは基本的に外出しています)。
前もって感謝します
アップデート:執筆時点で、ModelMapperはそうです 基本的に死んだ また、実際にはマッピングのリストやカスケードをサポートしていないため、リストになる可能性のあるすべてのオブジェクトのマップとコンバーターを作成することを余儀なくされます。
さらに、OrikaにはMapperBaseを拡張することにより、リファクタリングに優しいマッピングがあることがわかりました。さらに、Orikaは、個々の豆のマッピングと豆のリストを透過的に扱うことができます(両方の状況に単一のマッピングルールを使用)。
更新2:Orikaでは、CustomMapperを使用してコレクションの双方向の深いネストされたマッピングを行うことができます。これにより、双方向マッピングの実装の作成が可能になり、他のカスタムマッパーにカスケードできます。 A2ONEは、B2TWOのインスタンスを保持し、「A」に含まれる「B」をマッピングするときに透過的に使用します。
解決 2
Orikaを使用して、必要なすべての要件を簡単でフレンドリーな方法で取得することができました。
他のヒント
私はこれがモデルマッパーで今可能であることを示しているだけだと思いました...
リストをサポートしています(少なくともバージョン0.7.5で)。
それを行うためのpropertymapは次のようになります:
public class A2One extends PropertyMap<A, One> {
@Override
protected void configure() {
map().setId(source.getIdOfA());
map().setName(source.getName());
map(source.getB()).setOne(null);
}
}