I admit this is a contrived situation, but why does the following code not compile?
Environment details:
- Java: openjdk 11.0.20 2023-07-18
- AssertJ: 3.24.2 (discovered while running 3.21.0)
package example;
import org.junit.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.*;
public class ExampleTest {
public interface ICommon {
}
public static class TypeA implements ICommon {
// assume overridden equals
}
public static class TypeB implements ICommon {
// assume overridden equals
}
@Test
public void test() {
final List<ICommon> actual = List.of(new TypeA(), new TypeB());
final List<ICommon> expected = List.of(new TypeA());
final Iterable<? extends ICommon> thisCompiles = expected; // no problems
/*
* 'containsAnyElementsOf(java.lang.Iterable<? extends capture<? extends example.ExampleTest.ICommon>>)'
* in 'org.assertj.core.api.AbstractIterableAssert' cannot be applied to
* '(java.util.List<example.ExampleTest.ICommon>)'
*/
assertThat(actual).satisfies(r -> assertThat(r).containsAnyElementsOf(expected));
/*
*
* 'containsAnyElementsOf(java.lang.Iterable<? extends capture<? extends example.ExampleTest.ICommon>>)'
* in 'org.assertj.core.api.AbstractIterableAssert' cannot be applied to
* '(java.lang.Iterable<capture<? extends example.ExampleTest.ICommon>>)'
*/
assertThat(actual).satisfies(r -> assertThat(r).containsAnyElementsOf(thisCompiles));
}
}
(I Reiterate: this example is not a good way to test what is being tested, it is merely a stripped down model for example purposes only. DO NOT use it as an example of best practices. This is not a place of honor.)
A coworker came to me with code that ultimately boiled down to a similar situation. I managed to give them a better way to do the assertion, but I was personally disturbed because I realized I could not explain why this code does not compile. Because of this I am returning to StackOverflow after a long absence to throw this to the community. What is preventing the compiler from figuring this code out?
You need to assign the
assertThat(assertion)statement to a typedListAssert<ICommon>variable. This is because theassertThatmethod does not know what the concrete list type should be.Here is a working unit test. I used Lombok to annotate the classes to supply the
equals()andhashCode()methods. Also, I changedList.oftoArrays.asListfor Java 8 compatibility. Feel free to change it back.You could also cast the list inline:
Since the
org.assertj.core.api.Assertions#assertThatmethod is static, you are required to assign its result into aListAssert<ELEMENT>variables. WhereELEMENTis the type of list item to be checked. I believe they thing that is throwing you off is the<? extends ELEMENT>part.You could simplify this to just: