2016-11-29 7 views
0

複雑なオブジェクトをツリー構造でシリアル化しようとしています。例:Gson - 一部のフィールドのシリアライズ

class Tree{ 
    private Node1 rootNode; 
    private ArrayList<Node> allNodes; 
} 

class Node1 extends Node{ 
    private String id; 
    private Node2 node2; 
} 

class Node2 extends Node{ 
    private String id; 
    ... 
} 

フィールドrootNodeには、JSON内のrootNodeIdのみが含まれている必要があります。それでも、実際のNode1オブジェクトがコード内に必要です。 Node1のNode2プロパティでも同じことができます。完全なオブジェクトはallNodes配列に格納されるため、そこに参照を保存するだけです。 JSONは次のようになります。

{Tree: {rootNodeId: 1, allNodes: [{id: 1, node2Id: 2}, {id: 2}]}} 

どうすればいいですか?何かありがとう!

答えて

1

Data Transfer Objectパターンがあります。このパターンは、シリアライズおよびデシリアライズでよく使用されます。また、さまざまなアプリケーション層で同じ論理オブジェクトのさまざまな形式のデカップリング、特定のシリアライゼーションライブラリの正確な構成(ジャクソンに切り替えたい場合はどうすればよいでしょうか)など多くの利点があります。

お使いの値オブジェクト(DTOの反対は)コンストラクタを持っている、のは(私はあなたを混同しないように、ここで、後のJava 6を使用しています)最初のオブジェクトモデルを構築してみましょう:

​​

すると、ちょうどするために、あなたのDTOクラスを定義しますGSONの要件に沿って調整してください。

private static final class RootDto { 

    @SerializedName("Tree") 
    @SuppressWarnings("unused") 
    private final TreeDto tree; 

    private RootDto(final TreeDto tree) { 
     this.tree = tree; 
    } 

} 

private static final class TreeDto { 

    @SerializedName("rootNodeId") 
    @SuppressWarnings("unused") 
    private final String rootNodeId; 

    @SerializedName("allNodes") 
    @SuppressWarnings("unused") 
    private final List<NodeDto> allNodes; 

    private TreeDto(final String rootNodeId, final List<NodeDto> allNodes) { 
     this.rootNodeId = rootNodeId; 
     this.allNodes = allNodes; 
    } 

} 

private abstract static class NodeDto { 
} 

private static final class Node1Dto 
     extends NodeDto { 

    @SerializedName("id") 
    @SuppressWarnings("unused") 
    private final String id; 

    @SerializedName("node2Id") 
    @SuppressWarnings("unused") 
    private final String node2Id; 

    private Node1Dto(final String id, final String node2Id) { 
     this.id = id; 
     this.node2Id = node2Id; 
    } 

} 

private static final class Node2Dto 
     extends NodeDto { 

    @SerializedName("id") 
    @SuppressWarnings("unused") 
    private final String id; 

    private Node2Dto(final String id) { 
     this.id = id; 
    } 

} 

デモを簡略化するためにここではstatic finalクラス(外部クラス内で宣言されています)を使用しています。また、@SerializedNameを使用して、JSONフィールドの名前を明示的に定義しています(JSONフィールドに触れないで、Javaのフィールドの名前を変更することができます)。@SuppressWarningsは、コンパイラが未使用として知られているフィールドの警告を抑制するためです。とにかく結果JSONで使用されます。カスタムDTOの別のオプションはネストされたjava.util.Mapを使用していますが、私はクラスベースのDTOがより安全な型を提供すると信じています。

{ "ルートノードを":今ちょうどそのデータ転送表現に値オブジェクトを変換:

private static RootDto toDto(final Tree tree) { 
    final List<NodeDto> allNodes = new ArrayList<>(); 
    for (final Node node : tree.allNodes) { 
     final NodeDto nodeDto; 
     if (node instanceof Node1) { 
      final Node1 node1 = (Node1) node; 
      nodeDto = new Node1Dto(node1.id, node1.node2.id); 
     } else if (node instanceof Node2) { 
      final Node2 node2 = (Node2) node; 
      nodeDto = new Node2Dto(node2.id); 
     } else { 
      throw new AssertionError("must never happen: " + node); 
     } 
     allNodes.add(nodeDto); 
    } 
    final TreeDto treeDto = new TreeDto(tree.rootNode.id, allNodes); 
    return new RootDto(treeDto); 
} 

と一緒にそれをすべてを構築する次のように

final Gson gson = new Gson(); 
final Tree tree = createTree(); 
out.println(gson.toJson(tree)); 
out.println(gson.toJson(toDto(tree))); 

出力は次のようになります。 {"id": "1"}、 "allNodes":[{"" id ":" 1 "、" node2 ":{" id ":" 2 "}}、{" id ":" 2 "}}} "" {"id": "2"}}} {{"id": "1"、 "node2Id": "2"}、{{"TreeNumber:" 1 "、" allNodes " }

GSONはまた、より低レベルの方法で問題を解決できるカスタムserializersもサポートしていますが、ここでは間違いなく過激です。

+0

すべての説明と多くのサンプルコードでこの素晴らしい答えをありがとう!これは本当に私に多くの助けになります! – mapf

+0

@mapfよろしくお願いします! –

関連する問題