如何对复杂 TypeToken 的正确配置进行单元测试?
How can you unit test for a correct configuration of a complex TypeToken?
我有一些使用泛型和 TypeTokens 反序列化的服务代码 JSON。需要该服务来反序列化保持其通用参数类型的复杂 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 收到 class 转换错误。
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap
cannot be cast to com.myStuff.IPolicy
看来我调试的时候是对的。 toString() 函数表明它知道它的泛型类型参数:
com.myStuff.PolicyWrapper<com.myStuff.PolicyImpl>
终于要进行单元测试了。它通过但不测试泛型类型参数。我测试了 TypeToken 的 rawType() 并得到了正确的 class 但我不确定如何测试它的通用类型。
@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);
}
It appears that the TypeToken isn't working correctly because I get a class cast error from GSON.
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.myStuff.IPolicy
不是真的。在您的情况下,看起来 Gson 在反序列化时没有收到足够的类型信息。 LinkedTreeMap
是Gson内部的map实现,Gson默认用来反序列化任意结构的未知类型的对象。例如,如果由于某种原因通用 类 参数化信息是 lost/erased,则可能会发生这种情况。例如,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 成为使用默认策略。
the getContent returns a list but it needs the generic type tested
只需使用 TypeToken.getType()
即 returns 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());
我有一些使用泛型和 TypeTokens 反序列化的服务代码 JSON。需要该服务来反序列化保持其通用参数类型的复杂 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 收到 class 转换错误。
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap
cannot be cast to com.myStuff.IPolicy
看来我调试的时候是对的。 toString() 函数表明它知道它的泛型类型参数:
com.myStuff.PolicyWrapper<com.myStuff.PolicyImpl>
终于要进行单元测试了。它通过但不测试泛型类型参数。我测试了 TypeToken 的 rawType() 并得到了正确的 class 但我不确定如何测试它的通用类型。
@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);
}
It appears that the TypeToken isn't working correctly because I get a class cast error from GSON.
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.myStuff.IPolicy
不是真的。在您的情况下,看起来 Gson 在反序列化时没有收到足够的类型信息。 LinkedTreeMap
是Gson内部的map实现,Gson默认用来反序列化任意结构的未知类型的对象。例如,如果由于某种原因通用 类 参数化信息是 lost/erased,则可能会发生这种情况。例如,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 成为使用默认策略。
the getContent returns a list but it needs the generic type tested
只需使用 TypeToken.getType()
即 returns 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());