带有通配符的 AssertJ `containsExactly` 断言列表

Jmi*_*ini 6 java generics wildcard unbounded-wildcard assertj

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

import java.util.List;

public interface Foo {
    List<? extends Bar> getList();
}
Run Code Online (Sandbox Code Playgroud)

哪里Bar有其他接口。

当我用 AssertJ 编写断言时,如下所示:

assertThat(foo.getList()).containsExactly(bar1, bar3);
Run Code Online (Sandbox Code Playgroud)

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

Comparator<Bar> comparator = createBarComparator()
assertThat(foo.getList()).usingElementComparator(comparator).containsExactly(bar1, bar3);
Run Code Online (Sandbox Code Playgroud)

我收到此编译错误:

ListAssert 类型中的方法 containsExactly(capture#46-of ? extends Bar...) 不适用于参数 (Bar, Bar)


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

assertThat((List<Bar>)foo.getList()).containsExactly(bar1, bar3);
Run Code Online (Sandbox Code Playgroud)

然后我收到警告:

类型安全:从列表到列表的未经检查的转换

可以使用 删除警告@SuppressWarnings("unchecked"),但中间的强制转换仍然无法使断言真正具有可读性。


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

Assertions.<Bar>assertThat(foo.getList()).containsExactly(bar1, bar3);
Run Code Online (Sandbox Code Playgroud)

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


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

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

这样我应该能够写出这样的东西:

Assertions.assertThat(foo.getList(), Bar.class).containsExactly(bar1, bar3);
Run Code Online (Sandbox Code Playgroud)

Joe*_*ola 2

它曾经与 Oracle JDK 7 编译器一起使用,但这实际上是编译器中的一个错误,这已在 Java 8 JDK 中修复,因此编译错误是正常行为(尽管找不到错误参考)。

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

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

一个可能的技巧是定义你自己的assertThat方法,如下所示:

public static <T> ListAssert<Object> assertThat(final List<T> list) {
    return Assertions.assertThat(list);
}
Run Code Online (Sandbox Code Playgroud)

诀窍是返回一个ListAssert<Object>.

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