0

I have implemented an enum validator following the older posts here. I was wondering whether this following code is thread safe or not? I have got many different enums for which I need to use this validator. Is this going to create any problems?

@Documented
@Constraint(validatedBy = StringEnumerationValidator.class)
@Target({ElementType.FIELD,ElementType.ANNOTATION_TYPE,
ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@NotNull(message="Value must not be null.")
public @interface StringEnumeration {

    String message() default "{com.xxx.bean.validation.constraints.StringEnumeration.message}";
    Class<?>[] groups() default{};
    Class<? extends Payload>[] payload() default{};
    Class<? extends Enum<?>> enumClass();
}


public class StringEnumerationValidator implements
    ConstraintValidator<StringEnumeration, String> {

    private Set<String> AVAILABLE_ENUM_NAMES;

    public static Set<String> getNamesSet(Class<? extends Enum<?>> e){
        Enum<?>[] enums = e.getEnumConstants();
        String[] names = new String[enums.length];
        for (int i = 0; i < enums.length; i++) {
            names[i] = enums[i].name();
            System.out.println(enums.length);
            System.out.println(enums[i]);
        }
        Set<String> mySet = new HashSet<String>(Arrays.asList(names));
        return mySet;
    }

    @Override
    public void initialize(StringEnumeration stringEnumeration) {
        Class<? extends Enum<?>> enumSelected =   stringEnumeration.enumClass();
        AVAILABLE_ENUM_NAMES = getNamesSet(enumSelected);

    }
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
        return true;
        }
        else {
            return AVAILABLE_ENUM_NAMES.contains(value);
        }

  }

EDIT: Sources referred:

Community
  • 1
  • 1
Anmol Gupta
  • 2,797
  • 9
  • 27
  • 43
  • Since your `isValid` method does only reads, it is thread safe, assuming that the validation framework obeys the contract of not calling `isValid` before the completion of `initialize`. – Holger Jun 18 '15 at 18:37
  • Updated tags, fixed typos and removed thanks. Please add links to the "older posts" you are referring to. – Ram Jun 19 '15 at 04:00
  • @Ram Added the sources. – Anmol Gupta Jun 19 '15 at 04:59

1 Answers1

0

Yes and no. Strictly speaking, it is not thread safe, because your initialize method could be called concurrently by two different threads. This method writes to the AVAILABLE_ENUM_NAMES variable, and thus the two threads might interfer with each other.

But if you make sure that initialize is called only once for each instance, before other threads have access to that instance, it is thread safe because isValid only reads the set and does not modify it.

To ensure that initializing is done only once, you should do it in the constructor:

public StringEnumeratorValidator(StringEnumeration stringEnumeration) {
    Class<? extends Enum<?>> enumSelected = stringEnumeration.enumClass();
    AVAILABLE_ENUM_NAMES = getNamesSet(enumSelected);
}

and remove the intialize method.

Hoopje
  • 12,677
  • 8
  • 34
  • 50