Springカスタムプロパティエディタ

Springカスタムプロパティエディター

1. 前書き

簡単に言えば、SpringはString値とカスタムObject型の間の変換を管理するためにプロパティエディターを多用します。これはJava Beans PropertyEditorに基づいています。

このチュートリアルでは、automatic property editor binding and custom property editor bindingを示すための2つの異なるユースケースについて説明します。

2. プロパティエディタの自動バインド

標準のJavaBeansインフラストラクチャは、処理するクラスと同じパッケージにある場合、PropertyEditorクラスを自動的に検出します。 また、これらはそのクラスと同じ名前にEditorサフィックスを加えたものである必要があります。

たとえば、CreditCardモデルクラスを作成する場合は、エディタークラスにCreditCardEditor.という名前を付ける必要があります。

a practical property binding example.を見てみましょう

このシナリオでは、リクエストURLのパス変数としてクレジットカード番号を渡し、その値をa CreditCardオブジェクトとしてバインドします。

まず、フィールドrawCardNumber,の銀行識別番号(最初の6桁)、口座番号(7〜15の数字)、およびチェックコード(最後の桁)を定義するCreditCardモデルクラスを作成しましょう。

public class CreditCard {

    private String rawCardNumber;
    private Integer bankIdNo;
    private Integer accountNo;
    private Integer checkCode;

    // standard constructor, getters, setters
}

次に、CreditCardEditorクラスを作成します。 これにより、Stringとして指定されたクレジットカード番号をCreditCardオブジェクトに変換するためのビジネスロジックが実装されます。

プロパティエディタクラスは、PropertyEditorSupportを拡張し、getAsText()およびsetAsText()メソッドを実装する必要があります。

public class CreditCardEditor extends PropertyEditorSupport {

    @Override
    public String getAsText() {
        CreditCard creditCard = (CreditCard) getValue();

        return creditCard == null ? "" : creditCard.getRawCardNumber();
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if (StringUtils.isEmpty(text)) {
            setValue(null);
        } else {
            CreditCard creditCard = new CreditCard();
            creditCard.setRawCardNumber(text);

            String cardNo = text.replaceAll("-", "");
            if (cardNo.length() != 16)
                throw new IllegalArgumentException(
                  "Credit card format should be xxxx-xxxx-xxxx-xxxx");

            try {
                creditCard.setBankIdNo( Integer.valueOf(cardNo.substring(0, 6)) );
                creditCard.setAccountNo( Integer.valueOf(
                  cardNo.substring(6, cardNo.length() - 1)) );
                creditCard.setCheckCode( Integer.valueOf(
                  cardNo.substring(cardNo.length() - 1)) );
            } catch (NumberFormatException nfe) {
                throw new IllegalArgumentException(nfe);
            }

            setValue(creditCard);
        }
    }
}

getAsText()メソッドは、オブジェクトをString,にシリアル化するときに呼び出され、setAsText()Stringを別のオブジェクトに変換するために使用されます。

これらのクラスは同じパッケージ内にあるため、タイプCreditCardEditorをバインドするために他に何もする必要はありません。

これをRESTAPIのリソースとして公開できるようになりました。この操作では、クレジットカード番号を要求パス変数として受け取り、Springはそのテキスト値をCrediCardオブジェクトとしてバインドし、メソッド引数として渡します。

@GetMapping(value = "/credit-card/{card-no}",
  produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public CreditCard parseCreditCardNumber(
    @PathVariable("card-no") CreditCard creditCard) {
    return creditCard;
}

たとえば、サンプルのリクエストURL/property-editor/credit-card/1234-1234-1111-0019,の場合、次のような応答が返されます。

{
    "rawCardNumber": "1234-1234-1111-0011",
    "bankIdNo": 123412,
    "accountNo": 341111001,
    "checkCode": 9
}

3. カスタムプロパティエディタのバインド

同じパッケージに必要な型クラスとプロパティエディタクラスがない場合、または予想される命名規則がある場合は、必要な型とプロパティエディタの間にカスタムバインディングを定義する必要があります。

カスタムプロパティエディタのバインドシナリオでは、String値がパス変数としてURLに渡され、その値を属性として保持するだけのExoticTypeオブジェクトとしてバインドします。

セクション2と同様に、最初にモデルクラスExoticType:を作成しましょう。

public class ExoticType {
    private String name;

    // standard constructor, getters, setters
}

また、PropertyEditorSupport: を拡張するカスタムプロパティエディタクラスCustomExoticTypeEditor

public class CustomExoticTypeEditor extends PropertyEditorSupport {

    @Override
    public String getAsText() {
        ExoticType exoticType = (ExoticType) getValue();
        return exoticType == null ? "" : exoticType.getName();
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        ExoticType exoticType = new ExoticType();
        exoticType.setName(text.toUpperCase());

        setValue(exoticType);
    }
}

Springはプロパティエディタを検出できないため、we’ll need a method annotated with @InitBinder in our Controller class that registers the editor:

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.registerCustomEditor(ExoticType.class,
        new CustomExoticTypeEditor());
}

次に、ユーザー入力をExoticTypeオブジェクトにバインドできます。

@GetMapping(
  value = "/exotic-type/{value}",
  produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ExoticType parseExoticType(
  @PathVariable("value") ExoticType exoticType) {
    return exoticType;
}

サンプルリクエストURL/property-editor/exotic-type/passion-fruit, の場合、サンプルレスポンスを取得します。

{
    "name": "PASSION-FRUIT"
}

4. 結論

この簡単な記事では、自動およびカスタムのプロパティエディタバインディングを使用して、人間が読み取れるString値を複雑なJavaタイプに変換する方法を説明しました。

ここでの例の完全なソースコードは、いつものように、over on GitHubです。