継承元クラスでSelectのSQLを実行して、継承先クラスで戻り値を受け取る構造を作りたいと思っています。
想定している大体の構造は次のとおりです。
※この構造(型パラメータ)でなくても、
継承元で同一の基底クラスを持つCaseクラスをインスタンス化できるのであれば、
その方法が知りたいです。
scala
1// dbbase.scala 2 3/** 4 * 各行の基底クラス 5 */ 6public class RowBase { 7} 8 9/** 10 * DBに関するモデルベース 11 */ 12class DbAccessBase[T <: RowBase] { 13 14 /** 15 * Select文を実行する 16 * @param sql SQLオブジェクト 17 */ 18 def execSelect(sql: SQL[Nothing, NoExtractor]): List[T] = { 19 20 // この部分を動作できるようにさせたい 21 sql.map(T(_)).list.apply() 22 } 23} 24
scala
1// user.scala 2 3/** 4 * Userの行データのCaseClass 5 * 6 * @param id ID 7 * @param email メールアドレス 8 */ 9case class User(id : Int, email : String) extends RowBase{} 10 11/** 12 * DBからPeopleテーブルの内容を取得するためのコンパニオンオブジェクト 13 */ 14object User extends SQLSyntaxSupport[User] { 15 16 /** 17 * Apply caseu クラスへの置換用 18 * @param rs 19 * @return インスタンス 20 */ 21 def apply(rs: WrappedResultSet): PeopleRow = new PeopleRow(id = rs.long("id"), email = rs.string("email")) 22} 23 24/** 25 * Userテーブルのアクセサ 26 */ 27class PeopleData[User] extends DbAccessBase{ 28 29 /** 30 * ユーザ情報を取得 31 * @param id ID 32 * @return ユーザ情報 33 */ 34 def getUser(id:Int) : List[User] = { 35 36 // これは実行できるが、継承元クラスでしたい 37 // sql"select id, email from user where id = ${id}".map(User(_)).list.apply() 38 39 // このように継承元で実行したい 40 this.execSelect(sql"select id, email from user where id = ${id}") 41 } 42}
DbAccessBaseのexecSelectを実行できるようにしたいと思っています。
仕様的に、型パラメータはインスタンス化できないので、コンパイルも通らない状態です。
次のようにリフレクションを使う方法も考えましたが、
インスタンス化するときに引数を指定できないため、断念しました。
scala
1 2 3/** 4 * DBに関するモデルベース 5 */ 6class DbAccessBase[T <: RowBase] { 7 /** 8 * テンプレートをインスタンス化する 9 * @param sql SQLオブジェクト 10 */ 11 def createTypeInstance(arg: WrappedResultSet): T = { 12 val selfClass = this.getClass 13 val typeVal = selfClass.getGenericSuperclass 14 val pt = typeVal.asInstanceOf[ParameterizedType] 15 val atArgs = pt.getActualTypeArguments 16 val entityClass = atArgs(0).asInstanceOf[Class[_]] 17 entityClass.newInstance(/*ここに引数 arg を指定したい*/).asInstanceOf[T] 18 } 19 20 /** 21 * Select文を実行する 22 * @param sql SQLオブジェクト 23 */ 24 def execSelect(sql: SQL[Nothing, NoExtractor]): List[T] = { 25 sql.map(this.createTypeInstance(_)).list.apply() 26 } 27}
本来型パラメータをインスタンス化するという発想そのものが言語仕様から見たらご法度なのかもしれませんが、
いくつかのSelect結果のキャッシュ化など、共通処理を基底クラスで行いたいためこういう構造で実装したいと考えています。
何か良いアイディアはありませんでしょうか。
よろしくお願いいたします。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。