Question

J'utilise GSON pour décoder JSON dans un objet de type T par exemple.

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

retourne cependant une exception -

java.lang.AssertionError: Type inattendu. Prévue l'un des: java.lang.reflect.ParameterizedType, java.lang.reflect.GenericArrayType, mais a obtenu: sun.reflect.generics.reflectiveObjects.TypeVariableImpl, pour le type de jeton: T

Je pensais que je l'aide TypeToken évitais type Erasure.

Ai-je tort?

Merci

Était-ce utile?

La solution

Tout d'abord, je ne vois pas comment il est utile d'envelopper Gson comme ça.

En ce qui concerne votre problème, les informations sur T de type générique lui-même est pas disponible lors de l'exécution. Il a été effacé. Il est disponible uniquement pendant la compilation. Vous voulez paramétrer avec le type réel au lieu comme new TypeToken<List<String>>.

En raison du manque de réifiées Generics en Java (il est impossible de faire un T t = new T()), Gson lui-même est obligé d'utiliser l'approche TypeToken, comme vous le voyez. Dans le cas contraire Gson aurait fait de façon beaucoup plus élégante.

Pour pouvoir passer le type réel autour, vous avez à réinventer la même chose que TypeToken est déjà en train de faire. Et cela n'a pas de sens :) Juste réutiliser ou tout simplement utiliser Gson droit sans l'emballer dans une classe d'aide comme ça.

Autres conseils

Je pense que la première réponse ne pointe pas la solution réelle: vous devez également passer par exemple de classe avec T, comme suit:

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

Ceci est parce que « T » est ici une variable de type, pas une référence de type; et seulement utilisé par le compilateur pour ajouter des moulages implicites et vérifier la compatibilité des types. Mais si vous passez la classe réelle, il peut être utilisé; et compilateur de vérifier la compatibilité de type pour réduire la chance de non-concordance.

vous pouvez prendre TypeToken Alternativement et le transmettre; mais TypeToken doit être construit avec le type réel, pas une variable de type; variable de type est peu utile ici. Mais si vous ne voulez envelopper des choses que vous ne voudriez pas utiliser l'appelant TypeToken (qui est un type Gson).

mécanisme d'emballage même travaillerait avec d'autres libs comme Jackson, que vous avez mentionné.

Ma solution à c'était d'utiliser l'analyseur de JSON et le casser en morceaux

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);
}

Lorsque la structure de l'objet est: {String: Type, générique: Object}

Et les variables sont les suivantes: jObj est le JSONObject de la chaîne passée en et l'emploi est le JSONObject de l'objet générique

Alors je l'ai utilisé l'analyseur JSON pour obtenir le type séparément, et de réflexion pour l'objet.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top