Skip to content

Spring Test: Methods should allow supertypes of Matcher using lower bounded wildcards #25610

@mjustin

Description

@mjustin

I was working with a test helper method a colleague wrote that took in an arbitrary status code Matcher to test whether a status code matched a particular value, which was implemented under the hood using StatusResultMathers.is(Matcher<Integer> matcher). I had one use case where I didn't actually care to assert anything, so I wanted to pass in Hamcrest's Matchers.anything() to the method. However, Matchers.anything() returns a Matcher<Object>, not a Matcher<Integer>, so it cannot be used with StatusResultMathers.is.

I ended up rewriting my test to not require the use of this matcher, but regardless of this fact, pretty much any method that takes in a specific type of Matcher to match against an object (e.g. Matcher<Integer>) should be allowed to take in a Matcher that matches a superclass as well, since that's still applicable to the object being matched.

Therefore, I propose that this method (and any other such test method in Spring Test) have its input type relaxed to allow the given type or any supertype. For this specific case, StatusResultMathers.is(Matcher<Integer> matcher) should be changed to StatusResultMathers.is(Matcher<? super Integer> matcher).

Example

This fails to compile:

MockMvcResultMatchers.status().is(Matchers.anything());

Methods with this issue

A quick search of the Spring Test project reveals the following methods that could have their generics widened:

Additionally, there are five methods containing Matcher<T> matcher, Class<T> targetType which I think could be widened to being Matcher<? super T> matcher, Class<T> targetType to allow a more general Matcher than the target type:

  • JsonPathAssertions.value(Matcher<T> matcher, Class<T> targetType)
  • JsonPathExpectationsHelper.assertValue(String content, Matcher<T> matcher, Class<T> targetType)
  • JsonPathRequestMatchers.value(Matcher<T> matcher, Class<T> targetType)
  • JsonPathResultMatchers.value(Matcher<T> matcher, Class<T> targetType)
  • MockMvcResultMatchers.jsonPath(String expression, Matcher<T> matcher, Class<T> targetType)

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions