AndroidにおけるBean間変換
8646 ワード
問題の説明:
以前のプロジェクトで、次のような問題が発生しました.インタフェースA要求結果変換後のEntity Aはコントロールと高度に結合されており、コントロールの大部分の機能はEntity Aの各属性によって制御されている(これは問題なく、コントロールとビジネスロジックは分離できるが、ほとんどの場合は依然として難しい). には、サービス側がインタフェースAと非常に類似したインタフェースBを提供し、既存のコントロールを多重化することを望む新しいニーズがある.
ほとんどの場合、このような状況は発生しませんが、複数のバックエンドチームがサポートを提供している場合に発生する可能性があります(たとえば、パラメータ仕様がアルパカ式なのか下線なのか).
Java開発ではBean(Entity)間変換のツールが多く,大部分がXMLマッピング方式を採用している.この方法はサービス側で開発するのがもっと便利かもしれませんが、android開発ではXMLのプロパティファイルのサポートが足りません(XMLプロパティファイルの処理はあまり上手ではありません).ではandroidに便利なEntity間変換案はありますか?
実装シナリオ:
Javaでの注釈と反射の使用に基づいて,androidプラットフォーム上のentity間の変換を実現できるツールクラスを作成し,このツールを紹介する.
annotationとannotationHandlerの作成
1.まず、annotationを宣言します.Entity AをEntity Bにマッピングする場合は、Entity Aでマッピングする必要がある属性に対してmapClassとmapProperty注記を行います.
単層Entity(Entityのプロパティはすべて基本タイプまたはString)の場合、mapPropertyを使用するだけです.
多層Entity(EntityにカスタムEntityプロパティが含まれている)では、mapPropertyを使用して対応するプロパティ名を設定するだけでなく、mapClassを使用して対応するクラス名を設定する必要があります.
コードは次のとおりです.
2.それから、annotation-handlerをもう一つ書きます.annotationを処理しなければ、意味がありません.
ツールクラスの最初のパラメータはソースentity、2番目のパラメータはターゲットentityクラスです.言い換えれば、src ObjをdesObjに移動するには、アクティブobjとターゲットobjクラスの2つのパラメータが必要です.
まずリストタイプであれば,リストを処理する(json変換されたentityの多くはリストがある).リスト(配列と似ている)という属性は特殊で、カスタムEntityでも基本的なタイプでもないので、リストを遍歴してitemを1つずつ変換する必要があります.次に、変換する必要があるのは、基本的なタイプとカスタムタイプにほかならない.注記書きの比較的詳細は、ソースobj属性がマッピングされる必要があるかどうかを反射的に検出するターゲットobjオブジェクトを生成します.マッピングを必要としない場合は直接pass(ターゲットobjにはこの属性はまったく必要ありません).マッピングが必要で基本タイプであれば直接値を取り、ターゲットobjにセットし、マッピングがカスタムタイプであれば再帰処理して結果セットを入れます.
コードは次のとおりです.
例(Entity AをEntity Bに変換)
限界:バックエンドのA,Bインタフェースは基本的に一致しているため,上述した実現方法は筆者が直面した問題を確かに解決した.
しかし、多層Entityの場合、例えば1つのbooleanをカスタムクラスの変数に変換したり、1つのカスタムクラスの変数を1つのbooleanに変換したりする場合、このような実装方法では問題を解決することはできません.もし本当にこのような状況に遭遇し、この状況が比較的少ない場合は、単独で値を取った後のsetを考慮することができます.
以前のプロジェクトで、次のような問題が発生しました.
ほとんどの場合、このような状況は発生しませんが、複数のバックエンドチームがサポートを提供している場合に発生する可能性があります(たとえば、パラメータ仕様がアルパカ式なのか下線なのか).
Java開発ではBean(Entity)間変換のツールが多く,大部分がXMLマッピング方式を採用している.この方法はサービス側で開発するのがもっと便利かもしれませんが、android開発ではXMLのプロパティファイルのサポートが足りません(XMLプロパティファイルの処理はあまり上手ではありません).ではandroidに便利なEntity間変換案はありますか?
実装シナリオ:
Javaでの注釈と反射の使用に基づいて,androidプラットフォーム上のentity間の変換を実現できるツールクラスを作成し,このツールを紹介する.
annotationとannotationHandlerの作成
1.まず、annotationを宣言します.Entity AをEntity Bにマッピングする場合は、Entity Aでマッピングする必要がある属性に対してmapClassとmapProperty注記を行います.
単層Entity(Entityのプロパティはすべて基本タイプまたはString)の場合、mapPropertyを使用するだけです.
多層Entity(EntityにカスタムEntityプロパティが含まれている)では、mapPropertyを使用して対応するプロパティ名を設定するだけでなく、mapClassを使用して対応するクラス名を設定する必要があります.
コードは次のとおりです.
/**
* 1:1
*
* Created by puff on 15/7/31.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MapProperty {
public String mapClass() default "";
public String mapProperty() default "";
}
2.それから、annotation-handlerをもう一つ書きます.annotationを処理しなければ、意味がありません.
ツールクラスの最初のパラメータはソースentity、2番目のパラメータはターゲットentityクラスです.言い換えれば、src ObjをdesObjに移動するには、アクティブobjとターゲットobjクラスの2つのパラメータが必要です.
まずリストタイプであれば,リストを処理する(json変換されたentityの多くはリストがある).リスト(配列と似ている)という属性は特殊で、カスタムEntityでも基本的なタイプでもないので、リストを遍歴してitemを1つずつ変換する必要があります.次に、変換する必要があるのは、基本的なタイプとカスタムタイプにほかならない.注記書きの比較的詳細は、ソースobj属性がマッピングされる必要があるかどうかを反射的に検出するターゲットobjオブジェクトを生成します.マッピングを必要としない場合は直接pass(ターゲットobjにはこの属性はまったく必要ありません).マッピングが必要で基本タイプであれば直接値を取り、ターゲットobjにセットし、マッピングがカスタムタイプであれば再帰処理して結果セットを入れます.
コードは次のとおりです.
1 /**
2 * Created by puff on 15/7/31.
3 */
4 public class AnnotationUtils {
5 /**
6 * *
7 * entity entity MapProperty
8 *
9 * @param obj entity
10 * @param c entity
11 * @return entity
12 * @throws Exception annotation
13 */
14 public static Object transformEntity(Object obj, Class c) throws Exception {
15 if (obj == null || c == null) {
16 return null;
17 }
18 if (obj instanceof List) {
19 //
20 List src = (List) obj;
21 List result = new LinkedList();
22 for (Object item : src) {
23 result.add(transformEntity(item, c));
24 }
25 return result;
26 } else {
27 // entity,
28 Object result = c.newInstance();
29 Field[] declaredFields = obj.getClass().getDeclaredFields();
30 for (Field field : declaredFields) {
31 //
32 field.setAccessible(true);
33 if (field.isAnnotationPresent(MapProperty.class)) {
34 //
35 MapProperty annotation = field.getAnnotation(MapProperty.class);
36 Object value = field.get(obj);
37 if (!TextUtils.isEmpty(annotation.mapClass())) {
38 // ,
39 value = transformEntity(value, Class.forName(annotation.mapClass()));
40 }
41 Field resultField = c.getDeclaredField(annotation.mapProperty());
42 resultField.setAccessible(true);
43 resultField.set(result, value);
44 }
45 }
46 return result;
47 }
48 }
49
50 }
例(Entity AをEntity Bに変換)
1 /**
2 *
3 * @author puff
4 */
5 public class EntityA {
6
7 @MapProperty(mapProperty = "value_1")
8 private String value1;
9 @MapProperty(mapProperty = "value_2", mapClass = "javaannotation.EntityB2")
10 private List<List<EntityA2>> value2;
11
12 public String getValue1() {
13 return value1;
14 }
15
16 public void setValue1(String value1) {
17 this.value1 = value1;
18 }
19
20 public List<List<EntityA2>> getValue2() {
21 return value2;
22 }
23
24 public void setValue2(List<List<EntityA2>> value2) {
25 this.value2 = value2;
26 }
27
28 }
29
30 /**
31 *
32 * @author puff
33 */
34 public class EntityB {
35
36 private String value_1;
37 private List<List<EntityB2>> value_2;
38
39 public String getValue_1() {
40 return value_1;
41 }
42
43 public void setValue_1(String value_1) {
44 this.value_1 = value_1;
45 }
46
47 public List<List<EntityB2>> getValue_2() {
48 return value_2;
49 }
50
51 public void setValue_2(List<List<EntityB2>> value_2) {
52 this.value_2 = value_2;
53 }
54
55 }
56
57 public static void main(String[] args) throws Exception {
58 EntityA entityA = getEntityA();
59 Object object = transformEntity(entityA, EntityB.class);
60 if (!(object instanceof EntityB)) {
61 System.out.println("error1");
62 }
63 EntityB entityB = (EntityB) object;
64 System.out.println("succ1");
65 }
限界:バックエンドのA,Bインタフェースは基本的に一致しているため,上述した実現方法は筆者が直面した問題を確かに解決した.
しかし、多層Entityの場合、例えば1つのbooleanをカスタムクラスの変数に変換したり、1つのカスタムクラスの変数を1つのbooleanに変換したりする場合、このような実装方法では問題を解決することはできません.もし本当にこのような状況に遭遇し、この状況が比較的少ない場合は、単独で値を取った後のsetを考慮することができます.