Spring Boot自定义类级ConstraintValidator:invalidValue返回整个对象的问题
环境
Spring Boot 2.7.18
问题
在实现自定义ConstraintValidator时,即便指定了嵌套属性节点,处理生成的ConstraintViolation对象时,getInvalidValue()仍返回整个对象。但使用@NotNull等内置属性级约束时,该方法能正常返回属性值。请问类级约束能否实现让invalidValue返回对应属性值?
待验证类
@Data @Accessors(chain = true) @Entity @EqualsAndHashCode(onlyExplicitlyIncluded = true) @EventConstraint public class Event { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotNull @EqualsAndHashCode.Include private String productId; @Positive private Long positiveNumber; }
约束定义
@Documented @Constraint(validatedBy = EventValidator.class) @Target({TYPE}) @Retention(RUNTIME) public @interface EventConstraint { String message() default "Event is invalid"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
验证方法
public Event saveEvent(Event event) { Set<ConstraintViolation<Event>> violations = validator.validate(event); if (!violations.isEmpty()) { throw new ConstraintViolationException("Invalid event", violations); } return eventRepository.save(event); }
isValid实现(原代码)
public boolean isValid(@NotNull Event event, ConstraintValidatorContext context) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("Invalid event") .addPropertyNode("productId") .addConstraintViolation(); return false; }
现有结果
使用@Positive的结果
{ "message": "must be greater than 0", "field": "positiveNumber", "invalidValue": -1 }
使用自定义约束的结果
{ "message": "Invalid event", "field": "productId", "invalidValue": { "id": null, "productId": "someValue", "positiveNumber": -1 } }
预期结果
{ "message": "Invalid event", "field": "productId", "invalidValue": "someValue" }
解决方案
类级约束默认会把整个对象作为invalidValue,即便指定了属性节点也不会自动提取属性值,需要手动在构建约束违规时指定对应属性值。修改isValid方法如下:
public boolean isValid(@NotNull Event event, ConstraintValidatorContext context) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("Invalid event") .addPropertyNode("productId") // 显式指定当前属性节点的违规值 .addValue(event.getProductId()) .addConstraintViolation(); return false; }
这样修改后,生成的ConstraintViolation对象的getInvalidValue()就会返回productId的属性值,而非整个Event对象,符合预期结果。
内容的提问来源于stack exchange,提问作者Mike H
相关产品推荐
相关产品推荐

