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

SpringBoot自定义校验器报错HV000030:找不到String类型的校验器

问题描述

SpringBoot应用返回UNMAPPED_ERROR,具体报错:

"code": "UNMAPPED_ERROR", "message": "Request processing failed: jakarta.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint .... validating type 'java.lang.String'. Check configuration for 'channel'"

相关代码片段:

SessionInfo的channel字段

@NotBlank(message = "channel is required")
@ChannelValidationConstraint
@JsonProperty("channel")
private String channel;

ChannelType枚举

public enum ChannelType {
    // allowed values for "channel" field in the SessionInfo payload
    Mobile("mobile"),
    Online("online");
    private final String fieldName;
    private static final Map<String, ChannelType> lookup = new HashMap<>();

    static {
        for (ChannelType channelType : EnumSet.allOf(ChannelType.class)) {
            lookup.put(channelType.getFieldName(), channelType);
        }
    }
    ChannelType(String fieldName) {
        this.fieldName = fieldName;
    }

    public String getFieldName() {
        return fieldName;
    }
    public static ChannelType getByFieldName(String fieldName) {
        return lookup.get(fieldName);
    }
}

ChannelValidator校验器

public class ChannelValidator implements ConstraintValidator<ChannelValidationConstraint, List<IRequestPayload>> {
    @Override
    public boolean isValid(List<IRequestPayload> value, ConstraintValidatorContext context) {

        SessionInfo sessionInfo = null;

        for (IRequestPayload requestPayload : value) {
            if (requestPayload instanceof SessionInfo) {
                sessionInfo = (SessionInfo) requestPayload;
            }
        }
        if (sessionInfo == null) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("Invalid 'handler' in request payload")
                    .addConstraintViolation();
            return false;
        }

        ChannelType channelType = ChannelType.getByFieldName(sessionInfo.getChannel());

        switch (channelType) {
            case Online:
                return true;
            case Mobile:
                return true;
            default:
                if (StringUtils.isBlank(channelType.toString())) {
                    context.disableDefaultConstraintViolation();
                    context.buildConstraintViolationWithTemplate("channel is required").addConstraintViolation();
                    return false;
                } else if (channelType.toString().equals(ChannelType.Online.toString()) || !channelType.toString().equals(ChannelType.Mobile.toString())) {
                    context.disableDefaultConstraintViolation();
                    context.buildConstraintViolationWithTemplate("invalid channel").addConstraintViolation();
                    return false;
                }
        }

        return true;
    }
}

ChannelValidationConstraint注解

@Documented
@Constraint(validatedBy = {ChannelValidator.class})
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)

public @interface ChannelValidationConstraint {
    String message() default "";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
解决方法

核心问题:校验器与标注字段的类型不匹配。@ChannelValidationConstraint标注在String类型的字段上,但ChannelValidator实现的是针对List<IRequestPayload>类型的校验逻辑,Validator框架无法找到适配String的校验器,因此抛出异常。

按以下步骤修复:

1. 修改ChannelValidator的泛型与逻辑

将校验器的泛型改为适配String类型,同时简化校验逻辑:

public class ChannelValidator implements ConstraintValidator<ChannelValidationConstraint, String> {
    @Override
    public boolean isValid(String channelValue, ConstraintValidatorContext context) {
        // 空值校验可依赖@NotBlank,这里做兜底或自定义提示
        if (StringUtils.isBlank(channelValue)) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("channel is required")
                    .addConstraintViolation();
            return false;
        }

        // 根据传入的字符串查找枚举
        ChannelType channelType = ChannelType.getByFieldName(channelValue);
        if (channelType == null) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("invalid channel")
                    .addConstraintViolation();
            return false;
        }

        return true;
    }
}

原代码中遍历List<IRequestPayload>查找SessionInfo的逻辑完全冗余,现在直接校验字段的String值即可。

2. 保留注解的Target配置

@ChannelValidationConstraint的@Target({ElementType.FIELD})配置正确,无需修改,确保注解可以标注在字段上。

3. 验证修复结果

重启应用后:

  • 当channel字段为mobile或online时,校验通过;
  • 当channel为空或其他非法值时,会返回对应的自定义错误信息,不再出现UNMAPPED_ERROR。

内容的提问来源于stack exchange,提问作者ResourceReaper

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 20:35:58