如何在春季数据休息中有条件地应用验证组?

发布于 2025-01-24 16:36:47 字数 3041 浏览 0 评论 0 原文

我有一个 spring data rest rest 带有基于属性的实体验证的实体类型的project 实体。我想使用当该属性设置为特定值时。

作为具体的示例,以以下实体类:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;

@Entity
public class Animal {
    public enum Type { FLYING, OTHER }

    /**
     * Validation group.
     */
    public interface Flying {}

    @Id
    @GeneratedValue
    private Integer id;

    private Type type;

    @NotNull(groups = Flying.class)
    private Integer airSpeedVelocity;

    @NotNull
    private Integer weight;

    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public Type getType() { return type; }
    public void setType(Type type) { this.type = type; }
    public Integer getAirSpeedVelocity() { return airSpeedVelocity; }
    public void setAirSpeedVelocity(Integer airSpeedVelocity) { this.airSpeedVelocity = airSpeedVelocity; }
    public Integer getWeight() { return weight; }
    public void setWeight(Integer weight) { this.weight = weight;}
}

当保存 Animal type 飞行时,我想验证 airspeedvelocity 是非null 。保存其他动物时,我不希望这种验证。

目前,我有验证允许在保存之前检查验证,因此如果对象无效,则返回400不良请求错误:

    @Bean
    public ValidatingRepositoryEventListener preSaveValidator(
            @Qualifier("defaultValidator") SmartValidator validator,
            ObjectFactory<PersistentEntities> persistentEntitiesFactory) {
        ValidatingRepositoryEventListener eventListener = 
                new ValidatingRepositoryEventListener(persistentEntitiesFactory);
        eventListener.addValidator("beforeCreate", validator);
        eventListener.addValidator("beforeSave", validator);
        return eventListener;
    }
}

请求:

{ "type": "FLYING" }

当前400错误响应:

{
    "errors": [
        {
            "entity": "Animal",
            "property": "weight",
            "invalidValue": null,
            "message": "must not be null"
        }
    ]
}

所需的400错误响应:

{
    "errors": [
        {
            "entity": "Animal",
            "property": "airSpeedVelocity",
            "invalidValue": null,
            "message": "must not be null"
        },
        {
            "entity": "Animal",
            "property": "weight",
            "invalidValue": null,
            "message": "must not be null"
        }
    ]
}

我如何执行此条件验证,应用程序应用程序飞行验证组当请求实体为动物其中 type == flage

I have a Spring Data REST project with an entity type with conditional validation based on a property of the entity. I want to enable certain validations using validation groups when that property is set to a specific value.

As a concrete example, take the following entity class:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;

@Entity
public class Animal {
    public enum Type { FLYING, OTHER }

    /**
     * Validation group.
     */
    public interface Flying {}

    @Id
    @GeneratedValue
    private Integer id;

    private Type type;

    @NotNull(groups = Flying.class)
    private Integer airSpeedVelocity;

    @NotNull
    private Integer weight;

    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public Type getType() { return type; }
    public void setType(Type type) { this.type = type; }
    public Integer getAirSpeedVelocity() { return airSpeedVelocity; }
    public void setAirSpeedVelocity(Integer airSpeedVelocity) { this.airSpeedVelocity = airSpeedVelocity; }
    public Integer getWeight() { return weight; }
    public void setWeight(Integer weight) { this.weight = weight;}
}

When saving an Animal with type FLYING, I want to validate that airSpeedVelocity is non-null. When saving any other animal, I don't want this validation.

Currently, I have validations enable to be checked prior to save, so that a 400 Bad Request error is returned if an object is invalid:

    @Bean
    public ValidatingRepositoryEventListener preSaveValidator(
            @Qualifier("defaultValidator") SmartValidator validator,
            ObjectFactory<PersistentEntities> persistentEntitiesFactory) {
        ValidatingRepositoryEventListener eventListener = 
                new ValidatingRepositoryEventListener(persistentEntitiesFactory);
        eventListener.addValidator("beforeCreate", validator);
        eventListener.addValidator("beforeSave", validator);
        return eventListener;
    }
}

Request:

{ "type": "FLYING" }

Current 400 error response:

{
    "errors": [
        {
            "entity": "Animal",
            "property": "weight",
            "invalidValue": null,
            "message": "must not be null"
        }
    ]
}

Desired 400 error response:

{
    "errors": [
        {
            "entity": "Animal",
            "property": "airSpeedVelocity",
            "invalidValue": null,
            "message": "must not be null"
        },
        {
            "entity": "Animal",
            "property": "weight",
            "invalidValue": null,
            "message": "must not be null"
        }
    ]
}

How can I perform this conditional validation, applying the Flying validation group when the request entity is an Animal where type == FLYING?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鹿童谣 2025-01-31 16:36:47

一种解决方案是使用自定义的验证器自动检查输入类型,必要时自动应用自定义验证组:

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.SmartValidator;

import javax.validation.groups.Default;

@Configuration
public class RestRepositoryValidatorConfig {
    @Bean
    public ValidatingRepositoryEventListener preSaveValidator(
            AnimalValidationGroupAwareValidator validator,
            ObjectFactory<PersistentEntities> persistentEntitiesFactory) {
        ValidatingRepositoryEventListener eventListener =
                new ValidatingRepositoryEventListener(persistentEntitiesFactory);
        eventListener.addValidator("beforeCreate", validator);
        eventListener.addValidator("beforeSave", validator);
        return eventListener;
    }

    @Component
    public static class AnimalValidationGroupAwareValidator
            implements SmartValidator {
        private final SmartValidator delegate;

        public AnimalValidationGroupAwareValidator(
                @Qualifier("defaultValidator") SmartValidator delegate) {
            this.delegate = delegate;
        }

        @Override
        public boolean supports(Class<?> clazz) {
            return true;
        }

        @Override
        public void validate(Object target, Errors errors,
                             Object... validationHints) {
            // If hints are overridden, use those instead
            delegate.validate(target, errors, validationHints);
        }

        @Override
        public void validate(Object target, Errors errors) {
            if (target instanceof Animal animal &&
                Animal.Type.FLYING.equals(animal.getType())) {
                delegate.validate(target, errors,
                        Animal.Flying.class, Default.class);
            } else {
                delegate.validate(target, errors);
            }
        }
    }
}

请注意,这还添加了 默认 验证组,因为否则也不会执行标准验证。

One solution is to use a customized Validator that automatically checks the input type, automatically applying the custom validation groups if necessary:

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.SmartValidator;

import javax.validation.groups.Default;

@Configuration
public class RestRepositoryValidatorConfig {
    @Bean
    public ValidatingRepositoryEventListener preSaveValidator(
            AnimalValidationGroupAwareValidator validator,
            ObjectFactory<PersistentEntities> persistentEntitiesFactory) {
        ValidatingRepositoryEventListener eventListener =
                new ValidatingRepositoryEventListener(persistentEntitiesFactory);
        eventListener.addValidator("beforeCreate", validator);
        eventListener.addValidator("beforeSave", validator);
        return eventListener;
    }

    @Component
    public static class AnimalValidationGroupAwareValidator
            implements SmartValidator {
        private final SmartValidator delegate;

        public AnimalValidationGroupAwareValidator(
                @Qualifier("defaultValidator") SmartValidator delegate) {
            this.delegate = delegate;
        }

        @Override
        public boolean supports(Class<?> clazz) {
            return true;
        }

        @Override
        public void validate(Object target, Errors errors,
                             Object... validationHints) {
            // If hints are overridden, use those instead
            delegate.validate(target, errors, validationHints);
        }

        @Override
        public void validate(Object target, Errors errors) {
            if (target instanceof Animal animal &&
                Animal.Type.FLYING.equals(animal.getType())) {
                delegate.validate(target, errors,
                        Animal.Flying.class, Default.class);
            } else {
                delegate.validate(target, errors);
            }
        }
    }
}

Note that this also adds the Default validation group, since otherwise the standard validations would not also be performed.

゛清羽墨安 2025-01-31 16:36:47

Hibernate验证 可用于根据对象状态动态定义默认验证组。

per

Hibernate验证器还为默认组序列的动态重新定义提供了一个SPI,具体取决于对象状态。

为此,您需要实现接口 defaultGroupsequenceProvider 并通过 @groupsequenceProvider notation。

在这种情况下,可以创建 defaultGroupSequenceProvider ,该使用 flying group(加上标准默认组)时,当对象的 type> type 属性是飞行,否则标准默认组。

import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
import java.util.List;

public class AnimalTypeGroupSequenceProvider
        implements DefaultGroupSequenceProvider<Animal> {
    @Override
    public List<Class<?>> getValidationGroups(Animal object) {
        if (object != null && object.getType() == Animal.Type.FLYING) {
            return List.of(Animal.Flying.class, Animal.class);
        } else {
            return List.of(Animal.class);
        }
    }
}
import org.hibernate.validator.group.GroupSequenceProvider;
import javax.persistence.Entity;

@GroupSequenceProvider(AnimalTypeGroupSequenceProvider.class)
@Entity
public class Animal {
   // ...
}

A Hibernate Validation DefaultGroupSequenceProvider can be used to dynamically define the default validation group based on the state of the object.

Per the reference guide:

Hibernate Validator also provides an SPI for the dynamic redefinition of default group sequences depending on the object state.

For that purpose, you need to implement the interface DefaultGroupSequenceProvider and register this implementation with the target class via the @GroupSequenceProvider annotation.

In this case, a DefaultGroupSequenceProvider can be created which uses the Flying group (plus the standard default group) when the object's type property is FLYING, and the standard default group otherwise.

import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
import java.util.List;

public class AnimalTypeGroupSequenceProvider
        implements DefaultGroupSequenceProvider<Animal> {
    @Override
    public List<Class<?>> getValidationGroups(Animal object) {
        if (object != null && object.getType() == Animal.Type.FLYING) {
            return List.of(Animal.Flying.class, Animal.class);
        } else {
            return List.of(Animal.class);
        }
    }
}
import org.hibernate.validator.group.GroupSequenceProvider;
import javax.persistence.Entity;

@GroupSequenceProvider(AnimalTypeGroupSequenceProvider.class)
@Entity
public class Animal {
   // ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文