有没有一种方法可以将一个类用作GSON另一个类的变量类型?

时间:2019-02-22 09:28:54

标签: java json class gson

我正在使用Java和GSON。我有一个像这样的json数组:

[{"ID":1001,
  "name":"Egnatia-3isSeptembriou/Anatolika",
  "latitude":40.626216,
  "longitude":22.959864,
  "Edge":[
      {"destination_id":1030,"weight":6},
      {"destination_id":1012,"weight":12}]
},
{
  "ID":1002,
  "name":"Egnatia-3isSeptembriou/Boreia",
  "latitude":40.626055,
  "longitude":22.959845,
  "Edge":[
      {"destination_id":1025,"weight":3},
      {"destination_id":1008,"weight":5}]
}]

我想使用GSON来创建两个类,例如:

public class Node {
    int ID;
    String name;
    double latitude, longitude; 
    int previous = 0;
    boolean visited = false;
    double distance = Double.MAX_VALUE;
    Edge[] Edge;
 }

public class Edge {
    Node destinationNode;
    double weight;
}

有没有一种优雅的方法来代替每次复制Edge中的所有Nodes变量?

谢谢!

1 个答案:

答案 0 :(得分:0)

如果类之间的关系像聚合一样简单,那么您总是从子级链接到父级,则可以编写自定义反序列化器。就像这个问题一样:Reference parent object while deserializing a JSON using Gson。在您的情况下,您有一个聚合器列表,其中内部边缘指向同一列表中的其他聚合器。我建议稍微改变一下模型,并向Node类添加新的Edge属性。另外,为避免序列化,我使用了transient关键字。您可以更改它并使用@Expose注释,但是在这种情况下,transient要简单得多。我添加了SerializedName批注以使类中的属性具有更好的名称:

class Node {

    @SerializedName("ID")
    private int id;

    private String name;
    private double latitude, longitude;
    private int previous = 0;
    private boolean visited = false;
    private double distance = Double.MAX_VALUE;

    @SerializedName("Edge")
    private List<Edge> edges;

    // getters, setters, toString
}

class Edge {

    @SerializedName("destination_id")
    private int destinationId;
    private transient Node destinationNode;
    private double weight;

    // getters, setters, toString
}

我稍微修改了JSON以便参考:

[
  {
    "ID": 1001,
    "name": "Egnatia-3isSeptembriou/Anatolika",
    "latitude": 40.626216,
    "longitude": 22.959864,
    "Edge": [
      {
        "destination_id": 1030,
        "weight": 6
      },
      {
        "destination_id": 1002,
        "weight": 12
      }
    ]
  },
  {
    "ID": 1002,
    "name": "Egnatia-3isSeptembriou/Boreia",
    "latitude": 40.626055,
    "longitude": 22.959845,
    "Edge": [
      {
        "destination_id": 1025,
        "weight": 3
      },
      {
        "destination_id": 1001,
        "weight": 5
      }
    ]
  }
]

现在,我们可以从给定的payload中反序列化类,然后在其后设置引用。

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;

import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.List;

public class GsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();
        Gson gson = new GsonBuilder()
                .setPrettyPrinting()
                .create();

        Type nodesType = new TypeToken<List<Node>>() {}.getType();
        List<Node> nodes = gson.fromJson(new FileReader(jsonFile), nodesType);
        nodes.forEach(node -> {
            nodes.forEach(node1 -> {
                node1.getEdges().forEach(edge -> {
                    if (node.getId() == edge.getDestinationId()) {
                        edge.setDestinationNode(node);
                    }
                });
            });
        });

        nodes.forEach(System.out::println);
    }
}

上面的代码显示:

Node{id=1001, name='Egnatia-3isSeptembriou/Anatolika', latitude=40.626216, longitude=22.959864, previous=0, visited=false, distance=1.7976931348623157E308, edges=[Edge{destinationId=1030, destinationNodeIsSet=false, weight=6.0}, Edge{destinationId=1002, destinationNodeIsSet=true, weight=12.0}]}
Node{id=1002, name='Egnatia-3isSeptembriou/Boreia', latitude=40.626055, longitude=22.959845, previous=0, visited=false, distance=1.7976931348623157E308, edges=[Edge{destinationId=1025, destinationNodeIsSet=false, weight=3.0}, Edge{destinationId=1001, destinationNodeIsSet=true, weight=5.0}]}