英文:
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根据类的验证约束来验证对象。
您可以:
- 始终“手动”验证
hash
(不使用@NotEmpty
注解) - 在调用
saveAndPublish
之前调用supplier.setHash(messageDigester.digest(supplier));
,并将@Valid
注解添加到saveAndPublish
的Supplier
参数上 - 将验证器实例作为字段添加到您的服务中,并在需要手动验证供应商时进行调用(当然,在设置了哈希之后,在
saveAndPublish
的情况下) - 实现两种不同类型的
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:
- Validate
hash
always "manually" (without the@NotEmpty
annotation) - Call
supplier.setHash(messageDigester.digest(supplier));
before callingsaveAndPublish
and add the@Valid
annotation to theSupplier
argument ofsaveAndPublish
- 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) - Implement two different types of
Supplier
, e.g,AddSupplier
(withouthash
being validated; used bysaveAndPublish
) andEditSupplier
(withhash
being validated; used bypersist
)
(this is probably an incomplete list)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论