13

正常に動作し、Beanに注釈が付けられていることを検証できる次のBeanValidationコードがあります。

  @EnumValue(enumClass = MyTestEnum.class)
  private String field;

  public enum MyTestEnum {
    VAL1, VAL2;
  }

フィールド値が「VAL1」または「VAL2」の場合にのみ検証されます。

public class EnumNameValidator implements ConstraintValidator<EnumValue, String> {

  private Set<String> AVAILABLE_ENUM_NAMES;

  @Override
  public void initialize(EnumValue enumValue) {
    Class<? extends Enum<?>> enumSelected = enumValue.enumClass();
    Set<? extends Enum<?>> enumInstances = Sets.newHashSet(enumSelected.getEnumConstants());
    AVAILABLE_ENUM_NAMES = FluentIterable
            .from(enumInstances)
            .transform(PrimitiveGuavaFunctions.ENUM_TO_NAME)
            .toImmutableSet();
  }

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

}

私が理解していないのは、私の最初の試みが失敗した理由です。上記の代わりにenumSelected.getEnumConstants()次のコードを使用します。

Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);

Intellij 12はエラーを強調表示しませんが、コンパイラーは次のように述べています。

java: method allOf in class java.util.EnumSet<E> cannot be applied to given types;
  required: java.lang.Class<E>
  found: java.lang.Class<capture#1 of ? extends java.lang.Enum<?>>
  reason: inferred type does not conform to declared bound(s)
    inferred: capture#1 of ? extends java.lang.Enum<?>
    bound(s): java.lang.Enum<capture#1 of ? extends java.lang.Enum<?>>

私は問題を理解していません、そして私はまたうまく働くそのコードを持っています:

  private static <T extends Enum<T> & EnumAlternativeName> T safeGetByAlternativeName(Class<T> enumClass, String alternativeName) {
    for ( T t : EnumSet.allOf(enumClass) ) {
      if ( t.getAlternativeName().equals(alternativeName) ) {
        return t;
      }
    }
    return null;
  }
4

2 に答える 2

10

私の推測では? extends Enum<?>、2つ?は異なる可能性がありますが、両方が同じであるallOfと予想されます。T extends Enum<T>T

たとえば、次のコードについて考えてみます。

static enum MyEnum {}
static class EnumValue<T extends Enum<T>> {
    Class<T> enumClass;
    EnumValue(Class<T> enumClass) {
        this.enumClass = enumClass;
    }
    Class<T> enumClass() { return enumClass; }
}

これらの行はコンパイルされます:

EnumValue<?> enumValue = new EnumValue(MyEnum.class); // raw constructor
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumValue.enumClass());

Tの2つは同じであることがわかっていenumValue.enumClass()ますが、これはそうではありません。

EnumValue enumValue = new EnumValue(MyEnum.class);
Class<? extends Enum<?>> enumSelected = enumValue.enumClass();
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);

Class<? extends Enum<?>>中間ステップとしてを使用して情報を失ったためです。

于 2013-03-12T16:36:01.430 に答える
4

@assyliasのソリューションに関する私の説明:

クラスのタイプについて表現したいのは、それが

Class<E>, for some E, that E <: Enum<E>

Eただし、Javaでは、メソッド本体に型変数を導入することはできません。

通常、ワイルドカードとワイルドカードキャプチャを利用して、非表示型変数を導入できます

class G<T extends b(T)> { ... }  // b(T) is a type expression that may contain T

G<? extends A>   --capture-->   G<T>, for some T, that T <: A & b(T)

しかし、これは私たちの場合は機能しません。なぜなら、TinにClass<T>はそれを機能させる境界がないからです。

したがって、目的の境界を持つ新しいタイプを導入する必要があります

class EnumClass<E extends Enum<E>>   // called EnumValue in assylias's solution

    EnumClass(Class<E> enumClass) 

    Class<E> enumClass()

EnumClass<?>   --capture-->    EnumClass<E>, for some E, that E <: Enum<E>

次にEnumClass<E>.enumClass()

Class<E>, for some E, that E <: Enum<E>

これが私たちが達成しようとしてきた目標です。

しかし、どうすればのコンストラクターを呼び出すことができEnumClassますか?問題の原因は、の適切な型がないことですがenumClass、のコンストラクターはEnumClass適切に型指定されたを必要としていますenumClass

Class<not-proper> enumClass = ...;
new EnumClass<...>(enumClass);  // wont work

幸いなことに(?)生の型はここで役立ち、ジェネリック型の型チェックを無効にします

EnumClass raw = new EnumClass(enumClass);  // no generics
EnumClass<?> wild = raw; 

したがって、クラスを目的のタイプにキャストするために実行する必要のある最小限の体操は次のとおりです。

((EnumClass<?>)new EnumClass(enumClass)).enumClass()
于 2013-03-12T18:37:45.903 に答える