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

后端 未结 4 1568
时光取名叫无心
时光取名叫无心 2020-12-15 17:24

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 {
    C         


        
相关标签:
4条回答
  • 2020-12-15 17:30
     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");
    
    0 讨论(0)
  • 2020-12-15 17:38

    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.

    0 讨论(0)
  • 2020-12-15 17:44

    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.

    0 讨论(0)
  • 2020-12-15 17:53

    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;
    
    0 讨论(0)
提交回复
热议问题