A third way to add to the answer of @kevin, is:
To recieve the value as String and set a validation-annotation. The validation-annotation could like:
@Constraint(validatedBy = {ValidEnum.EnumValidator.class})
@Target({TYPE, FIELD, TYPE_USE, PARAMETER})
@Retention(RUNTIME)
@Documented
public @interface ValidEnum {
String message() default "your custom error-message";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> enumClass();
class EnumValidator implements ConstraintValidator<ValidEnum, String> {
protected List<String> values;
protected String errorMessage;
@Override
public void initialize(ValidEnum annotation) {
errorMessage = annotation.message();
values = Stream.of(annotation.enumClass().getEnumConstants())
.map(Enum::name)
.toList();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (!values.contains(value)) {
context.disableDefaultConstraintViolation();
context
.buildConstraintViolationWithTemplate(errorMessage)
.addConstraintViolation();
return false;
} else {
return true;
}
}
}
}
And use this newly created annotation to set on your class:
@Getter
@Setter
@NoArgsConstructor
public class UpdateUserByAdminDTO {
private Boolean isBanned;
private @ValidEnum(enumClass=RoleEnum.class) String role;
private @ValidEnum(enumClass=RoleEnum.class, message="an override of the default error message") String anotherRole;
}
This way you get to reuse this annotation on whatever enum variable and even have a custom error for each of the different enums you want to check.
One remark: the annotation does not take into account that the enum may be null, so adapt the code to your needs