私はこのコードを持っています:
Type typeOfObjectsList = new TypeToken<ArrayList<myClass>>() {}.getType();
List<myClass> objectsList = new Gson().fromJson(json, typeOfObjectsList);
JSON文字列をオブジェクトのList
に変換します。しかし、今では、_ArrayList
だけでなく、実行時に定義される動的な型でこのmyClass
を持ちたいです。
ArrayList
の項目タイプはreflectionで定義されます。
私はこれを試しました:
private <T> Type setModelAndGetCorrespondingList2(Class<T> type) {
Type typeOfObjectsListNew = new TypeToken<ArrayList<T>>() {}.getType();
return typeOfObjectsListNew;
}
しかし、それは機能しません。これは例外です。
Java.sql.SQLException: Fail to convert to internal representation: {....my json....}
提案している構文は無効です。以下
new TypeToken<ArrayList<Class.forName(MyClass)>>
型名が必要な場所でメソッド呼び出しを渡そうとしているため、無効です。
以下
new TypeToken<ArrayList<T>>()
ジェネリック(型消去)とリフレクションの仕組みのために不可能です。 Class#getGenericSuperclass()
は以下を行うため、TypeToken
ハック全体が機能します。
このクラスによって表されるエンティティ(クラス、インターフェース、プリミティブ型、またはvoid)の直接のスーパークラスを表すTypeを返します。
スーパークラスがパラメーター化された型である場合、返されるTypeオブジェクトは、ソースコードで使用される実際の型パラメーターを正確に反映する必要があります。
言い換えると、ArrayList<T>
が見つかった場合、それはParameterizedType
であり、型変数T
が持っていたであろうコンパイル時の値を抽出することはできません。
Type
とParameterizedType
は両方ともインターフェースです。独自の実装のインスタンスを提供できます。
Gson 2.8.0以降では、 TypeToken#getParameterized(Type rawType, Type... typeArguments)
を使用してTypeToken
を作成できます。その後、getType()
を使用してください。
例えば:
TypeToken.getParameterized(ArrayList.class, myClass).getType()
オプション1-Java.lang.reflect.ParameterizedType
を自分で実装し、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)
}
それから単に:
Type type = new ListParameterizedType(clazz);
List<T> list = gson.fromJson(json, type);
javadoc に従って、equalsメソッドも実装する必要があることに注意してください。
オプション2-(これをしないでください)gson internal ...を再利用します.
これは、少なくともGson 2.2.4でも機能します。
Type type = com.google.gson.internal.$Gson$Types.newParameterizedTypeWithOwner(null, ArrayList.class, clazz);
これは私のために働いた:
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);
}
}
これは、グアバのより強力な 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
が機能します。カスタム実装の必要はありません
Type type = ParameterizedTypeImpl.make(List.class, new Type[]{childrenClazz}, null);
List list = gson.fromJson(json, type);
マップおよびその他のコレクションで使用できます。
ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, childrenClazz}, null);
カスタムデシリアライザーでそれを使用する方法の素敵なデモは次のとおりです: Gson
実際に行うことができます。最初にデータを解析してJsonArray
にし、次に各オブジェクトを個別に変換し、それを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;