1

I am using hibernate validator for validating DTO object. Here facing one chalange not able check data is available or not in Enum I have used below enum

public enum DeliveryMethodEnum {
    IMMEDIATE(1), 
    SCHEDULED(2);

    private Integer deliveryMethod;

    private DeliveryMethodEnum(Integer deliveryMethod) {
        this.deliveryMethod = deliveryMethod;
    }

    public Integer getDeliveryMethod() {
        return deliveryMethod;
    }
}

In DTO use custom annotation as below

@EnumValidator(message = "1008", enumClass = DeliveryMethodEnum.class) private Integer deliveryMethod;

Request is below
{
    "deliveryMethod": 8
}

It should show invalid request but its not valided from enum.

I have below custome annotation code

@Documented
@Constraint(validatedBy = EnumValidatorImpl.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@NotNull(message = "Value cannot be null")
@ReportAsSingleViolation
public @interface EnumValidator {

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

    String message() default "Value is not valid";

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

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

}


public class EnumValidatorImpl implements ConstraintValidator<EnumValidator, Integer> {

    List<String> valueList = null;

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return !valueList.contains(String.valueOf(value));
    }

    @Override
    public void initialize(EnumValidator constraintAnnotation) {
        valueList = new ArrayList<>();
        Class<? extends Enum<?>> enumClass = constraintAnnotation.enumClass();

        @SuppressWarnings("rawtypes")
        Enum[] enumValArr = enumClass.getEnumConstants();

        for (@SuppressWarnings("rawtypes")
        Enum enumVal : enumValArr) {
            valueList.add(enumVal.toString().toUpperCase());
        }
    }
}
Shiladittya Chakraborty
  • 4,270
  • 8
  • 45
  • 94

1 Answers1

0

This is because there is error in your EnumValidatorImpl class.
Following line

!valueList.contains(String.valueOf(value));

Actual value of valueList: [IMMEDIATE, SCHEDULED]
and value: 8 from body payload {"deliveryMethod": 8}
So validation will fail always.
Also !valueList.contains this will be valid for non-enum value, if you need to validate for only enum values then remove ! symbol.

Solutions
1. Accept as String from request as

{
    "deliveryMethod": "IMMEDIATE"
}

or

{
    "deliveryMethod": "SCHEDULED"
}

Hence need to updateDTO, Now value is one of the enum/not and gets validated

  1. Create valueList as [1, 2] and validate.

Here is updated EnumValidatorImpl.java

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class EnumValidatorImpl implements ConstraintValidator<EnumValidator, Integer> {

    List<Integer> valueList = null;

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return valueList.contains(value);
    }

    @Override
    public void initialize(EnumValidator constraintAnnotation) {
        valueList = new ArrayList<>();  
        Class<? extends Enum<?>> enumClass = constraintAnnotation.enumClass();

        Enum[] enumValArr = enumClass.getEnumConstants();
        valueList = Arrays.stream(enumValArr)
                .map(anEnum -> ((DeliveryMethodEnum) anEnum).deliveryMethod)
                .collect(Collectors.toList()); // This will make problem, since it will only be used for DeliveryMethodEnum enum type and not for any other enum, if it is not the problem then this can be done,else  I could not think of any other way
    }
}

dkb
  • 4,389
  • 4
  • 36
  • 54