はじめに
先日タイトルの件について必要になって調べたのですが、意外と日本語の情報が無いのでメモ。
私の探し方が下手だという可能性も大いにありますが。
環境
- Wicket 1.3.6
そもそもresourceKeyとは?
ValidatorとConverterのresourceKeyは、プロパティファイルからエラーメッセージを拾うためのキーです。
resourceKeyの部分をちゃんと実装することで、自作のValidatorとConverterについても、エラーメッセージをプロパティファイルから取得することが可能になります。
標準のValidatorとConverterのリソースキーについては書籍の「オープンソース徹底活用WicketによるWebアプリケーション開発」に記載があります。
Validatorの場合
AbstractValidator#resourceKey()をオーバーライドすることによって、任意のリソースキーを使用することが可能になります。
デフォルトの実装を以下に引用します。
protected String resourceKey() { return Classes.simpleName(getClass()); }
Validatorの興味深い点としては、IValidatorインターフェースにはresourceKey()が存在しないことです。
ということを踏まえてソースを追っていくと、一つのValidatorで複数のメッセージキーを使い分けることが可能であることに気づくのですが、そのあたりは省略。
Converterの場合
Converterは、エラーを表示したい場合、IConverter#convertToObject(String, Locale)でConversionExceptionを送出するかと思います。
で、throw前にConversionException#setResourceKey(String)を呼んで任意のリソースキーを設定します。
setResourceKey(String)を呼ばなかった場合の挙動がどんな感じであるかは、FormComponent#convertInput()とValidationError#getErrorMessage(IErrorMessageSource)を読むと何となくわかります。
以下にFormComponent#convertInput()を引用します。
protected void convertInput() { if (typeName == null) { try { convertedInput = convertValue(getInputAsArray()); } catch (ConversionException e) { ValidationError error = new ValidationError(); if (e.getResourceKey() != null) { error.addMessageKey(e.getResourceKey()); } if (e.getTargetType() != null) { error.addMessageKey("ConversionError." + Classes.simpleName(e.getTargetType())); } error.addMessageKey("ConversionError"); reportValidationError(e, error); } } else { final IConverter converter = getConverter(getType()); try { convertedInput = converter.convertToObject(getInput(), getLocale()); } catch (ConversionException e) { ValidationError error = new ValidationError(); if (e.getResourceKey() != null) { error.addMessageKey(e.getResourceKey()); } String simpleName = Classes.simpleName(getType()); error.addMessageKey("IConverter." + simpleName); error.addMessageKey("IConverter"); error.setVariable("type", simpleName); reportValidationError(e, error); } } }以下にValidationError#getErrorMessage(IErrorMessageSource)を引用します。
public final String getErrorMessage(IErrorMessageSource messageSource) { String errorMessage = null; // try any message keys ... for (Iterator iterator = keys.iterator(); iterator.hasNext();) { errorMessage = messageSource.getMessage((String)iterator.next()); if (errorMessage != null) { break; } } // ... if no keys matched try the default if (errorMessage == null && message != null) { errorMessage = message; } // if a message was found perform variable substitution if (errorMessage != null) { final Map p = (vars == null) ? Collections.EMPTY_MAP : vars; errorMessage = messageSource.substitute(errorMessage, p); } return errorMessage; }
さいごに
ValidatorとConverterで実装方法が違うのがちょっと覚えにくいですね。
それはさておき、これを知っているとエラーメッセージをソースに埋め込まなくともよいので、ValidatorとConverterの実装が少し幸せになるかと思います。