Ich habe diesen Code:
Type typeOfObjectsList = new TypeToken<ArrayList<myClass>>() {}.getType();
List<myClass> objectsList = new Gson().fromJson(json, typeOfObjectsList);
Es konvertiert eine JSON-Zeichenfolge in ein List
Objekt. Aber jetzt möchte ich dies ArrayList
mit einem dynamischen Typ (nicht nur myClass
) haben, der zur Laufzeit definiert wird.
Der ArrayList
Artikeltyp des wird mit Reflexion definiert .
Ich habe es versucht:
private <T> Type setModelAndGetCorrespondingList2(Class<T> type) {
Type typeOfObjectsListNew = new TypeToken<ArrayList<T>>() {}.getType();
return typeOfObjectsListNew;
}
Aber es funktioniert nicht. Dies ist die Ausnahme:
java.sql.SQLException: Fail to convert to internal representation: {....my json....}
java
reflection
arraylist
gson
Amin Sh
quelle
quelle
TypeToken<ArrayList<T>>()
Code den dynamischen Arraylist-Typ akzeptiert. so etwas wie das:TypeToken<ArrayList<Class.forName(MyClass)>>
Antworten:
Die von Ihnen vorgeschlagene Syntax ist ungültig. Folgende
new TypeToken<ArrayList<Class.forName(MyClass)>>
ist ungültig, weil Sie versuchen, einen Methodenaufruf zu übergeben, bei dem ein Typname erwartet wird.
Folgende
new TypeToken<ArrayList<T>>()
ist nicht möglich, da Generika (Typ Löschung) und Reflexion funktionieren. Der ganze
TypeToken
Hack funktioniert, weil erClass#getGenericSuperclass()
folgendes tutMit anderen Worten, wenn es angezeigt
ArrayList<T>
wird,ParameterizedType
wird es zurückgegeben, und Sie können den Kompilierungszeitwert, den die TypvariableT
gehabt hätte, nicht extrahieren .Type
undParameterizedType
sind beide Schnittstellen. Sie können eine Instanz Ihrer eigenen Implementierung bereitstellen.quelle
Class
Objekt verwendet, sodass Gson sehr gut wissen kann, auf welchen Typ es deserialisiert werden soll. In der Frage des OP möchten sie dies ohne Verwendung desClass
Objekts und nur über das Argument type tun , das in der Methode selbst nicht verfügbar ist.Seit Gson 2.8.0 können Sie das
TypeToken#getParameterized(Type rawType, Type... typeArguments)
erstellenTypeToken
, danngetType()
sollten Sie den Trick machen.Zum Beispiel:
quelle
Option 1 - Implementieren
java.lang.reflect.ParameterizedType
Sie sich und geben Sie es an Gson weiter.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) }
Dann einfach:
Type type = new ListParameterizedType(clazz); List<T> list = gson.fromJson(json, type);
Beachten Sie, dass gemäß javadoc auch die Methode equals implementiert werden sollte.
Option 2 - (nicht tun) gson intern wiederverwenden ...
Dies wird auch funktionieren, zumindest mit Gson 2.2.4.
Type type = com.google.gson.internal.$Gson$Types.newParameterizedTypeWithOwner(null, ArrayList.class, clazz);
quelle
Das hat bei mir funktioniert:
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); } }
quelle
Sie können dies mit Guavas mächtigerem tun
TypeToken
:private static <T> Type setModelAndGetCorrespondingList2(Class<T> type) { return new TypeToken<ArrayList<T>>() {} .where(new TypeParameter<T>() {}, type) .getType(); }
quelle
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
arbeitet. Keine benutzerdefinierte Implementierung erforderlichType type = ParameterizedTypeImpl.make(List.class, new Type[]{childrenClazz}, null); List list = gson.fromJson(json, type);
Kann mit Karten und jeder anderen Sammlung verwendet werden:
ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, childrenClazz}, null);
Hier ist eine nette Demo, wie Sie sie in einem benutzerdefinierten Deserializer verwenden können: Deserializing ImmutableList using Gson
quelle
Sie können es tatsächlich tun. Sie müssen nur zuerst Ihre Daten in ein
JsonArray
Objekt analysieren und dann jedes Objekt einzeln transformieren und zu einem hinzufügenList
: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;
quelle
Voll funktionsfähige Lösung:
String json = .... //example: mPrefs.getString("list", ""); ArrayList<YouClassName> myTypes = fromJSonList(json, YouClassName.class); public <YouClassName> ArrayList<YouClassName> fromJSonList(String json, Class<YouClassName> type) { Gson gson = new Gson(); return gson.fromJson(json, TypeToken.getParameterized(ArrayList.class, type).getType()); }
quelle
Mit kotlin können Sie die folgenden Funktionen verwenden, um (von / nach) alle (JsonArray / JsonObject) nur in einer Zeile zu konvertieren, ohne ein TypeToken senden zu müssen: -
Konvertieren Sie eine Klasse oder ein Array in eine JSON-Zeichenfolge
inline fun <reified T : Any> T?.json() = this?.let { Gson().toJson(this, T::class.java) }
val list = listOf("1","2","3") val jsonArrayAsString = list.json() //output : ["1","2","3"] val model= Foo(name = "example",email = "[email protected]") val jsonObjectAsString = model.json() //output : {"name" : "example", "email" : "[email protected]"}
Konvertieren Sie die JSON-Zeichenfolge in eine beliebige Klasse oder ein beliebiges Array
inline fun <reified T : Any> String?.fromJson(): T? = this?.let { val type = object : TypeToken<T>() {}.type Gson().fromJson(this, type) }
val jsonArrayAsString = "[\"1\",\"2\",\"3\"]" val list = jsonArrayAsString.fromJson<List<String>>() val jsonObjectAsString = "{ "name" : "example", "email" : "t@t.com"}" val model : Foo? = jsonObjectAsString.fromJson() //or val model = jsonObjectAsString.fromJson<Foo>()
quelle