1前書き

簡単に言うと、Springは

String

値とカスタム

Object

型の間の変換を管理するためにプロパティエディタを多用しています。これはhttps://docs.oracle.com/javase/8/docs/api/java/beans/PropertyEditor.html[Java Beans PropertyEditor]に基づいています。

このチュートリアルでは、

自動プロパティエディタバインディングとカスタムプロパティエディタバインディング

のデモンストレーションについて、2つの異なるユースケースについて説明します。


2自動プロパティエディタバインディング

それらが扱うクラスと同じパッケージにある場合、標準の

JavaBeans

インフラストラクチャは自動的に

PropertyEditor

クラスを発見します。また、これらはそのクラスと同じ名前に

Editor

サフィックスを付けたものである必要があります。

たとえば、

CreditCard

モデルクラスを作成する場合は、エディタクラスに__CreditCardEditorという名前を付けます。

それでは、実際のプロパティバインディングの例を見てみましょう。

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

最初に、

rawCardNumber、

Bank Identification Number(最初の6桁)、Account Number(7〜15の数字)、Check Code(最後の桁)の各フィールドを定義する

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__を別のオブジェクトに変換するために使用されます。

これらのクラスは同じパッケージ内にあるので、

Editor



CreditCard

型にバインドするために他に必要な作業はありません。

これをREST APIのリソースとして公開できます。操作はリクエストパス変数としてクレジットカード番号を取り、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
}

そして私たちのカスタムプロパティエディタクラス

CustomExoticTypeEditor

は、やはり


_PropertyEditorSupportを継承しています:

_




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はプロパティエディタを検出できないので、エディタを登録する

Controller

クラスに

@ InitBinder

というアノテーションを付けたメソッドが必要です。

@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型に変換する方法を説明しました。

私たちの例の完全なソースコードは、いつものように、https://github.com/eugenp/tutorials/tree/master/spring-rest[GitHubでの使用]です。