11_Validation

Code-Dateien

DateinameAktion
CODECode_Bank.zipDownload
CODECode_Pizza.zipDownload
CODECode_Urlaub.zipDownload

Videos

DateinameAktion
VIDEOVideo_Bank_DAbspielen
VIDEOVideo_Pizza_EAbspielen
VIDEOVideo_Urlaub_DAbspielen

Lernmaterialien

Validation

set Validation

    public void setPrice(Double price) throws PizzaOrderException {
        if (price < 8)
            throw new PizzaOrderException("The min. price is 8.0 Eur");
        if (price > 30)
            throw new PizzaOrderException("The max. price is 30.0 Eur");

        this.price = price;
    }

    public void setSize(String size) throws PizzaOrderException {
        if (Arrays.asList(sizes).contains(size) == false)
            throw new PizzaOrderException("Wrong size must be: " + sizes.toString());
        this.size = size;
    }

The problem is:

  • Spring does not automatically know this is your validation rule
  • Vaadin Binder does not automatically know it
  • JPA/Hibernate does not automatically use it as Bean Validation metadata

So you must remember to call that logic yourself everywhere, or catch exceptions everywhere.

Jakarta Bean Validation

Jakarta Bean Validation is the standard Java validation API for declaring rules on objects and having them checked automatically or programmatically. The Jakarta specification describes it as a facility for validating objects, object members, methods, and constructors, plus a metadata/query API for constraints.

PizzaOrder.java

public class PizzaOrder {

    @NotNull(message = "Price is required")
    @DecimalMin(value = "8.0", message = "The min. price is 8.0 Eur")
    @DecimalMax(value = "30.0", message = "The max. price is 30.0 Eur")
    private Double price;

When you use Bean Validation annotations like @NotNull, @DecimalMin, or @Email, many Java frameworks can see those rules and run them automatically.

So instead of writing validation manually in every setter, controller, form, or save method, you declare the rule once on the field, and the framework uses it.

Of course — here it is again, now with custom error messages.

Most important constraints

Required value

@NotNull

Value must not be null.

@NotNull(message = "Price is required")
private Double price;

@NotEmpty

For strings, collections, arrays: must not be null and not empty.

@NotEmpty(message = "The list must not be empty")
private List<String> toppings;

@NotBlank

For strings: must not be null, empty, or only spaces.

@NotBlank(message = "Name must not be blank")
private String customerName;

Length / size

@Size

Checks the length of a string or size of a collection.

@Size(min = 3, max = 50, message = "Name must be between 3 and 50 characters")
private String customerName;

Numeric ranges

@Min / @Max

Mostly for integer values.

@Min(value = 1, message = "Quantity must be at least 1")
@Max(value = 10, message = "Quantity must not be greater than 10")
private Integer quantity;

@DecimalMin / @DecimalMax

Best for decimal values like prices.

@DecimalMin(value = "8.0", message = "The min. price is 8.0 Eur")
@DecimalMax(value = "30.0", message = "The max. price is 30.0 Eur")
private Double price;

Format constraints

@Email

Checks whether a string looks like an email address.

@Email(message = "Please enter a valid email address")
private String email;

@Pattern

Checks a value with a regular expression.

@Pattern(regexp = "\\d{4}", message = "PIN must contain exactly 4 digits")
private String pin;

Boolean constraint

@AssertTrue

Must be true.

@AssertTrue(message = "You must accept the terms")
private boolean termsAccepted;

Date constraints

@Past

Date must be in the past.

@Past(message = "Birth date must be in the past")
private LocalDate birthDate;

@Future

Date must be in the future.

@Future(message = "Appointment date must be in the future")
private LocalDate appointmentDate;

PizzaOrder

PizzaOrder.java

public class PizzaOrder implements Cloneable {
    @Id
    private Long      orderId;

    @NotNull(message = "Order date is required")
    @Past(message = "Order date must be in the past")
    private LocalDate orderDate;

    @NotBlank(message = "Pizza is required")
    private String    pizza;

    @NotBlank(message = "Size is required")
    @Pattern(
            regexp = "Small|Medium|Large|Family",
            message = "Size must be Small, Medium, Large, or Family"
    )
    private String    size;

    @DecimalMin(value = "8.0", message = "The min. price is 8.0 Eur")
    @DecimalMax(value = "30.0", message = "The max. price is 30.0 Eur")
    private Double    price;

    @NotNull(message = "Quantity is required")
    @Min(value = 1, message = "At least 1 pizza must be ordered")
    @Max(value = 20, message = "You cannot order more than 20 pizzas")
    private Integer   quantity;

    @NotNull(message = "Garlic is required")
    private Boolean   garlic;

TestPizzaOrder.java

    @Test
    public void testSetSize() {
        PizzaOrder o1 = new PizzaOrder();
        PizzaOrder o2 = new PizzaOrder(LocalDate.now(), "Pepperoni", "Slice", 15.0, 1, true);
        o1.setSize("Slice");
        System.out.println(o1);
        System.out.println(o2);
    }

Bean Validation does not run automatically just by calling setSize().

The most important ones to remember

These are the core ones:

  • @NotNull

  • @NotBlank

  • @Size

  • @Min / @Max

  • @DecimalMin / @DecimalMax

  • @Email

  • @Valid

For forms, @NotBlank, @Size, @Email, and range constraints are the ones you use most often.

Einheitlicher Mechanismus für Frameworks

Bean Validation wird von vielen Frameworks automatisch unterstützt:

  • Spring Boot prüft REST-Requests bei @Valid automatisch.
  • Vaadin Binder kann die Annotations direkt auswerten.
  • Hibernate/JPA prüft Entities beim Persistieren.

Wenn du Validierung nur in den Settern machst, weiß Spring/Vaadin davon nichts → du musst die Logik selbst an jeder Stelle aufrufen.

Flexibler Umgang mit Validierung

Mit Bean Validation kannst du Gruppen definieren:

@NotNull(groups = Create.class)
@Null(groups = Update.class)
private Long id;

Damit kannst du sagen: „Beim Erstellen muss id null sein, beim Ändern nicht.“

Mit Settern geht das kaum elegant.

Bessere Wiederverwendung & Lesbarkeit

Bean Validation ist deklarativ → jeder sieht sofort an der Klasse, welche Regeln gelten.

Settermethoden mit Validierung können unübersichtlich werden.

Standardisiert & erweiterbar

Jakarta Bean Validation ist ein Standard (JSR 380 / Jakarta EE) → in allen großen Frameworks gleich.

Du kannst eigene Annotations bauen (@UsernameOrEmail, @StrongPassword, …).

Bei Settern müsstest du die Logik jedes Mal neu schreiben.

Kurz gesagt

Setter-Validierung = geht, aber unflexibel, nicht wiederverwendbar, keine Framework-Unterstützung.

Bean Validation = deklarativ, lesbarer, automatisch von Spring/Vaadin/JPA unterstützt.

Deshalb: Bean Validation ist die bessere Wahl, gerade in Projekten mit Frameworks.

Grundidee

Du annotierst Felder oder Methoden deiner Klassen mit Constraints wie @NotNull, @Size, @Min, @Email

Ein Validator prüft dann automatisch, ob diese Regeln erfüllt sind.

Wird eine Regel verletzt, bekommst du eine ConstraintViolation zurück.

Das ist praktisch für:

  • Formulareingaben (z. B. Vaadin, JSF, REST-Requests)
  • Datenbank-Entities (z. B. mit JPA/Hibernate)
  • DTOs (Data Transfer Objects)

Wichtigsten Constraints

Allgemeine Constraints

  • @Null → Wert muss null sein
  • @NotNull → Wert darf nicht null sein (leerer String oder leere Liste ist aber erlaubt)
  • @NotEmpty → String/Collection/Array darf nicht null und nicht leer sein
  • @NotBlank → String darf nicht null, leer oder nur Whitespace sein

String / Collections

  • @Size(min, max) → prüft Länge (String) oder Anzahl (Collection, Array, Map)
  • @Pattern(regexp, flags) → String muss Regex entsprechen
  • @Email → prüft E-Mail-Adresse (einfaches Pattern)

Zahlen

  • @Min(value) → Zahl ≥ value
  • @Max(value) → Zahl ≤ value
  • @Positive → Zahl > 0
  • @PositiveOrZero → Zahl ≥ 0
  • @Negative → Zahl < 0
  • @NegativeOrZero → Zahl ≤ 0
  • @DecimalMin(value, inclusive) → wie @Min, aber für BigDecimal/String
  • @DecimalMax(value, inclusive) → wie @Max, aber für BigDecimal/String
  • @Digits(integer, fraction) → maximale Anzahl von Stellen vor/nach dem Komma

Datum/Zeit

  • @Past → muss in der Vergangenheit liegen
  • @PastOrPresent → muss heute oder früher sein
  • @Future → muss in der Zukunft liegen
  • @FutureOrPresent → muss heute oder später sein

Booleans

  • @AssertTrue → Wert muss true sein
  • @AssertFalse → Wert muss false sein

Beispiele

import jakarta.validation.constraints.*;

public class User {

    @NotBlank(message = "Der Benutzername darf nicht leer sein")
    private String username;

    @Size(min = 8, max = 20, message = "Das Passwort muss zwischen 8 und 20 Zeichen lang sein")
    private String password;

    @Email(message = "Bitte eine gültige E-Mail-Adresse angeben")
    private String email;
}

GitHub

Copy code