0

我希望能够将枚举映射到“替代值”,因为在我们的旧数据库中,一些枚举正在使用不可映射到枚举的值(即,在 int 时不以 0 开头,并且在字符串类型)。

以下工作正常,能够将枚举映射到替代名称:

public class EnumAlternativeNameHelper {

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


  public static <T extends Enum<T> & EnumAlternativeName> Optional<T> getIfPresent(Class<T> enumClass, String alternativeName) {
    T t = safeGetByAlternativeName(enumClass,alternativeName);
    return Optional.fromNullable(t);
  }


  public static <T extends Enum<T> & EnumAlternativeName> T valueOf(Class<T> enumClass, String alternativeName) {
    T t = safeGetByAlternativeName(enumClass,alternativeName);
    return checkNotNull(t,"No alternative name of " + enumClass + " correspond to the provided alternative name = [" + alternativeName+"]");
  }


  public static <T extends Enum<T> & EnumAlternativeName> Optional<T> valueOfNullSafe(Class<T> enumClass, String alternativeName) {
    if ( alternativeName == null) {
      return Optional.absent();
    }
    return Optional.of( valueOf(enumClass,alternativeName) );
  }

}

因为我现在需要处理一个替代的序数映射,所以我写了这样的东西:

public class EnumAlternativeValueHelper<EnumMappingInterface,ValueType> {

  private final Function<EnumMappingInterface,ValueType> mappingFunction;

  public EnumAlternativeValueHelper(Function<EnumMappingInterface, ValueType> mappingFunction) {
    Preconditions.checkArgument(mappingFunction != null);
    this.mappingFunction = mappingFunction;
  }


  private <EnumType extends Enum<EnumType> & EnumMappingInterface> EnumType safeGetByAlternativeValue(Class<EnumType> enumClass, ValueType value) {
    for ( EnumType enumInstance : EnumSet.allOf(enumClass) ) {
      if ( mappingFunction.apply(enumInstance).equals(value) ) {
        return enumInstance;
      }
    }
    return null;
  }

}

但是<EnumType extends Enum<EnumType> & EnumMappingInterface>由于 EnumMappingInterface: “interface expected here”,泛型声明确实可以编译。

我已经看到了这个答案: Type parameter with multiple bounds

实际上,我的 EnumMappingInterface 是一个表示接口的泛型类型。它将是 EnumAlternativeName 或 EnumAlternativeOrdinal ,它们都定义了一个返回替代值的方法。

有什么解决方案可以让我实现我想要做的事情吗?谢谢

编辑:

EnumMappingInterface 是泛型类型,因此它没有任何定义,但我应该将此接口作为泛型类型传递:

public interface EnumAlternativeName {

  String getAlternativeName();

  Function<EnumAlternativeName,String> GET_ALTERNATIVE_NAME = new Function<EnumAlternativeName,String>() {
    @Override
    public String apply(EnumAlternativeName input) {
      return input.getAlternativeName();
    }
  };

}
4

2 回答 2

1

当您为泛型类型指定边界时,您只能使用类和接口。您不能将您的泛型类型与另一个泛型类型绑定。在您的情况下,我建议您引入第三个标记接口 EnumMappingInterface:

public interface EnumMappingInterface {
}

并将其用作 EnumAlternativeName 和 EnumAlternativeOrdinal 接口的父接口:

public interface EnumAlternativeName extends EnumMappingInterface {
    ...
}

在这种情况下,您有资格用作泛型类型EnumMappingInterface的第二个界限。EnumType

于 2013-05-17T17:17:26.107 回答
0

最后,通过定义一个抽象这两种情况的接口,它可以很好地覆盖 enum name() 和 ordinal() :

public interface EnumAlternativeValue<ValueType> {
  ValueType getAlternativeValue();
}

然后我可以这样做:

public class EnumAlternativeValueHelper {


  private static <ValueType,EnumType extends Enum<EnumType> & EnumAlternativeValue<ValueType>> EnumType safeGetByAlternativeValue(Class<EnumType> enumClass, ValueType value) {
    for ( EnumType enumInstance : EnumSet.allOf(enumClass) ) {
      if ( enumInstance.getAlternativeValue().equals(value) ) {
        return enumInstance;
      }
    }
    return null;
  }


  public static <ValueType,EnumType extends Enum<EnumType> & EnumAlternativeValue<ValueType>> Optional<EnumType> getIfPresent(Class<EnumType> enumClass, ValueType value) {
    EnumType t = safeGetByAlternativeValue(enumClass,value);
    return Optional.fromNullable(t);
  }


  public static <ValueType,EnumType extends Enum<EnumType> & EnumAlternativeValue<ValueType>> EnumType valueOf(Class<EnumType> enumClass, ValueType value) {
    EnumType t = safeGetByAlternativeValue(enumClass,value);
    return checkNotNull(t,"No alternative value of " + enumClass + " correspond to the provided alternative value = [" + value+"]");
  }


  public static <ValueType,EnumType extends Enum<EnumType> & EnumAlternativeValue<ValueType>> Optional<EnumType> valueOfNullSafe(Class<EnumType> enumClass, ValueType value) {
    if ( value == null) {
      return Optional.absent();
    }
    return Optional.of( valueOf(enumClass,value) );
  }

  public static <ValueType> Function<EnumAlternativeValue<ValueType>,ValueType> getAlternativeValueFunction() {
    return new Function<EnumAlternativeValue<ValueType>,ValueType>() {
      @Override
      public ValueType apply(EnumAlternativeValue<ValueType> input) {
        return input.getAlternativeValue();
      }
    };
  }

}

和测试:

public class EnumAlternativeValueHelperTest {


  private enum EnumUnderTest implements EnumAlternativeValue<String> {
    VALUE1("AlternativeName1"),
    VALUE2("AlternativeName2"),
    ;
    private final String alternativeName;
    private EnumUnderTest(String alternativeName) {
      this.alternativeName = alternativeName;
    }
    @Override
    public String getAlternativeValue() {
      return alternativeName;
    }
  }

  private enum EnumUnderTest2 implements EnumAlternativeValue<Integer> {
    VALUE1(1),
    VALUE2(2),
    ;
    private final int alternativeOrdinal;
    private EnumUnderTest2(int alternativeOrdinal) {
      this.alternativeOrdinal = alternativeOrdinal;
    }
    @Override
    public Integer getAlternativeValue() {
      return alternativeOrdinal;
    }
  }



  @Test
  public void getIfPresentReturnsValueTest() {
    assertThat( EnumAlternativeValueHelper.getIfPresent(EnumUnderTest.class,"AlternativeName1") )
            .isEqualTo(Optional.of(EnumUnderTest.VALUE1));
    assertThat( EnumAlternativeValueHelper.getIfPresent(EnumUnderTest2.class,1) )
            .isEqualTo(Optional.of(EnumUnderTest2.VALUE1));
  }
  @Test
  public void getIfPresentReturnsAbsent1Test() {
    assertThat( EnumAlternativeValueHelper.getIfPresent(EnumUnderTest.class,"AlternativeNameUnknown") )
            .isEqualTo( Optional.<EnumUnderTest>absent() );
    assertThat( EnumAlternativeValueHelper.getIfPresent(EnumUnderTest2.class,0) )
            .isEqualTo( Optional.<EnumUnderTest2>absent() );
  }
  @Test
  public void getIfPresentReturnsAbsentWhenNonAlternativeValueIsProvidedTest() {
    assertThat( EnumAlternativeValueHelper.getIfPresent(EnumUnderTest.class, EnumUnderTest.VALUE1.name()) )
            .isEqualTo( Optional.<EnumUnderTest>absent() );
    assertThat( EnumAlternativeValueHelper.getIfPresent(EnumUnderTest2.class, EnumUnderTest2.VALUE1.ordinal()) )
            .isEqualTo( Optional.<EnumUnderTest2>absent() );
  }
  @Test
  public void getIfPresentWhenBadAlternativeValueReturnsAbsentTest() {
    assertThat( EnumAlternativeValueHelper.getIfPresent(EnumUnderTest.class,null) )
            .isEqualTo(Optional.<EnumUnderTest>absent());
    assertThat( EnumAlternativeValueHelper.getIfPresent(EnumUnderTest2.class,null) )
            .isEqualTo(Optional.<EnumUnderTest2>absent());
  }



  @Test
  public void valueOfReturnsValueTest() {
    assertThat( EnumAlternativeValueHelper.valueOf(EnumUnderTest.class, "AlternativeName1") )
            .isEqualTo( EnumUnderTest.VALUE1 );
    assertThat( EnumAlternativeValueHelper.valueOf(EnumUnderTest2.class, 1) )
            .isEqualTo( EnumUnderTest2.VALUE1 );
  }
  @Test(expected = NullPointerException.class)
  public void valueOfThrowsExceptionTest() {
    EnumAlternativeValueHelper.valueOf(EnumUnderTest.class, "AlternativeNameUnknown");
    EnumAlternativeValueHelper.valueOf(EnumUnderTest2.class, 0);
  }
  @Test(expected = NullPointerException.class)
  public void valueOfThrowsExceptionWhenBadAlternativeValueTest() {
    EnumAlternativeValueHelper.valueOf(EnumUnderTest.class, null);
    EnumAlternativeValueHelper.valueOf(EnumUnderTest2.class, null);
  }
  @Test(expected = NullPointerException.class)
  public void valueOfThrowsExceptionWhenNonAlternativeValueIsProvidedTest() {
    EnumAlternativeValueHelper.valueOf(EnumUnderTest.class, EnumUnderTest.VALUE1.name());
    EnumAlternativeValueHelper.valueOf(EnumUnderTest2.class, EnumUnderTest.VALUE1.ordinal());
  }


  @Test
  public void nullSafeValueOfReturnsValueTest() {
    assertThat(EnumAlternativeValueHelper.valueOfNullSafe(EnumUnderTest.class, "AlternativeName1"))
            .isEqualTo(Optional.of(EnumUnderTest.VALUE1));
    assertThat(EnumAlternativeValueHelper.valueOfNullSafe(EnumUnderTest2.class, 1))
            .isEqualTo(Optional.of(EnumUnderTest2.VALUE1));
  }
  @Test(expected = NullPointerException.class)
  public void nullSafeValueOfThrowsExceptionTest() {
    EnumAlternativeValueHelper.valueOfNullSafe(EnumUnderTest.class, "AlternativeNameUnknown");
    EnumAlternativeValueHelper.valueOfNullSafe(EnumUnderTest2.class, 1);
  }
  @Test
  public void nullSafeValueOfReturnsAbsentWhenBadAlternativeValueTest() {
    assertThat( EnumAlternativeValueHelper.valueOfNullSafe(EnumUnderTest.class, null) )
            .isEqualTo(Optional.<EnumUnderTest>absent());
    assertThat( EnumAlternativeValueHelper.valueOfNullSafe(EnumUnderTest2.class, null) )
            .isEqualTo(Optional.<EnumUnderTest2>absent());
  }
  @Test(expected = NullPointerException.class)
  public void nullSafeValueOfThrowsExceptionWhenNonAlternativeValueIsProvidedTest() {
    EnumAlternativeValueHelper.valueOf(EnumUnderTest.class, EnumUnderTest.VALUE1.name());
    EnumAlternativeValueHelper.valueOf(EnumUnderTest2.class, EnumUnderTest.VALUE1.ordinal());
  }



  @Test
  public void alternativeValueFunctionTest() {
    assertThat(EnumAlternativeValueHelper.<String>getAlternativeValueFunction().apply(EnumUnderTest.VALUE1)).isEqualTo("AlternativeName1");
    assertThat(EnumAlternativeValueHelper.<Integer>getAlternativeValueFunction().apply(EnumUnderTest2.VALUE1)).isEqualTo(1);
  }
于 2013-05-21T09:46:49.767 回答