【Java】Doma ~ 初期環境構築 / コード生成 / Hello World ~

■ はじめに

https://blogs.yahoo.co.jp/dk521123/37773041.html
の続き。

Oracle DB / Doma2(Spring等のフレームワークなし) / Gradle のサンプルって
意外となくて、結構ハマった。

■ 実行環境

 * OS : Windows10
 * Java : JDK1.8 
 * Eclipse Java EE IDE for Web Developers (Version: 2018-09 (4.9.0))
 * DB : Oracle 11g
 * Doma : Doma 2.19.3

■ 初期環境構築

事前準備 / 前提条件

 * Oracle ID を事前に取得しておく
  => 今回、例として、ID「demo@sample.com」、Password「password」 とする
 * Gradleプロジェクトで作成

テストデータ

 * 以下の関連記事のものを使用
https://blogs.yahoo.co.jp/dk521123/37756250.html

手順

[1] Eclipse上のプロジェクト内の「build.gradle」を以下を参考に修正する
[2] プロジェクト内を右クリックし、[Gradle]-[Reflash Gradle Project]で、
    依存するライブラリをダウンロードする
build.gradle
// Apply the java-library plugin to add support for Java Library
apply plugin: 'java-library'

// JavaクラスとSQLファイルの出力先ディレクトリを同じにする
processResources.destinationDir = compileJava.destinationDir
// SQLファイルを出力先ディレクトリにコピーするために依存関係を逆転する
compileJava.dependsOn processResources

configurations {
    domaGenRuntime
}

// In this section you declare where to find the dependencies of your project
repositories {
    // Use jcenter for resolving your dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
    mavenCentral()
    maven {url 'https://oss.sonatype.org/content/repositories/snapshots/'}
    maven {
      url "https://www.oracle.com/content/secure/maven/content"
      credentials {
        username 'demo@sample.com'
        password 'password'
      }
    }
}

dependencies {
    domaGenRuntime 'org.seasar.doma:doma-gen:2.19.3'
    domaGenRuntime 'com.oracle:ojdbc6:11.2.0.3'
        
    compile group: 'com.oracle', name: 'ojdbc6', version: '11.2.0.3'
    
    domaGenRuntime 'org.seasar.doma:doma-gen:2.19.3'
    compile group: 'org.seasar.doma', name: 'doma', version: '2.19.3'
    compile group: 'org.seasar.doma', name: 'doma-gen', version: '2.19.3'
    compile group: 'org.freemarker', name: 'freemarker', version: '2.3.28'
    
    // Use JUnit test framework
    testImplementation 'junit:junit:4.12'
}

// Javaコード生成する(★後述「■ コード生成」で使う★)
task gen {
    group = 'doma'
    description = 'Generate Java codes'
    doLast {
        ant.taskdef(resource: 'domagentask.properties',
            classpath: configurations.domaGenRuntime.asPath)
        ant.gen(
            url: 'jdbc:oracle:thin:@localhost:1521:xe', user: 'TEST_USER', password: 'password',
            templatePrimaryDir: 'templates') {

            entityConfig(packageName: 'com.sample.db.doma2.entity')
            daoConfig(packageName: 'com.sample.db.doma2.dao', configClassName: 'com.sample.db.doma2.DbConfig')
            sqlConfig()
        }
    }
}

■ コード生成

 * コード生成には、「Doma-Gen」を使用する

Doma-Gen

 * AntとFreeMarkerを使用したDoma2 のための コード生成ツール
目的
 * 以下のJavaコード生成
  + エンティティクラス
  + エンティティリスナークラス
  + Daoインタフェース
  + SQLをテストするためのJavaテストコード
 * 以下の生成
  + SQLのコード
テンプレートファイル
https://github.com/domaframework/doma-gen/tree/master/src/main/resources/org/seasar/doma/extension/gen/template

事前準備

[[https://doma.readthedocs.io/ja/stable/build/#eclipse]]
を参考に... (この設定がないと、DaoImplが生成されない)
【1】プロジェクトの設定で注釈処理を有効にする
[1-1] Eclipse の [Project]-[Properties]-[Java Compiler]-[Annotation Processing]を選択
[1-2] 以下のチェックボックスにチェックを入れる
 + 「Enable project specific settings」
 + 「Enable annotation processing」 / 「Enable processing in editor」
【2】Build Path に加えて Factory Path にも Doma の jar ファイルを設定する
[2-1] Eclipse の [Project]-[Properties]-[Java Compiler]-[Annotation Processing]-[Factory Path]を選択
[2-2] 以下のチェックボックスにチェックを入れる
 + 「Enable project specific settings」
[2-3] 「Add External JARs」を押下し、「doma-X.XX.X.jar」を選択
(今回は「C:\Users\USER-NAME\.gradle\caches\modules-2\files-2.1\org.seasar.doma\doma\2.19.3\3d2e8fe6a00f02b4cca8538a2f22a955a6093633\doma-2.19.3.jar」」)

手順

前提条件:上記の「■ 初期環境構築」が行われていること
[1] 「org.seasar.doma.jdbc.Config」を継承したDB設定クラスを作成する(以下の「」を参照のこと)
[2] プロジェクト内を右クリックし、[Run]-[Run Configuration]-[Gradle Project]で、
   「New lunch Project」を選択
[3] 「Gradle Task」タブの「Gradle Tasks:」欄に『gen』を入力し、「Run」ボタン押下し、
    コード生成を実行する
 => 以下が生成される
  + Javaコード「Person.java」「PersonDao.java」「PersonListener.java」
  + SQLファイル (src/main/resources/META-INFフォルダ内に生成)
DbConfig.java
package com.sample.db.doma2;

import javax.sql.DataSource;

import org.seasar.doma.SingletonConfig;
import org.seasar.doma.jdbc.Config;
import org.seasar.doma.jdbc.dialect.Dialect;
import org.seasar.doma.jdbc.dialect.OracleDialect;
import org.seasar.doma.jdbc.tx.LocalTransactionDataSource;
import org.seasar.doma.jdbc.tx.LocalTransactionManager;
import org.seasar.doma.jdbc.tx.TransactionManager;

@SingletonConfig
public class DbConfig implements Config {
  private static final DbConfig CONFIG = new DbConfig();
  private final Dialect dialect;
  private final LocalTransactionDataSource localTransactionDataSource;
  private final TransactionManager transactionManager;

  private DbConfig() {
    this.dialect = new OracleDialect();
    this.localTransactionDataSource = new LocalTransactionDataSource("jdbc:oracle:thin:@localhost:1521:xe", "TEST_USER",
        "password");
    this.transactionManager = new LocalTransactionManager(localTransactionDataSource.getLocalTransaction(getJdbcLogger()));
  }

  @Override
  public DataSource getDataSource() {
    return localTransactionDataSource;
  }

  @Override
  public Dialect getDialect() {
    return dialect;
  }
  
  //!! 重要 !! これがないと、UnsupportedOperationExceptionになる
  //
  // [親クラス Config.java より]
  // default TransactionManager getTransactionManager() {
  //  throw new UnsupportedOperationException();
  // }
  @Override
  public TransactionManager getTransactionManager() {
    return transactionManager;
  }

  // !! 重要 !! シングルトンを返すメソッド名は「singleton()」と決められている
  public static DbConfig singleton() {
    return CONFIG;
  }
}
Person.java (自動生成)
package com.sample.db.doma2.entity;

import org.seasar.doma.Column;
import org.seasar.doma.Entity;
import org.seasar.doma.Id;
import org.seasar.doma.Table;

/**
 */
@Entity(listener = PersonListener.class)
@Table(name = "PERSON")
public class Person {

    /** */
    @Id
    @Column(name = "ID")
    String id;

    /** */
    @Column(name = "NAME")
    String name;

    /** 
     * Returns the id.
     * 
     * @return the id
     */
    public String getId() {
        return id;
    }

    /** 
     * Sets the id.
     * 
     * @param id the id
     */
    public void setId(String id) {
        this.id = id;
    }

    /** 
     * Returns the name.
     * 
     * @return the name
     */
    public String getName() {
        return name;
    }

    /** 
     * Sets the name.
     * 
     * @param name the name
     */
    public void setName(String name) {
        this.name = name;
    }
}
PersonDao.java (自動生成)
package com.sample.db.doma2.dao;

import org.seasar.doma.Dao;
import org.seasar.doma.Delete;
import org.seasar.doma.Insert;
import org.seasar.doma.Select;
import org.seasar.doma.Update;

/**
 */
@Dao(config = DbConfig.class)
public interface PersonDao {

    /**
     * @param id
     * @return the Person entity
     */
    @Select
    Person selectById(String id);

    /**
     * @param entity
     * @return affected rows
     */
    @Insert
    int insert(Person entity);

    /**
     * @param entity
     * @return affected rows
     */
    @Update
    int update(Person entity);

    /**
     * @param entity
     * @return affected rows
     */
    @Delete
    int delete(Person entity);
}
PersonListener.java (自動生成)
package com.sample.db.doma2.entity;

import org.seasar.doma.jdbc.entity.EntityListener;
import org.seasar.doma.jdbc.entity.PostDeleteContext;
import org.seasar.doma.jdbc.entity.PostInsertContext;
import org.seasar.doma.jdbc.entity.PostUpdateContext;
import org.seasar.doma.jdbc.entity.PreDeleteContext;
import org.seasar.doma.jdbc.entity.PreInsertContext;
import org.seasar.doma.jdbc.entity.PreUpdateContext;

/**
 * 
 */
public class PersonListener implements EntityListener<Person> {

    @Override
    public void preInsert(Person entity, PreInsertContext<Person> context) {
    }

    @Override
    public void preUpdate(Person entity, PreUpdateContext<Person> context) {
    }

    @Override
    public void preDelete(Person entity, PreDeleteContext<Person> context) {
    }

    @Override
    public void postInsert(Person entity, PostInsertContext<Person> context) {
    }

    @Override
    public void postUpdate(Person entity, PostUpdateContext<Person> context) {
    }

    @Override
    public void postDelete(Person entity, PostDeleteContext<Person> context) {
    }
}
PersonDaoImpl.java
Javaのプロジェクト】\.apt_generated\com\sample\db\doma2\dao\PersonDaoImpl.java
に生成される
_Person.java
Javaのプロジェクト】\.apt_generated\com\sample\db\doma2\\entity\_Person.java
に生成される

Hello World

Main.java

package com.sample.db.doma2;

import org.seasar.doma.jdbc.tx.TransactionManager;

import com.sample.db.doma2.dao.PersonDao;
import com.sample.db.doma2.dao.PersonDaoImpl;
import com.sample.db.doma2.entity.Person;

public class Main {
  public static void main(String[] args) {
    TransactionManager transactionManager = DbConfig.singleton().getTransactionManager();
    PersonDao dao = new PersonDaoImpl();
    transactionManager.required(() -> {
      Person person = dao.selectById("002");
      System.out.println("ID : " + person.getId());
      System.out.println("Name : " + person.getName());
    });
  }
}

出力結果

10 31, 2018 10:12:59 午後 org.seasar.doma.jdbc.tx.LocalTransaction begin
情報: [DOMA2063] ローカルトランザクション[1343441044]を開始しました。
10 31, 2018 10:13:00 午後 com.sample.db.doma2.dao.PersonDaoImpl selectById
情報: [DOMA2220] ENTER  : クラス=[com.sample.db.doma2.dao.PersonDaoImpl], メソッド=[selectById]
10 31, 2018 10:13:01 午後 com.sample.db.doma2.dao.PersonDaoImpl selectById
情報: [DOMA2076] SQLログ : SQLファイル=[META-INF/com/sample/db/doma2/dao/PersonDao/selectById.sql],
select
  ID, NAME
from
  PERSON
where
  ID = '002'
10 31, 2018 10:13:01 午後 com.sample.db.doma2.dao.PersonDaoImpl selectById
情報: [DOMA2221] EXIT   : クラス=[com.sample.db.doma2.dao.PersonDaoImpl], メソッド=[selectById]
10 31, 2018 10:13:01 午後 org.seasar.doma.jdbc.tx.LocalTransaction commit
情報: [DOMA2067] ローカルトランザクション[1343441044]をコミットしました。
10 31, 2018 10:13:01 午後 org.seasar.doma.jdbc.tx.LocalTransaction commit
情報: [DOMA2064] ローカルトランザクション[1343441044]を終了しました。
ID : 002 << ★ 出力
Name : Tom << ★ 出力


関連記事

DBアクセスライブラリ [5] ~ Doma

https://blogs.yahoo.co.jp/dk521123/37773041.html