アノテーションでバリデーション

 Beanでバリデーションするなら、Beanに定義を持たせて、実際のバリデーション処理は違うクラスでやるべきだよね、と言う話になったのでそんな感じのものを作ってみました。

@Retention(RetentionPolicy.RUNTIME)
public @interface Validation {
	//最小文字数を定義
	int min() default 1;
	// 最大文字数を定義
	int max();
	// その項目の正規表現を定義
	String regex() default "";
}
public class SampleBean {

	@Validation( min=1, max=10 )
	private String name;
	@Validation( max=3, regex="\\d+" )
	private String old;
	@Validation( max=11, regex="\\d{2,4}-\\d{2,4}-\\d{4}" )
	private String phone;
	
	(中略)
}

 フィールドにアノテーションで定義情報を持たせています。この定義情報でもってバリデーションします。

public class SampleBeanValidator {

	public static String validate( String elem, String fieldName )
	{
		Validation val = getValidation( SampleBean.class, fieldName );
		
		if( val.min() > elem.length() || val.max() < elem.length() )
			return "文字数的にアレですよ";
		if( !elem.matches( val.regex() ) )
			return "規則的に正しくないですよ";
		return null;
	}
	
	public static Validation getValidation( Class clazz, String fieldName )
	{
		Validation validation = null;
		try{
			validation = clazz.getDeclaredField( fieldName ).getAnnotation(Validation.class);
		}catch( NoSuchFieldException nsfe ){
			nsfe.printStackTrace();
		}
		return validation;
	}
}

 なんでvalidateメソッドがStringを返すんですか、というのは便宜上なのであまり気にしないでもらいたいのです。

public class ValidatorTest {

	public static void main(String[] args) {
		SampleBean bean = new SampleBean();
		bean.setName("にゃんぽこにゃん3世の登場です");
		bean.setOld("1d");
		bean.setPhone("90-32-4343");
		
		System.out.println( SampleBeanValidator.validate( bean.getName(), "name" ) );
		System.out.println( SampleBeanValidator.validate( bean.getOld(), "old" ) );
		System.out.println( SampleBeanValidator.validate( bean.getPhone(), "phone" ) );
	}
}

すると

文字数的にアレですよ
規則的に正しくないですよ
null

と返ってきます。ValidationにNOT NULLだの何だの加えていくと楽しいのではないかと。

 それにつけても@Retention(RetentionPolicy.RUNTIME)を指定しないとアノテーションをリフレクションで読めないというのは罠だと思ったよ! 凄い勢いでハマったよ!