8

ジェネリック メソッドの明示的な型引数に問題があります。私はこれを行うことができることを知っています:

Foo.<Bar>function();

があると仮定して

void <T> function() {...}

Foo クラスの関数。正確な問題は次のとおりです。

  • コンテンツをダウンロードしたい (Android with Ion )

  • これらのコンテンツは類似しており (Article、BlogArticle など)、すべて ContentItem インターフェイスを実装しています。

  • 現時点でのダウンロードは次のようになります。

たとえばニュース

private void downloadNews() {
    Ion.with(this)
    .load(URL_NEWS)
    .as(new TypeToken<List<Article>>(){})
    .setCallback(new FutureCallback<List<Article>>() {
        @Override
        public void onCompleted(Exception e, List<Article> result) {
            // do something with result
        }
    });
}

ブログ記事をダウンロードしたい場合は、url と Article クラス (BlogArticle の場合) のみを変更する必要があります。

次のような汎用関数を作成しようとしました。

private <T extends ContentItem> void download(String url) {
    Ion.with(this)
    .load(url)
    .as(new TypeToken<List<T>>(){})
    .setCallback(new FutureCallback<List<T>>() {
        @Override
        public void onCompleted(Exception e, List<T> result) {
            // do something with result
        }
    });
}

そしてその関数を呼び出します

this.<Article>download(url);

大丈夫です、うまくコンパイルできます。走った後、私は得る

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap は com.my.packagename.model.ContentItem にキャストできません

問題は、Json を pojo にマッピングするために明示的なクラスを使用しないことです。

一般的な解決策を教えてもらえますか?

4

4 に答える 4

2

数年後ですが、誰かの役に立つと思いました。私はより簡単な解決策に行き着きました。これは単純な切り詰められたバージョンですが、アイデアを得ることができます:

public static <T> void asList(Context context, String url, Class<T[]> clazz, final FutureCallback<List<T>> callback) {
    Ion.with(context)
        .load(url)
        .as(clazz)
        .setCallback(new FutureCallback<T[]>() {
            @Override
                public void onCompleted(Exception e, T[] result) {
                    callback.onCompleted(e, Arrays.asList(result));
                }
        });
}

そして次のように使用します:

asList(context, url, YourObject[].class, new FutureCallback<List<YourObject>>() {...});
于 2017-09-29T07:26:08.377 に答える
1

TypeToken アプローチを使用して、一般的な方法で必要なものを実装する方法はないと思います。実際、型トークンを機能させるには、匿名の内部クラスを作成する必要があることに注意してください。これにより、スーパータイプが として具体化された新しいクラスファイルを効率的に作成できますList<Article>。つまり、次の宣言がある場合のようになります。

class ArticleToken extends TypeToken<List<Article>> { ... }

上記の宣言を自分で記述した場合、クラスファイル ArticleToken.class がいわゆるSignature属性のジェネリック スーパータイプを追跡していることがわかります ( JVMSを参照)。したがって、このトリックを使用すると、後で を呼び出すことで、そのような汎用スーパータイプにアクセスできますClass.getGenericSupertype。つまり、具体化されたジェネリックを偽造するのはイディオムです。

コードをジェネリック メソッドに変換し、Article を型変数 T に置き換えると、作成する型トークンは次のようになります。

class GenericToken extends TypeToken<List<T>> { ... }

したがって、T に関する情報はクラスファイルにそのまま保存されます。reflectionn が型トークンの汎用スーパータイプを要求した場合、期待どおりにTypeToken<List<T>>返されずTypeToken<List<Article>>、問題が発生します。この作業を行うために必要なのは、真の具体化されたジェネリックです。メソッド呼び出しサイトで T を Article にバインドすると、実行時の動作に影響しますnew TypeToken<List<T>>が、悲しいことに、消去されたジェネリックを使用する Java には当てはまりません。

于 2016-10-06T17:50:43.157 に答える
0

ContentItem を実装するさまざまなクラスに逆シリアル化するには、TypeAdapter を持つカスタム GSON インスタンスを使用する必要があると思います。

http://www.javacreed.com/gson-typeadapter-example/

于 2014-07-14T08:06:06.080 に答える