Java Gson JSON: сериализация объекта, содержащего список ‹Map.Entry‹, ››

В настоящее время я пытаюсь сериализовать и правильно десериализовать объект, содержащий список с кортежами, с помощью googles Gson. Я нашел здесь похожие вопросы, здесь и здесь, но я не смог приспособить их решения к моей проблеме, потому что мой список находится в объекте.

Вот небольшой пример:

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
}

Спасибо за помощь.


person Luca Herrmann    schedule 20.05.2021    source источник
comment
Экземпляры Map.Entry должны быть записями для Map. Они доступны через итератор. Поэтому, если вы хотите сериализовать / десериализовать, вам нужно перебирать запись за записью.   -  person memoricab    schedule 20.05.2021


Ответы (2)


Вы просто запутали GSON, когда изменили тип, который содержит streets. Вы создали HashMap, но затем ввели улицы как Map.Entry.

Если вы просто наберете streets как HashMap, его собственный тип, тогда все будет работать нормально.

Два изменения:

  1. используйте List.of(cityMap);, чтобы установить streets со списком HashMap
  2. измените объявление streets на List<HashMap<String,Integer>> streets;

Эти два простых изменения исправят это за вас:

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

Производит этот вывод:

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}]
person Randy Casburn    schedule 20.05.2021
comment
Ваше решение работает. Спасибо! Итак, простой совет - использовать Map.Entry только для локальных итераций над записями карты, а не для установки значений списка? - person Luca Herrmann; 20.05.2021
comment
Да! Это правильно. Рад помочь. - person Randy Casburn; 20.05.2021

Затем вам нужно создать новый город и задать улицы. Потому что в основном, когда вы десериализуете, это не соответствует структуре данных вашего объекта City.

City city = new City();
city.streets = new ArrayList();
city.streets.addAll(thisStreets);
person memoricab    schedule 20.05.2021