web-dev-qa-db-ja.com

クラスから列挙インスタンスを取得しますか?文字列値を使用してEnum>を拡張しますか?

正確な質問を言葉にするのは難しいので、例を挙げます。

私には2つのEnumタイプがあります。

_enum Shape {
    CAT, DOG;
}

enum Color {
    BLUE, RED;
}
_

私には方法があります:

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

次のような方法を使用したいと思います。

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

getInstance()の実装方法を正確に判断するのに苦労しています。インスタンス化する正確なEnumクラスが分かれば、簡単です。

_Color.valueOf("RED");
_

しかし、この上記の行は、未知のClassを使用してどのように実現できますか? (ただし、someEnumClassEnumのサブクラスであることがわかっています。)

ありがとう!

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

そして、メソッドは次のように使用されます:

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

次に、いつでも使用できます

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

これはのショートカットです

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

だからここにSpring検証を使用しているコードがあり、私にとってはうまくいきます。以下の完全なコード。

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 {};

}

上記のクラスの実装:

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());
    }

  }

}

上記の注釈の使用ISとてもシンプル

 @JsonProperty("lead_id")
  @EnumValidator( enumClazz=DefaultEnum.class,message="This error is coming from the enum class", groups = {Group1.class })
  private String leadId;
2
Rajeev Singla

渡されたMethodvalueOfメソッドを反映するClassオブジェクトを取得します。これは、Stringパラメータを受け入れます。次に、invokeオブジェクトなし(静的であるため)と指定されたStringパラメーター:

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

さまざまな種類の例外のボートロードをキャッチする必要があります。

1
Karl Knechtel

あなたはあなたが探しているクラスのアイデアを持っているので、あなたが興味があるものを知っているかどうかを列挙に尋ねることができます:

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;
  }
}

ただし、文字列を複数の列挙型にプラグインして適合を探すと、列挙型で得られる型の安全性が損なわれます。 「赤」を両方にマッピングした場合MyColor.REDおよびNuclearThreatWarningLevel.REDすると、少なくとも、クラスが間違ってしまう可能性があります。最悪の場合、あなたが望むのは赤く塗られた車だけだったときに、空気が消えるのを待って6ヶ月間地下バンカーに行く可能性があります:)

可能であれば、コードのこの領域を再設計して、文字列をいくつかのクラスの1つのインスタンスに動的に変換する必要がないようにすることをお勧めします。答えを拡張して問題を含めれば、おそらくSOコミュニティはいくつかのアイデアを持つでしょう。

0
Paul