Skapa egna constraint-annoteringar
Skapa återanvändbara egna validators med ConstraintValidator för domänspecifik valideringslogik.
Skapa egna constraint-annoteringar är en gratis lektion i Spring Boot 4 – komplett guide på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Spring Boot 4 – komplett guide, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Spring Boot 4 – komplett guide innehåller totalt 4 lektioner.
Varför egna constraints?
Bean Validation levereras med annoteringar som @NotNull, @Size och @Email. Men verkliga applikationer har domänspecifika regler som ingen inbyggd annotering täcker.
- Ett användarnamn måste vara skrivet med små bokstäver och innehålla 3–20 tecken
- Ett telefonnummer måste följa formatet i ert land
- Ett statusfält måste vara ett av en tillåten uppsättning enum-värden
I stället för att skriva manuella kontroller i varje controller eller tjänst kan ni skapa en återanvändbar egen constraint-annotering som kopplas in i samma valideringspipeline som de inbyggda.
En egen constraints två delar
Varje egen constraint i Spring Boot 4 (som använder Jakarta Bean Validation) består av exakt två delar:
- Annoteringen — det ni skriver på ett fält, till exempel
@ValidUsername. Den deklarerar metadata och pekar på en validator. - ConstraintValidator — en klass som innehåller den faktiska logiken i
isValid().
Metaannoteringen @Constraint kopplar ihop de två. När validering körs instansierar ramverket er validator och anropar isValid() för varje annoterat fält.
Definiera annoteringen
En egen constraint-annotering måste deklarera tre standardattribut: message, groups och payload. @Constraint(validatedBy = ...) kopplar den till en validatorklass.
Observera att importerna kommer från jakarta.validation, inte från det gamla javax.validation.
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = UsernameValidator.class)
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidUsername {
String message() default "invalid username";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}Förstå @Target och @Retention
Två metaannoteringar styr var och när er constraint gäller:
- @Target — var annoteringen kan placeras.
FIELDför entitetsfält,PARAMETERför metodargument,METHODför getters ochTYPE_USEför generiska typer somList<@ValidUsername String>. - @Retention(RUNTIME) — annoteringen måste finnas kvar under körning så att valideringsmotorn kan läsa den via reflection. Detta är obligatoriskt; retention med
SOURCEellerCLASSskulle göra constrainten osynlig.
Skriva ConstraintValidator
Validatern implementerar ConstraintValidator<A, T>, där A är er annoteringstyp och T är typen för värdet som valideras (till exempel String).
Metoden isValid() returnerar true om värdet är giltigt. En viktig regel är att behandla null som giltigt och låta @NotNull hantera null-värden separat. Då förblir varje constraint fokuserad på en enda sak.
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class UsernameValidator
implements ConstraintValidator<ValidUsername, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext ctx) {
if (value == null) {
return true; // let @NotNull handle null
}
return value.matches("^[a-z0-9_]{3,20}$");
}
}Tillämpa constrainten
När constrainten väl är definierad används den precis som en inbyggd constraint. Placera den på ett DTO-fält och kombinera den med andra constraints. Spring utvärderar alla när objektet valideras.
Använd @NotNull tillsammans med @ValidUsername, eftersom validatern avsiktligt tillåter null.
import jakarta.validation.constraints.NotNull;
public record RegisterRequest(
@NotNull
@ValidUsername(message = "username must be 3-20 lowercase chars")
String username,
@NotNull
String password
) {}Utlösa validering i en controller
För att validera inkommande request bodies annoterar ni parametern med @Valid. Om någon constraint misslyckas kastar Spring en MethodArgumentNotValidException innan metodkroppen körs.
Det message som ni anger i annoteringen blir felmeddelandet som rapporteras tillbaka till klienten.
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping("/register")
public String register(@Valid @RequestBody RegisterRequest req) {
return "registered: " + req.username();
}
}Anpassa felmeddelandet dynamiskt
Ibland räcker inte ett statiskt meddelande – Ni vill att meddelandet ska återspegla varför valideringen misslyckades. Använd ConstraintValidatorContext för att inaktivera standardmeddelandet och skapa ett anpassat meddelande.
Ni måste först anropa disableDefaultConstraintViolation() och därefter lägga till Er egen validering. Annars visas båda meddelandena.
@Override
public boolean isValid(String value, ConstraintValidatorContext ctx) {
if (value == null) return true;
if (value.length() < 3 || value.length() > 20) {
ctx.disableDefaultConstraintViolation();
ctx.buildConstraintViolationWithTemplate(
"username length must be between 3 and 20")
.addConstraintViolation();
return false;
}
return value.matches("^[a-z0-9_]+$");
}Skicka parametrar till Er constraint
Gör constraints konfigurerbara genom att lägga till attribut i annoteringen. Till exempel kan @ValidUsername ta emot en minimi- och en maximilängd med min och max.
Validatorn läser in dessa i initialize(), som körs en gång innan anropen till isValid().
public @interface ValidUsername {
String message() default "invalid username";
int min() default 3;
int max() default 20;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}Läsa parametrar i initialize()
Överskugga initialize() för att spara annoteringens attributvärden i fält. Ramverket anropar metoden en gång per validatorinstans, innan något anrop till isValid() görs.
På så sätt kan en enda validatorklass användas för många olika konfigurationer.
public class UsernameValidator
implements ConstraintValidator<ValidUsername, String> {
private int min;
private int max;
@Override
public void initialize(ValidUsername ann) {
this.min = ann.min();
this.max = ann.max();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext ctx) {
if (value == null) return true;
return value.length() >= min && value.length() <= max
&& value.matches("^[a-z0-9_]+$");
}
}Ren Java: fristående valideringslogik
Den centrala regex- och längdlogiken är vanlig Java som Ni kan testa utan något ramverk. Här uttrycks samma regel som ett körbart program, så att Ni kan verifiera logiken innan Ni kopplar in den i Spring.
Denna isolering gör Era validatorer enkla att enhetstesta.
public class Main {
static boolean isValidUsername(String value, int min, int max) {
if (value == null) return true;
return value.length() >= min && value.length() <= max
&& value.matches("^[a-z0-9_]+$");
}
public static void main(String[] args) {
System.out.println(isValidUsername("alice_99", 3, 20)); // true
System.out.println(isValidUsername("Al", 3, 20)); // false
System.out.println(isValidUsername("Bad Name", 3, 20)); // false
System.out.println(isValidUsername(null, 3, 20)); // true
}
}Snabb kontroll
Ni implementerar en anpassad ConstraintValidator för ett String-fält. Fältet är valfritt, och en separat @NotNull hanterar redan null-värden. Vad ska isValid() returnera när värdet är null?
Sammanfattning
Ni har lärt Er att skapa återanvändbara anpassade constraint-annoteringar i Spring Boot 4:
- En constraint består av två delar: annoteringen (med
message,groupsochpayload) samt en ConstraintValidator. @Constraint(validatedBy = ...)kopplar ihop dem.@Retention(RUNTIME)och@Targetstyr synlighet och placering.isValid()innehåller logiken och bör behandlanullsom giltigt genom att överlåta kontrollen till@NotNull.- Använd
initialize()för att läsa annoteringsparametrar ochConstraintValidatorContextför att skapa dynamiska meddelanden. - Använd constrainten på DTO-fält och utlös den med
@Validi controllers.
Med dessa mönster finns domänreglerna på en enda testad plats och kan anslutas sömlöst till Springs valideringspipeline.
Lär dig Java med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 21
- Lektioner
- 84
Vanliga frågor
Är lektionen ”Skapa egna constraint-annoteringar” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Spring Boot 4 – komplett guide, inklusive ”Skapa egna constraint-annoteringar”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Spring Boot 4 – komplett guide innehåller totalt 4 lektioner.
Vad lär jag mig i ”Skapa egna constraint-annoteringar”?
Skapa återanvändbara egna validators med ConstraintValidator för domänspecifik valideringslogik. Ni övar på Spring Boot 4 – komplett guide med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Spring Boot 4 – komplett guide?
Du behöver inga förkunskaper. Utbildningen i Spring Boot 4 – komplett guide på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Skapa egna constraint-annoteringar”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Spring Boot 4 – komplett guide-lektionen?
Ja. Varje Spring Boot 4 – komplett guide-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Bean Validation-begränsningar och constraint-grupper
- Skapa egna constraint-annoteringar
- Global felhantering med @ControllerAdvice
- RFC 7807-svar med problemdetaljer