S-JIS[2013-09-14/2016-02-04] 変更履歴

Xtextジェネレーター

Xtextのジェネレーターのメモ。


概要

“Xtextで生成されたエディター”で入力したDSLから、他のファイルを生成することが出来る。

Xtextでエディターを生成すると、IGeneratorインターフェースを実装したMyDslGeneratorといったクラスが作られる(デフォルトでは中身は空)。
DSLファイルを保存するとこのクラスが呼ばれるので、その中で独自のコンパイル(ファイル生成)を行うことが出来る。

また、Eclipseプロジェクトのクリーンを行った際にも、各ファイル毎に呼ばれる。[2014-08-02]


import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.generator.IFileSystemAccess;
import org.eclipse.xtext.generator.IGenerator;
public class BatchDslGenerator implements IGenerator {

	public void doGenerate(Resource resource, IFileSystemAccess fsa) {
		StringBuilder sb = new StringBuilder(1024);

		EList<EObject> list = resource.getContents();
		for (EObject object : list) {
			〜sbにファイルの内容を構築〜
		}

		String fileName = "hoge/test.txt";
		fsa.generateFile(fileName, sb);
	}
}

IFileSystemAccess#generateFile()で、ファイルにテキストを保存する。
ファイルのパスは、デフォルトでは「プロジェクト/src-gen」の下になる。
これは、EclipseのPreference(設定ページ)(ツリーは「自分のDSL」→「Compiler」)で変更することが出来る。


ジェネレーター(自動ビルド)のオン・オフ

ファイル保存時にジェネレーターを呼び出すかどうかは、設定ページやプロパティーページのCompilerページでユーザーが指定できる。[2014-08-02]

Compilerページの「General」→「Compiler is activated」メニューのチェックを外すと、ジェネレーターが呼ばれなくなる。
※Eclipseプロジェクト全体の設定である「Build Automatically(自動的にビルド)」がオフになっている場合も、ジェネレーターは呼ばれない。

独自の設定ページ(プロパティーページ)でオン・オフを設定する方法


ジェネレーターを使用しない例

Xtextのジェネレーター機能を使わない場合、設定ページやプロパティーページのCompilerページは不要である。[2013-09-21]
Compilerページを消すには、plugin.xmlのジェネレーター関連部分を削除する。

uiプロジェクト/plugin.xml:

<!--
   <extension
         point="org.eclipse.xtext.builder.participant">
      <participant
            class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.IXtextBuilderParticipant">
      </participant>
   </extension>
   <extension
         point="org.eclipse.ui.preferencePages">
      <page
            category="jp.hishidama.xtext.dmdl_editor.DMDL"
            class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage"
            id="jp.hishidama.xtext.dmdl_editor.DMDL.compiler.preferencePage"
            name="Compiler">
         <keywordReference id="jp.hishidama.xtext.dmdl_editor.ui.keyword_DMDL"/>
      </page>
   </extension>
   <extension
         point="org.eclipse.ui.propertyPages">
      <page
            category="jp.hishidama.xtext.dmdl_editor.DMDL"
            class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage"
            id="jp.hishidama.xtext.dmdl_editor.DMDL.compiler.propertyPage"
            name="Compiler">
         <keywordReference id="jp.hishidama.xtext.dmdl_editor.ui.keyword_DMDL"/>
         <enabledWhen>
            <adapt type="org.eclipse.core.resources.IProject"/>
         </enabledWhen>
         <filter name="projectNature" value="org.eclipse.xtext.ui.shared.xtextNature"/>
      </page>
   </extension>
-->

ジェネレーターの使用有無だけ設定できるようにする方法

設定ページやプロパティーページのCompilerページには、生成時のオプション(作成場所とか)を指定できるようになっている。[2014-08-02]

このうち、ジェネレーター(自動ビルド)の使用有無だけユーザーに指定させたいような場合は、Compilerページを使用しないようにし、自分独自の設定ページ(プロパティーページ)で指定できるようにすればよい。

uiプロジェクト/plugin.xml:

   <extension
         point="org.eclipse.xtext.builder.participant">
      <participant
            class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.IXtextBuilderParticipant">
      </participant>
   </extension>

<!-- デフォルトのCompilerページを無効化する
   <extension
         point="org.eclipse.ui.preferencePages">
      <page
            category="jp.hishidama.xtext.dmdl_editor.DMDL"
            class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage"
            id="jp.hishidama.xtext.dmdl_editor.DMDL.compiler.preferencePage"
            name="Compiler">
         <keywordReference id="jp.hishidama.xtext.dmdl_editor.ui.keyword_DMDL"/>
      </page>
   </extension>
   <extension
         point="org.eclipse.ui.propertyPages">
      <page
            category="jp.hishidama.xtext.dmdl_editor.DMDL"
            class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage"
            id="jp.hishidama.xtext.dmdl_editor.DMDL.compiler.propertyPage"
            name="Compiler">
         <keywordReference id="jp.hishidama.xtext.dmdl_editor.ui.keyword_DMDL"/>
         <enabledWhen>
            <adapt type="org.eclipse.core.resources.IProject"/>
         </enabledWhen>
         <filter name="projectNature" value="org.eclipse.xtext.ui.shared.xtextNature"/>
      </page>
   </extension>
-->

uiプロジェクト/src/〜/DMDLRootPreferencePage.java:

import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.xtext.builder.preferences.BuilderPreferenceAccess;
import org.eclipse.xtext.ui.editor.preferences.LanguageRootPreferencePage;
@SuppressWarnings("restriction")
public class DMDLRootPreferencePage extends LanguageRootPreferencePage {

	public static final String FORMAT_ON_SAVE = "formatOnSave";
	@Override
	protected void createFieldEditors() {
		Composite parent = getFieldEditorParent();
		addField(new BooleanFieldEditor(FORMAT_ON_SAVE, "format dmdl source on save", parent));
		addField(new BooleanFieldEditor(BuilderPreferenceAccess.PREF_AUTO_BUILDING, "auto building", parent));
	}
}

ジェネレーター(自動ビルド)の使用有無の設定キー(PREF_AUTO_BUILDING)はBuilderPreferenceAccessで定義されている。
ただしこのクラスは(Eclipseプラグインのルールに従って)非公開なので、無理やり使っている。(restrictionの警告が出るので、抑止している)


フルビルドの判定

ビルドが発生する(ジェネレーターが呼ばれる)のは、ファイルを保存した時やEclipseのプロジェクトのクリーンを実行した時である。[2014-08-02]

どういう理由で呼ばれたのかは、IBuildContextで保持されている。
ただし、IGeneratorには渡されないので、使いたいなら、IGeneratorを呼び出しているBuilderParticipantで何とかする必要がある。

uiプロジェクト/src/〜/DMDLBuilderParticipant.java:

import jp.hishidama.xtext.dmdl_editor.generator.DMDLGenerator;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.xtext.builder.BuilderParticipant;
import org.eclipse.xtext.generator.IGenerator;
public class DMDLBuilderParticipant extends BuilderParticipant {

	@Override
	public void build(final IBuildContext context, IProgressMonitor monitor) throws CoreException {
		DMDLGenerator gen = (DMDLGenerator) getGenerator(); // Xtext2.8まで
		long time = (context.getBuildType() == BuildType.FULL) ? System.currentTimeMillis() : 0;
		gen.setFullBuildStartTime(time);

		super.build(context, monitor);
	}
}

uiプロジェクト/src/〜/DMDLUiModule.java:

public class DMDLUiModule extends jp.hishidama.xtext.dmdl_editor.ui.AbstractDMDLUiModule {
〜
	@Override
	public Class<? extends org.eclipse.xtext.builder.IXtextBuilderParticipant> bindIXtextBuilderParticipant() {
		return DMDLBuilderParticipant.class;
	}
}

Xtext2.9で、getGenerator()メソッドが非推奨になった。[2016-02-04]
しかも返ってくるインスタンスがGeneratorDelegateになったので、今までの自分のGeneratorでは無くなった。
つまり、上記の様にキャストしていると、ClassCastExceptionが発生してしまう。

Xtext2.9では、GeneratorDelegateのgetLegacyGeneratorメソッドで従来のIGeneratorが取得できる。

import org.eclipse.xtext.generator.GeneratorDelegate;
	@Override
	public void build(final IBuildContext context, IProgressMonitor monitor) throws CoreException {
		@SuppressWarnings("deprecation")
		GeneratorDelegate delegate = (GeneratorDelegate) getGenerator();
		DMDLGenerator gen = (DMDLGenerator) delegate.getLegacyGenerator();
		long time = (context.getBuildType() == BuildType.FULL) ? System.currentTimeMillis() : 0;
		gen.setFullBuildStartTime(time);

		super.build(context, monitor);
	}

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