ビデオ

Mavenエンハンスメント

Mavenエンハンスメント機能を使用したエンティティとクエリビーンのエンハンスメント

IntelliJプラグイン

IntelliJ IDEAプラグインを使用したエンハンスメント

IntelliJデバッガ

遅延ロードを呼び出すIdeaデバッガ設定について

Eclipseプラグイン

Eclipseプラグインを使用したエンハンスメント

Eclipse APT

クエリビーン生成のためのEclipse設定(Javaアノテーションプロセッサ経由)。

推奨事項

IDEプラグインエンハンスメント(IdeaまたはEclipse)とビルド時エンハンスメントの両方を使用してください。

IntelliJ IDEAとEclipseユーザーの場合、IDEプラグインに加えて、ビルド時エンハンスメント(Mavenプラグイン)またはエージェントのいずれかを使用することをお勧めします。

つまり、IDEプラグインは、IDEがクラスをコンパイルする際にビーンをエンハンスする開発中に使用すると便利です。IDEプラグインを使用すると、開発中と単体テスト中のエンハンスメントの手間を減らすことができます。本番環境では、Mavenによるビルド時エンハンスメントまたはjavaagentによるランタイムエンハンスメントを選択できます。

概要

「エンハンスメント」という用語は、エンティティビーンを変更するために使用されるすべての方法(javaagent、Ant、Maven、IDEプラグインなど)を網羅しています。エンハンスメントを表す他の用語には、「Weaving」、「Transformation」、「バイトコード操作」などがあります。

ロード時ウィービングは、クラスの操作が「ロード時」に発生する場合(通常はjavaagent経由)を指し、クラスの操作が「ビルド時」に発生する場合(通常はMaven、Ant、またはIDEプラグイン経由)とは対照的です。

生の用語では、クラスはbyte[]であり、エンハンスメントはそのクラスがClassLoaderによって定義される前に、それらのバイトを操作することです。

複数のエンハンサーの使用

Ebeanエンハンスメントは、エンハンスメントが既に発生したかどうかを認識しています。このように、IDEプラグインとMavenプラグインの両方を使用してエンハンスメントを実行するなど、複数のエンハンスメント形式を同時に使用することは一般的であり、期待されています。

Mavenエンハンスメント

Mavenプラグインは、Mavenコンパイルプロセスの一部としてエンハンスメントを実行します。これは「ビルド時エンハンスメント」と説明できます。

Mavenエンハンスメントタイル

Ebeanは、エンティティビーンのエンハンサーとクエリビーンのエンハンスメントの両方を提供するMavenタイルを提供します。これは、従来の(タイル以外の)方法でプラグインを定義するよりもシンプルで、クリーンで冗長性が少なく、現在推奨されるアプローチです。

Ebeanエンハンスメントタイルは、以下のプラグイン設定を提供します。
  • メインとテストのエンティティビーンと@Transactionalエンハンスメント
  • メインとテストのクエリビーンエンハンスメント
  • ebean-codegenプラグイン(ファインダーなどを生成するためのヘルパー)
ebeanエンハンスメントタイル
<plugin>
  <groupId>io.repaint.maven</groupId>
  <artifactId>tiles-maven-plugin</artifactId>
  <version>2.22</version>
  <extensions>true</extensions>
  <configuration>
    <tiles>
      <!-- other tiles ... -->
      <tile>io.ebean.tile:enhancement:13.25.0</tile>
    </tiles>
  </configuration>
</plugin>

mvn help:effective-pomを使用して、タイルが提供するプラグインを表示します。

Mavenプラグイン

Mavenタイルを使用しない場合は、従来の方法でMavenエンハンスメントプラグインを指定できます。タイルとは異なり、これはクエリビーンエンハンスメントを提供しないことに注意してください。

<plugin>
  <groupId>io.ebean</groupId>
  <artifactId>ebean-maven-plugin</artifactId>
  <version>${version}</version>
  <executions>
    <execution>
      <id>main</id>
      <phase>process-classes</phase>
      <configuration>
        <transformArgs>debug=1</transformArgs>
      </configuration>
      <goals>
        <goal>enhance</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Eclipse + Mavenエンハンスメント

Maven構成を使用して、ビルド中にクラスをエンハンスするようにEclipseを構成できます。

<build>
  <plugins>
    <!-- plugins here -->
  </plugins>
  <pluginManagement>
    <plugins>
      <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. -->
      <plugin>
        <groupId>org.eclipse.m2e</groupId>
        <artifactId>lifecycle-mapping</artifactId>
        <version>1.0.0</version>
        <configuration>
          <lifecycleMappingMetadata>
            <pluginExecutions>
              <pluginExecution>
                <pluginExecutionFilter>
                  <groupId>io.ebean</groupId>
                  <artifactId>ebean-maven-plugin</artifactId>
                  <versionRange>[${version},)</versionRange>
                  <goals>
                    <goal>enhance</goal>
                  </goals>
                </pluginExecutionFilter>
                <action>
                  <execute>
                    <runOnConfiguration>true</runOnConfiguration>
                    <runOnIncremental>true</runOnIncremental>
                  </execute>
                </action>
              </pluginExecution>
            </pluginExecutions>
          </lifecycleMappingMetadata>
        </configuration>
      </plugin>
    </plugins>
  </pluginManagement>
</build>

エージェント

以下の例のように、コマンドラインでjavaagentパラメータを使用できます。これは、「ランタイムエンハンスメント」または「ロード時エンハンスメント」と呼ばれることがよくあります。

Ebeanエージェントのバージョン4.7.1以降では、エンハンスするパッケージを指定しなくてもエージェントが適切に動作することが期待されています。つまり、エージェントは、興味のないクラス(JDK、Groovy、Scala、Kotlin、JDBCドライバ、Apache、Google、テストなどからの多くの一般的なライブラリ)を無視するのが非常に得意です。

java -javaagent:ebean-agent-${version}.jar MyApplication
java -javaagent:ebean-agent-${version}.jar=debug=3 MyApplication

ebean-agent jarはMavenからダウンロードできます。現在のバージョンは…

<dependency>
  <groupId>${groupid}</groupId>
  <artifactId>${artifactid}</artifactId>
  <version>${version_str}</version>
</dependency>
<dependency org="${groupid}" name="${artifactid}" rev="${version_str}"/>
@Grapes(
  @Grab(group='${groupid}', module='${artifactid}', version='${version_str}')
)
'${groupid}:${artifactid}:${version_str}'
'${groupid}:${artifactid}:${version_str}'
libraryDependencies += "${groupid}" % "${artifactid}" % "${version_str}"
[${groupid}/${artifactid} "${version_str}"]

エージェントローダー

エージェントローダーは推奨されません

エージェントローダーを使用して、実行中のJVMにjavaagentをプログラムでロードできます。ただし、エンティティビーンクラスが何らかの理由でエージェントがJVMにロードされる前にロードされるため、ビーンがエンハンスされないことがごくまれにあります。このため、この方法は推奨されていません。

このアプローチはEbean自体のテストコードで使用されており、このアプローチを使用する場合は、エンティティビーンまたはトランザクションビーンのクラスローディングの前にエージェントのローディングが行われるようにする必要があります。

<dependency>
  <groupId>${groupid}</groupId>
  <artifactId>${artifactid}</artifactId>
  <version>${version_str}</version>
</dependency>
<dependency org="${groupid}" name="${artifactid}" rev="${version_str}"/>
@Grapes(
  @Grab(group='${groupid}', module='${artifactid}', version='${version_str}')
)
'${groupid}:${artifactid}:${version_str}'
'${groupid}:${artifactid}:${version_str}'
libraryDependencies += "${groupid}" % "${artifactid}" % "${version_str}"
[${groupid}/${artifactid} "${version_str}"]

以下のコードは、実行中のJVMにエンハンサーエージェントをプログラムでロードします。

import org.avaje.agentloader;
...
public void someApplicationBootupMethod() {
  // Load the agent into the running JVM process
  if (!AgentLoader.loadAgentFromClasspath("ebean-agent","debug=1;packages=org.example.model")) {
    logger.info("ebean-agent not found in classpath - not dynamically loaded");
  }
}

Antエンハンスメント

Antのbuild.xmlファイルを以下のように変更します。

  1. AntEnhanceTaskを定義します。
  2. AntEnhanceTaskを使用してエンティティクラスをエンハンスするターゲットを作成します。
<taskdef
    name="ebeanEnhance"
    classname="io.ebean.enhance.ant.AntEnhanceTask"
    classpath="your_path_to/ebean-x.x.x.jar"/>

<target name="ormEnhance" depends="clean,compile">
  <!--
  classSource: This is the directory that contains your class files. That is, the directory where your IDE will compile your java class files to, or the directory where a previous ant task will compile your java class files to.

  packages: a comma delimited list of packages that contain entity classes. All the classes in these packages are searched for entity classes to be enhanced. transformArgs: This contains a debug level (0 - 10) .
  -->
  <ebeanEnhance
      classSource="your_classes_directory"
      packages="app.domain.*"
      transformArgs="debug=1"/>
</target>

プログラムによるエンハンスメント

エージェントのTransformerクラスを使用して、エンハンスメントをプログラムで実行できます。

Transformer transformer = new Transformer("", "debug=1");
InputStreamTransform streamTransform = new InputStreamTransform(transformer, Ebean.class.getClassLoader());

// Or use ASM or Javassist get bytecode and new InputSream
// eg. in = new ByteArrayInputStream(ctClass.toBytecode());
InputStream in = new URL("your.class.file.class").openStream();

byte[] result = null;
try {
  result = streamTransform.transform("your.class.name", in);//class must be not loaded by classLoader
} finally {
  in.close();
}
if (result == null) {
  throw new CannotCompileException("ebean enhance model fail!");
}
defineClass("your.class.name", result, 0, result.length);