У меня есть Spring Boot API с некоторыми контроллерами, которые используют перечисление в качестве RequestParam. Это все работает нормально. Если я использую значение, которого нет в перечислении, я получу ошибку. Однако я нигде не могу найти, можно ли проверить, является ли requestParam частью подмножества перечисления.
Перечисление выглядит примерно так:
public enum Type {
@JsonProperty("een")
ONE("een"),
@JsonProperty("twee")
TWO("twee"),
@JsonProperty("drie")
THREE("drie");
private final String value;
private static final Map<String, Type> lookup = new HashMap<String, Type>();
static {
for (Type type : Type.values()) {
lookup.put(type.value, type);
}
}
private Type(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public static Type get(String value) {
return lookup.get(value);
}
@Override
public String toString() {
return this.value;
}
}
Я создал org.springframework.core.convert.converter.Converter, чтобы использовать такое перечисление (значение с другим именем перечисления).
Конечные точки выглядят примерно так:
@GetMapping("/my-endpoint")
public ResponseEntity<Set<Item>> getItems(
@RequestParam Type type
) {
<... etc>
return new ResponseEntity<Set<Item>>(items, HttpStatus.OK);
}
Так, например, я хотел бы проверить для одной из моих конечных точек, имеет ли RequestParam значение «een» или «twee» и должен вернуть неверный запрос, если он имеет значение «drie». И для другой конечной точки я хотел бы проверить, имеет ли RequestParam значение «twee» или «drie». Это упрощенный пример, на самом деле у меня гораздо больше параметров в перечислении и множество конечных точек, которые используют все перечисление или его подмножество. Я знаю, что могу создавать разные перечисления с подмножествами, но поскольку они часто используются в разных подмножествах каждый раз, это не вариант.
Есть ли другой способ сделать это?
Я понял, как это сделать, благодаря этой статье: https://www.baeldung.com/javax-validations-enums.
По сути, я создал аннотацию, специфичную для моего перечисления (я не уверен, что ее можно сделать более общей).
@Constraint(validatedBy = TypeSubsetValidator.class)
@Target({ ElementType.TYPE, ElementType.PARAMETER, ElementType.FIELD })
@Retention(RUNTIME)
public @interface TypeSubset {
Type[] anyOf();
String message() default "error.wrongType";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
И создал сопутствующий валидатор:
public class TypeSubsetValidator implements ConstraintValidator<TypeSubset, Type> {
private Type[] subset;
@Override
public void initialize(TypeSubset annotation) {
this.subset = annotation.anyOf();
}
@Override
public boolean isValid(Type value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return Arrays.asList(subset).contains(value);
}
}
Затем валидацию можно использовать следующим образом:
@GetMapping("/my-endpoint")
public ResponseEntity<Set<Item>> getItems(
@TypeSubset(anyOf = { Type.ONE, Type.TWO}) @RequestParam Type type
) {
<... etc>
return new ResponseEntity<Set<Item>>(items, HttpStatus.OK);
}
Теперь в качестве RequestParam можно использовать только Type.ONE и Type.TWO, другие значения вернут неверный запрос.