2017-03-07 82 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没问题,欢迎光临。 –