Использование дженериков с помощью GSON
Я использую GSON для декодирования JSON в объект типа T, например.
public T decode(String json) {
Gson gson = new Gson();
return gson.fromJson(json, new TypeToken<T>() {}.getType());
}
Это возвращает исключение -
java.lang.AssertionError: Неожиданный тип.
Ожидается, что один из:
java.lang.reflect.ParameterizedType,
java.lang.reflect.GenericArrayType,
но получил: sun.reflect.generics.reflectiveObjects.TypeVariableImpl, для токена типа: T
Я думал, что с помощью TypeToken я избегал Type Erasure.
Я не прав?
Спасибо
Ответы
Ответ 1
Прежде всего, я не вижу, как полезно обернуть такой Gson.
Что касается вашей проблемы, то информация о типичном типе T
сама по себе не доступна во время выполнения. Он был удален. Он доступен только во время компиляции. Вы хотите параметризовать его с фактическим типом, а не как new TypeToken<List<String>>
.
Из-за отсутствия редизайна Generics в Java (невозможно сделать T t = new T()
), сам Gson вынужден использовать подход TypeToken
, как вы видите. В противном случае Гссон сделал бы это более элегантно.
Чтобы иметь возможность передавать фактический тип вокруг, вы должны изобрести ту же самую вещь, что и TypeToken
. И это не имеет смысла:) Просто используйте его повторно или просто используйте Gson прямо, не упаковывая его в какой-то вспомогательный класс.
Ответ 2
Я думаю, что первый ответ не указывает на фактическое решение: вы ДОЛЖНЫ также передать экземпляр класса вместе с T, например:
public T decode(String json, Class<T> cls) {
Gson gson = new Gson();
return gson.fromJson(json, cls);
}
Это связано с тем, что здесь "T" - это тип VARIABLE, а не тип ссылки; и используется только компилятором для добавления неявных бросков и проверки совместимости типов. Но если вы пройдете текущий класс, его можно использовать; и компилятор проверяет совместимость типов, чтобы уменьшить вероятность несоответствия.
В качестве альтернативы вы можете взять TypeToken и передать его; но TypeToken должен быть построен с реальным типом, а не с переменной типа; тип переменной здесь мало используется. Но если вы хотите обернуть вещи, вы не хотите, чтобы вызывающий абонент использовал TypeToken (который является типом Gson).
Такой же механизм обертывания будет работать с другими библиотеками, такими как Jackson, которые вы упомянули.
Ответ 3
Моим решением было использовать парсер json и разбить его на куски
public static <TT> PushObj<TT> fromJSON(String json, Class<TT> classType)
{
JsonObject jObj = new JsonParser().parse(json).getAsJsonObject();
String type = jObj.get("type").getAsString();
JsonObject job = jObj.get("object").getAsJsonObject();
TT obj = new Gson().fromJson(job, classType);
return new PushObj<TT>(type, obj);
}
Если структура объекта:
{String: Тип, общий: объект}
И переменные:
jObj - это JSONObject строки, переданной в
и задание - это JSONObject общего объекта
Итак, я использовал парсер json, чтобы получить тип отдельно, и отражение для объекта.