Search code examples
javagenericscollectionsgeneric-collections

Calling java method with Set with nested "?" generic type


I have a method like this in a reusable class:

public String buildMessageForViolation(ConstraintViolation<?> constraintViolation) {
    return constraintViolation.getPropertyPath().toString().replace(".<collection element>", "") + ": " + constraintViolation.getMessage();
}

It's called from another class like this:

 fieldValidator.appendErrorMessage(getUslValidator().buildMessageWithProperty(constraintViolations.iterator().next()) +
                (constraintViolations.size() > 1 ? ", and other errors" : ""));

So, since I expect this block to be repeated in many classes, I wanted to refactor this so the complexity is in the reusable class, not in the client code.

So, I then added this to the reusable class:

public String buildMessageForViolations(Set<ConstraintViolation<?>> constraintViolations) {
    return buildMessageForViolation(constraintViolations.iterator().next()) +
            (constraintViolations.size() > 1 ? ", and other errors" : "");
}

And then changed the client code to this:

fieldValidator.appendErrorMessage(getUslValidator().buildMessageForViolations(constraintViolations));

This does not compile, saying:

The method buildMessageForViolations(Set<ConstraintViolation<?>>) in the type USLValidator is not applicable for the arguments (Set<ConstraintViolation<ClientSpecificClassName>>)

Clearly this has something to do with the fact that I specify "?" for the nested type parameter. From my point of view, this is appropriate because the reusable class doesn't care about the type parameter of the ConstraintViolation.

Is there something simple I can do to resolve this?

Update:

I was reading an answer that was posted to this, along with subsequent edits to the answer, but then it was deleted for some reason (guess the responder gave up trying to make it right).

While the answer was still there, it at least helped me find a somewhat reasonable workaround.

The client code can instead do this:

fieldValidator.appendErrorMessage(getUslValidator().buildMessageForViolations(new HashSet<ConstraintViolation<?>>(constraintViolations)));

That's at least a little better than the original, even though there's still some boilerplate that people have to remember.


Solution

  • Nested wildcards can cause some unexpected incompatibilities. Try this:

    public String buildMessageForViolations(Set<? extends ConstraintViolation<?>> constraintViolations) {