如何使用google-gson将这样的自定义类型序列化为json?

时间:2011-12-20 08:25:34

标签: json serialization gson

首先,我有一个非常简单的java bean,可以很容易地序列化为json:

class Node {
    private String text;
    // getter and setter
}

Node node = new Node();
node.setText("Hello");

String json = new Gson().toJson(node);
// json is { text: "Hello" }

然后为了使这样的bean有一些动态值,所以我创建了一个“WithData”基类:

Class WithData {
    private Map<String, Object> map = new HashMap<String, Object>();
    public void setData(String key, Object value) { map.put(key, value); }
    public Object getData(String key) = { return map.get(key); }
}

class Node extends WithData {
    private String text;
    // getter and setter
}

现在我可以为节点设置更多数据:

Node node = new Node();
node.setText("Hello");
node.setData("to", "The world");

但是Gson会忽略“to”,结果仍然是{ text: "Hello" }。我希望它是:{ text: "Hello", to: "The world" }

有没有办法为类型WithData编写一个序列化程序,所有类扩展它不仅会为json生成自己的属性,还会生成map中的数据?

我尝试实现自定义序列化程序,但失败了,因为我不知道如何让Gson首先序列化属性,然后是地图中的数据。

2 个答案:

答案 0 :(得分:6)

我现在所做的是创建自定义序列化程序:

public static class NodeSerializer implements JsonSerializer<Node> {
    public JsonElement serialize(Node src,
            Type typeOfSrc, JsonSerializationContext context) {
        JsonObject obj = new JsonObject();
        obj.addProperty("id", src.id);
        obj.addProperty("text", src.text);
        obj.addProperty("leaf", src.leaf);
        obj.addProperty("level", src.level);
        obj.addProperty("parentId", src.parentId);
        obj.addProperty("order", src.order);
        Set<String> keys = src.getDataKeys();
        if (keys != null) {
            for (String key : keys) {
                obj.add(key, context.serialize(src.getData(key)));
            }
        }
        return obj;
    };
}

然后使用GsonBuilder转换它:

Gson gson = new GsonBuilder().
    registerTypeAdapter(Node.class, new NodeSerializer()).create();

Tree tree = new Tree();
tree.addNode(node1);
tree.addNode(node2);

gson.toJson(tree);

然后树中的节点将按照我的预期进行转换。唯一无聊的是我每次都需要创建一个特殊的Gson

答案 1 :(得分:4)

实际上,您应该期望Node:WithData序列化为

{
  "text": "Hello",
  "map": {
    "to": "the world"
  }
}

(打开“漂亮的打印”)

当我尝试你的例子时,我能够获得序列化。这是我的确切代码

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.net.MalformedURLException;

import java.util.HashMap;
import java.util.Map;


public class Class1 {

  public static void main(String[] args) throws MalformedURLException {
    GsonBuilder gb = new GsonBuilder();
    Gson g = gb.setPrettyPrinting().create();

    Node n = new Node();
    n.setText("Hello");
    n.setData("to", "the world");

    System.out.println(g.toJson(n));
  }
  private static class WithData {
    private Map<String, Object> map = new HashMap<String, Object>();
    public void setData(String key, Object value) { map.put(key, value); }
    public Object getData(String key) { return map.get(key); }
  }
  private static class Node extends WithData {
    private String text;
    public Node() { }
    public String getText() {return text;}
    public void setText(String text) {this.text = text;}
  }
}

我正在使用JDK(javac)进行编译 - 这很重要,因为其他编译器(包含在某些IDE中的编译器)可能会删除Gson在优化或混淆过程中所依赖的信息。

以下是我使用的编译和执行命令:

  

“C:\ Program Files \ Java \ jdk1.6.0_24 \ bin \ javac.exe”-classpath gson-2.0.jar Class1.java

     

“C:\ Program Files \ Java \ jdk1.6.0_24 \ bin \ java.exe”-classpath .; gson-2.0.jar Class1

出于本次测试的目的,我将Gson jar文件放在与测试类文件相同的文件夹中。

请注意,我正在使用Gson 2.0; 1.x可能表现不同。

您的JDK可能安装在与我不同的位置,因此如果您使用这些命令,请务必根据需要调整JDK的路径。