S-JIS[2011-08-15/2015-07-25] 変更履歴

Asakusa Frameworkデータモデルドライバー

Asakusa Framework0.2.1のJavaDataModelDriverのメモ。
(→最新のJavaDataModelDriverのメモ


概要

Asakusa Frameworkでは、DMDL(dmdlファイル)でデータモデルを記述すると、Modelクラス(やio/Input・io/Outputクラス)のJavaソースファイルが生成される。
これらはcom.asakusafw.dmdl.java.spi.JavaDataModelDriverを継承したクラスで生成されている。
(特にInput・OutputクラスはModelInputDriver・ModelOutputDriverで作られている。ModelクラスはConcreteModelEmitterを始めとする色々なDriverで分散して作っている模様)

これらのドライバーはJavaのサービスプロバイダー(SPI)の仕組みを使って呼ばれている。
したがって、自分でドライバーを作ってSPIに入れれば、独自のクラス(Javaソース)を生成することが出来る。

AsakusaFWのソースコードリーディングでSPIを使っていると聞いていたので、AsakusaFWのjarファイルの中からSPIのファイルを探したら それらしいクラス(JavaDataModelDriver)を見つけたので、試してみたもの。


SPIの実験

まずはSPIで自分のDriverが呼び出せる状態にする必要がある。

Driverを記述する為のEclipse(ワークスペース)のプロジェクトを新たに作成し、まずは空っぽのDriverを作成してみる。

afw-driver/src/jp/hishidama/asakusafw/dmdl/EmptyDriver.java:

package jp.hishidama.asakusafw.dmdl;
import java.io.IOException;
import java.util.List;

import com.asakusafw.dmdl.java.emitter.EmitContext;
import com.asakusafw.dmdl.java.spi.JavaDataModelDriver;
import com.asakusafw.dmdl.semantics.ModelDeclaration;
import com.asakusafw.dmdl.semantics.PropertyDeclaration;
import com.ashigeru.lang.java.model.syntax.Annotation;
import com.ashigeru.lang.java.model.syntax.MethodDeclaration;
import com.ashigeru.lang.java.model.syntax.Type;
public class EmptyDriver extends JavaDataModelDriver {
	@Override
	public List<Annotation> getTypeAnnotations(EmitContext context, ModelDeclaration model) throws IOException {
		System.out.println("+++EmptyDriver#getTypeAnnotations\t" + model);
		return super.getTypeAnnotations(context, model);
	}

	@Override
	public List<Type> getInterfaces(EmitContext context, ModelDeclaration model) throws IOException {
		System.out.println("+++EmptyDriver#getInterfaces\t" + model);
		return super.getInterfaces(context, model);
	}

	@Override
	public List<Annotation> getMemberAnnotations(EmitContext context, PropertyDeclaration property) throws IOException {
		System.out.println("+++EmptyDriver#getMemberAnnotations\t" + property);
		return super.getMemberAnnotations(context, property);
	}

	@Override
	public List<MethodDeclaration> getMethods(EmitContext context, ModelDeclaration model) throws IOException {
		System.out.println("+++EmptyDriver#getMethods\t" + model);
		return super.getMethods(context, model);
	}
}

JavaDataModelDriverで定義されているメソッドは4つ。
(0.7.3ではgetFieldsというメソッドもある。[2015-07-25]

どんなものが引数で渡されるのか、とりあえずコンソールに表示してみる。
(各メソッドで親クラスのメソッドを呼び出しているが、何も処理しない(空のリストを返している))


このソースをコンパイルするのに必要なjarファイルは以下の通り。

asakusa-dmdl-java-0.2.1.jar
asakusa-dmdl-core-0.2.1.jar
DMDL関連
asakusa-runtime-0.2.1.jar AsakusaFWのランタイム
java-dom-0.1.0.jar Javaソースの構築用

適当にインポート文を書けばコンパイルエラーになるので、Eclipseのクイック・フィックスで「プロジェクト・セットアップの修正」を選べば候補となるjarファイルを探してくれるので楽。


SPIを使う際は、META-INF/servicesというディレクトリーの下に親クラスの名前をしたテキストファイルを作成し、その中に具象クラスを記述する。

afw-driver/src/META-INF/services/com.asakusafw.dmdl.java.spi.JavaDataModelDriver:

jp.hishidama.asakusafw.dmdl.EmptyDriver

Driverを実行するにはモデルの生成を行う(モデルの生成を行うとDriverを読み込んで実行してくれる)が、これを実行する為に以下のjarファイルが必要。(ビルドパスに追加しておく)

commons-cli-1.2.jar コマンドラインの解析
slf4j-api-1.6.1.jar
logback-classic-0.9.28.jar
logback-core-0.9.28.jar
ログ出力
simple-graph-0.1.0.jar たぶんグラフの作成
hadoop-core-0.20.2-cdh3u0.jar Hadoopのコア(Writable等)

まぁ、プロジェクトの下の.classpathファイルを書き換えるのが早そう。
(環境によってバージョンが違う可能性もあるので、自分のAsakusaFW用プロジェクトからコピーしてくるのが確実そう)

<classpathentry kind="var" path="M2_REPO/com/asakusafw/asakusa-dmdl-core/0.2.1/asakusa-dmdl-core-0.2.1.jar" sourcepath="M2_REPO/com/asakusafw/asakusa-dmdl-core/0.2.1/asakusa-dmdl-core-0.2.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/asakusafw/asakusa-dmdl-java/0.2.1/asakusa-dmdl-java-0.2.1.jar" sourcepath="M2_REPO/com/asakusafw/asakusa-dmdl-java/0.2.1/asakusa-dmdl-java-0.2.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/asakusafw/asakusa-runtime/0.2.1/asakusa-runtime-0.2.1.jar" sourcepath="M2_REPO/com/asakusafw/asakusa-runtime/0.2.1/asakusa-runtime-0.2.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/ashigeru/lang/java/java-dom/0.1.0/java-dom-0.1.0.jar" sourcepath="M2_REPO/com/ashigeru/lang/java/java-dom/0.1.0/java-dom-0.1.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/commons-cli/commons-cli/1.2/commons-cli-1.2.jar" sourcepath="M2_REPO/commons-cli/commons-cli/1.2/commons-cli-1.2-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.6.1/slf4j-api-1.6.1.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.6.1/slf4j-api-1.6.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/ashigeru/util/simple-graph/0.1.0/simple-graph-0.1.0.jar" sourcepath="M2_REPO/com/ashigeru/util/simple-graph/0.1.0/simple-graph-0.1.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-core/0.20.2-cdh3u0/hadoop-core-0.20.2-cdh3u0.jar" sourcepath="M2_REPO/org/apache/hadoop/hadoop-core/0.20.2-cdh3u0/hadoop-core-0.20.2-cdh3u0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-classic/0.9.28/logback-classic-0.9.28.jar" sourcepath="M2_REPO/ch/qos/logback/logback-classic/0.9.28/logback-classic-0.9.28-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-core/0.9.28/logback-core-0.9.28.jar" sourcepath="M2_REPO/ch/qos/logback/logback-core/0.9.28/logback-core-0.9.28-sources.jar"/>

実行方法

モデルの生成にはcom.asakusafw.dmdl.java.Mainを実行する。
これを実行する為の「実行の構成」は以下の通り。

タブ 設定内容 備考
メイン プロジェクト(P) afw-driver 自分のプロジェクト
メイン・クラス(M) com.asakusafw.dmdl.java.Main 実行するクラス名
引数 プログラムの引数(A) -output C:/cygwin/tmp/afw/
-package sample.modelgen
-source ../afw-wordcount/src/main/dmdl
sourceで指定した場所にあるdmdlファイルを読み込み、
outputで指定した場所にJavaソースを出力する。
参考: DMDLユーザーガイド#DMDLコンパイラの実行

※普通、SPIを使う際はjarファイル化するのだが、今回はclassesがパスに含まれているのでjarファイルを作らなくても動作する。

実行結果:

〜
16:36:58.312 [main] DEBUG c.a.dmdl.analyzer.DmdlAnalyzer - Resolving attributes: word_count_model
16:36:58.312 [main] DEBUG c.a.dmdl.analyzer.DmdlAnalyzer - Resolving attributes: line_model
16:36:58.312 [main] INFO com.asakusafw.dmdl.java.GenerateTask - 2個のモデルからJavaデータモデルクラスを生成します
16:36:58.312 [main] INFO com.asakusafw.dmdl.java.GenerateTask - データモデルクラスを生成しています: word_count_model
+++EmptyDriver#getTypeAnnotations	RECORD word_count_model
+++EmptyDriver#getInterfaces	RECORD word_count_model
+++EmptyDriver#getMemberAnnotations	word_count_model.word : TEXT
+++EmptyDriver#getMemberAnnotations	word_count_model.count : INT
+++EmptyDriver#getMethods	RECORD word_count_model
16:36:58.890 [main] INFO com.asakusafw.dmdl.java.GenerateTask - データモデルクラスを生成しています: line_model
+++EmptyDriver#getTypeAnnotations	RECORD line_model
+++EmptyDriver#getInterfaces	RECORD line_model
+++EmptyDriver#getMemberAnnotations	line_model.text : TEXT
+++EmptyDriver#getMethods	RECORD line_model
16:36:58.984 [main] INFO com.asakusafw.dmdl.java.GenerateTask - データモデルクラスの生成が完了しました

dmdlファイル内のモデル毎にDriverが呼ばれている。
一番最初に呼ばれるメソッドはgetTypeAnnotations()らしい。

Mavenコマンドによるモデル生成時に自分のドライバーを実行させる方法


Javaソースの生成

では、とりあえず空っぽのJavaソースを生成してみる。

afw-driver/src/jp/hishidama/asakusafw/dmdl/SimpleDriver.java:

package jp.hishidama.asakusafw.dmdl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.asakusafw.dmdl.java.emitter.EmitContext;
import com.asakusafw.dmdl.java.spi.JavaDataModelDriver;
import com.asakusafw.dmdl.semantics.ModelDeclaration;
import com.ashigeru.lang.java.model.syntax.Annotation;
import com.ashigeru.lang.java.model.syntax.Attribute;
import com.ashigeru.lang.java.model.syntax.ClassDeclaration;
import com.ashigeru.lang.java.model.syntax.Javadoc;
import com.ashigeru.lang.java.model.syntax.ModelFactory;
import com.ashigeru.lang.java.model.syntax.SimpleName;
import com.ashigeru.lang.java.model.syntax.Type;
import com.ashigeru.lang.java.model.syntax.TypeBodyDeclaration;
import com.ashigeru.lang.java.model.syntax.TypeParameterDeclaration;
import com.ashigeru.lang.java.model.util.AttributeBuilder;
import com.ashigeru.lang.java.model.util.JavadocBuilder;

このソースは、ModelInputDriverを参考にしている。
なぜなら、Input(やOutput)はモデルとは別のソースファイルを生成しているから。
今回は新しいソースを生成したい。

/**
 * @see com.asakusafw.dmdl.java.emitter.driver.ModelInputDriver
 */
public class SimpleDriver extends JavaDataModelDriver {

	@Override
	public List<Annotation> getTypeAnnotations(EmitContext context, ModelDeclaration model) throws IOException {
		System.out.println("+++SimpleDriver#getTypeAnnotations\t" + model);
		generate(context, model);
		return Collections.emptyList();
	}

JavaDataModelDriverの中で最初に呼ばれるのがgetTypeAnnotations()なので、この中で新しいソースファイルを作るよう設定する。


	private void generate(EmitContext context, ModelDeclaration model) throws IOException {
		String categoryName = "simple";
		String typeNamePattern = "{0}Simple";
		EmitContext next = new EmitContext(context.getSemantics(), context.getConfiguration(), model,
			categoryName, typeNamePattern);
		Generator.emit(next, model);
	}

ここで新しく生成するソースファイルを設定している。

categoryName( カテゴリー名)は、パッケージ名の一部。
パッケージ名は「Mainの引数で指定されたパッケージ名」+「dmdl」+「カテゴリー名」になるので、今回は「sample.dmdl.simple」になる。

typeNamePatternはクラス名のパターン。
「{0}」がモデル名に置換される。今回だと「{0}Simple」なので、「LineModelSimple」「WordCountModelSimple」というクラスが生成される。


実際にクラスの中身を定義するのがGenerator。
特にemit()で まずクラスそのものの定義を行っている。

	private static class Generator {
		private final EmitContext context;
		private final ModelDeclaration model;
		private final ModelFactory f;

		private Generator(EmitContext context, ModelDeclaration model) {
			assert context != null;
			assert model != null;
			this.context = context;
			this.model = model;
			this.f = context.getModelFactory();
		}

		static void emit(EmitContext context, ModelDeclaration model) throws IOException {
			assert context != null;
			assert model != null;
			Generator emitter = new Generator(context, model);
			emitter.emit();
		}

		private void emit() throws IOException {
			Javadoc javadoc = new JavadocBuilder(f).text("とりあえず{0}のクラスを生成してみる。", model.getName()).toJavadoc();
			List<Attribute> modifiers = new AttributeBuilder(f).Public().toAttributes();
			SimpleName name = context.getTypeName();
			List<TypeParameterDeclaration> typeParameters = Collections.emptyList();
			Type superClass = null;
			List<Type> superInterfaceTypes = Collections.emptyList();

			ClassDeclaration decl = f.newClassDeclaration(
				javadoc,            	//クラスのJavadoc。不要な場合はnull
				modifiers,          	//修飾子。publicやstatic・final等
				name,               	//クラス名
				typeParameters,     	//ジェネリクスの型引数。無い場合は空リスト
				superClass,         	//extendsしている親クラス。無い場合はnull
				superInterfaceTypes,	//implementsしているインターフェース。無い場合は空リスト
				createMembers()     	//クラス内の定義(フィールドやメソッド)。無い場合は空リスト
			);
			context.emit(decl);
		}

		// クラス内のフィールドやメソッドを定義する
		private List<TypeBodyDeclaration> createMembers() {
			List<TypeBodyDeclaration> results = new ArrayList<TypeBodyDeclaration>();
			// results.add(createParserField());
			// results.add(createConstructor());
			// results.add(createReader());
			// results.add(createCloser());
			return results;
		}
	}
}

基本的に、ModelFactoryの「newなんちゃら」メソッドを呼び出してJavaの構文を生成していく。


SPI用のservicesSimpleDriverを追加しておく。

afw-driver/src/META-INF/services/com.asakusafw.dmdl.java.spi.JavaDataModelDriver:

#jp.hishidama.asakusafw.dmdl.EmptyDriver
jp.hishidama.asakusafw.dmdl.SimpleDriver

↓生成されたファイル

C:/cygwin/tmp/afw/sample/dmdl/simple/WordCountModelSimple.java:

package sample.modelgen.dmdl.simple;
/**
 * とりあえずword_count_modelのクラスを生成してみる。
 */
public class WordCountModelSimple {
}

メソッド生成

SimpleDriverにメソッド生成の処理を加えてみる。

出力したいメソッドはこんな感じ。

	public void method1() {
		System.out.println("Hello");
	}

まず、createMembers()からメソッド生成サブルーチンを呼ぶように修正する。

		// クラス内のフィールドやメソッドを定義する
		private List<TypeBodyDeclaration> createMembers() {
			List<TypeBodyDeclaration> results = new ArrayList<TypeBodyDeclaration>();
			results.add(createMethod1());
			return results;
		}

メソッドの生成処理を記述する。

		private TypeBodyDeclaration createMethod1() {
			Javadoc javadoc = null;
			List<Attribute> modifiers = new AttributeBuilder(f).Public().toAttributes();
			List<TypeParameterDeclaration> typeParameters = Collections.emptyList();
			Type returnType = context.resolve(void.class);
			SimpleName name = f.newSimpleName("method1");
			List<FormalParameterDeclaration> formalParameters = Collections.emptyList();
			List<Type> exceptionTypes = Collections.emptyList();

			return f.newMethodDeclaration(
				javadoc,
				modifiers,      	//修飾子
				typeParameters,  	//メソッドの型引数
				returnType,      	//戻り値の型
				name,            	//メソッド名
				formalParameters,	//メソッドの引数
				0,               	//メソッド名の後ろに配列定義の「[]」を付ける個数(そんな書き方出来るなんて初めて知ったよ…)
				exceptionTypes,  	//例外(throws)
				f.newBlock(createMethod1Body())	//メソッド本体
			);
		}
		private List<Statement> createMethod1Body() {
			List<Statement> results = new ArrayList<Statement>();
			results.add(
				new ExpressionBuilder(f, f.newSimpleName("System"))
				.field("out")
				.method("println", f.newLiteral("\"Hello\""))
				.toStatement()
			);
			return results;
		}

やれやれ、ちょっとしたものを書くだけでもえらく大変そうだ(苦笑)


生成結果:

package sample.modelgen.dmdl.simple;
/**
 * とりあえずword_count_modelのクラスを生成してみる。
 */
public class WordCountModelSimple {
    public void method1() {
        System.out.println("Hello");
    }
}

インデントは入れてくれるのだが、空行は入れてくれない^^;


ソース生成の為の構文

生成するJavaソースは、構文解析した状態を表すクラスを組み合わせて表現する。[2011-08-16]

構文要素を扱うクラス 説明
f ModelFactory 構文インスタンスを生成する為のメソッドが揃っている。
context EmitContext 全体的な情報を保持している。
model ModelDeclaration 生成対象のDMDLのモデル名やプロパティー(生成対象のフィールド)の名前・データ型などを保持している。
  Models FQCNの識別子を生成するのに使える。
  ExpressionBuilder 式(演算)を構築する。
ModelFactoryにも式を生成するメソッドはあるけれど、ExpressionBuilderの方が(長くなるけど)分かりやすい。

どんな風に構築していくのか、例をちょっと挙げてみる。

Java
構文
生成方法 備考
識別子 f.newSimpleName 単純名を生成する。(変数名やクラス名など) SimpleName name = f.newSimpleName("value");
Models.toName 識別子を生成する。(単純名または修飾名 Name name = Models.toName("sample.Sample");
context.resolve 型を生成する。
これによって指定したクラスは、必要に応じてインポート文が自動的に生成される。
(ただ、pack.C1.E1といった内部enumを指定して「E1.V1」という使い方をした場合に
インポート文が生成されないっぽい?)
Type t1 = context.resolve(String.class);
Type t2 = context.resolve(Models.toName("sample.Sample"));
リテラル f.newLiteral リテラル(定数)を生成する。 Literal l1 = f.newLiteral("123");
Literal l2 = f.newLiteral("\"string\"");
フィールド定義 f.newFieldDeclaration フィールドを定義する。(初期化も定義出来る)  
メソッド定義 f.newMethodDeclaration メソッドを定義する。  
ローカル変数定義 f.newLocalVariableDeclaration ローカル変数を定義する。(初期化も定義出来る)  
変数への代入 f.newAssignmentExpression 代入式を定義する。  
インスタンス生成 f.newClassInstanceCreation
Expression
newでインスタンスを生成する。 f.newClassInstanceCreationExpression(
  f.newParameterizedType(
    context.resolve(ArrayList.class),
    context.resolve(String.class
  )
)

new ArrayList<String>()
メソッド呼び出し ExpressionBuilder#method メソッドを呼び出す。 new ExpressionBuilder(f, f.newSimpleName("bean"))
.method("setValue", f.newLiteral("123"))
.toStatement()

bean.setValue(123);
フィールドアクセス ExpressionBuilder#field フィールドを指定する。 new ExpressionBuilder(f, f.newSimpleName("bean"))
.field("value")
.toExpression()

bean.value
.class f.newClassLiteral 「.class」を指定する。
classはJavaの予約語なので、ExpressionBuilder#fieldでは指定できない。
f.newClassLiteral(context.resolve(String.class))

String.class
this
super
f.newThis
f.newSuper
「this」や「super」という識別子を取得する。
thisやsuperはJavaの予約語なので、f.newSimpleName()では取得できない。
 
取得
内容
生成方法 備考
モデル名 model.getName モデル名を取得する。 model.getName()

word_count_model
モデルクラス名 model.getSymbol
context.getTypeName
context.getQualifiedTypeName
モデルのクラス・クラス名を取得する。[/2011-08-28] Type t = context.resolve(model.getSymbol());

WordCountModel
SimpleName name = context.getTypeName();

WordCountModel
QualifiedName name =
context.getQualifiedTypeName();

sample.modelgen.dmdl.model.WordCountModel
パッケージ名 configuration.getBasePackage モデルのベースパッケージ名を取得する。[2011-08-28] Name name = context.getConfiguration().getBasePackage();

sample.modelgen
プロパティー一覧 model.getDeclaredProperties プロパティー一覧を取得する。 for (PropertyDeclaration property : model.getDeclaredProperties()) { 〜 }
プロパティー名 context.getFieldName プロパティー名を取得する。 SimpleName name = context.getFieldName(property);

word
データ型 property.getType プロパティーのデータ型を取得する。
ただしこの型はDMDLの型であり、Java構文のTypeではない。
Javaのプリミティブ型およびラッパークラスを返してくれるものがあると便利なのだが。
 
ゲッター context.getValueGetterName プロパティーのゲッターメソッド名を取得する。
TEXT型の場合のAsStringが付いたメソッドを直接取得する方法は無いようだ。
SimpleName getter = context.getValueGetterName(property);

getWord
セッター context.getValueSetterName プロパティーのセッターメソッド名を取得する。 SimpleName setter = context.getValueSetterName(property);

setWord

HiveのSerDe・PigのStorageを生成するドライバーでjarファイルを公開しているが、その中にソースも含まれているので、参考になるかも。


感想

これらのクラスはとてもよく出来ている。よくここまで網羅して作り込んだものだと、本当に感心する。[2011-08-16]
(ModelFactoryのメソッドを見れば、Javaで出来る構文が全て分かるのではないかと思う)
使用したクラスのインポート文が自動生成されるとか、面白い。

しかし、HiveのSerDe・PigのStorageを生成するドライバーを作ってみてよく分かったが、これを使って構築していくのは人間のやることじゃない^^;
手でやるのは生産性が悪すぎる。特に保守性は壊滅的だろう。

生成するJavaソースのほとんどは固定された文なので、ベタのテキストを出力するように(つまり、素のServletでHTMLを出力する感じに)なっている方が絶対楽。
(改行まで扱いたいので、Scalaの"""が使えると便利だなー)

実際、DMDLから各種ツール用の定義が作れると色々幅が広がると思う。
そしてその定義の記述方法はJavaとは限らないわけで、やはりモデルやプロパティーの情報提供機能だけで充分なような。
ドライバーを記述する人は、それらの情報だけ受け取って、ファイルへの出力はWriterとかPrintStreamで行えばいい。

つーか、getTypeAnnotations()が呼ばれた時点で自分でファイルをオープンして書き込んじゃえばいいのか?!(爆)


追記 [2011-08-17]
ベタのテキストで…というのは、新しいファイルを作ることを考えたときのやり方。

AsakusaFWではモデルクラス(Java)の生成自体を複数のドライバーで分担して処理している。

もしこれらの生成中に別々のクラスをインポートする必要があったら、インポート文は先に書く必要があるし、重複して同じクラスをインポートする事も出来ないので
どこかで集中管理する必要がある。

そういった事を踏まえて、AsakusaFWのデータモデルドライバーはこういう構文クラスを使う方式を採っているのかもしれない。

でもやっぱり“やりすぎ”感が否めない…^^;


リソース生成時に実行する方法

先の例では、ドライバーを起動するMainクラスを直接実行して独自ドライバーを呼び出した。[2011-08-28]

通常、DMDLからモデルクラスを生成するにはMavenのコマンドでgenerate-resources等を実行する。
このときに自分のドライバーも実行させるには、Mavenに自分のドライバーを登録する。

  1. 自分のドライバーをjarファイル化する。
  2. Mavenのローカルリポジトリーにjarファイルを登録する。
  3. AsakusaFWのプロジェクトのpom.xmlの依存関係に自分のドライバーを追加する。
  4. (ドライバーを修正したら、jarファイル化とローカルリポジトリーの登録をやり直す)

これで、モデルクラスの生成を行ったときに自分のドライバーも呼ばれるようになる。


しかしMavenのリポジトリーをいじるのはちょっと面倒。
モデル生成の実行にはAntが使われているので、build.xmlを修正する方が簡単(というか、自分には馴染みがあるw)。

  1. (自分のドライバーをjarファイル化する)
  2. asakusa-build.xmlのモデル生成部分に自分のドライバーのクラスパスを追加する。
  3. (ドライバーを修正したら、(jarファイル化している場合は)jarファイル生成だけやり直す)

AsakusaFWプロジェクト/src/main/scripts/asakusa-build.xml:

	<java classname="com.asakusafw.dmdl.java.Main" classpath="${compile_classpath}" fork="true" failonerror="true">
〜
		<arg value="-plugin" />
		<arg value="C:\workspace\sample-driver\classes" />
<!--		<arg value="C:\workspace\sample-driver\bin\sample-driver.jar" /> -->
	</java>

Mainクラスは「-plugin」オプションでドライバーを指定できるので、その指定を追加する。パスはjarファイルでもclassesディレクトリーでもよい。
パス区切り文字(Windowsではセミコロン「;」、UNIXではコロン「:」)で区切って複数のパスを指定できるようだ。

なお、独自のパラメーター(引数)を渡したい場合、Mainが使用する以外の引数を保持してくれないので自分のドライバーまで値が回ってこない。
今のところはシステムプロパティー「<vmarg value="-Dプロパティー=値" />」を使うしか無さそう。


AsakusaFW目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま