Gson desearilize список и класс, как стирание работает здесь? - PullRequest
1 голос
/ 10 апреля 2020

Я намереваюсь написать обобщенный c метод для преобразования списка json в его специфицированный c список с классом. Это обобщенный c json парсер:

public class JsonParserUtils {

    private static Gson gson = new Gson();

    public static <T> String toJson(T object) {
        if (object == null) {
            return null;
        }
        return gson.toJson(object);
    }

    public static <T> T fromJson(String json, Class<T> className) {
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        T object = gson.fromJson(json, className);
        return object;
    }

    public static <T> List<T> fromJsonList(String jsonList, Class<T> className) {
        // return gson.fromJson(jsonList, TypeToken.getParameterized(List.class, className).getType());
        return gson.fromJson(jsonList, new TypeToken<List<T>>() {}.getType());
    }

}

Вот фиктивный класс, который я хотел бы преобразовать в Json и обратно в Pojo.

public class City {

    private String city;

    public City(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "City [city=" + city + "]";
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

}

Вот простой тест, чтобы увидеть, работает ли он:

public class TestParser {

    public static void main(String[] args) {
        City city = new City("test");
        String cityJson = JsonParserUtils.toJson(city);
        System.out.println(cityJson);

        City fromJson = JsonParserUtils.fromJson(cityJson, City.class);
        System.out.println(fromJson.getCity());  // Why does this work?

        List<City> list = new LinkedList<>();
        list.add(city);
        String cityListJson = JsonParserUtils.toJson(list);
        System.out.println(cityListJson);

        List<City> fromJsonList = JsonParserUtils.fromJsonList(cityListJson, City.class);
        System.out.println(fromJsonList.get(0).getCity()); // Why does this not work?


    }

}

Вывод на консоль выглядит следующим образом:

{"city":"test"}
test
[{"city":"test"}]
Exception in thread "main" java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.jtraq.hospital.vos.City
    at com.jtraq.hospital.vos.TestParser.main(TestParser.java:24)

Я пытаюсь понять, почему fromJson(json, class) работает, но fromJsonList(json, class) нет. Если стирание применимо, то не относится ли оно к обоим случаям? Почему первый метод определяет, что класс имеет тип City, а не LinkedHashMap, как во втором случае?

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

Стирание типа означает, что T теряется во время выполнения, поэтому

new TypeToken<List<T>>() {}.getType()

становится

new TypeToken<List>() {}.getType()

, что означает, что Gson не знает тип элемента списка (City).

Поскольку он не знает, как разбить объекты JSON в списке на объекты City, он разбирает их на объекты Map<String, Object>, поэтому сообщение об ошибке «Map не может» быть приведенным к City ".

Код с комментариями, использующий TypeToken.getParameterized(), будет работать, так что просто придерживайтесь этого.

0 голосов
/ 10 апреля 2020

Я видел, что правильное решение уже есть в вашем коде,

Я думаю, что решение, которое вы ищете, это:

Type type = TypeToken
                .getParameterized(List.class, className)
                .getType();
        return gson.fromJson(jsonList, type);

Если вы хотите знать, почему работает и другие нет, это из-за типа стирания. Класс TypeToken захватывает типы, которые полностью известны во время компиляции.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...