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)
它曾经与 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>.
尽管我理解编译错误的基本原理,但我不同意只读方法。