daisuzz.log

【Spring】Boolean型のパラメータに対してnullが送られたときにfalseとして受け取りたい

Boolean型で定義しているフォームの項目に対してnullが送られてきた場合にfalseに変換して受け取りたいことがあり、調べたことを備忘録として残していく。

前提

PropertyEditor

Spring Frameworkでは、リクエストとして送られてきたパラメータをオブジェクトに変換する際やオブジェクトを文字列にシリアライズする際に、PropertyEditorを使ってオブジェクト→文字列, 文字列→オブジェクトの変換を行なっている。

PropertyEditorは指定した型のプロパティ値を編集できるようにするためのサポートを提供するクラス。 Springが提供しているものではなく、Javaが提供しているインターフェースである。 またその基本実装クラスであるPropertyEditorSupportJavaが提供していて、このクラスをSpring Framework側で拡張して、さまざまなPropertyEditorを提供している。

PropertyEditor (Java SE 17 & JDK 17)

PropertyEditorSupport (Java SE 17 & JDK 17)

例えば、Collection型に対するPropertyEditorとしてCustomCollectionEditorが提供されていたり、Integer型に対してCustomNumberEditorが提供されていたりする。 具体的にデフォルトでどの型に対してどのPropertyEditorが実行されるのかは、以下の処理で記載されている。

https://github.com/spring-projects/spring-framework/blob/main/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java#L201-L270

また、独自のPropertyEditorを作ることもでき、その場合はPropertyEditorSupportを継承してクラスを実装する。 以前書いた以下の記事で、Collection型や文字列型の独自PropertyEditorの例を説明している。

iikanji.hatenablog.jp

iikanji.hatenablog.jp

今回はBoolean型に対するPropertyEditorであるCustomBooleanEditorを継承した独自PropertyEditorを実装して変換を行う。

CustomBooleanEditor

CustomBooleanEditorは、コンストラクタで以下3つのパラメータを指定できる。

  • allowEmpty:空文字を許容するか。許容する場合、入力値をnullに変換してフォームの項目にセットする。
  • trueString:trueとして扱いたい文字列。nullを指定した場合、"true", "yes", "on", "1"という文字列のみtrueとして扱う。(大文字/小文字は無視)
  • falseString:falseとして扱いたい文字列。nullを指定した場合、"false", "no", "off", "0"という文字列のみtrueとして扱う。(大文字/小文字は無視)
new CustomBooleanEditor("真", "偽", true)

例えば、↑のようなCustomBooleanEditorのインスタンスを生成した場合、以下のようなロジックで文字列を変換する。

  • 空文字が送られてきた場合、nullに変換する
  • "真"という文字列が送られてきた場合、trueに変換する
  • "偽"という文字列が送られてきた場合、falseに変換する
  • 上記以外の文字列が送られてきた場合、IllegalArgumentExceptionをthrowする

独自PropertyEditor

CustomBooleanEditorを継承した独自PropertyEditorを実装し、以下のロジックで変換を行う。

  • 空文字を許容しない
  • "true", "yes", "on", "1"という文字列が送られてきた場合、trueに変換する
  • "null", "false", "no", "off", "0"という文字列が送られてきた場合、falseに変換する
  • 上記以外の文字列が送られてきた場合、IllegalArgumentExceptionをthrowする

実装した独自PropertyEditorは以下。

package com.daisuzz.samplepropertyeditor.propertyeditor;

import org.springframework.beans.propertyeditors.CustomBooleanEditor;
import org.springframework.lang.Nullable;

public class NullSupportCustomBooleanEditor extends CustomBooleanEditor {

    public NullSupportCustomBooleanEditor(boolean allowEmpty) {
        super(allowEmpty);
    }

    @Override
    public void setAsText(@Nullable String text) throws IllegalArgumentException {
        String input = (text != null ? text.trim() : null);
        if ("null".equalsIgnoreCase(input)) {
            setValue(Boolean.FALSE);
            return;
        }
        super.setAsText(text);
    }
}

Boolean型にバインドしたいので、WebDataBinderを使って登録処理を行う。

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Boolean.class, new NullSupportCustomBooleanEditor(false));
    }

サンプルコードは以下

https://github.com/daisuzz/spring-sandbox/tree/main/sample-property-editor

実際にアプリケーションを立ち上げてリクエストを送ってみるとnullがfalseに変換されていることが確認できた。

$ curl -XGET "http://localhost:8080/person?age=20&canVote=null"
{"age":20,"canVote":false}