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ライフを!
