見習いプログラミング日記

Javaを中心に色々なことを考えてみます。目指せ本物のプログラマ。

@NotNull/@NotEmpty/@NotBlankの違い

JavaEE6から新しい仕様BeanValidation(JSR303)が導入されています。

BeanValidationではアノテーションでユーザ入力チェックを定義することができます。Struts1.xではvalidation.xmlの記述量が多く、度重なるタイプミスとランタイムエラーに苦しめられてきましたが、アノテーションのタイプミスはコンパイル時にチェックされるので、苦しみが軽減されています。

JSF2.0と組み合わせて使用するとき、「必須入力チェック」について同じような意味を持つアノテーションがいくつかあったので、違いを以下にまとめておきます。

以下のようなPersonクラスを定義し、各アノテーションの挙動の違いを確認します。

import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;

public class Person {
	@NotNull private String firstName;
	@NotEmpty private String middleName;
	@NotBlank private String lastName;
        // getterとsetterは省略
}

このPersonクラスに対して、以下のようなユニットテストを書いてみます。
このテストコードの結果は興味深いことに"グリーン(成功)"です。

public class PersonValidatorTest {
	private static Validator validator;
	
	@BeforeClass
	public static void init() {
		ValidatorFactory factory 
                    = Validation.buildDefaultValidatorFactory();
		validator = factory.getValidator();
	}
	
	@Test
	public void nameIsRequired() {
		Person person = new Person();
		person.setFirstName("");   // @NotNullは空文字エラーにする?
		person.setMiddleName(" "); // @NotEmptyは空白のみをエラーにする?
		person.setLastName(" ");   // @NotBlankは空白のみをエラーにする?
		
		Set<ConstraintViolation<Person>> constraintValidation 
                    = validator.validate(person);

                 // エラーは1件だけ(@NotBlankの部分)
		assertThat(constraintValidation.size(), is(1));
	}
}


挙動をまとめると、以下のようになります。×はチェックエラー、○は許可を表します。

Null ""(空文字) 空白のみ
@NotNull ×
@NotEmpty × ×
@NotBlank × × ×


JSF2.0と組み合わせて使う場合に注意したいのは、「必須入力チェック」に対してJavaEE標準で用意されている@NotNullを使うと、デフォルトではフォームに何も入力されていない場合(空文字となる)、Validationをパスしてしまうことです。

以下の設定をweb.xmlに加えると、@NotNullでも必須入力チェックが可能です。
フォームに何も入力されていない場合、空文字ではなくnullと見なされます。

<context-param>
  <param-name>
    javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
  </param-name>
  <param-value>true</param-value>
</context-param>

HibernateValidatorの独自実装である@NotBlankを使わなくて済むので便利な設定です。