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

陌路散爱 提交于 2019-11-27 15:39:56

问题


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!


回答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");



回答2:


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;



回答3:


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.




回答4:


Since you have an idea of what class you're looking for you can just ask the enum if it knows what you're interested in:

public enum MyColor
{
  RED  ("red", Color.RED),
  BLUE ("blue", Color.BLUE),
  TAUPE ("brownish", new COLOR(80,64,77));

  private final String _name;
  private final Color _color;

  MyColor(String name, Color color)
  {
    _name = name;
    _color = color;
  }

  public static Color parseColor(String colorName)
  {
    for (MyColor mc : MyColor.values())
    {
      if (mc._name.equalsIgnoreCase(colorName))
        return mc._color;
    }
    return null;
  }
}

However, plugging strings into multiple enums looking for a fit compromises the type safety you get with enums. If you map "red" to both MyColor.RED and NuclearThreatWarningLevel.RED then you may, at the very least, end up with the wrong class. At the worst you could end up in your underground bunker for 6 months waiting for the air to clear, when all you wanted was a car painted red :)

It would be better to redesign this area of your code if possible so you don't have to convert a string to an instance of one of several classes dynamically. If you expand your answer to include the problem you're trying to solve perhaps the SO community will have some ideas.



来源:https://stackoverflow.com/questions/6768905/get-enum-instance-from-class-extends-enum-using-string-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!