質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

境界型ジェネリクスで型を取得したい

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 3,225

lupus_dingo

score 279

お世話になっております。
Daoクラスをテンプレート化するために親クラスを作成しているのですが
境界型ジェネリクスで型を指定する際に以下のEからどのように型を取得すればいいのでしょうか?

abstract public class BaseDao<E extends BaseEntity> {

    protected static void findAll(String sql) throws Exception {
        Connection con = getConnect();

        RowProcessor rp = new BasicRowProcessor(new MyBeanProcessor());
        QueryRunner qr = new QueryRunner();

        ResultSetHandler<List<E>> h = new BeanListHandler<E>(E.class, rp);// E.classがコンパイルエラー
        List<E> list = qr.query(con, sql, h);
        con.close();
    }
~省略~
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+1

クラス名などから察するに、Commons-dbutilsをお使いなのだと思いますが(違っていたらすみません)

Commons-dbutilsでDAOを作る場合には、便利な実装例があります。
Apache Commons公式|DbUtils: JDBC Utility Component Examples

クエリを投げるクラスと、結果1行ごとに制御するハンドラとを分けると、例えば以下のようにすると良いでしょうか。

あとは、型情報(ここでは T)はインスタンス化できないので、引数に追加してあげると良いでしょう。

import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

public class BaseDataAccessObject<T> {

    private DataSource dataSource = null;

    public List<T> findAll(String queryString,Class<T> clazz) throws SQLException {
        ResultSetHandler<List<T>> h = new BeanListHandler<T>(clazz);

        QueryRunner run = new QueryRunner(dataSource);

        List<T> result = run.query(queryString, h, "PlaceHolder");

        return result;
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/04 19:10

    回答ありがとうございます。

    クラス自体を引数に渡すという発想がなかったので勉強になりました。
    他の方の回答も参考にさせていただき、実装に反映させていただきます。

    ありがとうございました。

    キャンセル

checkベストアンサー

0

基本的はジェネリクスは抽象的に扱うものであって実態やクラスは取得できません。
必要になってしまった場合には設計を見直すべきです。

一応裏技的な解決策はありますが、あまりいいソースとは言えません...

Class<?> clazz = this.getClass();
Type type = clazz.getGenericSuperclass();
ParameterizedType pt = (ParameterizedType)type;
Type[] actualTypeArguments = pt.getActualTypeArguments();
Class<?> entityClass = (Class<?>)actualTypeArguments[0];

追記

abstract public class BaseDao {

    protected static <E extends BaseEntity> void findAll(String sql) throws Exception {
        Connection con = getConnect();

        RowProcessor rp = new BasicRowProcessor(new MyBeanProcessor());
        QueryRunner qr = new QueryRunner();

        ResultSetHandler<List<E>> h = new BeanListHandler<E>(getEntityClass(), rp);// E.classがコンパイルエラー
        List<E> list = qr.query(con, sql, h);
        con.close();
    }

    protected abstruct  <E extends BaseEntity> Class<E> getEntityClass(); 
~省略~
}

とかですかね?実装クラスではgetEntityClass()を記載する必要がありますが、クラスの総称型を書く必要がなくなります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/04 18:36

    回答ありがとうございます。
    他の方にも同じ質問になってもうしわけないのですが、

    Daoの基底クラスでコネクションからクエリ実行などの共通処理を行い、
    子クラスではSQLの作成のみを行いたい場合通常はどのように設計するのが正しいでしょうか?
    サンプルが載っているようなサイトがあったら教えていただきたいです。

    キャンセル

  • 2017/02/04 18:49

    Eをクラスとして欲しいのであれば、抽象メソッドなどで取得するほうがいいのではないでしょうか?
    回答に追記します。

    キャンセル

  • 2017/02/04 19:08

    回答ありがとうございます。
    なるほど参考になります。
    こちらと他のアドバイスをからどれを採用するか考えようと思います。

    ありがとうございました。

    キャンセル

0

  1. 一番簡単な方法
    このクラスのコンストラクターに派生クラスからEのクラスを渡してこのクラスのフィールドに覚えておく。

  2. リフレクションを使う(条件付き)
    細かな条件を忘れたのですが・・・(^^;
    例えばこのクラスの派生クラスをnew DerivedDao<DerivedEntry>() {};のように無名クラスとして生成してやるとリフレクションで型引数のクラスを実行時に参照できます。無名クラスにせずにインスタンスを生成すると型が消去されてしまうのでリフレクションでも参照できません。

abstract public class BaseDao<E extends BaseEntity> {
  final Class<E> classE;

  BaseDao() {
    ParameterizedType superType =
      (ParameterizedType)getClass().getGenericSuperclass();
    Type[] atvs = superType.getActualTypeArguments();
    classE = (Class<E>)atvs[0];
  }
}

このコードではBaseDaoを直接継承したクラス(無名クラスとか)しかないと前提を置いてます。
派生の派生・・・というふうに継承が深くなるともう少し配慮が必要だと思います。

無名クラスで取れるのでclass DerivedDao extends BaseDao<DerivedEntity> { ... }のように普通に派生クラスを定義しても同じ方法でクラスが参照できると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/04 18:33

    回答ありがとうございます。
    ただ見慣れないクラスがいろいろ出てきてちょっと理解しきれません^^;

    Daoの基底クラスでコネクションからクエリ実行などの共通処理を行い、
    子クラスではSQLの作成のみを行いたい場合通常はどのように設計するのが正しいでしょうか?
    参考になりそうなサイトでもあれば教えていただきたいです。

    キャンセル

  • 2017/02/04 19:16

    残念ながら自分はDBアプリの経験が乏しすぎるので回答に示した「言語仕様上のテクニック」以上のアドバイスはできそうもないです。自分の場合は「あるインターフェースの個別クラスに対して生成、加工、出力までの共通の処理パターンがあって生成もジェネリックスクラス内で書けるかやってみた」といった動機だったのです。他の方のコメントを見て自分も勉強したいと思います。

    キャンセル

  • 2017/02/04 19:26

    回答ありがとうございます。
    お互い頑張りましょう。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る