Metodebegrænsninger med Bean Validation 2.0

1. Oversigt

I denne artikel vil vi diskutere, hvordan man definerer og validerer metodebegrænsninger ved hjælp af Bean Validation 2.0 (JSR-380).

I den forrige artikel diskuterede vi JSR-380 med dens indbyggede kommentarer, og hvordan man implementerer ejendomsvalidering.

Her vil vi fokusere på de forskellige typer metodebegrænsninger såsom:

  • begrænsninger med en enkelt parameter
  • tværparameter
  • returbegrænsninger

Vi vil også se på, hvordan man validerer begrænsningerne manuelt og automatisk ved hjælp af Spring Validator.

I de følgende eksempler har vi brug for nøjagtigt de samme afhængigheder som i Java Bean Validation Basics.

2. Erklæring om metodebegrænsninger

For at komme i gang, vi vil først diskutere, hvordan man erklærer begrænsninger for metodeparametre og returværdier for metoder.

Som nævnt før kan vi bruge kommentarer fra javax.validation.constraints, men vi kan også specificere brugerdefinerede begrænsninger (f.eks. for brugerdefinerede begrænsninger eller grænseoverskridende begrænsninger).

2.1. Begrænsninger for en enkelt parameter

At definere begrænsninger for enkelte parametre er ligetil. Vi er simpelthen nødt til at tilføje kommentarer til hver parameter efter behov:

offentlig ugyldig createReservation (@NotNull @Future LocalDate begynder, @Min (1) int varighed, @NotNull kundekunde) {// ...}

På samme måde kan vi bruge den samme tilgang til konstruktører:

offentlig klasse Kunde {offentlig kunde (@Size (min = 5, max = 200) @NotNull String firstName, @Size (min = 5, max = 200) @NotNull String lastName) {this.firstName = firstName; this.lastName = efternavn; } // egenskaber, getters og setters}

2.2. Brug af tværparameterbegrænsninger

I nogle tilfælde er vi muligvis nødt til at validere flere værdier på én gang, f.eks. Er to numeriske beløb den ene større end den anden.

For disse scenarier kan vi definere brugerdefinerede begrænsninger på tværs af parametre, som kan afhænge af to eller flere parametre.

Tværparameterbegrænsninger kan betragtes som metodevalidering svarende til begrænsninger på klasseniveau. Vi kunne bruge begge dele til at implementere validering baseret på flere egenskaber.

Lad os tænke på et simpelt eksempel: en variation af createReservation () metode fra det foregående afsnit tager to parametre af typen LocalDate: en startdato og en slutdato.

Derfor vil vi sikre os det begynde er i fremtiden, og ende er efter begynde. I modsætning til i det foregående eksempel kan vi ikke definere dette ved hjælp af begrænsninger for en enkelt parameter.

I stedet har vi brug for en begrænsning på tværs af parametre.

I modsætning til begrænsninger med en enkelt parameter, grænseoverskridende begrænsninger erklæres på metoden eller konstruktøren:

@ConsistentDateParameters public void createReservation (LocalDate begin, LocalDate end, Customer customer) {// ...}

2.3. Oprettelse af grænseoverskridende parametre

At implementere @ConsistentDateParameters begrænsning, har vi brug for to trin.

Først skal vi definere begrænsningskommentarer:

@Constraint (validatedBy = ConsistentDateParameterValidator.class) @Target ({METHOD, CONSTRUCTOR}) @Retention (RUNTIME) @Documented public @interface ConsistentDateParameters {Strengmeddelelse () standard "Slutdato skal være efter startdato og begge skal være i fremtiden "; Klasse [] grupper () standard {}; Klasse [] nyttelast () standard {}; }

Her er disse tre egenskaber obligatoriske for begrænsningskommentarer:

  • besked - returnerer standardnøglen til oprettelse af fejlmeddelelser, dette gør det muligt for os at bruge meddelelsesinterpolation
  • grupper - giver os mulighed for at specificere valideringsgrupper for vores begrænsninger
  • nyttelast - kan bruges af klienter i Bean Validation API til at tildele brugerdefinerede nyttelastgenstande til en begrænsning

For detaljer om, hvordan du definerer en brugerdefineret begrænsning, skal du kigge på den officielle dokumentation.

Derefter kan vi definere validatorklassen:

@SupportedValidationTarget (ValidationTarget.PARAMETERS) public class ConsistentDateParameterValidator implementerer ConstraintValidator {@Override public boolean isValid (Object [] value, ConstraintValidatorContext context) {if (værdi [0] == null || værdi [1] true {1 = true) ; } hvis (! (værdi [0] forekomst af LocalDate) ||! (værdi [1] forekomst af LocalDate)) {kast ny IllegalArgumentException ("Ulovlig metodesignatur, forventet to parametre af typen LocalDate."); } returner ((LocalDate) værdi [0]). er Efter (LocalDate.now ()) && ((LocalDate) værdi [0]). er Før ((LocalDate) værdi [1]); }}

Som vi kan se, er er gyldig() metoden indeholder den faktiske valideringslogik. Først sørger vi for, at vi får to parametre af typen LocalDate. Derefter kontrollerer vi, om begge er i fremtiden og ende er efter begynde.

Det er også vigtigt at bemærke, at @SupportedValidationTarget (ValidationTarget.PARAMETRE) kommentar på ConsistentDateParameterValidator klasse er påkrævet. Årsagen til dette er fordi @ConsistentDateParameter er indstillet på metodeniveau, men begrænsningerne skal anvendes på metodeparametrene (og ikke på metodens returværdi, som vi vil diskutere i det næste afsnit).

Bemærk: Bean Validation-specifikationen anbefaler at overveje nul-værdier som gyldige. Hvis nul er ikke en gyldig værdi, @NotNull-anmærkning skal bruges i stedet.

2.4. Begrænsninger for returneringsværdi

Nogle gange skal vi validere et objekt, da det returneres ved hjælp af en metode. Til dette kan vi bruge begrænsninger for returværdi.

Følgende eksempel bruger indbyggede begrænsninger:

public class ReservationManagement {@NotNull @Size (min = 1) public List getAllCustomers () {return null; }}

Til getAllCustomers (), gælder følgende begrænsninger:

  • For det første må den returnerede liste ikke være nul og skal have mindst en post
  • Desuden må listen ikke indeholde nul poster

2.5. Returværdi tilpassede begrænsninger

I nogle tilfælde skal vi muligvis også validere komplekse objekter:

offentlig klasse ReservationManagement {@ValidReservation offentlig reservation getReservationsById (int id) {return null; }}

I dette eksempel returneres Reservation objektet skal opfylde de begrænsninger, der er defineret af @ValidReservation, som vi definerer næste.

Igen, vi er først nødt til at definere begrænsningsannotationen:

@Constraint (validatedBy = ValidReservationValidator.class) @Target ({METHOD, CONSTRUCTOR}) @Retention (RUNTIME) @Documented public @interface ValidReservation {Strengmeddelelse () standard "Slutdato skal være efter startdato" + "og begge skal være i fremtiden skal værelsesnummeret være større end 0 "; Klasse [] grupper () standard {}; Klasse [] nyttelast () standard {}; }

Derefter definerer vi validatorklassen:

offentlig klasse ValidReservationValidator implementerer ConstraintValidator {@Override public boolean isValid (Reservation reservation, ConstraintValidatorContext context) {if (reservation == null) {return true; } if (! (reservation instanceof Reservation)) {throw new IllegalArgumentException ("Illegal method signatur," + "forventet parameter af typen Reservation."); } hvis (reservation.getBegin () == null || reservation.getEnd () == null || reservation.getCustomer () == null) {returner falsk; } returner (reservation.getBegin (). isAfter (LocalDate.now ()) && reservation.getBegin (). isBefore (reservation.getEnd ()) && reservation.getRoom ()> 0); }}

2.6. Returværdi i konstruktører

Som vi definerede METODE og BYGGER som mål inden for vores ValidReservation interface før, vi kan også kommentere konstruktøren af Reservation for at validere konstruerede forekomster:

public class Reservation {@ValidReservation public Reservation (LocalDate begin, LocalDate end, Customer customer, int room) {this.begin = begin; this.end = ende; this.customer = kunde; this.room = værelse; } // egenskaber, getters og setters}

2.7. Kaskaderet validering

Endelig giver Bean Validation API os mulighed for ikke kun at validere enkelte objekter, men også objektgrafer ved hjælp af den såkaldte kaskadevalidering.

Derfor kan vi bruge @Gyldig til en kaskadevalidering, hvis vi vil validere komplekse objekter. Dette fungerer både for metodeparametre og for returværdier.

Lad os antage, at vi har en Kunde klasse med nogle egenskabsbegrænsninger:

offentlig klasse kunde {@Size (min = 5, max = 200) privat streng fornavn; @Size (min = 5, max = 200) privat streng efternavn; // konstruktør, getters og setters}

EN Reservation klasse kan have en Kunde ejendom samt yderligere egenskaber med begrænsninger:

offentlig klassereservation {@Valid privat kundekunde; @Positive private int værelse; // yderligere egenskaber, konstruktør, getters og setter}

Hvis vi nu henviser Reservation som en metodeparameter vi kan tvinge den rekursive validering af alle egenskaber:

public void createNewCustomer (@Valid Reservation reservation) {// ...}

Som vi kan se, bruger vi @Gyldig to steder:

  • På den reservation-parameter: det udløser validering af Reservation-objekt, hvornår createNewCustomer () Hedder
  • Da vi har en indlejret objektgraf her, skal vi også tilføje en @Gyldig på den kunde-attribut: derved udløser det validering af denne indlejrede ejendom

Dette fungerer også for metoder, der returnerer et objekt af typen Reservation:

@Valid offentlig reservation getReservationById (int id) {return null; }

3. Valideringsmetodebegrænsninger

Efter erklæringen om begrænsninger i det foregående afsnit kan vi nu fortsætte med at validere disse begrænsninger. Til det har vi flere tilgange.

3.1. Automatisk validering med fjeder

Spring Validation giver en integration med Hibernate Validator.

Bemærk: Spring Validation er baseret på AOP og bruger Spring AOP som standardimplementering. Derfor fungerer validering kun for metoder, men ikke for konstruktører.

Hvis vi nu ønsker, at Spring automatisk validerer vores begrænsninger, er vi nødt til at gøre to ting:

For det første skal vi kommentere bønnerne, som skal valideres, med @Valideret:

@Validated public class ReservationManagement {public void createReservation (@NotNull @Future LocalDate begin, @Min (1) int duration, @NotNull Customer customer) {// ...} @NotNull @Size (min = 1) public List getAllCustomers ( ) {return null; }}

For det andet skal vi give en MethodValidationPostProcessor bønne:

@Configuration @ComponentScan ({"org.baeldung.javaxval.methodvalidation.model"}) public class MethodValidationConfig {@Bean public MethodValidationPostProcessor methodValidationPostProcessor () {returner ny MethodValidationPostProcessor (); }}

Containeren vil nu kaste en javax.validation.ConstraintViolationException, hvis en begrænsning overtrædes.

Hvis vi bruger Spring Boot, vil containeren registrere en MethodValidationPostProcessor bønne til os så længe dvale-validator er i klassestien.

3.2. Automatisk validering med CDI (JSR-365)

Fra version 1.1 fungerer Bean Validation med CDI (Contexts and Dependency Injection for Jakarta EE).

Hvis vores applikation kører i en Jakarta EE-container, validerer containeren automatisk metodebegrænsninger på tidspunktet for påkaldelsen.

3.3. Programmatisk validering

Til manuel metodevalidering i et enkeltstående Java-program, kan vi bruge javax.validation.executable.ExecutableValidator interface.

Vi kan hente en forekomst ved hjælp af følgende kode:

ValidatorFactory fabrik = Validation.buildDefaultValidatorFactory (); ExecutableValidator executableValidator = factory.getValidator (). ForExecutables ();

ExecutableValidator tilbyder fire metoder:

  • validateParameters () og validateReturnValue () til metodevalidering
  • validateConstructorParameters () og validateConstructorReturnValue () til validering af konstruktører

Validering af parametrene for vores første metode createReservation () ville se sådan ud:

ReservationManagement-objekt = nyt ReservationManagement (); Metodemetode = ReservationManagement.class .getMethod ("createReservation", LocalDate.class, int.class, Customer.class); Objekt [] parameterValues ​​= {LocalDate.now (), 0, null}; Sæt overtrædelser = eksekverbarValidator.validateParameters (objekt, metode, parameterValues);

Bemærk: Den officielle dokumentation fraråder at ringe til denne grænseflade direkte fra applikationskoden, men at bruge den via en metode til aflytningsteknologi, såsom AOP eller proxyer.

Hvis du er interesseret i, hvordan du bruger ExecutableValidator interface, kan du se på den officielle dokumentation.

4. Konklusion

I denne vejledning havde vi et hurtigt kig på, hvordan man bruger metodebegrænsninger med Hibernate Validator, og vi diskuterede også nogle nye funktioner i JSR-380.

Først diskuterede vi, hvordan man erklærer forskellige typer begrænsninger:

  • Begrænsninger for en enkelt parameter
  • Kryds-parameter
  • Begrænsninger for returværdi

Vi har også kigget på, hvordan man validerer begrænsningerne manuelt og automatisk ved hjælp af Spring Validator.

Som altid er den fulde kildekode for eksemplerne tilgængelig på GitHub.