6

I have a getter returning a List with a wildcard:

import java.util.List;

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

Where Bar is an other interface.

When I write an assertion with AssertJ like this:

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

EDIT: my complete usage is to chain a usingElementComparator and to provide a Comparator<Bar> to compare the expected Bar instances.

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

I get this compilation error:

The method containsExactly(capture#46-of ? extends Bar...) in the type ListAssert is not applicable for the arguments (Bar, Bar)


My first solution is to cast the result:

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

Then I get a warning:

Type safety: Unchecked cast from List to List

Warning can be removed with @SuppressWarnings("unchecked"), but still the cast in the middle do not make the assertion really readable.


My second solution is to indicate the value the ELEMENT generic parameter:

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

A little better, but also not that nice (no static import possible, the beginning of the line do not facilitate the readability)


I guess I am looking for an other assertThat method for list, where the class type can be specified as second parameter:

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

This way I should be able to write something like this:

Assertions.assertThat(foo.getList(), Bar.class).containsExactly(bar1, bar3);
Jmini
  • 9,189
  • 2
  • 55
  • 77

1 Answers1

2

That used to work with the Oracle JDK 7 compiler but this was actually a bug in the compiler, this has been fixed in Java 8 JDK so having the compilation error is the normal behavior (can't find the bug reference though).

I would be happy to support but I'm not sure this is possible in AssertJ except by removing all generics usage in collections assertions.

assertThat(List, Class) already exists but for another purpose so no luck for that option.

A possible hack is to define your own assertThat method like that:

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

The trick being to return a ListAssert<Object>.

Although I understand the rationale of the compilation error I disagree with it for read only method.

Joel Costigliola
  • 6,308
  • 27
  • 35
  • Thank you for your detailed answer. Do not remove all generics usage in collection assertions. They are 95% correct and helpfull. Returning a `ListAssert` is not working for me, because I also use a `usingElementComparator`method in the chain (see updated question). I might go with own `assertThatListOf(Class, List)` By the way, *THANK YOU* for AssertJ, It is a great library! – Jmini Nov 16 '17 at 05:53
  • Thanks for the kind words, appreciated. – Joel Costigliola Nov 17 '17 at 01:34