J'ai ce code:
Type typeOfObjectsList = new TypeToken<ArrayList<myClass>>() {}.getType();
List<myClass> objectsList = new Gson().fromJson(json, typeOfObjectsList);
Il convertit une chaîne JSON en un List
d'objets. Mais maintenant, je veux avoir ce ArrayList
avec un type dynamique (pas seulement myClass
), défini au moment de l'exécution.
Le type d'élément de ArrayList
sera défini avec une réflexion .
J'ai essayé ceci:
private <T> Type setModelAndGetCorrespondingList2(Class<T> type) {
Type typeOfObjectsListNew = new TypeToken<ArrayList<T>>() {}.getType();
return typeOfObjectsListNew;
}
Mais ça ne marche pas. C'est l'exception:
Java.sql.SQLException: Fail to convert to internal representation: {....my json....}
La syntaxe que vous proposez n'est pas valide. Le suivant
new TypeToken<ArrayList<Class.forName(MyClass)>>
n'est pas valide car vous essayez de passer un appel de méthode pour lequel un nom de type est attendu.
Le suivant
new TypeToken<ArrayList<T>>()
n'est pas possible à cause du fonctionnement des génériques (effacement des types) et de la réflexion. L'ensemble TypeToken
hack fonctionne parce que Class#getGenericSuperclass()
effectue les opérations suivantes
Retourne le Type représentant la superclasse directe de l'entité (classe, interface, type primitif ou void) représentée par cette classe.
Si la superclasse est un type paramétré, l'objet Type renvoyé doit refléter avec précision les paramètres de type réels utilisés dans le code source.
En d’autres termes, s’il voit ArrayList<T>
, C’est le ParameterizedType
qu’il retournera et vous ne pourrez pas extraire la valeur de compilation de la variable type T
avait.
Type
et ParameterizedType
sont les deux interfaces. Vous pouvez fournir une instance de votre propre implémentation.
Depuis Gson 2.8.0, vous pouvez utiliser TypeToken#getParameterized(Type rawType, Type... typeArguments)
pour créer le TypeToken
, puis getType()
devrait faire l'affaire.
Par exemple:
TypeToken.getParameterized(ArrayList.class, myClass).getType()
Option 1 - implémenter Java.lang.reflect.ParameterizedType
toi-même et passe-le à Gson.
private static class ListParameterizedType implements ParameterizedType {
private Type type;
private ListParameterizedType(Type type) {
this.type = type;
}
@Override
public Type[] getActualTypeArguments() {
return new Type[] {type};
}
@Override
public Type getRawType() {
return ArrayList.class;
}
@Override
public Type getOwnerType() {
return null;
}
// implement equals method too! (as per javadoc)
}
Alors simplement:
Type type = new ListParameterizedType(clazz);
List<T> list = gson.fromJson(json, type);
Notez que selon javadoc , la méthode equals devrait également être mise en œuvre.
Option 2 - (ne le faites pas) réutilisez gson internal ...
Cela fonctionnera aussi, du moins avec Gson 2.2.4.
Type type = com.google.gson.internal.$Gson$Types.newParameterizedTypeWithOwner(null, ArrayList.class, clazz);
Cela a fonctionné pour moi:
public <T> List<T> listEntity(Class<T> clazz)
throws WsIntegracaoException {
try {
// Consuming remote method
String strJson = getService().listEntity(clazz.getName());
JsonParser parser = new JsonParser();
JsonArray array = parser.parse(strJson).getAsJsonArray();
List<T> lst = new ArrayList<T>();
for(final JsonElement json: array){
T entity = GSON.fromJson(json, clazz);
lst.add(entity);
}
return lst;
} catch (Exception e) {
throw new WsIntegracaoException(
"WS method error [listEntity()]", e);
}
}
Vous pouvez faire cela avec le plus puissant de Guava TypeToken
:
private static <T> Type setModelAndGetCorrespondingList2(Class<T> type) {
return new TypeToken<ArrayList<T>>() {}
.where(new TypeParameter<T>() {}, type)
.getType();
}
Sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
workes. Pas besoin d'implémentation personnalisée
Type type = ParameterizedTypeImpl.make(List.class, new Type[]{childrenClazz}, null);
List list = gson.fromJson(json, type);
Peut être utilisé avec des cartes et toute autre collection:
ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, childrenClazz}, null);
Voici une belle démonstration de la façon dont vous pouvez l’utiliser dans un désérialiseur personnalisé: Désérialisation de ImmutableList avec Gson
Vous pouvez réellement le faire. Il vous suffit d’analyser d’abord vos données dans un JsonArray
, puis de transformer chaque objet individuellement et de l’ajouter à un List
:
Class<T> dataType;
//...
JsonElement root = jsonParser.parse(json);
List<T> data = new ArrayList<>();
JsonArray rootArray = root.getAsJsonArray();
for (JsonElement json : rootArray) {
try {
data.add(gson.fromJson(json, dataType));
} catch (Exception e) {
e.printStackTrace();
}
}
return data;