Подтвердить что ты не робот

Использование дженериков с помощью 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.

Я не прав?

Спасибо

4b9b3361

Ответ 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, чтобы получить тип отдельно, и отражение для объекта.