簡體   English   中英

Gson-簡化某些字段上的序列化

[英]Gson - Simplify serialization on some fields

我正在嘗試序列化樹結構中的復雜對象。 例:

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}]}}

我該如何實現? 感謝您的任何想法!

在串行化和反序列化中經常使用“ 數據傳輸對象”模式。 它還具有很多優點,例如在不同的應用程序層上解耦同一邏輯對象的各種形式,為特定的序列化庫進行精確配置(如果有一天您想切換到Jackson,該怎么辦?)等。

假設您的值對象(與DTO相反)具有構造函數,讓我們首先構建對象模型(我在這里使用Java 6,稍后再也不用讓您感到困惑):

private static Tree createTree() {
    final Tree tree = new Tree();
    tree.rootNode = new Node1("1");
    tree.allNodes = new ArrayList<Node>();
    tree.allNodes.add(new Node1("1", new Node2("2")));
    tree.allNodes.add(new Node2("2"));
    return tree;
}

然后,只需定義您的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;
    }

}

請注意,我在這里使用靜態最終類(在一個外部類中聲明)只是為了簡化演示。 另外,我正在使用@SerializedName顯式定義JSON字段的名稱(它允許重命名Java中的字段而不接觸JSON字段)和@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)));

輸出如下:

{“ rootNode”:{“ id”:“ 1”},“ allNodes”:[{“ id”:“ 1”,“ node2”:{“ id”:“ 2”}}},{“ id”:“ 2“}]}
{“ Tree”:{“ rootNodeId”:“ 1”,“ allNodes”:[{“ id”:“ 1”,“ node2Id”:“ 2”},{“ id”:“ 2”}]}}

GSON還支持自定義序列化程序 ,這些序列化程序可以讓您以更底層的方式解決問題,但是我想這絕對是一個過大的殺傷力。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM