Vincoli specifici del validatore di ibernazione

1. Panoramica

In questo tutorial, esamineremo i vincoli di Hibernate Validator, che sono incorporati in Hibernate Validator ma non rientrano nelle specifiche di Bean Validation.

Per un riepilogo della convalida dei bean, fare riferimento al nostro articolo sulle nozioni di base sulla convalida di Java Bean.

2. Configurazione del validatore ibernato

Per lo meno, dovremmo aggiungere Hibernate Validator alle nostre dipendenze:

 org.hibernate.validator hibernate-validator 6.0.16.Final 

Nota che Hibernate Validator non dipende da Hibernate, l'ORM, che abbiamo trattato in molti altri articoli.

Inoltre, alcune delle annotazioni che introdurremo si applicano solo se il nostro progetto utilizza determinate librerie. Quindi, per ognuno di questi, indicheremo le dipendenze necessarie.

3. Convalida dei valori relativi al denaro

3.1. Convalida dei numeri di carta di credito

I numeri di carta di credito validi devono soddisfare un checksum, che calcoliamo utilizzando l'algoritmo di Luhn. Il vincolo @CreditCardNumber riesce quando una stringa soddisfa il checksum.

@CreditCardNumber non esegue nessun altro controllo sulla stringa di input. In particolare, non controlla la lunghezza dell'ingresso. Pertanto, può rilevare solo numeri non validi a causa di un piccolo errore di battitura.

Nota che, per impostazione predefinita, il vincolo fallisce se la stringa contiene caratteri che non sono cifre, ma possiamo dirgli di ignorarli:

@CreditCardNumber(ignoreNonDigitCharacters = true) private String lenientCreditCardNumber;

Quindi, possiamo includere caratteri come spazi o trattini:

validations.setLenientCreditCardNumber("7992-7398-713"); constraintViolations = validator.validateProperty(validations, "lenientCreditCardNumber"); assertTrue(constraintViolations.isEmpty());

3.2. Convalida dei valori monetari

Il validatore @Currency controlla se un determinato importo monetario è nella valuta specificata:

@Currency("EUR") private MonetaryAmount balance;

La classe MonetaryAmount fa parte di Java Money. Pertanto, @Currency si applica solo quando è disponibile un'implementazione di Java Money.

Una volta impostato correttamente Java Money, possiamo verificare il vincolo:

bean.setBalance(Money.of(new BigDecimal(100.0), Monetary.getCurrency("EUR"))); constraintViolations = validator.validateProperty(bean, "balance"); assertEquals(0, constraintViolations.size());

4. Validazione degli intervalli

4.1. Gamme numeriche e monetarie

La specifica di convalida del bean definisce diversi vincoli che possiamo applicare ai campi numerici. Oltre a questi, Hibernate Validator fornisce una comoda annotazione, @Range , che funge da combinazione di @Min e @Max, facendo corrispondere un intervallo in modo inclusivo:

@Range(min = 0, max = 100) private BigDecimal percent;

Come @Min e @Max , @Range è applicabile ai campi di tipi di numeri primitivi e ai relativi wrapper; BigInteger e BigDecimal , rappresentazioni di stringa dei campi precedenti e, infine, MonetaryValue .

4.2. Durata del tempo

Oltre alle annotazioni JSR 380 standard per i valori che rappresentano punti nel tempo, Hibernate Validator include anche vincoli per Durata s. Assicurati di controllare prima le classi Periodo e Durata di Java Time.

Quindi, possiamo applicare durate minime e massime su una proprietà:

@DurationMin(days = 1, hours = 2) @DurationMax(days = 2, hours = 1) private Duration duration;

Anche se non li abbiamo mostrati tutti qui, l'annotazione ha parametri per tutte le unità di tempo, dai nanosecondi ai giorni.

Si noti che, per impostazione predefinita, i valori minimo e massimo sono inclusi. Vale a dire, un valore che è esattamente uguale al minimo o al massimo supererà la convalida.

Se vogliamo che i valori limite non siano validi, definiamo invece falsa la proprietà inclusiva :

@DurationMax(minutes = 30, inclusive = false)

5. Convalida delle stringhe

5.1. Lunghezza della stringa

Possiamo usare due vincoli leggermente diversi per imporre che una stringa sia di una certa lunghezza.

In generale, vogliamo assicurarci che la lunghezza di una stringa in caratteri, quella che misuriamo con il metodo della lunghezza , sia compresa tra un minimo e un massimo. In tal caso, utilizziamo @Length su una proprietà o un campo String:

@Length(min = 1, max = 3) private String someString;

Tuttavia, a causa della complessità di Unicode, a volte la lunghezza in caratteri e la lunghezza in punti di codice differiscono. Quando vogliamo controllare quest'ultimo, usiamo @CodePointLength:

@CodePointLength(min = 1, max = 3) private String someString;

Ad esempio, la stringa "aa \ uD835 \ uDD0A" è lunga 4 caratteri, ma contiene solo 3 punti di codice, quindi fallirà il primo vincolo e supererà il secondo.

Inoltre, con entrambe le annotazioni, possiamo omettere il valore minimo o massimo.

5.2. Controlli su stringhe di cifre

Abbiamo già visto come verificare che una stringa sia un numero di carta di credito valido. Tuttavia, Hibernate Validator include diversi altri vincoli per le stringhe di cifre.

The first one we're reviewing is @LuhnCheck. This is the generalized version of @CreditCardNumber, in that it performs the same check, but allows for additional parameters:

@LuhnCheck(startIndex = 0, endIndex = Integer.MAX_VALUE, checkDigitIndex = -1) private String someString;

Here, we've shown the default values of the parameters, so the above is equivalent to a simple @LuhnCheck annotation.

But, as we can see, we can perform the check on a substring (startIndex and endIndex) and tell the constraint which digit is the checksum digit, with -1 meaning the last one in the checked substring.

Other interesting constraints include the modulo 10 check (@Mod10Check) and the modulo 11 check (@Mod11Check), which are typically used for barcodes and other codes such as ISBN.

However, for those specific cases, Hibernate Validator happens to provide a constraint to validate ISBN codes, @ISBN, as well as an @EAN constraint for EAN barcodes.

5.3. URL and HTML Validation

The @Url constraint verifies that a string is a valid representation of a URL. Additionally, we can check that specific component of the URL has a certain value:

@URL(protocol = "https") private String url;

We can thus check the protocol, the host and the port. If that's not sufficient, there's a regexp property that we can use to match the URL against a regular expression.

We can also verify that a property contains “safe” HTML code (for example, without script tags):

@SafeHtml private String html;

@SafeHtml uses the JSoup library, which must be included in our dependencies.

We can tailor the HTML sanitization to our needs using built-in tag whitelists (the whitelist property of the annotation) and including additional tags and attributes (the additionalTags and additionalTagsWithAttributes parameters).

6. Other Constraints

Let's mention briefly that Hibernate Validator includes some country and locale-specific constraints, in particular for some Brazilian and Polish identification numbers, taxpayer codes and similar. Please refer to the relevant section of the documentation for a full list.

Also, we can check that a collection does not contain duplicates with @UniqueElements.

Finally, for complex cases not covered by existing annotations, we can invoke a script written in a JSR-223 compatible scripting engine. We've, of course, touched on JSR-223 in our article about Nashorn, the JavaScript implementation included in modern JVMs.

In this case, the annotation is at the class level, and the script is invoked on the entire instance, passed as the variable _this:

@ScriptAssert(lang = "nashorn", script = "_this.valid") public class AdditionalValidations { private boolean valid = true; // standard getters and setters }

Then, we can check the constraint on the whole instance:

bean.setValid(false); constraintViolations = validator.validate(bean); assertEquals(1, constraintViolations.size());

7. Conclusione

In questo articolo, abbiamo elencato i vincoli in Hibernate Validator che vanno oltre il set minimo definito nella specifica Bean Validation.

L'implementazione di tutti questi esempi e frammenti di codice può essere trovata su GitHub.