Есть ли способ использовать класс как тип переменной другого класса с GSON? - PullRequest
0 голосов
/ 22 февраля 2019

Я использую 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 каждый раз?

Спасибо!

1 Ответ

0 голосов
/ 23 февраля 2019

Если бы связь между классами была бы простой как агрегация, когда вы всегда связываете от дочернего элемента к родительскому, вы можете написать собственный десериализатор.Как в этом вопросе: Ссылка на родительский объект при десериализации JSON с использованием 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}]}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...