Metodebegrensninger med Bean Validation 2.0

1. Oversikt

I denne artikkelen vil vi diskutere hvordan du definerer og validerer metodebegrensninger ved hjelp av Bean Validation 2.0 (JSR-380).

I forrige artikkel diskuterte vi JSR-380 med de innebygde kommentarene, og hvordan du implementerer eiendomsvalidering.

Her vil vi fokusere på de forskjellige typene av metodebegrensninger som:

  • begrensninger for enparameter
  • kryssparameter
  • begrensninger for retur

Vi vil også se på hvordan vi kan validere begrensningene manuelt og automatisk ved hjelp av Spring Validator.

For de følgende eksemplene trenger vi nøyaktig de samme avhengighetene som i Java Bean Validation Basics.

2. Erklæring om metodebegrensninger

For å komme i gang, Vi vil først diskutere hvordan man kan erklære begrensninger for metodeparametere og returverdier for metoder.

Som nevnt tidligere kan vi bruke merknader fra javax.validation.constraints, men vi kan også spesifisere egendefinerte begrensninger (f.eks. for egendefinerte begrensninger eller begrensninger på tvers av parametere).

2.1. Enkeltparameterbegrensninger

Å definere begrensninger for enkeltparametere er grei. Vi må bare legge til merknader til hver parameter etter behov:

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

På samme måte kan vi bruke samme tilnærming for konstruktører:

offentlig klasse Kunde {offentlig kunde (@Size (min = 5, max = 200) @NotNull streng fornavn, @Size (min = 5, max = 200) @NotNull streng etternavn) {this.firstName = firstName; this.lastName = etternavn; } // eiendommer, getters og setters}

2.2. Bruke begrensninger på tvers av parametere

I noen tilfeller kan det hende at vi trenger å validere flere verdier samtidig, for eksempel to numeriske mengder som er større enn den andre.

For disse scenariene kan vi definere egendefinerte begrensninger på tvers av parametere, som kan avhenge av to eller flere parametere.

Tverrparameterbegrensninger kan betraktes som metodevalidering som tilsvarer klassens begrensninger. Vi kan bruke begge til å implementere validering basert på flere egenskaper.

La oss tenke på et enkelt eksempel: en variant av createReservation () metoden fra forrige avsnitt tar to parametere av typen LocalDate: en startdato og en sluttdato.

Derfor vil vi sørge for at det begynne er i fremtiden, og slutt er ute etter begynne. I motsetning til i forrige eksempel, kan vi ikke definere dette ved å bruke begrensninger for en enkelt parameter.

I stedet trenger vi en begrensning på tvers av parametere.

I motsetning til begrensninger med en parameter, kryssparameterbegrensninger blir deklarert på metoden eller konstruktøren:

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

2.3. Opprette begrensninger på tvers av parametere

Å implementere @ConsistentDateParameters begrensning, trenger vi to trinn.

Først må vi definere begrensningsanmerkingen:

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

Her er disse tre egenskapene obligatoriske for begrensningskommentarer:

  • beskjed - returnerer standardnøkkelen for å opprette feilmeldinger, dette gjør at vi kan bruke meldingsinterpolasjon
  • grupper - lar oss spesifisere valideringsgrupper for våre begrensninger
  • nyttelast - kan brukes av klienter i Bean Validation API for å tilordne egendefinerte nyttelastobjekter til en begrensning

For detaljer om hvordan du definerer en tilpasset begrensning, kan du ta en titt på den offisielle dokumentasjonen.

Etter det kan vi definere validatorklassen:

@SupportedValidationTarget (ValidationTarget.PARAMETERS) offentlig klasse ConsistentDateParameterValidator implementerer ConstraintValidator {@Override public boolean isValid (Object [] value, ConstraintValidatorContext context) {if (verdi [0] == null || verdi [1] true {1 = true) ; } hvis (! (verdi [0] forekomst av LocalDate) ||! (verdi [1] forekomst av LocalDate)) {kast ny IllegalArgumentException ("Ulovlig metodesignatur, forventet to parametere av typen LocalDate."); } returner ((LocalDate) verdi [0]). er Etter (LocalDate.now ()) && ((LocalDate) verdi [0]). er Før ((LocalDate) verdi [1]); }}

Som vi kan se, er er gyldig() metoden inneholder den faktiske valideringslogikken. Først sørger vi for at vi får to parametere av typen LocalDate. Etter det sjekker vi om begge er i fremtiden og slutt er ute etter begynne.

Det er også viktig å legge merke til at @SupportedValidationTarget (ValidationTarget.PARAMETERE) kommentar på ConsistentDateParameterValidator klasse er påkrevd. Årsaken til dette er fordi @ConsistentDateParameter er satt på metodenivå, men begrensningene skal brukes på metodeparametrene (og ikke på returverdien til metoden, som vi vil diskutere i neste avsnitt).

Merk: Bean Validation-spesifikasjonen anbefaler å vurdere null-verdier som gyldige. Hvis null er ikke en gyldig verdi, den @Ikke null-kommentar bør brukes i stedet.

2.4. Begrensninger for returverdien

Noen ganger må vi validere et objekt ettersom det returneres etter en metode. For dette kan vi bruke returverdibegrensninger.

Følgende eksempel bruker innebygde begrensninger:

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

Til getAllCustomers (), gjelder følgende begrensninger:

  • Først må ikke den returnerte listen være null og må ha minst en oppføring
  • Videre må ikke listen inneholde null innganger

2.5. Returverdier tilpassede begrensninger

I noen tilfeller kan det hende vi også trenger å validere komplekse objekter:

public class ReservationManagement {@ValidReservation public Reservation getReservationsById (int id) {return null; }}

I dette eksemplet returneres Reservasjon objektet må tilfredsstille begrensningene definert av @ValidReservation, som vi definerer neste.

En gang til, Vi må først definere begrensningsanmerkingen:

@Constraint (validatedBy = ValidReservationValidator.class) @Target ({METHOD, CONSTRUCTOR}) @Retention (RUNTIME) @Documented public @interface ValidReservation {Strengmelding () standard "Sluttdato må være etter startdato" + "og begge må være i fremtiden må romnummeret være større enn 0 "; Klasse [] grupper () standard {}; Klasse [] nyttelast () standard {}; }

Etter det definerer vi validatorklassen:

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

2.6. Avkastningsverdi i konstruktører

Som vi definerte METODE og BYGGER som mål innenfor vårt ValidReservation grensesnitt før, vi kan også kommentere konstruktøren av Reservasjon for å validere konstruerte forekomster:

public class Reservation {@ValidReservation public Reservation (LocalDate begin, LocalDate end, Customer customer, int room) {this.begin = begin; this.end = slutt; denne. kunde = kunde; this.room = rom; } // egenskaper, getters og setters}

2.7. Cascaded Validation

Til slutt lar Bean Validation API oss ikke bare validere enkeltobjekter, men også objektgrafer, ved hjelp av den såkalte kaskadevalideringen.

Derfor kan vi bruke @Gyldig for en kaskadert validering, hvis vi vil validere komplekse objekter. Dette fungerer både for metodeparametere og for returverdier.

La oss anta at vi har en Kunde klasse med noen eiendomsbegrensninger:

offentlig klasse kunde {@Size (min = 5, max = 200) privat streng fornavn; @Size (min = 5, max = 200) privat streng etternavn; // constructor, getters and setters}

EN Reservasjon klassen kan ha en Kunde eiendom, samt ytterligere eiendommer med begrensninger:

Offentlig klasse Reservation {@Valid privat kundekunde; @Positivt privat int rom; // ytterligere egenskaper, konstruktør, getters og setters}

Hvis vi nå refererer Reservasjon som en metodeparameter, vi kan tvinge rekursiv validering av alle eiendommer:

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

Som vi ser, bruker vi @Gyldig to steder:

  • reservasjon-parameter: det utløser validering av Reservasjon-objekt, når createNewCustomer () er kalt
  • Siden vi har en nestet objektgraf her, må vi også legge til en @Gyldigkunde-attributt: dermed utløser det validering av denne nestede egenskapen

Dette fungerer også for metoder som returnerer et objekt av typen Reservasjon:

@Valid public Reservation getReservationById (int id) {return null; }

3. Valideringsmetodebegrensninger

Etter erklæringen om begrensninger i forrige avsnitt, kan vi nå fortsette med å faktisk validere disse begrensningene. For det har vi flere tilnærminger.

3.1. Automatisk validering med vår

Spring Validation gir en integrasjon med Hibernate Validator.

Merk: Vårvalidering er basert på AOP og bruker Spring AOP som standardimplementering. Derfor fungerer validering bare for metoder, men ikke for konstruktører.

Hvis vi nå vil at våren skal validere begrensningene våre automatisk, må vi gjøre to ting:

For det første må vi kommentere bønnene, som skal valideres, med @Validert:

@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 andre må vi gi en MethodValidationPostProcessor bønne:

@Configuration @ComponentScan ({"org.baeldung.javaxval.methodvalidation.model"}) offentlig klasse MethodValidationConfig {@Bean public MethodValidationPostProcessor methodValidationPostProcessor () {return new MethodValidationPostProcessor (); }}

Containeren vil nå kaste en javax.validation.ConstraintViolationException, hvis en begrensning blir brutt.

Hvis vi bruker Spring Boot, vil containeren registrere en MethodValidationPostProcessor bønne for oss så lenge dvalemodus er i klassestien.

3.2. Automatisk validering med CDI (JSR-365)

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

Hvis applikasjonen vår kjører i en Jakarta EE-container, vil beholderen automatisk validere metodebegrensninger på påkallingstidspunktet.

3.3. Programmatisk validering

Til manuell metodevalidering i et frittstående Java-program, kan vi bruke javax.validation.executable.ExecutableValidator grensesnitt.

Vi kan hente en forekomst ved hjelp av følgende kode:

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

ExecutableValidator tilbyr fire metoder:

  • validateParameters () og validateReturnValue () for metodevalidering
  • validateConstructorParameters () og validateConstructorReturnValue () for validering av konstruktører

Validering av parametrene til vår første metode createReservation () vil se slik ut:

ReservationManagement object = new ReservationManagement (); Metodemetode = ReservationManagement.class .getMethod ("createReservation", LocalDate.class, int.class, Customer.class); Objekt [] parameterValues ​​= {LocalDate.now (), 0, null}; Sett brudd = executableValidator.validateParameters (objekt, metode, parameterValues);

Merk: Den offisielle dokumentasjonen fraråder å ringe dette grensesnittet direkte fra applikasjonskoden, men å bruke det via en metode for avlyttingsteknologi, som AOP eller fullmakter.

I tilfelle du er interessert i hvordan du bruker ExecutableValidator grensesnitt, kan du ta en titt på den offisielle dokumentasjonen.

4. Konklusjon

I denne veiledningen så vi raskt på hvordan du bruker metodebegrensninger med Hibernate Validator, og vi diskuterte også noen nye funksjoner i JSR-380.

Først diskuterte vi hvordan man kunne erklære forskjellige typer begrensninger:

  • Begrensninger for enkeltparameter
  • Kryssparameter
  • Begrensninger for returverdien

Vi har også sett på hvordan vi kan validere begrensningene manuelt og automatisk ved hjelp av Spring Validator.

Som alltid er hele kildekoden til eksemplene tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found