如何在Jakarta Validation中验证集合为空?是否存在@Empty注解?
问题描述
我需要验证以下两个集合属性为空:
// should be empty! @JsonbTransient @JsonIgnore @XmlAnyAttribute private Map<QName, Object> unknownAttributes; // should be empty! @JsonbTransient @JsonIgnore @XmlAnyElement private List<Element> unknownElements;
我了解@NotEmpty注解可用于反向验证,目前通过以下方式实现验证:
@AssertTrue(message = "unknown attributes should be empty") private boolean isUnknownAttributesEmpty() { if (unknownAttributes == null) { return true; } return unknownAttributes.isEmpty(); } @AssertTrue(message = "unknown elements should be empty") private boolean isUnknownElementsEmpty() { if (unknownElements == null) { return true; } return unknownElements.isEmpty(); }
请问是否有更优的实现方式?为何Jakarta Validation中没有@Empty注解,还是说该注解实际存在?
解答
一、更优实现方式
有两种更简洁的方案可以替代当前的@AssertTrue写法:
方案1:利用现有@Size注解(无需自定义)
如果你使用Hibernate Validator(Jakarta Validation的主流实现),可以直接用@Size(max = 0)来实现需求:
@Size(max = 0, message = "unknown attributes should be empty") @JsonbTransient @JsonIgnore @XmlAnyAttribute private Map<QName, Object> unknownAttributes; @Size(max = 0, message = "unknown elements should be empty") @JsonbTransient @JsonIgnore @XmlAnyElement private List<Element> unknownElements;
@Size(max=0)会校验集合/映射的元素数量不超过0,也就是必须为空,同时null会被判定为有效(和你当前的校验逻辑完全一致),这种方式无需额外代码,最简洁。
方案2:自定义通用@Empty注解(高复用性)
如果需要更语义化的注解,或者项目中有多处类似校验,可以自定义一个@Empty注解:
1. 定义注解类
import jakarta.validation.Constraint; import jakarta.validation.Payload; import java.lang.annotation.*; @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = EmptyValidator.class) @Documented public @interface Empty { String message() default "集合或映射必须为空"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
2. 实现校验器
import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; import java.util.Collection; import java.util.Map; public class EmptyValidator implements ConstraintValidator<Empty, Object> { @Override public boolean isValid(Object value, ConstraintValidatorContext context) { if (value == null) { return true; } if (value instanceof Collection) { return ((Collection<?>) value).isEmpty(); } if (value instanceof Map) { return ((Map<?, ?>) value).isEmpty(); } // 非集合/映射类型默认通过校验,也可根据需求抛出异常 return true; } }
3. 直接在属性上使用
@Empty(message = "unknown attributes should be empty") @JsonbTransient @JsonIgnore @XmlAnyAttribute private Map<QName, Object> unknownAttributes; @Empty(message = "unknown elements should be empty") @JsonbTransient @JsonIgnore @XmlAnyElement private List<Element> unknownElements;
这种方式的优势是语义清晰,后续其他属性需要校验为空时直接复用注解即可。
二、Jakarta Validation中没有内置@Empty注解的原因
Jakarta Validation的内置注解聚焦于高频通用的校验场景,比如@NotEmpty(非空)、@NotNull(非null)、@Size(范围校验)等。而"必须为空"属于相对小众的校验需求,因此官方规范中并未定义@Empty注解,主流实现(如Hibernate Validator)也没有额外提供这个内置注解。
不过通过上面提到的两种方案,完全可以轻松实现对应的校验逻辑。
内容的提问来源于stack exchange,提问作者Jin Kwon
相关产品推荐
相关产品推荐

