タツノオトシゴのブログ

主にJavaに関するものです。

EL式をスタンドアローンで使用する

BeanValidation1.1でEL式が利用できるようになったので、他のライブラリでもメッセージ中にEL式が利用できる方法を調べて見た。

ようは、Servletコンテナなして、EL式を利用する方法を紹介します。

EL2.0

EL2.0の実装としてcommons-el
があります。

ただし、2003年作成と古いです。

EL2.x

EL2.xを単独で利用するには、Glassfishが提供しているライブラリを利用します。

ただし、これだけではだめで、ELContext、ELResolverなど単独で利用できるように別途実装が必要になります。

実は、Hibernate Validator5.xのパッケージ「org.hibernate.validator.internal.engine.messageinterpolation.el」内のクラスがその実装になります。

【参考】


【準備】
EL式のライブラリとその実装用のライブラリを追加します。

<dependency>
	<groupId>javax.el</groupId>
	<artifactId>el-api</artifactId>
	<version>2.2</version>
</dependency>
<dependency>
	<groupId>org.glassfish</groupId>
	<artifactId>el-impl</artifactId>
	<version>2.2</version>
</dependency>

【単独で利用できるように実装したもの】
Githubに参考にして作った実装を上げておきます。
EL3.0のELProcessorと似た使い方ができます。

ELProcessor elProc = new ELProcessor();

elProc.setVariable("currentDate", new Date());
elProc.setVariable("formatter", new FormatterWrapper(Locale.getDefault()));

String eval = elProc.eval("formatter.format('%1$tY/%1$tm/%1$td%n', currentDate)", String.class);

System.out.println(eval);

【注意点】
EL式中で呼び出すオブジェクトの中のメソッドは、オーバライドオーバロードしていると、区別つかないためラップなどして使用する。

'java.util.Formatter#formatter'は、FormatterWrapperクラスでラップして呼び出す必要がある。

EL3.x

EL3.xから、スタンドアローンで利用できるように、専用クラスELProcessor、StandartELContextクラスが追加になりました。

【参考】

【準備】
EL式のライブラリとその実装用のライブラリを追加します。

<dependency>
	<groupId>javax.el</groupId>
	<artifactId>javax.el-api</artifactId>
	<version>3.0.0</version>
</dependency>
<dependency>
	<groupId>org.glassfish</groupId>
	<artifactId>javax.el</artifactId>
	<version>3.0.0</version>
</dependency>

【使い方】

ELProcessor elProc = new ELProcessor();

// 式中で利用する変数の追加
elProc.defineBean("a1", 5);
elProc.defineBean("a2", 3);

// 式の評価
int ret = elProc.eval("a1 + a2");

Hibernate Validator5.x(Bean Validatoin1.1)中のEL式

Hibernate Valiador5.xから、EL式が利用できるようになりました。
しかし、ラムダ式などのEL3.xで追加された機能は利用できません


基本的にEL2.xの機能が利用できます。

Hibernate ValidatorのEL式を解釈するクラス「org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTerm」を見ると、EL2.x系の使い方になっているためということがわかります。


EL3.0で追加された、ELProcessorを利用するように実装を切り替えれば、EL3.0が使えるようになります。


BeanValidationからMessageInterpolatorが独自のものが設定できるようになっているため、org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator中のメソッド「interpolateExpression」の中を変更すれば動作するようになると思います。

public class ResourceBundleMessageInterpolator implements MessageInterpolator

	private String interpolateExpression(TokenIterator tokenIterator, Context context, Locale locale)
			throws MessageDescriptorFormatException {
		while ( tokenIterator.hasMoreInterpolationTerms() ) {
			String term = tokenIterator.nextInterpolationTerm();
			
			// EL式の処理部分。↓の処理を独自なものに変更する。
			InterpolationTerm expression = new InterpolationTerm( term, locale );
			String resolvedExpression = expression.interpolate( context );
			tokenIterator.replaceCurrentInterpolationTerm( resolvedExpression );
		}
		return tokenIterator.getInterpolatedMessage();
	}
	
}