Hibernate Validatorとは、ドメインモデルに対する制約条件をエンティティクラスにアノテーションで記述することが出来るようにしたHibernateのプロダクトです。エンティティクラスに書くのでバリデーションのコードが重複しにくいことや、アノテーションで手軽にかけるということくらいがウリでしょうか。
Beanのバリデーションを行う仕様は、JSR303 Bean Validationで進められているようです。
- 必要なライブラリ
- ejb3-persistence.jar
- hibernate-annotations.jar
- hibernate-commons-annotations.jar
- hibernate-validator.jar
- エンティティクラス
- nameはNULLであってはいけない
- nameは10文字以内でなければならない
- ageは0から100の範囲内にある数値でなければならない
- emailはEメールアドレスの仕様に沿った記述でなければならない
- birthdayは過去日付でなければならない
- 定義ファイル
- 動かす
Hibernate Validatorを用いるにはHibernate Core本体、およびCoreが依存するjarに加え、Hibernate Annotationが必要です。
Core以外には以下のjarがあればよいと思います。
最近色々なHibernateのプロダクトがTOPレベルに昇格してきましたが、各プロダクトのバージョンをそろえないとうまく動かなかったりするので注意する必要があります。特にAnnotationは、バージョンが違っていても例外やエラーとなるのではなくアノテーションが適用されずに正常終了というケースもあるので不具合の判別が難しいことがあります。以下はhibernate.orgのCompatibility Matrixの抜粋です。
| Package | Version | Core | Annotations | EntityManager | Validator | Search | Shards | Tools |
| Hibernate Core | 3.2.2 GA | - | 3.2.x, 3.3.x | 3.2.x, 3.3.x | 3.0.x | 3.0.x | 3.0.x | 3.2.0 Beta9 |
AnnotationとValidatorを使ったエンティティです。すごく簡単です。
@Entity
public class Customer implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int id;
@NotNull
@Length(max = 10)
public String name;
@Range(min = 0, max = 100)
public int age;
public String email;
@Past
public Date birthday;
}
アノテーションによって上記のエンティティに設定した制約を纏めると以下のような感じです。
これがアノテーションで書けるのは簡単でいいですね。ビルトインで用意されている制約は他にも@CreditCardNumberとか@Size(コレクションなどのサイズ)などがあります。
hibernate.cfg.xmlはこんな感じです。Hibernate Annotation用のmapping定義を追加している程度です。
<hibernate-configuration>
<session-factory>
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<property name="connection.url">jdbc:hsqldb:hsql://localhost:9001</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hbm2ddl.auto">create</property>
<mapping package="net.grandnature.example.entity"/>
<mapping class="net.grandnature.example.invoice.entity.Customer"/>
</session-factory>
</hibernate-configuration>
・・・と言っても普通に動かすだけなのですが
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.name = "KIDA Taro";
customer.age = 76;
customer.email = "kida@example.com";
DateFormat parser = DateFormat.getDateInstance();
ex.birthday = parser.parse("1930/12/06");
session.save(ex);
tx.commit();
session.close();
このまま動かすと普通に登録されます。もし、例えばbirthdayが未来日付だったりEメールアドレスに不正なものが設定されていたりと、エンティティの状態が制約に違反していると、save時にorg.hibernate.validator.InvalidStateExceptionが投げられます。制約に違反している内容の詳細はInvalidStateExceptionのgetInvalidValuesメソッドで返されるorg.hibernate.validator.InvalidValueの配列に格納されています。
ただし、@NotNullの制約に引っかかったときはorg.hibernate.PropertyValueExceptionが投げられます。