Protocol Buffers(gRPC通信)でBean Validationができるようになりましたが、
いざ「やってみよう!」と思ったらXMLで書かないといけないのに文献が少ない。。
出てきたエラーも解決方法がわからない。。
ので遭遇した注意事項をまとめます。※gRPC以外でも使える、はず。(gRPCは公式も参照のこと)
ベース
jp.co.sample.grpc.SampleRequest
というクラスに対するXMLとします。
<constraint-mappings xmlns="http://xmlns.jcp.org/xml/ns/validation/mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/validation/mapping
http://xmlns.jcp.org/xml/ns/validation/mapping/validation-mapping-2.0.xsd"
version="2.0">
<default-package>jp.co.sample.grpc</default-package>
<bean class="SampleRequest">
...(後述)
</bean>
</constraint-mappings>
ここがポイント
-
<default-package>
を定義せず、<bean class="jp.co.sample.grpc.SampleRequest">
とすることもできます。
制約をつける
フィールドにアノテーションを付けてみます。
※フィールド名に"_"がついてるものは、gRPC特有のものです。
(前略)
<bean class="SampleRequest">
<field name="fullName_">
<constraint annotation="javax.validation.constraints.NotNull">
<groups>
<value>org.lognet.springboot.grpc.validation.group.RequestMessage</value>
</groups>
</constraint>
</field>
</bean>
(後略)
ここがポイント
-
<field>
タグの中に<constraint>
タグを並べてください。 -
<groups>
タグはgRPC(with SpringBoot)特有で、"Request時だけ適用"するものです。公式参照。
クラスがネストする
SampleRequestクラスのフィールドにJob
クラスの値を持つ場合です。(gRPC特有かな?)
(前略)
<bean class="SampleRequest">
<field name="job_">
<valid/>
</field>
</bean>
<bean class="Job">
<field name="companyName_">
<constraint annotation="javax.validation.constraints.NotNull>
<groups>
<value>org.lognet.springboot.grpc.validation.group.RequestMessage</value>
</groups>
</constraint>
</field>
</bean>
(後略)
ここがポイント
-
<constraint>
ではなく、<valid/>
1つを持たせて、同じXMLに<bean>
タグを追加します。 - 追加した
<bean>
タグの中は他と同じです。
フィールドがList型(repeated)である
フィールドがList型(gRPCで言うrepeated)の場合です。
以下はList<Hobby>
型のフィールドを持つ場合です。※constraint
タグにはとりあえずNotNullを指定していますが、お好みのものを付けてください(今更ですが)
(前略)
<bean class="SampleRequest">
<field name="hobbies">
<container-element-type>
<valid/>
</container-element-type>
<constraint annotation="javax.validation.constraints.NotNull">
<groups>
<value>org.lognet.springboot.grpc.validation.group.RequestMessage</value>
</groups>
</constraint>
</field>
</bean>
<bean class="Hobby">
<field name="genre_">
<constraint annotation="javax.validation.constraints.NotNull>
<groups>
<value>org.lognet.springboot.grpc.validation.group.RequestMessage</value>
</groups>
</constraint>
</field>
</bean>
(後略)
ここがポイント
- Listの中身を再帰評価するのが
<container-element-type>
タグです。 - このタグの中に
<constaint>
や<valid/>
とかを定義してください。 -
<重要>
<container-element-type>
タグは他の<constraint>
タグより先に定義してください(エラーになります)。
遭遇したエラー
Caused by: javax.validation.ValidationException: HV000105: jp.co.sample.grpc.SampleRequest does not contain the fieldType aaa
XMLの<field name="aaa">
に定義したフィールド名"aaa"がSampleRequestクラス(Java/Kotlin)に存在しない場合に出るエラーです。
実装だけが修正されてXMLが置いてけぼりになったケースが多いです。
cvc-complex-type.2.3: タイプのコンテンツ・タイプが要素のみであるため、要素'???'には文字[children]を使用できません。
この場合は、<field name="hobbies">
タグの中に変な文字が紛れ込んでいます。
(前略)
<field name="hobbies">
タグじゃない文字とか全角スペースとか
<constraint annotation="javax.validation.constraints.NotNull">
<groups>
<value>org.lognet.springboot.grpc.validation.group.RequestMessage</value>
</groups>
</constraint>
</field>
(後略)
Caused by: java.lang.ClassNotFoundException: jp.co.sample.annotation.xxx
<constraint>
タグで指定した自作annotationが未実装 or package誤りのときに出ます。設計を見直すときは開発担当と横連携しましょう。
〆
楽しいBean Validationライフを!