Spring Custom Property Editor

Éditeur de propriétés personnalisées Spring

1. introduction

En termes simples, Spring utilise fortement les éditeurs de propriétés pour gérer la conversion entre les valeursString et les typesObject personnalisés; ceci est basé surJava Beans PropertyEditor.

Dans ce didacticiel, nous allons passer en revue deux cas d'utilisation différents pour la démonstration deautomatic property editor binding and custom property editor binding.

2. Liaison automatique de l'éditeur de propriétés

L'infrastructure standard deJavaBeans découvrira automatiquement les classes dePropertyEditor si elles sont dans le même package que la classe qu'elles gèrent. En outre, ceux-ci doivent avoir le même nom que cette classe plus le suffixeEditor.

Par exemple, si nous créons une classe de modèleCreditCard, nous devrions nommer la classe d'éditeurCreditCardEditor.

Passons maintenant àa practical property binding example.

Dans notre scénario, nous transmettrons un numéro de carte de crédit comme variable de chemin dans l'URL de la demande, et nous lierons cette valeur en tant qu'objeta CreditCard.

Créons d'abord la classe de modèleCreditCard définissant les champsrawCardNumber, Numéro d'identification bancaire (les 6 premiers chiffres), Numéro de compte (chiffres de 7 à 15) et Code de chèque (dernier chiffre):

public class CreditCard {

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

    // standard constructor, getters, setters
}

Ensuite, nous allons créer la classeCreditCardEditor. Ceci implémente la logique métier pour convertir le numéro de carte de crédit donné sous forme deString en objetCreditCard.

La classe de l'éditeur de propriétés doit étendrePropertyEditorSupport et implémenter les méthodesgetAsText() etsetAsText():

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);
        }
    }
}

La méthodegetAsText() est appelée lors de la sérialisation d'un objet en unString, tandis quesetAsText() est utilisé pour convertir unString en un autre objet.

Comme ces classes sont situées dans le même package, nous n'avons rien d'autre à faire pour lier lesEditor pour le typeCreditCard.

Nous pouvons maintenant exposer ceci en tant que ressource dans une API REST; l'opération prend un numéro de carte de crédit comme variable de chemin de demande et Spring liera cette valeur de texte en tant qu'objetCrediCard et la passera comme argument de méthode:

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

Par exemple, pour un exemple d'URL de requête/property-editor/credit-card/1234-1234-1111-0019,, nous obtiendrons la réponse:

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

3. Liaison de l'éditeur de propriétés personnalisées

Si nous n'avons pas la classe de type requise et la classe de l'éditeur de propriété dans le même package ou avec les conventions de dénomination attendues, nous devrons définir une liaison personnalisée entre le type requis et l'éditeur de propriété.

Dans notre scénario de liaison d'éditeur de propriétés personnalisées, une valeurString sera transmise dans l'URL en tant que variable de chemin, et nous lierons cette valeur en tant qu'objetExoticType qui conserve simplement la valeur en tant qu'attribut.

Comme dans la section 2, commençons par créer une classe de modèleExoticType:

public class ExoticType {
    private String name;

    // standard constructor, getters, setters
}

Et notre classe d'éditeur de propriétés personnaliséesCustomExoticTypeEditor qui étend à nouveauPropertyEditorSupport: 

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);
    }
}

Puisque Spring ne peut pas détecter l'éditeur de propriétés,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());
}

Ensuite, nous pouvons lier l'entrée utilisateur à l'objetExoticType:

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

Pour l'exemple d'URL de requête/property-editor/exotic-type/passion-fruit, , swe obtiendra l'exemple de réponse:

{
    "name": "PASSION-FRUIT"
}

4. Conclusion

Dans cet article rapide, nous avons vu comment utiliser la liaison automatique et personnalisée de l'éditeur de propriétés pour convertir les valeursString lisibles par l'homme en types Java complexes.

Le code source complet de nos exemples ici est, comme toujours,over on GitHub.