简体   繁体   中英

Ιs there a way to use a class as a type of variable of another class with GSON?

I am using Java and GSON. I have a json array like this:

[{"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}]
}]

I would like to use GSON to make two classes such as:

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

Is there an elegant way to do that instead of copying all Nodes variables in Edge every time?

Thanks!

If relation between classes would be simple as aggregation where you always link from child to a parent you could write custom deserialiser. Like in this question: Reference parent object while deserializing a JSON using Gson . In your case you have list of aggregators where inner edges point to other aggregators on the same list. I propose to change a little bit your model and add new Node property to Edge class. Also, To avoid serialisation I used transient keyword. You can change it and use @Expose annotation but in this case transient is much simpler. I added SerializedName annotation to make properties in class with better names:

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
}

I changed a little bit JSON to have reference:

[
  {
    "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
      }
    ]
  }
]

Now, we can deserialise classes from given payload and set references after that.

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);
    }
}

Above code prints:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM