最近 JavaEE 触り始めてます。JSR 303: Bean Validation というアノテーションベースの検証機能があります。.NET でいうと System.ComponentModel.DataAnnotations 名前空間 () のような感じでしょうか。
BeanValidation の使い方等々の話しは無しで、Xtend - Modernized Java の Active Annotation @Property を使った際にハマった事を書きます。
Xtend の @Property はこんな Java コードに変換されます。
Hoge.xtend
class Hoge { @Property String name }Hoge.java
@SuppressWarnings("all") public class Hoge { private String _name; public String getName() { return this._name; } public void setName(final String name) { this._name = name; } }
これを踏まえて BeanValidation で検証機能を追加していきましょう。
Hoge.xtend
import javax.validation.constraints.* class Hoge { @Property @NotNull @Size(min = 1, max = 10) String name }HogeText.xtend
import org.junit.Test import static org.junit.Assert.* import javax.validation.Validation class HogeTest { @Test def void validation() { val validator = Validation.buildDefaultValidatorFactory.validator val target = new Hoge => [ name = "" ] assertFalse(validator.validateProperty(target, "name").empty) } }
本来失敗欲しいこのテストが成功してしまいます。
理由は生成された Hoge の Java コードを見ると分かります。
Hoge.java
import javax.validation.constraints.* @SuppressWarnings("all") public class Hoge { @NotNull @Size(min = 1, max = 10) private String _name; public String getName() { return this._name; } public void setName(final String name) { this._name = name; } }
となっており、validationProperty で指定する場合は、"_name" と指定しなければなりません。または、 getName に BeanValidation のアノテーションを付ける必要があります。
validationProperty では存在しないプロパティ名を指定された場合例外が吐かれるようですが、getName があるため例外も吐かれません。
せっかく Xtend 使ってるのにこれは不便だ!ということで、@Property に似せた Active Annotation を書いてみました。
PropertyEx.xtend
import java.lang.annotation.ElementType import java.lang.annotation.Target import org.eclipse.xtend.lib.macro.AbstractFieldProcessor import org.eclipse.xtend.lib.macro.Active import org.eclipse.xtend.lib.macro.TransformationContext import org.eclipse.xtend.lib.macro.declaration.MutableFieldDeclaration @Target(ElementType.FIELD) @Active(PropertyExProcessor) annotation PropertyEx { } class PropertyExProcessor extends AbstractFieldProcessor { override doTransform(MutableFieldDeclaration field, extension TransformationContext context) { field.declaringType.addMethod('get' + field.simpleName.toFirstUpper) [ returnType = field.type body = ['''return this.«field.simpleName»;'''] ] field.declaringType.addMethod('set' + field.simpleName.toFirstUpper) [ addParameter(field.simpleName, field.type) body = ['''this.«field.simpleName» = «field.simpleName»;'''] ] } }※ソースコード中の « » は、«» です。上手く表示してくなかった。。Xtend の Template Expressions の機能です。
これを使って Hoge.xtend を書き換えると…
Hoge.xtend
import javax.validation.constraints.* class Hoge { @PropertyEx @NotNull @Size(min = 1, max = 10) String name }Hoge.java
import javax.validation.constraints.* @SuppressWarnings("all") public class Hoge { @NotNull @Size(min = 1, max = 10) private String name; public String getName() { return this.name; } public void setName(final String name) { this.name = name; } }
となり、先ほどのテストも正しく失敗してくれます。
という訳で @Property + BeanValidation は気を付けた方が良さそうですね。