Serializovat Enum jako Řetězec pro ověření použití Jackson

0

Otázka

Snažím potvrdit Enum pomocí vlastní validátor, v mé vlastní validátor snažím se vrátit vlastní zprávu, když parametr není v enum hodnot.

Níže moje enum

public enum Type {
    MISSING_SITE,
    INACTIVE_SITE;
}

Níže moje PostMapping metoda

@PostMapping(value = "/line-kpi", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Find Kpis by one or more customer property")
public ResponseEntity<List<KpiDTO>> findKPILineByCustomer(@RequestBody @ValidCustomerParameter CustomerParameter customerParameter, @RequestParam @ValidExtractionDate String extractionDate) {
    var linesKpi = Optional.ofNullable(
            kpiService.findKPILineByCustomer(
                    Optional.ofNullable(customerParameter.getEntityPerimeter()).orElse(List.of()),
                    Optional.ofNullable(customerParameter.getName()).orElse(List.of()),
                    Optional.ofNullable(customerParameter.getIc01()).orElse(List.of()),
                    Optional.ofNullable(customerParameter.getSiren()).orElse(List.of()),
                    Optional.ofNullable(customerParameter.getEnterpriseId()).orElse(List.of()),
                    LocalDate.parse(extractionDate)
            )
    );
    return linesKpi.map(ResponseEntity::ok).orElseThrow(() -> new ResourceNotFoundException(KPIS));
}

Nemůžu přepínat typ enum řetězec v metodě samotné, protože jsem pomocí swagger, který zobrazuje pěkný výběr seznamu pro výčtové typy.

Bohužel, když se snažím dát jinou hodnotu pro Typ, vrátí chybný požadavek a můj validátory nejsou spuštěna.

Takže se snažím serializovat můj enum být interpretován jako Řetězec, když to přijde k regulátoru a k tomu, že musím použít Jackson, snažil jsem se hledat řešení, ale nemůžu najít dobrý pro můj případ.

Níže jsou mé validátory

public class ReportTypeValidator implements ConstraintValidator<ValidReportType, Type> {
    private String globalMessage;

    @Override
    public void initialize(ValidReportType constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
        globalMessage = constraintAnnotation.message();
    }

    @Override
    public boolean isValid(Type type, ConstraintValidatorContext constraintValidatorContext) {
        if (Arrays.stream(Type.values()).filter(type1 -> type1.equals(type)).toList().isEmpty()) {
            constraintValidatorContext
                    .buildConstraintViolationWithTemplate(globalMessage + ", report type does not exist")
                    .addConstraintViolation();
            return false;
        }
        return true;
    }
}
@Constraint(validatedBy = ReportTypeValidator.class)
@Target( { ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Valid
public @interface ValidReportType {
    String message() default "Invalid value for report type";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Mohl by mi někdo říct, jak se mohu obrátit svou enum jako řetězec, takže můj validátor, že to zvládnu?

enums jackson java spring-boot
2021-11-22 16:29:39
2

Nejlepší odpověď

2

Přidat speciální enum konstanta označující požadavek JSON obsažené neplatný enum konstantní jméno. Žádost JSON by vlastně nikdy obsahovat jméno tohoto enum konstantní. Také přidat metodu, že Jackson bude odvolávat, zatímco při rekonstrukci převést řetězec JSON položku konstantní. Tato metoda vrátí speciální enum konstantní, pokud řetězec JSON není známo, enum konstantní jméno.

public enum Type {
    MISSING_SITE,
    INACTIVE_SITE,

    @JsonProperty("SHOULD NEVER ACTUALLY APPEAR IN REQUEST JSON")
    INVALID;

    /**
     * Converts enum constant name to enum constant.
     *
     * @param name
     *         enum constant name
     * @return enum constant, or {@link #INVALID} if there is no enum constant with that name
     */
    @JsonCreator
    public static Type valueOfOrInvalid(String name) {
        try {
            return Type.valueOf(name);
        } catch (IllegalArgumentException e) {
            return INVALID;
        }
    }
}

Uvnitř ReportTypeValidator.isValid( metoda, podívejte se na enum je konstantní INVALID.

if (type == Type.INVALID) {
    // Add constraint violation.
2021-11-22 19:52:27

inspirativní! Udělal jsem, jak jste řekl, ale to nezabralo, možná proto, že jsem přijal enum jako @RequestParam a ne jako json hodnotu v metodě řadič, vše, co dostávám teď je špatná žádost, mohl by to být důvod?
extraHassan
0

Našel jsem to, byl jsem schopen to udělat tím, že provádí novou converter, který převede řetězec na platný enum hodnota nebo NEPLATNOU hodnotu:

public class TypeConverter implements Converter<String, Type> {
    @Override
    public Type convert(String source) {
        if (Arrays.stream(Type.values()).filter(type -> Objects.equals(type.toString(), source)).toList().isEmpty()) {
            return Type.INVALID;
        }
        return Type.valueOf(source.toUpperCase());
    }
}

Poté, co jsem přidal novou Konfiguraci pro můj converter:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new TypeConverter());
    }
}

Také jsem se musel skrývat NEPLATNÁ hodnota mého enum od naparování přidáním @Schéma anotace:

@Schema(allowableValues = {"MISSING_SITE","INACTIVE_SITE"}, type = "String")
public enum Type {
    MISSING_SITE,
    INACTIVE_SITE,
    INVALID
}

Konečně v validátory, měl bych odmítnout NEPLATNÉ hodnoty a zobrazit vlastní zprávu:

public class ReportTypeValidator implements ConstraintValidator<ValidReportType, Type> {
    private String globalMessage;

    @Override
    public void initialize(ValidReportType constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
        globalMessage = constraintAnnotation.message();
    }

    @Override
    public boolean isValid(Type type, ConstraintValidatorContext constraintValidatorContext) {
        if (type == Type.INVALID) {
            constraintValidatorContext
                    .buildConstraintViolationWithTemplate(globalMessage)
                    .addConstraintViolation();
            return false;
        }
        return true;
    }

}

Anotace za předchozí validátor:

@Constraint(validatedBy = ReportTypeValidator.class)
@Target( { ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Valid
public @interface ValidReportType {
    String message() default "Invalid value for report type";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
2021-11-22 19:40:26

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................