jakartaee / jakartaee/validation

Feature Request: Add `@ValidEnum` Constraint for Enum Validation

Open
#229 8 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

EE12
Dominant language
Java
Stars
163
Forks
67
Avg merge
3d 15h
Merged PRs (30d)
2

Description

#### 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:

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

Class> enumClass();

boolean ignoreCase() default false;

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

Class[] groups() default {};

Class[] payload() default {};
}
```

And the corresponding validator class:

```java
public class EnumValidator implements ConstraintValidator {

private List 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 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:

```java
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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the ConstraintValidator interface and the related jakarta.validation.constraints.Pattern and jakarta.validation.MessageSource references. Compare the proposed ValidEnum annotation and EnumValidator behavior with the project's validation conventions. Done means enum names, optional case-insensitive matching, null handling, and customizable messages are covered by the project's tests and documented for REST or form inputs.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, backend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.