Bean Validation XML書き方まとめ

Protocol Buffers(gRPC通信)で[Bean Validationができるようになりました](https://qiita.com/yamatok/items/cfba82cc9d760c67a631)が、

いざ「やってみよう！」と思ったらXMLで書かないといけないのに文献が少ない。。

出てきたエラーも解決方法がわからない。。

ので遭遇した注意事項をまとめます。※gRPC以外でも使える、はず。(gRPCは[公式](https://github.com/LogNet/grpc-spring-boot-starter#5-implementing-message-validation)も参照のこと)

# ベース
`jp.co.sample.grpc.SampleRequest` というクラスに対するXMLとします。

```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特有のものです。

```SampleRequest.xml
(前略)
  <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時だけ適用"するものです。[公式](https://github.com/LogNet/grpc-spring-boot-starter#5-implementing-message-validation)参照。

# クラスがネストする
SampleRequestクラスのフィールドに`Job`クラスの値を持つ場合です。（gRPC特有かな？）

```SampleRequest.xml
(前略)
  <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/>`１つを持たせて、同じXMLに`<bean>`タグを追加します。
 - 追加した`<bean>`タグの中は他と同じです。

# フィールドがList型(repeated)である
フィールドがList型（gRPCで言うrepeated）の場合です。
以下は`List<Hobby>`型のフィールドを持つ場合です。※`constraint`タグにはとりあえずNotNullを指定していますが、お好みのものを付けてください(今更ですが)

```SampleRequest.xml
(前略)
  <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">`タグの中に変な文字が紛れ込んでいます。

```SampleRequest.xml
(前略)
    <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ライフを！