Get Enum Instance from Class<? extends Enum> using String value?

39,541

Solution 1

 public static <T extends Enum<T>> T getInstance(final String value, final Class<T> enumClass) {
     return Enum.valueOf(enumClass, value);
 }

And the method is to be used as:

final Shape shape = getInstance("CAT", Shape.class);

Then again, you can always use

final Shape shape = Shape.valueOf("CAT");

which is a shortcut for

Enum.valueOf(Shape.class, "CAT");

Solution 2

We want to get the Method object which reflects the valueOf method of the passed-in Class, which accepts a String parameter; then invoke it with no object (since it's static) and the supplied String parameter:

type.getDeclaredMethod("valueOf", String.class).invoke(null, value);

You will need to catch a boatload of different types of exceptions.

Solution 3

So here is the code being using Spring validation and works great for me. Full code given below.

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import javax.validation.constraints.NotNull;

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

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

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

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

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

}

Implementation of the above class:

import java.util.ArrayList;
import java.util.List;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class EnumValidatorImpl implements ConstraintValidator<EnumValidator, String> {

  List<String> valueList = null;

  @Override
  public boolean isValid(String value, ConstraintValidatorContext context) {
    if(!valueList.contains(value.toUpperCase())) {
      return false;
    }
    return true;
  }

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

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

    for(@SuppressWarnings("rawtypes")
    Enum enumVal : enumValArr) {
      valueList.add(enumVal.toString());
    }

  }

}

USAGE OF THE ABOVE ANNOTATION IS VERY SIMPLE

 @JsonProperty("lead_id")
  @EnumValidator( enumClazz=DefaultEnum.class,message="This error is coming from the enum class", groups = {Group1.class })
  private String leadId;
Share:
39,541
Craig Otis
Author by

Craig Otis

Updated on January 12, 2020

Comments

  • Craig Otis
    Craig Otis over 4 years

    I'm finding it difficult to put the exact question into words, so I'll just give an example.

    I have two Enum types:

    enum Shape {
        CAT, DOG;
    }
    
    enum Color {
        BLUE, RED;
    }
    

    I have a method:

    public Object getInstance(String value, Class<?> type);
    

    I would like to use the method like:

    // someValue is probably "RED", and someEnumClass is probably Color.class
    Color c = getInstance(someValue, someEnumClass);
    

    I've been having trouble determining exactly how to implement getInstance(). Once you know the exact Enum class that you want to instantiate, it's easy:

    Color.valueOf("RED");
    

    But how can this above line be accomplished with an unknown Class? (It is, however, known that the someEnumClass is a subclass of Enum.)

    Thanks!