Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Add @ValidEnum Constraint for Enum Validation #229

Open
aalamu opened this issue Nov 25, 2024 · 0 comments
Open

Feature Request: Add @ValidEnum Constraint for Enum Validation #229

aalamu opened this issue Nov 25, 2024 · 0 comments

Comments

@aalamu
Copy link

aalamu commented Nov 25, 2024

Description:

I would like to propose the addition of a new constraint annotation @ValidEnum that allows developers to validate whether a string or a character sequence matches any value in an enum, with optional case-insensitivity.

Use Case:

The @ValidEnum annotation will be useful in scenarios where developers want to validate if an input (usually a string or character sequence) corresponds to a value in a given enum. This is particularly useful for REST APIs where enums are often represented as strings in requests and need validation before converting them into enums in the backend.

For example, consider a DTO class where a string field needs to represent a value from an enum like VerificationType. The @ValidEnum constraint will ensure that the string input is one of the defined enum values, providing better validation for incoming data.

Proposed Solution:

The @ValidEnum annotation would look like this:

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = EnumValidator.class)
public @interface ValidEnum {

  Class<? extends Enum<?>> enumClass();

  boolean ignoreCase() default false;

  String message() default "must be any of enum {enumClass}";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};
}

And the corresponding validator class:

public class EnumValidator implements ConstraintValidator<ValidEnum, CharSequence> {

  private List<String> acceptedValues;
  private boolean ignoreCase;

  @Override
  public void initialize(ValidEnum constraintAnnotation) {
    ignoreCase = constraintAnnotation.ignoreCase();
    Enum<?>[] enumConstants = constraintAnnotation.enumClass().getEnumConstants();
    initializeAcceptedValues(enumConstants);
  }

  @Override
  public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
    if (value != null) {
      return checkIfValueTheSame(acceptedValues, value.toString());
    }
    return true;
  }

  protected boolean checkIfValueTheSame(List<String> acceptedValues, String value) {
    for (String acceptedValue : acceptedValues) {
      if (ignoreCase && acceptedValue.equalsIgnoreCase(value)) {
        return true;
      } else if (acceptedValue.equals(value)) {
        return true;
      }
    }
    return false;
  }

  protected void initializeAcceptedValues(Enum<?>... enumConstants) {
    if (enumConstants == null || enumConstants.length == 0) {
      acceptedValues = Collections.emptyList();
    } else {
      acceptedValues = Stream.of(enumConstants)
          .map(Enum::name)
          .collect(Collectors.toList());
    }
  }
}

Example Usage:

Consider a DTO class for updating user details like phone number or email, where the verificationType should only be one of the values defined in the VerificationType enum:

public class UpdateEmailAddressOrPhoneNumberDto {

  @ValidEnum(enumClass = VerificationType.class, message = "{user.verificationType.Type}")
  private String verificationType;

  public VerificationType getVerificationType() {
    return VerificationType.valueOf(verificationType);
  }
}

Advantages:

  • Developer Convenience: Developers can easily validate if an input string corresponds to a valid enum constant without manually writing custom validation logic.
  • Customizability: Optional case-insensitive validation provides flexibility, especially when user input can vary in case.
  • Error Messages: Customizable error messages ensure that users receive clear feedback about validation errors.

Potential Impact:

This addition could greatly enhance input validation capabilities when dealing with enums in APIs or form inputs. It would save time for developers who currently have to implement this logic manually and improve the overall developer experience.

Are There Related Issues?

Please let me know if similar requests have been made in the past. I couldn’t find any exact match for this request, but if there are any existing solutions or workarounds, feel free to point them out.

References:

  • jakarta.validation.constraints.Pattern
  • jakarta.validation.MessageSource
  • ConstraintValidator interface for validation logic
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant