Дезаминирование общих типов с помощью GSON
У меня есть некоторые проблемы с реализацией Json Deserialization в моем приложении 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 верен.
Итак, есть ли способ реализовать десериализационный вызов без создания настраиваемого десериализатора?
Ответы
Ответ 1
Вы пробовали?
gson.create().fromJson(reader, MyJson.class);
ИЗМЕНИТЬ
После чтения этого сообщения кажется, что вы используете Type
правильно. Я считаю, что ваша проблема заключается в использовании T
. Вы должны помнить, что с Java существует стирание типа. Это означает, что во время выполнения все экземпляры T
заменяются на Object
. Поэтому во время выполнения то, что вы проходите, GSON действительно MyJson<Object>
. Если вы попробовали это с конкретным классом вместо <T>
, я считаю, что это сработает.
Google Gson - список deserialize <class> объект? (общий тип)
Ответ 2
Вы должны указать тип T
во время десериализации. Как будет создан ваш List
of 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);
Ответ 3
Таким образом, приведенный выше ответ не помог мне после проб и ошибок, что мой код закончился:
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.