0Pricing
Java Academy · Lektion

Eigene Constraint-Annotationen

Erstellen Sie eine eigene @UniqueEmail-Annotation mit einer ConstraintValidator-Implementierung.

Eigene Constraint-Annotationen ist eine kostenlose Java Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Java Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.

Wenn Standard-Constraints nicht ausreichen

Die Standard-Annotationen von Bean Validation decken häufige Fälle ab. Für domänenspezifische Regeln (z. B. eine eindeutige E-Mail-Adresse, eine gültige IBAN oder die Passwortstärke) erstellen Sie eigene Constraint-Annotationen.

Constraint-Annotation definieren

Erstellen Sie eine Annotation mit @Constraint(validatedBy = ...), den erforderlichen Elementen message, groups und payload sowie der passenden Aufbewahrungsdauer und dem passenden Ziel.

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@Documented
@Constraint(validatedBy = UniqueEmailValidator.class)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueEmail {
    String message() default "Email already registered";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

ConstraintValidator implementieren

Implementieren Sie ConstraintValidator<UniqueEmail, String>. Die Methode initialize liest die Annotationselemente aus; isValid führt die eigentliche Prüfung durch.

@Component
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
    @Autowired private UserRepository repo;
    @Override
    public boolean isValid(String email, ConstraintValidatorContext ctx) {
        if (email == null) return true; // let @NotBlank handle null
        return !repo.existsByEmail(email);
    }
}

Benutzerdefinierten Constraint verwenden

Wenden Sie die Annotation wie jeden Standard-Constraint auf ein Feld, einen Parameter oder einen Rückgabewert an.

public record CreateUserRequest(
    @NotBlank
    String name,
    @NotBlank @Email @UniqueEmail
    String email
) {}

Benutzerdefinierte Nachricht mit Interpolation

Verweisen Sie in der Nachricht mit {elementName} auf Annotationselemente. Verwenden Sie ctx.buildConstraintViolationWithTemplate(), um benutzerdefinierte Nachrichten mit dynamischen Daten hinzuzufügen.

@Constraint(validatedBy = RangeValidator.class)
public @interface InRange {
    int min() default 0;
    int max() default 100;
    String message() default "Must be between {min} and {max}";
    // ...
}

Constraint auf Klassenebene

Wenden Sie einen Constraint auf Klassenebene an, um mehrere Felder gemeinsam zu validieren – dies eignet sich beispielsweise für feldübergreifende Regeln wie die Bestätigung eines Passworts.

@Documented
@Constraint(validatedBy = PasswordMatchValidator.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PasswordMatch {
    String message() default "Passwords do not match";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Validator auf Klassenebene implementieren

Der Validator erhält das vollständige Objekt. Greifen Sie auf mehrere Felder zu, um eine feldübergreifende Validierung durchzuführen.

public class PasswordMatchValidator implements ConstraintValidator<PasswordMatch, ChangePasswordRequest> {
    public boolean isValid(ChangePasswordRequest req, ConstraintValidatorContext ctx) {
        if (req.getNewPassword() == null) return true;
        boolean match = req.getNewPassword().equals(req.getConfirmPassword());
        if (!match) {
            ctx.disableDefaultConstraintViolation();
            ctx.buildConstraintViolationWithTemplate("Passwords do not match")
               .addPropertyNode("confirmPassword").addConstraintViolation();
        }
        return match;
    }
}

Constraints kombinieren

Erstellen Sie einen Meta-Constraint, indem Sie Ihre benutzerdefinierte Annotation mit vorhandenen Constraints annotieren. Beide werden automatisch angewendet.

@NotBlank
@Email
@Size(max = 255)
@Constraint(validatedBy = {})
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidEmail {
    String message() default "Invalid email";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Mehrere Verstöße zurückgeben

Verwenden Sie ctx.disableDefaultConstraintViolation() und fügen Sie für jedes in einem einzigen Validator-Durchlauf gefundene Problem eine eigene Fehlermeldung hinzu.

public boolean isValid(String password, ConstraintValidatorContext ctx) {
    List<String> issues = new ArrayList<>();
    if (password.length() < 8) issues.add("Too short");
    if (!password.matches(".*\\d.*")) issues.add("Must contain a digit");
    if (issues.isEmpty()) return true;
    ctx.disableDefaultConstraintViolation();
    issues.forEach(msg -> ctx.buildConstraintViolationWithTemplate(msg).addConstraintViolation());
    return false;
}

Von Spring verwaltete Validatoren

Da UniqueEmailValidator mit @Component annotiert ist, injiziert Spring Repositories in den Validator. Dies funktioniert nur, wenn der Validator über den Validator von Spring initialisiert wird, den Spring Boot automatisch einbindet.

Benutzerdefinierte Validatoren testen

Testen Sie Validatoren direkt als Unit-Tests – für reine Validierungslogik ist kein Spring-Kontext erforderlich. Verwenden Sie Validation.buildDefaultValidatorFactory() für Integrationstests.

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
CreateUserRequest req = new CreateUserRequest("", "bad-email", null);
Set<ConstraintViolation<CreateUserRequest>> violations = validator.validate(req);
System.out.println(violations.size()); // 3

Kurze Überprüfung

Welches Interface implementiert ein Validator für einen benutzerdefinierten Constraint?

Zusammenfassung

Erstellen Sie ein @interface mit @Constraint(validatedBy=...). Implementieren Sie ConstraintValidator. Verwenden Sie @Component für die Injektion durch Spring. Constraints auf Klassenebene validieren mehrere Felder gemeinsam. Kombinieren Sie vorhandene Constraints, um Duplikate zu vermeiden.

Häufig gestellte Fragen

Ist die Lektion „Eigene Constraint-Annotationen“ kostenlos?

Ja — der vollständige Text von „Eigene Constraint-Annotationen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Java Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Eigene Constraint-Annotationen“?

Erstellen Sie eine eigene @UniqueEmail-Annotation mit einer ConstraintValidator-Implementierung. Du übst Java Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Java Academy zu starten?

Keine Vorkenntnisse erforderlich. Java Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.

Wie lange dauert die Lektion „Eigene Constraint-Annotationen“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Java Academy-Lektion Code schreiben und ausführen?

Ja. Jede Java Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Bean Validation: @NotNull, @Size, @Pattern
  2. Eigene Constraint-Annotationen
  3. Globale Ausnahmebehandlung mit @ControllerAdvice
  4. RFC 7807 Problem Details und konsistente Fehlerantworten
← Zurück zu Java Academy