使用带有嵌套“?”的 Set 调用 java 方法泛型
Calling java method with Set with nested "?" generic type
我在可重复使用的 class:
中有这样的方法
public String buildMessageForViolation(ConstraintViolation<?> constraintViolation) {
return constraintViolation.getPropertyPath().toString().replace(".<collection element>", "") + ": " + constraintViolation.getMessage();
}
它是从另一个 class 调用的,像这样:
fieldValidator.appendErrorMessage(getUslValidator().buildMessageWithProperty(constraintViolations.iterator().next()) +
(constraintViolations.size() > 1 ? ", and other errors" : ""));
所以,因为我希望这个块在许多 class 中重复,所以我想重构它,所以复杂性在于可重用 class,而不是客户端代码。
所以,然后我将其添加到可重复使用的 class:
public String buildMessageForViolations(Set<ConstraintViolation<?>> constraintViolations) {
return buildMessageForViolation(constraintViolations.iterator().next()) +
(constraintViolations.size() > 1 ? ", and other errors" : "");
}
然后将客户端代码更改为:
fieldValidator.appendErrorMessage(getUslValidator().buildMessageForViolations(constraintViolations));
这个编译不通过,说:
The method buildMessageForViolations(Set<ConstraintViolation<?>>) in the type USLValidator is not applicable for the arguments (Set<ConstraintViolation<ClientSpecificClassName>>)
很明显,这与我指定“?”这一事实有关。对于嵌套类型参数。在我看来,这是合适的,因为可重用的 class 不关心 ConstraintViolation 的类型参数。
有什么简单的方法可以解决这个问题吗?
更新:
我正在阅读发布到此的答案,以及对答案的后续编辑,但由于某种原因它被删除了(猜测回复者放弃了尝试使其正确)。
虽然答案还在,但它至少帮助我找到了一个比较合理的解决方法。
客户端代码可以改为这样做:
fieldValidator.appendErrorMessage(getUslValidator().buildMessageForViolations(new HashSet<ConstraintViolation<?>>(constraintViolations)));
这至少比原来的好一点,尽管仍然有一些人们必须记住的样板。
嵌套的通配符可能会导致一些意外的不兼容性。试试这个:
public String buildMessageForViolations(Set<? extends ConstraintViolation<?>> constraintViolations) {
我会把方法写成:
public String buildMessageForViolations(Set<ConstraintViolation> constraintViolations) {..}
这告诉编译器它接受一组任何类型的 ConstraintViolation
。我认为在这种情况下,这就是您要告诉编译器的内容。
客户端代码如下:
ConstraintViolation cv = new StringConstraintViolation();
USLValidator uslValidator = new USLValidator();
Set<ConstraintViolation> constraintViolationSet = new HashSet<>();
constraintViolationSet.add(cv);
uslValidator.buildMessageForViolations(constraintViolationSet);
我在可重复使用的 class:
中有这样的方法public String buildMessageForViolation(ConstraintViolation<?> constraintViolation) {
return constraintViolation.getPropertyPath().toString().replace(".<collection element>", "") + ": " + constraintViolation.getMessage();
}
它是从另一个 class 调用的,像这样:
fieldValidator.appendErrorMessage(getUslValidator().buildMessageWithProperty(constraintViolations.iterator().next()) +
(constraintViolations.size() > 1 ? ", and other errors" : ""));
所以,因为我希望这个块在许多 class 中重复,所以我想重构它,所以复杂性在于可重用 class,而不是客户端代码。
所以,然后我将其添加到可重复使用的 class:
public String buildMessageForViolations(Set<ConstraintViolation<?>> constraintViolations) {
return buildMessageForViolation(constraintViolations.iterator().next()) +
(constraintViolations.size() > 1 ? ", and other errors" : "");
}
然后将客户端代码更改为:
fieldValidator.appendErrorMessage(getUslValidator().buildMessageForViolations(constraintViolations));
这个编译不通过,说:
The method buildMessageForViolations(Set<ConstraintViolation<?>>) in the type USLValidator is not applicable for the arguments (Set<ConstraintViolation<ClientSpecificClassName>>)
很明显,这与我指定“?”这一事实有关。对于嵌套类型参数。在我看来,这是合适的,因为可重用的 class 不关心 ConstraintViolation 的类型参数。
有什么简单的方法可以解决这个问题吗?
更新:
我正在阅读发布到此的答案,以及对答案的后续编辑,但由于某种原因它被删除了(猜测回复者放弃了尝试使其正确)。
虽然答案还在,但它至少帮助我找到了一个比较合理的解决方法。
客户端代码可以改为这样做:
fieldValidator.appendErrorMessage(getUslValidator().buildMessageForViolations(new HashSet<ConstraintViolation<?>>(constraintViolations)));
这至少比原来的好一点,尽管仍然有一些人们必须记住的样板。
嵌套的通配符可能会导致一些意外的不兼容性。试试这个:
public String buildMessageForViolations(Set<? extends ConstraintViolation<?>> constraintViolations) {
我会把方法写成:
public String buildMessageForViolations(Set<ConstraintViolation> constraintViolations) {..}
这告诉编译器它接受一组任何类型的 ConstraintViolation
。我认为在这种情况下,这就是您要告诉编译器的内容。
客户端代码如下:
ConstraintViolation cv = new StringConstraintViolation();
USLValidator uslValidator = new USLValidator();
Set<ConstraintViolation> constraintViolationSet = new HashSet<>();
constraintViolationSet.add(cv);
uslValidator.buildMessageForViolations(constraintViolationSet);