2013-05-17 62 views
0

我想能夠枚舉映射到「替代值」,因爲在我們的遺留數據庫中,一些枚舉使用的值不能映射到枚舉(即,不是開始當int爲0時,在String類型時不能表示爲枚舉名)。枚舉和泛型「界面預期」與多個邊界

下工作正常,以便能夠枚舉映射到的替代名稱:

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:「此處預期的接口」。

我已經看到了這樣的回答: Type parameter with multiple bounds

其實,我EnumMappingInterface是一個泛型類型,這將代表一個接口。它將是EnumAlternativeName或EnumAlternativeOrdinal,它們都定義了一個返回替代值的方法。

有沒有解決方案,以便我可以實現我想要做的?由於

編輯:

EnumMappingInterface是一個通用的類型,因此它不具有任何defition但我認爲這個接口傳遞的泛型類型:

public interface EnumAlternativeName { 

    String getAlternativeName(); 

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

} 
+0

請問你能展示你的'EnumMappingInterface'的定義嗎? – hoaz

+0

它沒有任何定義,因爲它是通用類型 –

回答

0

最後,它通過定義一個接口,抽象兩種情況下工作正常,覆蓋枚舉名稱()和序數() :

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

在指定範圍對於泛型類型,您只能使用類和接口。您不能將泛型與其他泛型綁定。你的情況我建議你介紹第三標記接口EnumMappingInterface:

public interface EnumMappingInterface { 
} 

而且使用它作爲EnumAlternativeName和EnumAlternativeOrdinal interaces父接口:

public interface EnumAlternativeName extends EnumMappingInterface { 
    ... 
} 

在這種情況下,你有資格使用EnumMappingInterface作爲第二個界限爲您的EnumType泛型類型。

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

} 

而且測試

+0

是的,但請解釋如何創建2個EnumAlternativeValueHelper實例(一個用於替代名稱,另一個用於替代序數),以及如何使用它們,因爲我可以通過參數可能無法映射到我提供的值的枚舉。我正在尋找一個類型安全的解決方案 –

+0

一個解決方案,我能想到的就是把所有常用的方法'EnumMappingInterface',直接放在你的助手使用它們 – hoaz

+0

那麼就意味着複製方法字符串VS整數結果,您準確像複製EnumAlternativeNameHelper(像我的帖子中的肖恩)並創建EnumAlternativeOrdinalHelper:代碼沒有因式分解 –