英文:
Annotation based validation on DTO level happens before field level validation like @NotNull @Size etc
问题
我有一个DTO类,在其中我设置了一些字段为必填项。
而且,基于另一个类型的字段,其值可以是A和B。
如果是类型A,则只需要检查传递的项目中是否只有1个项目;如果是B,则可以是多于1个项目。
我需要检查列表中是否至少有一个值在DTO类级别上。在自定义注解验证中,我需要根据DTO的类型字段检查列表的大小。
因此,在DTO中:
@NotNull
@Size(min = 1)
private List<@NotBlank String> items;
在注解内部:
if (cancelType == CancellationTypeEnum.A && cancelDto.getItems().size() > 1) {
isValid = false;
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(
"Only one item can be sent for 'A' cancel type.").addConstraintViolation();
}
但是,由于字段级别的验证稍后进行,如果我对项目字段传递null,它将进入此注解验证器并抛出NPE,因为字段为null,而我正在尝试获取大小。
临时解决方案是我做了null检查,然后检查大小,但是在字段级别,我们无论如何都已经使用了@NotNull。
是否有任何方法可以在字段级别验证发生后执行类级别的自定义注解验证。
在那种情况下,它将由于字段为null而引发字段级别验证,而不会进入自定义类级别注解。
英文:
I have a DTO class where I made some fields mandatory.
And, based on another type field where value can be assume A & B
if type A, need to check only 1 item can be passed, if B it can be more than 1 also.
I need to check if a list has at least 1 value in DTO class level. And, in custom annotation validation I need to check size of list based on type field of DTO.
So, in DTO
@NotNull
@Size(min = 1)
private List<@NotBlank String> items;
And, inside annotation
if (cancelType == CancellationTypeEnum.A && cancelDto.getItems().size() > 1) {
isValid = false;
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(
"Only one item can be sent for 'A' cancel type.").addConstraintViolation();
}
But, since field level happens later, if I pass null for items field, it goes to this annotation validator & throw NPE as field is null & I am trying to get size
Temporary solution is I do null check, then check size, but in field level anyway we are giving @NotNull.
Is there any way to do class level custom annotation to validate after field level validation happens.
In that case, it will throw field level validation as field is null & will not go to custom class level annotation
答案1
得分: 1
你可以使用 JS-303 验证组(参见这里),结合@Validated,文档中如下所示:
JSR-303的Valid的变体,支持指定验证组规范。
例如:
@CheckEnumSize(groups = {Secondary.class})
public class CancelDto {
public CancelDto(List<String> items) {
this.items = items;
}
@NotNull(groups = {Primary.class})
@Size(min = 1)
public List<@NotNull String> items;
public CancellationTypeEnum cancelType;
public List<String> getItems() {
return items;
}
}
其中 Primary
是一个简单的接口:
public interface Primary {
}
Secondary
同样也是这样的接口:
public interface Secondary {
}
最后,你可以如下方式使用验证:
@Service
@Validated({Primary.class, Secondary.class})
public class CancelService {
public void applyCancel(@Valid CancelDto cancel) {
//TODO
}
}
当使用上述代码中的 CancelDto
,且 items
为 null 时,会产生如下异常:
Caused by: javax.validation.ConstraintViolationException: applyCancel.cancel.items: must not be null
英文:
You could use JS-303 validation groups (see here), in conjunction with @Validated, from the documentation:
> Variant of JSR-303's Valid, supporting the specification of validation
> groups.
For example:
@CheckEnumSize(groups = {Secondary.class})
public class CancelDto {
public CancelDto(List<String> items) {
this.items = items;
}
@NotNull(groups = {Primary.class})
@Size(min = 1)
public List<@NotNull String> items;
public CancellationTypeEnum cancelType;
public List<String> getItems() {
return items;
}
}
where Primary
is a simple interface:
public interface Primary {
}
and the same for Secondary
:
public interface Secondary {
}
finally you could use validated as follows:
@Service
@Validated({Primary.class, Secondary.class})
public class CancelService {
public void applyCancel(@Valid CancelDto cancel) {
//TODO
}
}
when using the above code with a CancelDto
with items null, you should get:
Caused by: javax.validation.ConstraintViolationException: applyCancel.cancel.items: must not be null
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论