2016-04-06 7 views
15

Retrofitのラッパーを作成してサービス実装を抽象化しようとしています。私は今のところ正常にコンパイルするコンパイラを得ている:入れ子のクラス<MyInterface <T>>をAndroidのパラメータとして渡す

package com.example.spark.testapp.services; 

import com.example.spark.testapp.services.apis.Get; 
import com.example.spark.testapp.services.apis.Post; 
import com.example.spark.testapp.services.utils.*; 
import com.example.spark.testapp.services.utils.Error; 

import java.util.List; 

import retrofit2.Call; 
import retrofit2.Callback; 
import retrofit2.Response; 
import retrofit2.Retrofit; 




public class ServiceLayer { 
    public <T> void performGet(String url, final Class<Get<T>> clazz, com.example.spark.testapp.services.utils.Callback<T> callback) { 
     Retrofit retrofit = new Retrofit.Builder().baseUrl("").build(); 
     Get<T> service = retrofit.create(clazz); 
     //Pass authentication token here 
     Call<T> t = service.get(url, ""); 
     executeCallback(callback,t); 
    } 

    public <T> void performPost(String url, final Class<Post<T>> clazz,com.example.spark.testapp.services.utils.Callback<T> callback) { 
     Retrofit retrofit = new Retrofit.Builder().baseUrl("").build(); 
     Post<T> service = retrofit.create(clazz); 

     //Pass authentication token here 
     Call<T> t = service.post(url, ""); 
     executeCallback(callback,t); 
    } 

    public <T> void executeCallback(final com.example.spark.testapp.services.utils.Callback<T> callback , Call<T> call) { 
     call.enqueue(new Callback<T>() { 
      @Override 
      public void onResponse(Call<T> call, Response<T> response) { 
       callback.onSuccess(response.body()); 
      } 


      @Override 
      public void onFailure(Call<T> call, Throwable t) { 
       ///Find out what exactly went wrong. Populate Error. and then... 
       com.example.spark.testapp.services.utils.Error e = new Error(); 
       callback.onFailure(e); 
      } 
     }); 
    } 
} 

これはコンパイルが、問題は、メソッドを呼び出した時点で、次のとおりです。

private void getString() { 

     ServiceLayer s = new ServiceLayer(); 
     s.performGet("",Get<String>.class,this); //Cannot select from parameterised type 

    } 

私はこの問題を回避ビットをGoogleで検索していることを発見しましたこれはタイプ消去のため不可能です。ファイン。

しかし私の質問は、コンパイラはここでエラーを発生させるべきではないですか?この行に? :

public <T> void performGet(String url, final Class<Get<T>> clazz, com.example.spark.testapp.services.utils.Callback<T> callback) 

サービス層はどのようにコンパイルされましたか?

EDIT

質問が誤解しているようです。私はこのデザインを動作させる方法を探していません。私はその欠陥を理解しており、私たちはサービスを階層化するより良い方法を見つけました。質問は、言語自体の興味深い/奇妙な振る舞いに関するものです。

+0

'this'は' Callback 'を実装しているとしますか? – njzk2

+0

関連:http://stackoverflow.com/questions/27000227/cannot-select-parameterized-type – njzk2

+0

@ njk2 - はい。あなたが正しいです。 'this'はコールバックを実装しています。そして、それはまったく関連していません。問題は、単に呼び出すことができない場合、私のサービス層はどのようにコンパイルされるのでしょうか? – avismara

答えて

0

いくつかのテストを行い、解決策が見つかったらうまくいけば助けになります。

このコードは(Aは何もしない、いくつかの一般的なクラスです)がtrueを返すので:

A<String> a = new A<String>(); 
System.out.println(A.class == a.getClass()); 

それはあなたが「ゲット< T>」のクラスを取得する必要がありますが、単に「を取得していないことを意味し「あなたのレトロフィットのために必要なもの

は、たとえば、このTであるかを知るための機能のために、他の引数としてTを送信することです:

public <T> void performGet(String url, final Class<Get> clazz, final Class<T> t, com.example.spark.testapp.services.utils.Callback<T> callback) { 
    Retrofit retrofit = new Retrofit.Builder().baseUrl("").build(); 
    Get<T> service = retrofit.create(clazz); 
    ... 
+0

これまではこの解決策を試しましたが、 'retrofit.create(clazz)'の中で 'T'の型情報が失われることは望ましくありません。返すものは、 'Get 'ではないタイプのものです。 – avismara

+0

タイプによって、あなたはクラスを意味しますか?最初の例では、 'Get 'と 'Get'は同じクラスです。もしあなたが 'Get = ...'でそれを設定した後にどのようなエラーが出るのかわからないのですか? –

+0

タイプ別には、タイプを意味します。 私にはエラーはありませんが、自然に警告が表示されます。 'Get 'と 'Get'の型は同じではありません。あなたが提案したようにこれを行っても、それはコンパイルされますが、私がしたいことを間違いなく実行します。 :) プラス、これはとにかく私の質問への答えではありません。 – avismara

-1

あなたがジェネリックを維持したい場合クラスパラメータ(T)の情報がメソッド内で到達可能な場合は、クラス情報を指定する必要があります。例:

public class SomeClass<T, X, C> { 
    Class<X> xClass; 
    Class<T> tClass; 
    Class<C> cClass; 

    public SomeClass<T, X, C>(Class<T> a, Class<X> b, Class<C> c){ 
     tClass = a; 
     xClass = b; 
     cClass = c; 
    } 
} 

その方法は、あなたが「消費者」クラスの内部クラス情報を使用することができ、どちらかさてなど、一般的なメソッドを呼び出して、

を共通の署名、シリアライズ/デシリアライズプロセス、オブジェクトの作成にアクセスするためのあなただけのメソッド内ジェネリッククラス・パラメータの情報を使用したい場合は、以下を行う必要があります。

public <T> void performGet(String url, final Class<T> clazz, com.example.spark.testapp.services.utils.Callback<T> callback) { 
    Retrofit retrofit = new Retrofit.Builder().baseUrl("").build(); 
    Get<T> service = retrofit.create(clazz); 
    //Pass authentication token here 
    Call<T> t = service.get(url, ""); 
    executeCallback(callback,t); 
} 

これはあなたのメソッドを含むクラスにジェネリッククラスの情報を保存するよりも、同じことができます。あなたのメソッド内でそのメソッドにアクセスし、それを他のジェネリックメソッドやその他すべてのパラメータとして使用することができます。

もっと例が必要な場合は、これをご覧ください。それもラッパーですが、SpringのRestTemplate-Androidの周りを回るので、多分あなたはそれからいくつかのアイデアを得ることができます。 (免責事項 - 私はTEH devのだ)

https://github.com/fcopardo/EasyRest/blob/master/src/main/java/com/grizzly/rest/GenericRestCall.java

+0

編集を見てください。私はこれを動作させるための解決策を探しているわけではありません。私はなぜコンパイラがこのコードをコンパイルしてくれるのか尋ねています---メソッドシグネチャが呼び出せないコード--- ---これは有益ではないので、この答えは私のものではありません。探している – avismara

4

しかし、私の質問は、コンパイラが、ここでエラーを発生させるべきではないのですか?

メソッドシグネチャは、Javaでは完全に正しいです。ジェネリックメソッドシグネチャは、通常のメソッドと同じ規則で制御されます。

一般的な方法では、コード内で実行できるアクションはパラメーターの種類によって異なります。たとえば、あなたは、このメソッドを持っている場合:

public static <T> void test(List<T> list, Class<T> clazz) 
     throws InstantiationException, IllegalAccessException 
{ 
    list.add(clazz.newInstance()); 
} 

それはコンパイルが、私たちは次の行を追加した場合:

list.add(new Integer(1)); 

それはコンパイル時listにのみTのインスタンスを受け付けませんので。したがって、一般的な方法はよく定義されています。

汎用メソッドを呼び出そうとすると、コンパイラはパラメータからTを推論できません。主な問題は明らかに、Class<Get<T>>構造体です。メソッドシグネチャでは有効ですが、推奨されません。けれども、あなたはメソッド呼び出しのコンパイルと動作させるために、安全でないと奇妙なキャストを行うことができます。

s.performGet("",(Class<Get<String>>)(Class) Get.class,this); 

は、ジェネリック型のみコンパイル時にチェックされているため、コンパイラは今、Tを推測することができ、このキャストチェーンをやって。実行時には、Class<Get<T>>は常にGet.classになります。

このトピックに関するいくつかの関連質問:

Passing the Class<T> in java of a generic list?

Generic type as parameter in Java Method

1

まず、あなたの構文は、コンパイラは、したがって、与えられたラインでダウ船エラー有効ではありませんです。あなたが持っているエラーはおそらくそれに関連していますClassは、VMによって作成される特別なクラスであり、エラーのチェック中にコンパイラは通常のクラスとして扱います。

は、この例を見てください:あなたは

ServiceLayer a = new ServiceLayer(); 
    Clazz<Get<String>> clazz = new Clazz<Hello.Get<String>>(); 
    Callback<String> callback = new Callback<String>(); 
    a.performGet("someurl", clazz, callback); 

を呼び出そうと

class Get<T> { 
    } 

class Callback<T> { 
    } 
class Clazz<T> { 
    } 

static class ServiceLayer { 

     public <T> void performGet(String url, final Clazz<Get<T>> clazz, 
       Callback<T> callback) { 
     } 
    } 

は今、あなたはすべての問題を持って欲しいです。ですから、その構文には問題はありませんが、特別なオブジェクトがあります。

関連する問題