4

In a test class using AssertJ, I have code similar to the following:

public void someTest() {
    assertThat(getNames()).has(sameNamesAs(getExpectedNames()));
    assertThat(getNames()).doesNotHave(sameNamesAs(getOtherNames()));
}

private List<String> getNames() {
    return null;
}
private List<String> getExpectedNames() {
    return null;
}
private List<String> getOtherNames() {
    return null;
}

private Condition<List<String>> sameNamesAs(List<String> rhs) {
    return new Condition<List<String>>("same names as " + rhs) {
        @Override
        public boolean matches(final List<String> lhs) {
            return lhs.containsAll(rhs) && rhs.containsAll(lhs);
        }
    };
}

I get a compilation error on the calls to has and doesNotHave:

has/doesNotHave
(org.assertj.core.api.Condition<? super java.util.List<? extends java.lang.String>>)
in AbstractListAssert cannot be applied
to
(org.assertj.core.api.Condition<java.util.List<java.lang.String>>).

I'm new to Java and I don't understand the problem: java.util.List is a super-type of java.util.List and java.lang.String extends java.lang.String, don't they?

1 Answers1

3

In your case, the has and doesNotHave methods take a Condition<? super List<? extends T> condition, not a Condition<? super List<T>> as you are returning from your Condition<List<T>> sameNamesAs method.

You need an instance of the Condition<List<? extends String>> type (it's a subclass of the original type Condition<? super List<? extends String>>):

private Condition<List<? extends String>> sameNamesAs(List<String> rhs) {
    return new Condition<List<? extends String>>("same names as " + rhs) { ... };
}

I tried to illustrate this with the following snippet:

List<String> list = getNames();

// ELEMENT = String, ACTUAL = List<? extends ELEMENT>
ListAssert<String> assertThat = assertThat(list);

// by the signature, we have to pass Condition<? super ELEMENT> or Condition<? super ACTUAL>
// Condition<? super ACTUAL> = Condition<? super List<? extends String>>
Condition<List<? extends String>> condition = sameNamesAs(list);

// Condition<List<? extends String>> extends Condition<? super List<? extends String>>
assertThat.has(condition);
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • Thank you for the solution and the explanation. If I understand correctly, my mistake was to believe that `List` is a super-type of `List extends String>` while the two types actually have no inheritance relationship. I just don't understand this line in your answer: `// by the signature, we have to pass Condition super ELEMENT> or Condition super ACTUAL>`. What is `ACTUAL` here? – Christophe Fuzier Dec 13 '16 at 17:49
  • @ChristopheFuzier, yes, because `List` is *a child* of `List extends String>`. `ACTUAL`, `ELEMENT` are just different generic parameters of methods and the `Assertions` class respectively (`ACTUAL = List extends ELEMENT>`) – Andrew Tobilko Dec 13 '16 at 18:16
  • I haven't been able to differentiate between the keywords "super" when used in place of "extends". What is difference between Condition super ELEMENT> and Condition extends ELEMENT>? Why aren't using the lattter? – sidnc86 Dec 24 '19 at 08:12