【问题标题】:How can you unit test for a correct configuration of a complex TypeToken?如何对复杂 TypeToken 的正确配置进行单元测试?
【发布时间】:2017-07-28 01:55:43
【问题描述】:

我有一些使用泛型和 TypeToken 反序列化 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 的类转换错误。

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

  }

【问题讨论】:

    标签: java unit-testing generics gson guava


    【解决方案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&lt;IPolicy&gt; list; 可以被 ProGuard 之类的工具处理,所以它可能变成private final List list;,除非使用-keepattributes Signature——一般来说它是合法的 Java 代码,但 Gson 没有足够的类型信息并使用LinkedTreeMap。这是您尝试将此类列表元素分配给IPolicy 引用时应该得到的结果。另一种情况是typeToken.getRawType() 而不是type.getToken():原始类型不包含参数化信息,所以new TypeToken&lt;List&lt;IPolicy&gt;&gt;(){}.getRawType() 只是一个List.class——仍然没有关于使 Gson 使用默认策略的元素类型的信息。

    getContent 返回一个列表,但它需要测试泛型类型

    只需使用返回java.lang.reflect.TypeTypeToken.getType(),它是所有类型的基本接口。参数化泛型类型用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());
    

    【讨论】:

      猜你喜欢
      • 2021-01-10
      • 2016-09-26
      • 2010-09-23
      • 1970-01-01
      • 2014-01-28
      • 2023-03-20
      • 2014-01-30
      • 2011-02-02
      • 1970-01-01
      相关资源
      最近更新 更多