it-swarm.com.ru

Десериализация общих типов с помощью GSON

У меня есть некоторые проблемы с реализацией десериализации Json в моем приложении Android (с библиотекой Gson)

Я сделал урок, как это

public class MyJson<T>{
    public List<T> posts;
}

И десериализация вызова это:

public class JsonDownloader<T> extends AsyncTask<Void, Void, MyJson<T>> {
...
protected MyJson<T> doInBackground(Void... params) {
  ...
    Reader reader = new InputStreamReader(content);
    GsonBuilder gson = new GsonBuilder();
    Type collectionType = new TypeToken<MyJson<T>>() {}.getType();
    result = gson.create().fromJson(reader, collectionType);
  ...
  }
}

Проблема в том, что список result.posts после вызова содержит один массив объектов LinkedTreeMap (с правильными значениями, поэтому проблема заключается в десериализации) вместо объектов MyJson. Когда я использую MyObject вместо T, все работает нормально, и MyObject работает правильно.

Так есть ли способ реализовать вызов десериализации без создания собственного десериализатора?

39
VizGhar

Вы должны указать тип T во время десериализации. Как бы ваш List из posts был создан, если Gson не знал, что Type создать? Это не может оставаться T навсегда. Таким образом, вы должны указать тип T в качестве параметра Class.

Теперь, предположив, что тип posts был String, вы бы десериализовали MyJson<String> как (я также добавил параметр String json для простоты; вы читали бы из вашей reader, как и раньше):

doInBackground(String.class, "{posts: [\"article 1\", \"article 2\"]}");

protected MyJson<T> doInBackground(Class<T> type, String json, Void... params) {

    GsonBuilder gson = new GsonBuilder();
    Type collectionType = new TypeToken<MyJson<T>>(){}.getType();

    MyJson<T> myJson = gson.create().fromJson(json, collectionType);

    System.out.println(myJson.getPosts()); // ["article 1", "article 2"]
    return myJson;
}

Аналогично, для десериализации объектов MyJson из Boolean

doInBackground(Boolean.class, "{posts: [true, false]}");

protected MyJson<T> doInBackground(Class<T> type, String json, Void... params) {

    GsonBuilder gson = new GsonBuilder();
    Type collectionType = new TypeToken<MyJson<T>>(){}.getType();

    MyJson<T> myJson = gson.create().fromJson(json, collectionType);

    System.out.println(myJson.getPosts()); // [true, false]
    return myJson;
}

Я предположил MyJson<T> для моих примеров как

public class MyJson<T> {

    public List<T> posts;

    public List<T> getPosts() {
        return posts;
    }
}

Итак, если вы искали десериализацию List<MyObject>, вы бы вызвали метод как

// assuming no Void parameters were required
MyJson<MyObject> myJson = doInBackground(MyObject.class);
26
Ravi Thapliyal

Ты пытался?

gson.create().fromJson(reader, MyJson.class);

ПРАВКА

После прочтения этого сообщения кажется, что вы используете Type правильно. Я считаю, что ваша проблема заключается в использовании T. Вы должны помнить, что в Java есть стирание типов. Это означает, что во время выполнения все экземпляры T заменяются на Object. Поэтому во время выполнения то, что вы передаете GSON, действительно MyJson<Object>. Если вы попробуете это с конкретным классом вместо <T>, я думаю, это сработает.

Google Gson - десериализовать список <class> объект? (универсальный тип)

24
John B

Таким образом, приведенный выше ответ не сработал для меня, после проб и ошибок вот так закончился мой код:

public class AbstractListResponse<T> {
    private List<T> result;

    public List<T> getResult() {
        return this.result;
    }
}

Важной частью здесь является сигнатура метода, включая «<T>» слева.

protected <T> AbstractListResponse<T> parseAbstractResponse(String json, TypeToken type) {
    return new GsonBuilder()
            .create()
            .fromJson(json, type.getType());
}

При вызове Gson метод получает TypeToken универсального объекта.

TypeToken<AbstractListResponse<MyDTO>> typeToken = new TypeToken<AbstractListResponse<MyDTO>>() {};
AbstractListResponse<MyDTO> responseBase = parseAbstractResponse(json, typeToken);

И, наконец, TypeToken может использовать MyDTO или даже простой объект, просто MyDTO.

3
Davi Alves

Для тех, кто борется с Kotlin, как я, я нашел этот способ работать

val type = object : TypeToken<MyJson<MyObject>>() { }.type
val response = gson.fromJson<MyJson<MyObject>>(reader, type)

Обратите внимание, что для вызова универсальной функции требуются аргументы типа на сайте вызова после имени функции (видно здесь )

0
tudor