Groovy で S2JDBC を使用してみる

急に思い立ったので、Groovy スクリプト上で S2JDBC(S2・S2Tiger 2.4.18 RC3)を試してみることにした。

なんとなくハマリそうな気もしたのだが、Groovy 1.1 ならアノテーションを使えるし Groovy だけで S2JDBC が書けると色々活用できるかなと思い、とりあえずやってみる事に。

import javax.persistence.*
import org.seasar.framework.container.SingletonS2Container
import org.seasar.framework.container.factory.SingletonS2ContainerFactory
import org.seasar.extension.jdbc.JdbcManager

@Entity
class Dept {
    @Id
    @GeneratedValue
    Integer id

    Integer deptNo

    String deptName

    String loc

    @Version
    Integer versionNo
}

SingletonS2ContainerFactory.init()

def jdbcManager = SingletonS2Container.getComponent(JdbcManager.class)

def dept = new Dept(deptNo : 5, deptName : "テスト・データ")

jdbcManager.insert(dept).execute()

println("id : ${dept.id}")

def insDept = jdbcManager.from(Dept.class).where("id = ?", dept.id).getSingleResult()

println("result : ${insDept.id}, ${insDept.deptNo}, ${insDept.deptName}")

上記のスクリプトを Groovy 1.1 RC3(JavaSE 6)で実行してみると。案の定、以下のようなエラーが発生。エンティティクラスに Java で定義したものを使って Groovy 1.0 で実行しても同様のエラーが発生。

>groovy test.groovy
Caught: java.lang.LinkageError: loader constraint violation in interface itable
initialization: when resolving method "org.seasar.extension.dbcp.impl.XAConnectionImpl.getXAResource()Ljavax/transaction/xa/XAResource;" the class loader (instance of org/codehaus/groovy/tools/RootLoader) of the current class, org/seasar/extension/dbcp/impl/XAConnectionImpl, and the class loader (instance of <bootloader>) for interface javax/sql/XAConnection have different Class objects for the type javax/transaction/xa/XAResource used in the signature
        at test.run(test.groovy:29)
        at test.main(test.groovy)

やっぱり駄目かなとは思ったものの、メカニズムはよくわからないが、別々の JAR ファイルに含まれている javax.transaction.xa.XAResource クラスが、それぞれ別のクラスローダーに読み込まれてるのが原因だと予想し、一方の XAResource クラスを JAR ファイルから排除するというかなり強引な方法を試してみる事にした。

実際に、以下の方法を実施した JAR ファイルを作成し geronimo-j2ee_1.4_spec-1.0.jar の代わりに使って上記のスクリプトを実行してみたところ、エラーも発生せずに見事実行に成功した。

  • seasar2/lib の geronimo-j2ee_1.4_spec-1.0.jar から javax/transaction/xa パッケージを取り除く

これにより多少手間がかかるものの、Groovy 1.1 で一応は S2JDBC を実行できる事を確認した。

なお、dicon ファイルは以下のものだけを使い、app.dicon 以外は JavaS2JDBC を使った時(id:fits:20071127)のファイルをそのまま使用した。

  • app.dicon
  • convention.dicon
  • jdbc.dicon
  • s2jdbc.dicon

ちなみに、app.dicon は以下のように変更。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
    "http://www.seasar.org/dtd/components24.dtd">
<components>
    <include path="s2jdbc.dicon"/>
</components>