cavo
cavo

Reputation: 23

Spring Boot - String to Enum conversion accepts value and index of the enum. How to reject numeric inputs and only accept enum value?

I have some simple enums like below.

public enum Status {
  ACTIVE,
  PASSIVE;

  private Status() {
  }
}

I have a String status field in my REST service input object.

It converts it to PASSIVE when the service receives both requests.

CASE 1 status = 1

{
    "name": "Walter",
    "surname": "White"
    "status": "1"
}

CASE 2 status = "PASSIVE"

{
    "name": "Walter",
    "surname": "White"
    "status": "PASSIVE"
}

I do not want the default convertor accepts the numeric inputs (CASE 1). I mean I do not want it to convert 1 to PASSIVE by using the index of the enum.

I want it only accepts Non numeric values as it is in CASE 2.

Also consider that I have many enums like this and I want to apply the restriction to all my enums.

How can I make it works as I explained above ?

Upvotes: 2

Views: 2033

Answers (1)

Eklavya
Eklavya

Reputation: 18480

Update:

By default, Number for Enum deserialize by mapping enum ordinal. Add configuration DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS as true in ObjectMapper which is by default false.

@Configuration
public class JacksonConfig {

  @Bean
  @Primary
  public ObjectMapper configureObjectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
    return objectMapper;
  }
}

Another way is to write a custom annotation for enum validation. And use it on the field with possible values

@EnumNamePattern
private Status status;

Custom Annotation for enum validation

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = EnumNamePatternValidator.class)
public @interface EnumNamePattern {
    String message() default "invalid";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

And write validator for the annotation

public class EnumNamePatternValidator implements ConstraintValidator<EnumNamePattern, Enum<?>> {
    @Override
    public boolean isValid(Enum<?> value, ConstraintValidatorContext context) {
        if (value == null) return true;
        return Arrays.stream(Status.values()).anyMatch(e -> e.name().equals(value.name()));
    }
}

Upvotes: 2

Related Questions