Hamcrest 1.2ライブラリを使用していくつかのマッチャーを作成していますが、Java ワイルドカードに苦労しています。次のコードをコンパイルしようとすると
public class GenericsTest {
public void doesNotCompile() {
Container<String> container = new Container<String>();
// this is the desired assertion syntax
assertThat(container, hasSomethingWhich(is("foo")));
}
// these two are a custom made class and matcher; they can be changed
public static class Container<T> {
public boolean hasSomethingMatching(Matcher<T> matcher) {
T something = null; // here is some application logic
return matcher.matches(something);
}
}
public static <T> Matcher<Container<T>> hasSomethingWhich(final Matcher<T> matcher) {
return new TypeSafeMatcher<Container<T>>() {
@Override
protected boolean matchesSafely(Container<T> container) {
return container.hasSomethingMatching(matcher);
}
};
}
// the following signatures are from the Hamcrest 1.2 library; they cannot be changed
public static <T> void assertThat(T actual, Matcher<? super T> matcher) {
}
public static <T> Matcher<? super T> is(T value) {
return null;
}
public interface Matcher<T> {
boolean matches(Object item);
}
public static abstract class TypeSafeMatcher<T> implements Matcher<T> {
@SuppressWarnings({"unchecked"})
@Override
public final boolean matches(Object item) {
return matchesSafely((T) item);
}
protected abstract boolean matchesSafely(T item);
}
}
コンパイルエラーが発生します
$ javac GenericsTest.java
GenericsTest.java:7: <T>assertThat(T,GenericsTest.Matcher<? super T>) in GenericsTest cannot be applied to (GenericsTest
.Container<java.lang.String>,GenericsTest.Matcher<GenericsTest.Container<capture#928 of ? super java.lang.String>>)
assertThat(container, hasSomethingWhich(is("foo")));
^
1 error
コンパイルできるようにコードを変更するにはどうすればよいですか? ? super
Container クラスと hasSomethingWhich メソッドのシグネチャのとのさまざまな組み合わせを試しまし? extends
たが、コンパイルできませんでした (明示的なメソッド型パラメーターを使用せずに、醜いコードを生成します: GenericsTest.<String>hasSomethingWhich
)。
また、簡潔で読みやすいアサーション構文を作成するための代替アプローチも歓迎します。構文に関係なく、Container と、Container 内の要素を照合するための Matcher をパラメーターとして受け入れる必要があります。