Search code examples
javagsonjson-deserializationjson-serialization

Java Gson JSON: Serializing an Object which contains a List<Map.Entry<...,...>>


I am currently trying serialze and correctly deserialize an Object containing a List with tuples using googles Gson. I have found similar questions here here and here but I wasnt able to adjust their solutions to my problem, because my List is in an Object.

Here a quick example:

import com.google.gson.*;
import java.util.*;


public class SerializeTheCity  {

    public static void main(String[] args) {

        HashMap <String, Integer> cityMap = new HashMap <>();
        cityMap.put("Street A", 4);
        cityMap.put("Street B", 3);
        cityMap.put("Street C", 7);
        cityMap.put("Street D", 8);
        cityMap.put("Street E", 9);

        City someCity = new City();

        someCity.streets= new ArrayList<>();
        someCity.streets.addAll(cityMap.entrySet());
        System.out.println(someCity.streets.get(1).getValue()); //works fine, how do I serialize it?

        Gson gson = new Gson();


        String saveCity = gson.toJson(someCity);
        System.out.println(saveCity); //does not work (empty List)


        // here I tried to use a solution [link 1] that worked for a similar question.
        Gson gson2 = new Gson();
        JsonElement jsonTree = gson2.toJsonTree(cityMap, Map.class);
        JsonObject jsonObject = new JsonObject();
        jsonObject.add("city", jsonTree);
        System.out.println("city = "+jsonObject); //how do I deserialize this into an object of city?


       City thisCity = gson.fromJson(jsonObject, City.class);
       System.out.println("streets = "+thisCity.streets); // doesnt work

       //works like in [link 1]. But its not a city-object.
       HashMap <String, Integer> thisStreets = gson.fromJson(jsonObject.get("city"), HashMap.class); 
       System.out.println("this streets = "+thisStreets);
       System.out.println("is this street A?"+thisStreets.get("Street A"));
         // this works, but I would like having the streets
        //in a city object (I could build a new city object like "newCity.streets=thisStreets",
        //but perhaps you know a smarter solution)
    }
}
class City { 
    List<Map.Entry<String,Integer>> streets; //Street, HouseNumber
}

Thank you for your help.


Solution

  • You've simply confused GSON when you rearranged the type that streets holds. You've created a HashMap, but then type streets as a Map.Entry.

    If you simply type streets as a HashMap, its native type, then everything works just fine.

    Two changes:

    1. use List.of(cityMap); to set streets with a List of HashMap
    2. change the declaration of streets to be List<HashMap<String,Integer>> streets;

    Those two simple changes fix it for you:

    public class Main {
    
      public static void main(String[] args) {
    
        HashMap < String, Integer > cityMap = new HashMap < > ();
        cityMap.put("Street A", 4);
        cityMap.put("Street B", 3);
        cityMap.put("Street C", 7);
        cityMap.put("Street D", 8);
        cityMap.put("Street E", 9);
    
        City someCity = new City();
        // Don't do this
        // someCity.streets = new ArrayList<>>();
        // someCity.streets.addAll(cityMap.entrySet());
    
        // Do this instead
        someCity.streets = List.of(cityMap);
        System.out.printf("Streets in City Object: %s%n", someCity.streets);
    
        Gson gson = new Gson();
        String saveCity = gson.toJson(someCity);
        System.out.printf("Serialized City (JSON): %s%n", saveCity);
    
        City otherCity = gson.fromJson(saveCity, City.class);
        System.out.printf("Streets in DESERIALIZED City Object: %s%n", someCity.streets);
    
    
      }
    }
    class City {
      // Use a HashMap
      List < HashMap < String, Integer >> streets;
    }
    

    Produces this output:

    Streets in City Object: [{Street E=9, Street D=8, Street C=7, Street B=3, Street A=4}]
    Serialized City (JSON): {"streets":[{"Street E":9,"Street D":8,"Street C":7,"Street B":3,"Street A":4}]}
    Streets in DESERIALIZED City Object: [{Street E=9, Street D=8, Street C=7, Street B=3, Street A=4}]