繁体   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