概要

Domaは、S2Daoのスタイル(DAOパターンや2 Way SQL)を踏襲したJava6(JDBC4.0)対応のO/Rマッパーです。 S2Daoの良いアイデアや機能は受け継ぎつつも、扱いにくかったりプログラミングミスにつながりやすかったりする点については積極的に改善を試みています。 また、aptを利用することで、S2Daoでは実現できなかった新しい機能も提供しています。

Domaは、S2Daoの次のアイデアや機能を受け継いでいます。

一方、Domaは、S2Daoの次の点を改善しています。

さらに、Domaは、新しく次のような機能を提供します。

開発にあたっては、S2Daoのほかに、 S2JDBCHibernateDBFluteを参考にしています。

DomaではS2Daoと同様にDAOパターンを採用しています。

DAOパターンを採用するのは、次のような利点があるからです。

  • データアクセスの箇所を特定しやすい
  • データアクセス処理をカプセル化できる(SQLの自動生成処理をJDBCを直接利用した処理に変更しても利用側プログラムに影響を与えない)
  • テストをしやすい(モックを作成しやすい)

S2Daoでは、外部ファイルに記述したSQLを、Javaとマッピングした形でフレームワークの一部として取り込むことも、単独でSQLツール上で実行することも可能としています(2 Way SQL)。

Domaでは、このアイデアをそのまま採用しています。ただし、マッピングルールやSQLコメントの用い方については変更を加えています。

2 Way SQLは、フレームワークで扱うSQLを単独でテストしたり、Java開発者とSQL作成者の作業を分離したりするのに非常に有効な方法です。

S2Daoでは、SQLファイル名にRDBMS名を含めることで特定のRDBMS専用のSQLを用意できました。 例えば、「EmployeeDao_selectByName.sql」という名前のSQLファイルと「EmployeeDao_selectByName_oracle.sql」という名前のSQLファイルが存在する場合、 拡張子の直前にアンダースコア区切りで「oracle」という名前が記述されている後者のファイルがOracle Database専用のSQLファイルになります。 このファイルはOracle Databaseに接続している場合にのみ使用され、それ以外のRDBMSでは「EmployeeDao_selectByName.sql」が使用されます。

Domaでも、このアイデアをほぼそのまま採用しています。 ただし、SQLファイルにRDBMS名を含めるルールをアンダースコアではなくハイフンに変更しています。 例えば、Oracle Database専用のSQLファイルは「selectByName-oracle.sql」という名前になります。

RDBMSごとにSQLを切り替える手法は、フレームワークで吸収するのが困難なRDBMS独自のSQLを活用したい場合に役立ちます。

S2Daoを利用するには、Seasar2のライブラリが必須でした。

一方、Domaでは、Seasar2への依存が一切ありません。このため、Spring FrameworkGuiceといったSeasar2以外のDIコンテナと組み合わせやすくなっています。 また、単独で利用することも可能です。 Domaはdoma-x.x.x.jarというたった1つのjarファイルのみで動作します。

S2Daoでは、実行時にDaoのインタフェースにAOPを適用することで動作していました。

一方、Domaでは、コンパイル時にaptでインタフェースから実装クラスをソースコードとして生成し、実行時には生成されたソースコードに対応する実装クラスを使用します。

AOPは便利な機能ですが、挙動が把握しにくかったりデバッグがしにくかったりといった問題点がありました。 Domaではこれらの問題点を避けるため、AOPではなくaptによるコード生成を利用しています。

ただし、S2DaoであれDomaであれ、アプリケーション開発者が作成するのはインタフェースのみという点は同じです。

S2Daoでは、たとえば、Daoのメソッド名が「update」で始まる場合そのメソッドはUPDATE文を発行するメソッドである、といった命名規約を持っていました。

一方、Domaでは、暗黙的な命名規約ではなく、アノテーションを採用しています。 たとえば、UPDATE文を発行するメソッドには@Updateを注釈します。 メソッド名に制約はありません。 Domaでは、アノテーションを利用することで意図をより明確にプログラムコード上に表現し、挙動をわかりやすくしています。

S2Daoでは、DaoのメソッドにアノテーションでSQL全体やSQLの一部を記述することを認めていました。

Domaでは、DaoのメソッドにアノテーションでSQLの全体や一部を記述することを認めません。 JavaのコードにSQLを記述することは、アプリケーションの保守性を損ねるからです。 SQLの記述は、すべて外部ファイルで行うことになっています。

S2Daoでは、SQLに含まれたSQLコメントの前後にスペースがあるかどうかの違いでエラーが発生するなど非常に細かな間違いやすい文法を持っていました。 また、間違いが含まれていた場合のエラーメッセージもわかりにくいものでした。

Domaでは、文法を見直し厳密にしました。また、aptで検証することで、間違いがあっても「コンパイル」時にエラーを検出し、わかりやすいメッセージを表示するようにしています。 実行しなくてもエラーの有無を確認できるのは、S2Daoに比べて大きな利点です。

S2Daoでは、Daoの特定のメソッドでJDBCを直接利用するには、インタフェースの実装クラスを作成しメソッドをオーバーライドしなければいけませんでした。 クラス名を設定ファイル等に記述している場合、この方法では、設定を変更する必要がありました。

selectByName(String name) { ... } }]]>

Domaでは、@Delegateというアノテーションを使って、JDBCを直接利用する処理を別クラスに委譲できます。

selectByName(String name); }]]> selectByName(String name) { .... } }]]>

この方法は、クラス階層に変更を加えないためより柔軟です。 たとえ、クラス名が設定ファイルに記述されていても変更を加える必要がありません。

詳細は、デリゲート定義を参照してください。

S2Daoでは、SQLファイルをDaoと同じパッケージに配置しなければいけませんでした。 この仕様では、Daoが同じパッケージに複数存在する場合に、ひとつのパッケージ内に存在するSQLファイルが多くなりすぎて管理が難しくなります。

Domaでは、Daoごとに異なるディレクトリでSQLファイルを管理する仕様になっています。 このため、SQLファイルをDaoごとに管理しやすくなっています。 また、DaoメソッドとSQLファイルを相互に遷移するEclipseプラグインを用意しているので、これを使うとさらに開発/管理がしやすくなります。

詳細は、SQLファイルを参照してください。

S2Daoでは、メソッドのパラメータがSQLファイル内のバインド変数コメントで参照できるようにArgumentsアノテーションを使用してパラメータごとに名前をつける必要がありました。

selectEmployeeByJobDeptno(String job, BigDecimal salary);]]>

Domaでは、Argumentsアノテーションに相当するものは不要です。aptによりメソッドのパラメータ名をそのまま使用できるからです。

selectEmployeeByJobDeptno(String job, BigDecimal salary);]]>

S2Daoでは、Daoの最初のアクセス時に、Daoのメタ情報を作成するための初期化コストがかかっていました。 ここでのメタ情報とは、どのメソッドがどのCRUDに相当するのか、そのメソッドではSQLを自動生成するのかSQLファイルにマッピングするのかといった情報です。

Domaでは、コンパイル時にメタ情報をソースコードで表現し、実行時にはそのソースコードに対応するバイトコードを実行するため、そのようなコストがありません。

aptを使い、コンパイル時にコードを生成できます。 たとえば、次のインタフェースをコンパイルすると、インタフェースの実装クラスが自動生成されます。

selectByName(String name); }]]>

コンパイル時のコード生成には次のような利点があります。

  • 実行時に必要なメタ情報をソースコードで記述できるので、リフレクションを使ってメタ情報を構築するフレームワークに比べてパフォーマンスがよい
  • ソースコードに記述された通りに動作するので、コンパイル時や実行時にバイトコードエンハンスが行われるコードよりも見通しがよい
  • ブレークポイントを設定したりステップ実行をしたりとデバッグがしやすい

aptを使い、コンパイル時にコードがフレームワークの規約を満たしているかチェックできます。 たとえば、次のコードをコンパイルすると、updateメソッドの部分にエラー表示がされます。 なぜならば、@Updateを注釈したメソッドは更新件数を表すint型の値を返さなければいけないというルールがあるからです。 エラーは、Eclipseを使っている場合にはエディタに表示され、Antなどでjavacを実行した場合にはAntを実行したコンソールに表示されます。

コンパイル時に規約をチェックすることで、わざわざアプリケーションを実行しなくてもエラーに気づくことができます。

aptを使い、コンパイル時にDaoメソッドに対応するSQLファイルが実際に存在しているかチェックできます。 たとえば、次のコードをコンパイルすると、selectByIdメソッドに対応するSQLファイルが存在するかどうかクラスパスの検索が行われます。

SQLファイルが存在しない場合は、その時点でselectByIdメソッドの部分にエラーが表示されます。 SQLファイルが存在する場合は、続いてSQLコメントの文法チェックが行われます。

たとえば、selectByIdメソッドに対応するSQLファイルが次のようなSQLの場合、エラーが発生します。 なぜならば、メソッドではパラメータ名が「id」であるのに、SQLコメントでは「employeeId」と記述されているからです。

コンパイル時にSQLファイルの存在チェックやSQLコメントの文法チェックを行うことで、必ず発生する実行時エラーをコンパイル時に検出できます。

アプリケーション固有の値型を作成し、そのクラスをデータベースのテーブルのカラムに対応づけることができます。 Domaではそのようなクラスを基本型と区別してドメインクラスと呼んでいます。 たとえば、電話番号を扱うアプリケーションであれば、PhoneNumberというドメインクラスが作成できるでしょう。

ドメインクラスには次のような利点があります。

  • データベース上のカラムの型が同じあってもアプリケーション上意味が異なるものを別のJavaの型で表現できる
  • 概念をクラスとして明確に表現することでプログラミングをわかりやすくできる
  • 値と振る舞いを同じクラスで表現できる