I was trying to add custom annotation validation on the age field. as I saw some JSR 303 topics
Controller
@Validated
@Controller
public class StudentController {
@Autowired
private StudentRepository repository;
@PostMapping("/send")
public ResponseEntity saveStudent(@AgeValidator @RequestBody Student student) {
System.out.println("saveStudent invoked");
repository.save(student);
ResponseData responseData = new ResponseData();
responseData.setResultId("result");
responseData.setResultValue("saved");
ResponseEntity entity = new ResponseEntity(responseData, HttpStatus.OK);
return entity;
}
}
Model
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
@Id
@Column(length = 7)
private String Id;
private String fullName;
private Integer age;
private String department;
}
AgeValidator
package com.example.demo4;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = AgeValidatorImpl.class)
public @interface AgeValidator {
String message()
default "Please enter a valid age";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
AgeValidatorImpl
class AgeValidatorImpl implements ConstraintValidator<AgeValidator, Student> {
@Override
public void initialize(AgeValidator constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation); //To change body of generated methods, choose Tools | Templates.
}
@Override
public boolean isValid(Student t, ConstraintValidatorContext cvc) {
System.out.println("AgeValidatorImpl invoked");
if (t.getAge() < 18) {
return false;
} else if (t.getAge() > 40) {
return false;
}
return true;
}
}
so if am sending using postman at any age it saves the record and it's not validating. I saw many peoples commented to add annotation on controller @validated which I import from import org.springframework.validation.annotation.Validated. Still Why this is not working. what am missing?
You can try this,
I have updated @Age
annotation. You can provide upper and lower limit for validation. Note I that have added ElementType.FIELD
to @Target
. It allows you to use this in class fields as well.
@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = AgeValidator.class)
public @interface Age {
int lower() default 14;
int upper() default 60;
String message() default "Please enter a valid age";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
This is the validation constrain for the annotation.
public class AgeValidator implements ConstraintValidator<Age, Integer> {
private int upperLimit;
private int lowerLimit;
@Override
public boolean isValid(Integer i, ConstraintValidatorContext constraintValidatorContext) {
return lowerLimit < i && i < upperLimit;
}
@Override
public void initialize(Age constraintAnnotation) {
this.lowerLimit = constraintAnnotation.lower();
this.upperLimit = constraintAnnotation.upper();
}
}
You can pass the annotation to class fields and override the upper and lower limit.
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
@Id
@Column(length = 7)
private String Id;
private String fullName;
@Age(lower = 10, upper = 70)
private Integer age;
private String department;
}
Used @Validated
annotation to validate the Student
object against all the validation constraints.
@PostMapping("/send")
public ResponseEntity saveStudent(@Validated @RequestBody Student student)
Replace this dependency,
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
<type>jar</type>
</dependency>
by this
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>