验证不适用于 RestController 中的映射键

Validation not working on Map keys in RestController

使用 Spring Boot 2.2.6,给定此控制器:

@RestController
@Validated
class MyController {
    @GetMapping("foo")
    fun getFirmwareVersionDifference(
        @RequestParam @Valid versions: @Valid Map<
            @Pattern(regexp = "a|b|c")
            String, String>
    ): String {
       // …
    }
}

我希望请求 foo?d=any 抛出 ConstraintViolationException,但控制器被正常调用。

我的上下文中有一个 MethodValidationPostProcessor,它适用于其他验证。如果我将 RequestParam 更改为 @RequestParam @Valid @Length(min=3) installedFirmwareVersion: String,它会按预期正常工作。

我错过了什么?

也许我的回答不是对您正在寻找的答案的更正,但它确实会检查您尝试在控制器中进行的验证。

import in.silentsudo.validators.annotations.RequestMap;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Map;

public class MapParamValidator implements ConstraintValidator<RequestMap, Map<String, String>> {

    @Override
    public boolean isValid(Map<String, String> stringStringMap, ConstraintValidatorContext constraintValidatorContext) {
        return stringStringMap.containsKey("a") || stringStringMap.containsKey("c") || stringStringMap.containsKey("b");
    }
}

import in.silentsudo.validators.MapParamValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = {MapParamValidator.class})
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMap {
    String message() default "Invalid Request Map";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

控制器实现:

@GetMapping("foo")
    public String getFirmwareVersionDifference(
            @RequestParam @Valid
            @RequestMap
                    Map<String, String> versions) {

        return "OK";
    }

请确保像这样在控制器上添加 @Validated

@RestController
@Validated
@RequestMapping("/somepath")
public class StatusController {
...
}

如果一切顺利,你应该得到这样的东西

There was an unexpected error (type=Internal Server Error, status=500).
getFirmwareVersionDifference.versions: Invalid Request Map
javax.validation.ConstraintViolationException: getFirmwareVersionDifference.versions: Invalid Request Map
...

这是一个 kotlin 编译器错误/缺少的功能:https://youtrack.jetbrains.com/issue/KT-13228

https://youtrack.jetbrains.com/issue/KT-35843 中所述,这在 kotlin 1.3.70 中得到了部分解决。

以下是如何在 build.gradle.kts

中设置编译器标志
tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xemit-jvm-type-annotations")
        jvmTarget = "11" // at least 8 should work, I only tested 11
    }
}