AssertJ`在带有通配符的列表中包含Exactly`断言

时间:2017-11-15 21:18:37

标签: java generics wildcard assertj unbounded-wildcard

我有一个getter返回带有通配符的List:

import java.util.List;

public interface Foo {
    List<? extends Bar> getList();
}

其中Bar是其他界面。

当我用这样的AssertJ写一个断言时:

assertThat(foo.getList()).containsExactly(bar1, bar3);

编辑:我的完整用法是链接usingElementComparator并提供Comparator<Bar>来比较预期的Bar个实例。

Comparator<Bar> comparator = createBarComparator()
assertThat(foo.getList()).usingElementComparator(comparator).containsExactly(bar1, bar3);

我收到此编译错误:

  

该方法包含ListAssert类型中的确切(捕获#46-of?extends Bar ...)不适用于参数(Bar,Bar)

我的第一个解决方案是投射结果:

assertThat((List<Bar>)foo.getList()).containsExactly(bar1, bar3);

然后我收到警告:

  

类型安全:从列表到列表的未选中投射

可以使用@SuppressWarnings("unchecked")删除警告,但中间的强制转换不会使断言真正可读。

我的第二个解决方案是指示ELEMENT通用参数的值:

Assertions.<Bar>assertThat(foo.getList()).containsExactly(bar1, bar3);

好一点,但也不是那么好(没有静态导入可能,行的开头不方便可读性)

我想我正在寻找列表的其他assertThat方法,其中类类型可以指定为第二个参数:

@CheckReturnValue
public static <ELEMENT> ListAssert<ELEMENT> assertThat(List<? extends ELEMENT> actual, Class<ELEMENT> c) {
    return AssertionsForInterfaceTypes.assertThat(actual);
}

这样我就能写出这样的东西:

Assertions.assertThat(foo.getList(), Bar.class).containsExactly(bar1, bar3);

1 个答案:

答案 0 :(得分:1)

以前用过Oracle JDK 7编译器,但这实际上是编译器中的一个错误,这已在Java 8 JDK中修复,因此编译错误是正常行为(无法找到错误参考虽然)。

我很乐意支持,但我不确定在AssertJ中是否可行,除非删除集合断言中的所有泛型用法。

assertThat(List, Class)已经存在,但出于其他目的,所以没有运气。

可能的hack是定义你自己的assertThat方法:

public static <T> ListAssert<Object> assertThat(final List<T> list) {
    return Assertions.assertThat(list);
}

诀窍是返回ListAssert<Object>

虽然我理解编译错误的基本原理,但我不同意它的只读方法。