4

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

import java.util.List;

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

Bar另一个接口在哪里。

当我像这样用 AssertJ 编写断言时:

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

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

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

我得到这个编译错误:

ListAssert 类型中的 containsExactly(capture#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);
4

1 回答 1

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

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

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

于 2017-11-16T02:14:11.420 回答