SpringBoot Bean Validation 注解

huangapple go评论78阅读模式
英文:

SpringBoot Bean Validation annotation

问题

我目前正在为服务中的bean验证编写一些@SpringBootTest。

@Data
@Document
public final class Supplier {

    @Id
    @NotEmpty
    private String supplierId;
    ...
    @NotEmpty
    private String hash;
    ....
}

测试部分:

// 标注为:
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.MOCK)

// 和

@Test
void testValidation() {
    Supplier invalidSupplier = SupplierTestDataUtil.createSupplier("1234");
    invalidSupplier.setSupplierId(null);

    //works
    assertThrows(ConstraintViolationException.class, () -> supplierService.publish(invalidSupplier));

    //works
    assertThrows(ConstraintViolationException.class, () -> supplierService.persist(invalidSupplier));
    
    //works not
    assertThrows(ConstraintViolationException.class, () -> supplierService.saveAndPublish(invalidSupplier));

    //works
    assertThrows(ConstraintViolationException.class, () -> supplierService.delete(invalidSupplier));
}

服务部分:

@Transactional
public Supplier saveAndPublish(@NotNull Supplier supplier) {
    supplier.setHash(messageDigester.digest(supplier));
    Supplier persisted = persist(supplier);
    publish(supplier);
    return persisted;
}

@Transactional
public Supplier persist(@Valid @NotNull Supplier supplier) {
    return repository.save(supplier);
}

// 在saveAndFlush中的Supplier在此时不必是有效的,因为所需的hash将在该方法内部生成并设置。
// 尽管如此,我期望也会抛出ConstraintViolationException,因为我还调用了persist和publish方法,并传递了该无效文档。
// 我的观点是在同一类内部可以绕过BeanValidation。
英文:

I am currently writing some @SpringBootTest for bean validation in services.

@Data
@Document
public final class Supplier {

    @Id
    @NotEmpty
    private String supplierId;
    ...
    @NotEmpty
    private String hash;
    ....
}

Test

Annotated with:

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.MOCK)

and

 @Test
    void testValidation() {
        Supplier invalidSupplier = SupplierTestDataUtil.createSupplier("1234");
        invalidSupplier.setSupplierId(null);

        //works
        assertThrows(ConstraintViolationException.class, () -> supplierService.publish(invalidSupplier));

        //works
        assertThrows(ConstraintViolationException.class, () -> supplierService.persist(invalidSupplier));
        
        //works not
        assertThrows(ConstraintViolationException.class, () -> supplierService.saveAndPublish(invalidSupplier));

        //works
        assertThrows(ConstraintViolationException.class, () -> supplierService.delete(invalidSupplier));
    }

Service:

@Transactional
public Supplier saveAndPublish(@NotNull Supplier supplier) {
    supplier.setHash(messageDigester.digest(supplier));
    Supplier persisted = persist(supplier);
    publish(supplier);
    return persisted;
}

@Transactional
public Supplier persist(@Valid @NotNull Supplier supplier) {
    return repository.save(supplier);
}

Supplier at saveAndFlush must not be valid at this point because required hash will be generated and set inside that method.
Nevertheless my expectation was that ConstraintViolationException will be also thrown because I also call persist and publish method and pass that invalid document.

My point is that you can bypass BeanValidation within the same class.

答案1

得分: 1

ConstraintViolationException会被Spring Validator抛出,如果您在调用persist时不会被使用。如果从Spring上下文中调用了persist@Valid注解将告诉Spring根据类的验证约束来验证对象。

您可以:

  1. 始终“手动”验证hash(不使用@NotEmpty注解)
  2. 在调用saveAndPublish之前调用supplier.setHash(messageDigester.digest(supplier));,并将@Valid注解添加到saveAndPublishSupplier参数上
  3. 将验证器实例作为字段添加到您的服务中,并在需要手动验证供应商时进行调用(当然,在设置了哈希之后,在saveAndPublish的情况下)
  4. 实现两种不同类型的Supplier,例如AddSupplier(不验证hash;由saveAndPublish使用)和EditSupplier(验证hash;由persist使用)

(这可能是一个不完整的列表)

英文:

The ConstraintViolationException will be thrown by a Spring Validator which won't be used if you call persist "manually". If persist is called from a Spring context, the @Valid annotation will tell Spring to validate the object based on the class's validation constraints.

You could:

  1. Validate hash always "manually" (without the @NotEmpty annotation)
  2. Call supplier.setHash(messageDigester.digest(supplier)); before calling saveAndPublish and add the @Valid annotation to the Supplier argument of saveAndPublish
  3. Add a Validator instance as a field to your service and call it manually on the Supplier to be validated (in case of saveAndPublish after setting the hash, of course)
  4. Implement two different types of Supplier, e.g, AddSupplier (without hash being validated; used by saveAndPublish) and EditSupplier (with hash being validated; used by persist)

(this is probably an incomplete list)

huangapple
  • 本文由 发表于 2020年10月19日 17:13:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/64424360.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定