Использование дженериков с GSON - PullRequest
21 голосов
/ 19 ноября 2010

Я использую 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

Я думал, что с помощью TypeTЯ избегал Erasure Type.

Я не прав?

Спасибо

Ответы [ 3 ]

14 голосов
/ 19 ноября 2010

Прежде всего, я не вижу, как полезно обернуть Gson таким образом.

Что касается вашей проблемы, то информация о самом типе T сама по себе недоступна во время выполнения.Это было стерто.Это доступно только во время компиляции.Вместо этого вы хотите параметризовать его фактическим типом, таким как new TypeToken<List<String>>.

Из-за отсутствия усовершенствованных обобщений в Java (невозможно сделать T t = new T()), сам Gson вынужден использоватьTypeToken подход, как вы видите.В противном случае Гсон сделал бы это гораздо более элегантно.

Чтобы иметь возможность передавать фактический тип, вы должны заново изобрести то же, что уже делает TypeToken.И это не имеет смысла :) Просто используйте его повторно или просто используйте Gson, не помещая его в какой-нибудь вспомогательный класс, подобный этому.

5 голосов
/ 04 января 2011

Я думаю, что первый ответ не указывает на реальное решение: вы ДОЛЖНЫ также передать экземпляр класса вместе с T, например, так:

public T decode(String json, Class<T> cls) {
    Gson gson = new Gson();
    return gson.fromJson(json, cls);
}

Это потому, что здесь T является типом VARIABLE, а не ссылкой на тип; и используется только компилятором для добавления неявных приведений и проверки совместимости типов. Но если вы пройдете реальный класс, его можно использовать; и компилятор проверит совместимость типов, чтобы уменьшить вероятность несоответствия.

В качестве альтернативы вы можете взять TypeToken и передать его; но TypeToken должен быть создан с реальным типом, а не с переменной типа; Переменная типа здесь малопригодна. Но если вы хотите обернуть вещи, вы не хотите, чтобы вызывающая сторона использовала TypeToken (это тип Gson).

Тот же механизм обертывания будет работать с другими библиотеками, такими как Джексон, о котором вы упомянули.

0 голосов
/ 25 января 2016

Моим решением было использовать парсер 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: Type, Generic: Object}

ИПеременные: jObj - это JSONObject передаваемой строки, а job - это JSONObject универсального объекта

Поэтому я использовал анализатор json для получения типа отдельно и отражения для объекта.

...