You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:59:52