2017-03-07 86 views
2

我有一些服務代碼,使用泛型和TypeTokens來反序列化JSON。需要該服務來反序列化保持其通用參數類型的複雜TypeToken。如何單元測試複雜TypeToken的正確配置?

下面是創建它的代碼:

<T extends IPolicy> TypeToken<PolicyWrapper<T>> makePolicyWrapperTypeToken(Class<T> policyClass) { 
    TypeToken<T> policyTypeToken = TypeToken.of(policyClass); 
    return new TypeToken<PolicyWrapper<T>>() {} 
     .where(new TypeParameter<T>() {}, policyTypeToken); 
    } 

看來,TypeToken不能正常工作,因爲我從GSON類強制轉換錯誤。

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap 
cannot be cast to com.myStuff.IPolicy 

它看起來像我調試時正確。 toString()函數表明它知道它的泛型類型參數:

com.myStuff.PolicyWrapper<com.myStuff.PolicyImpl> 

最後,我有一個單元測試。它通過但不測試泛型類型參數。我測試了TypeToken的rawType()並獲得了正確的類,但我不確定如何測試它的泛型類型。

@Test 
public void makePolicyWrapperTypeToken() throws NoSuchMethodException { 

    TypeToken<?> wrapperToken = makePolicyWrapperTypeToken(PolicyImpl.class); 
    assertEquals(wrapperToken.getRawType(), PolicyWrapper.class); 

    //the getContent returns a list but it needs the generic type tested 
    TypeToken<?> contentToken = wrapperToken.resolveType(PolicyWrapper.class.getMethod("getContent").getGenericReturnType()); 
    assertEquals(contentToken.getRawType(), List.class); 

    } 

回答

1

看來,TypeToken不能正常工作,因爲我從GSON類強制轉換錯誤。 java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.myStuff.IPolicy

不是真的。在你的情況下,Gson看起來像反序列化時沒有收到足夠的類型信息。 LinkedTreeMap是Gson用來在默認情況下用任意結構反序列化未知類型的對象的內部Gson映射實現。例如,如果通用類參數化信息由於某種原因丟失/擦除,則可能發生這種情況。例如,private final List<IPolicy> list;可以用像ProGuard這樣的工具處理,所以它可能會變成private final List list;,除非使用-keepattributes Signature--一般來說它是合法的Java代碼,但Gson沒有足夠的類型信息並使用LinkedTreeMap。一旦試圖將這樣一個列表元素分配給IPolicy引用,你應該得到這個。另一種情況是typeToken.getRawType()而不是type.getToken():原始類型不包含的參數信息,所以new TypeToken<List<IPolicy>>(){}.getRawType()只是一個List.class - 仍然沒有對元素類型,使GSON使用默認的策略信息。

中的getContent返回一個列表,但它需要的泛型類型測試

只需使用TypeToken.getType()返回java.lang.reflect.Type這是對所有類型的基本接口。參數化的泛型類型使用ParameterizedType表示,它提供了有關類型參數化的更多信息,這與更一般的Type不一樣,並且此信息也可以使用類型標記構建。所以,下面的說法是正確的:

// not really necessary, but just for the demonstration purposes: 
assertTrue(contentToken.getType() instanceof ParameterizedType); 
// this is enough: 
assertEquals(new TypeToken<List<PolicyImpl>>() {}.getType(), contentToken.getType()); 
+0

我明白了,謝謝 – superbAfterSemperPhi

+0

@superbAfterSemperPhi沒問題,歡迎光臨。 –