2016-10-29 10 views
8

私は学ぶことが私のデータベースのための私自身のリポジトリを作成しようとしていますので、私はこのような何かしようとしています:私はDatabaseObjectを拡張する多くのクラスを持っている、と私は構築することができるようにしたい言い換えればジェネリック型のコンストラクタをコールしますか?

@Override 
public <T extends DatabaseObject> List<T> getList() { 
    Cursor cursor = getCursor(somehowGetClassOfT(), null, null); //how to do this? 
    //excess code removed, rest of function not relevant to question 
    return list; 
} 

protected <T extends DatabaseObject> Cursor getCursor(Class<T> clazz, String selection, String[] selectionArgs) { 
    DatabaseObject databaseObject = instantiateFromT(clazz); //how to do this? 
    String tableName = databaseObject.getTableName(); 
    String[] projection = databaseObject.getProjection(); 
    String sortOrder = databaseObject.getDefaultOrderColumn() + " " + DEFAULT_SORT_ORDER; 
    Cursor cursor = database.query(
      tableName,        
      projection,    
      selection,        
      selectionArgs,        
      null,          
      null,          
      sortOrder         
    ); 
    return cursor; 
} 

を動的にカーソルを作成します。

テーブル名や列名の文字列配列など、データベースオブジェクトの基本メソッドを定義しましたが、(テーブル名などの)インターフェイスから静的メソッドをオーバーライドできないため、私はゲッターでテーブル名を取得することができます。

しかし、私は実装方法を確認していない:

  1. somehowGetClassOfT()Tが何であれ、そのクラスをCursor関数に渡したいと思います。

  2. instantiateFromT(clazz)。いくつかのクラスが与えられたら、そのオブジェクトのテーブル/投影/並べ替えフィールドにアクセスできるようにコンストラクタを呼び出します。

これは、私が聞いてきた「反射」を使用することで可能ですか?

答えて

4

実行時にジェネリックは改訂されません。情報が存在しないので、次の2つのソリューションを持っている:

それはあなたがインスタンスから、実行時にジェネリック型を解決するためにリフレクションを使用することができます
  • クラスにプライベートフィールドを導入することにより、コンパイル時に保存することができ
    • 。 ここ

    プライベートフィールドTとコンストラクタを持つたとえば、あなたのコードから開始することにより:ここ

    public abstract class MyRepository<T extends DatabaseObject> { 
    
        private Class<T> type; 
    
        public MyRepository(Class<T> type) { 
         this.type = type; 
        } 
    
        public <T> List<T> getList() { 
         Cursor cursor = getCursor(null, null); // how to do this? 
         // excess code removed, rest of function not relevant to question 
         return null; 
        } 
    
        protected <T extends DatabaseObject> Cursor getCursor(String selection, String[] selectionArgs) { 
         DatabaseObject databaseObject = instantiateFromType(); // how to do this? 
         String tableName = databaseObject.getTableName(); 
         String[] projection = databaseObject.getProjection(); 
         String sortOrder = databaseObject.getDefaultOrderColumn() + " " + DEFAULT_SORT_ORDER; 
         Cursor cursor = database.query(
         tableName, 
         projection, 
         selection, 
         selectionArgs, 
         null, 
         null, 
         sortOrder); 
         return cursor; 
        } 
    
        private DatabaseObject instantiateFromType() { 
         try { 
          T interfaceType = (T) type.newInstance(); 
          return interfaceType; 
         } 
         catch (Exception e) { 
          // TODO to handle 
         }   
        } 
    } 
    

    あなたDogRepository:DatabaseObjectを実装犬と

    public class DogRepository extends MyRepository<Dog> { 
    
        public DogRepository() {   
         super(Dog.class); 
        } 
    
    } 
    

    public class Dog implements DatabaseObject{ 
        //todo 
    } 
    

    あなたのコメントに答える。

    ラインDogRepository(クラスタイプ)は、クラスを引数として を渡す必要がありますか?

    コメントはありません。
    また、具体的なリポジトリのコンストラクタはボイラープレートのコードです。
    Refreshを使用してDogRepositoryで使用されるジェネリックの背後にあるクラスを解決する場合は、カスタムコンストラクタをそれ以上定義する必要はありません。

    は、リポジトリで使用されるタイプを取得するために、例えば、春にはそのようなものでJDKの反射メカニズムを使用して、独自のライブラリと仕事をしていません:それは多くのリフレクションを使用しているため

    Map<TypeVariable, Type> source = GenericTypeResolver.getTypeVariableMap(DogRepository.class); 
    

    春は、そのライブラリを持っています。
    あなたの場合、libを使わずに自分のユーティリティクラスを使って仕事をすることもできます。ここでは、ジェネリック型をリポジトリインスタンスから解決するためのサンプルです。

    public abstract class MyRepository<T extends DatabaseObject> { 
    
        private Class<T> type; 
    
        public MyRepository() { 
         type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
        } 
        ... 
    } 
    

    リポジトリ具象クラスはもはやカスタムコンストラクタを必要としない:

    public class DogRepository extends MyRepository<Dog> { 
    
    } 
    
  • +0

    ストレートな方法でMyRepositoryコンストラクタで効果的なジェネリック型を解決するための反射で

    DogRepository dogRepository = new DogRepository(); Class<?> typeClass = (Class<?>) ((ParameterizedType) dogRepository.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; System.out.println("typeClass=" + typeClass); 

    。私は答えました。 – davidxxx

    +0

    私は今見ました。すでにSOの助けを借りています。 Great :) – davidxxx

    +0

    'DogRepository(Class type)'という行は、引数としてクラスを渡す必要がありますか?私。 DogRepositoryは、何らかの理由でDog.classに内部参照があるので、引数を渡すべきではないので、リポジトリが呼び出されるたびに外部から渡される必要はありませんか? – user7085962

    関連する問題