web-dev-qa-db-ja.com

Java GSONの引数としてジェネリックを入力

GSONで、実行するオブジェクトのリストを取得します

Gson gson = new Gson();
Type token = new TypeToken<List<MyType>>(){}.getType();
return gson.fromJson(json, token);

それはうまく機能しますが、このコードでオブジェクトのリストを解析する一般的な機能を持つことができるように、さらに進んでMyTypeをパラメータ化したいです

// the common function 
public <T> List<T> fromJSonList(String json, Class<T> type) {
  Gson gson = new Gson();
  Type collectionType = new TypeToken<List<T>>(){}.getType();
  return gson.fromJson(json, collectionType);
}

// the call
List<MyType> myTypes = parser.fromJSonList(jsonString, MyType.class);

悲しいことに、型ではなくStringMapsの配列を返します。 Tは、私の型ではなく、別のジェネリック型として解釈されています。回避策はありますか?

48
Rodrigo Asensio

ジェネリックはコンパイル時に機能します。スーパータイプトークンが機能する理由は、(匿名の)内部クラスがバイト引数メタデータに直接格納されているジェネリックスーパークラス(スーパーインターフェイス)の型引数にアクセスできるためです。

.Javaソースファイルがコンパイルされると、タイプパラメータ_<T>_は明らかに破棄されます。コンパイル時には不明であるため、バイトコードに格納できないため、消去され、Gsonは読み取ることができません。

[〜#〜] update [〜#〜]

Newacctの答えの後、私は彼がオプション2で提案したもの、つまりParameterizedTypeを実装しようとしました。コードは次のようになります(基本的な test ):

_class ListOfSomething<X> implements ParameterizedType {

    private Class<?> wrapped;

    public ListOfSomething(Class<X> wrapped) {
        this.wrapped = wrapped;
    }

    public Type[] getActualTypeArguments() {
        return new Type[] {wrapped};
    }

    public Type getRawType() {
        return List.class;
    }

    public Type getOwnerType() {
        return null;
    }

}
_

このコードの目的は、getFromJsonList()内で使用することです。

_public List<T> fromJsonList(String json, Class<T> klass) {
    Gson gson = new Gson();
    return gson.fromJson(json, new ListOfSomething<T>(klass));
}
_

テクニックが機能し、実際に非常に巧妙であっても(私はそれを知りませんでしたし、考えもしなかったでしょう)、これが最終的な成果です。

_List<Integer> list = new Factory<Integer>()
         .getFromJsonList(text, Integer.class)
_

の代わりに

_List<Integer> list = new Gson().fromJson(text,
         new TypeToken<List<Integer>>(){}.getType());
_

私にとっては、TypeTokensがコードを厄介に見せることに同意しても、これらすべては役に立たないことになります:P

42
Raffaele

_gson 2.8.0_なので、 TypeToken#getParametized((Type rawType, Type... typeArguments)) を使用してtypeTokenを作成できます。その後、getType()がトリックを実行します。

例えば:

_TypeToken.getParameterized(List.class, myType).getType();
_
31
oldergod
public static final <T> List<T> getList(final Class<T[]> clazz, final String json)
{
    final T[] jsonToObject = new Gson().fromJson(json, clazz);

    return Arrays.asList(jsonToObject);
}

例:

getList(MyClass[].class, "[{...}]");
28
kayz1

Raffaele's をさらに一歩進めてクラスを生成し、すべてのクラスA(Bはパラメーター化されていないクラス)で機能するようにしました。セットやその他のコレクションに役立つ場合があります。

    public class GenericOf<X, Y> implements ParameterizedType {

    private final Class<X> container;
    private final Class<Y> wrapped;

    public GenericOf(Class<X> container, Class<Y> wrapped) {
        this.container = container;
        this.wrapped = wrapped;
    }

    public Type[] getActualTypeArguments() {
        return new Type[]{wrapped};
    }

    public Type getRawType() {
        return container;
    }

    public Type getOwnerType() {
        return null;
    }

}

@oldergodからの素晴らしい答えに基づいた完全なコードベースを次に示します。

public <T> List<T> fromJSonList(String json, Class<T> myType) {
    Gson gson = new Gson();
    Type collectionType = TypeToken.getParameterized(List.class, myType).getType();
    return gson.fromJson(json, collectionType);
}

を使用して

List<MyType> myTypes = parser.fromJSonList(jsonString, MyType.class);

お役に立てば幸いです

4
Phan Van Linh

これは以前の質問で回答されています。基本的に、2つのオプションがあります。

  1. 呼び出し元サイトからTypeを渡します。呼び出しコードはTypeTokenまたはそれを構築するために何でも使用します。
  2. パラメーター化された型に対応するTypeを自分で作成します。これには、ParameterizedTypeを実装するクラスを記述する必要があります
3
newacct

Kotlinでプログラミングする場合は、reified type parameterインライン関数

class GenericGson {

    companion object {
        inline fun <reified T : Any> Gson.fromJsonTokenType(jsonString: String): T {
            val type = object : TypeToken<T>() {}.type
            return this.fromJson(jsonString, type)
        }

        inline fun <reified T : Any> Gson.fromJsonType(jsonString: String): T = this.fromJson(jsonString, T::class.Java)

        inline fun <reified T : Any> fromJsonTokenType(jsonString: String): T = Gson().fromJsonTokenType(jsonString)

        inline fun <reified T : Any> fromJsonType(jsonString: String): T = Gson().fromJsonType(jsonString)
    }
}

そして、あなたのコードで以下のように使用してください

val arrayList = GenericGson.fromJsonTokenType<ArrayList<Person>>(json)
2
alijandro

Kotlinの簡単な使用例:

プレースの取得機能

fun getPlaces<T> (jsonString : String, clazz: Class<T>) : T { val places : T = Gson().fromJson(jsonString,clazz) return places }

その後、次のように使用できます

val places = getPlaces(Array<Place>::class.Java)
0
  public static <T> T getObject(String gsonStr) {
        Gson gson = new GsonBuilder()
                .setLenient()
                .create();
        Type collectionType = new TypeToken< T>(){}.getType();
        return gson.fromJson(gsonStr,
                collectionType);
    }

使用する場合:

Class1 class1=  getObject(jsonStr);
0
Ahmad Aghazadeh

私のために働いたコトリン「ListOfSomething」ソリューション:

fun <T: Any> getGsonList(json: String, kclass: KClass<T>) : List<T> {

    return getGsonInstance().fromJson<List<T>>(json, ListOfSomething<T>(kclass.Java))
}


internal class ListOfSomething<X>(wrapped: Class<X>) : ParameterizedType {

    private val wrapped: Class<*>

    init {
        this.wrapped = wrapped
    }

    override fun getActualTypeArguments(): Array<Type> {
        return arrayOf<Type>(wrapped)
    }

    override fun getRawType(): Type {
        return ArrayList::class.Java
    }

    override fun getOwnerType(): Type? {
        return null
    }
}
0