Java Bean 验证:如何手动创建 ConstraintViolation?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22938407/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bean Validation: How can I manually create a ConstraintViolation?
提问by odedia
I have a specific scenario where I can only check for violation conditions manually, at a later point in the flow.
我有一个特定的场景,我只能在流程的稍后点手动检查违规条件。
What I want to do is throw a ConstraintViolationException
, and provide a "real" ConstraintViolation object
to it (when I catch the exception up the stack, I use the #{validatedValue}
and violation.getPropertyPath()
parameters).
我想要做的是抛出一个ConstraintViolationException
,并为其提供一个“真实” ConstraintViolation object
(当我在堆栈中捕获异常时,我使用#{validatedValue}
和violation.getPropertyPath()
参数)。
How can I create a ConstraintViolation
myself without having the framework do it for me via annotations (I use Hibernate Validator)?
如何在ConstraintViolation
没有框架通过注释(我使用 Hibernate Validator)为我做的情况下创建自己?
Code example:
代码示例:
List<String> columnsListForSorting = new ArrayList<String>(service.getColumnsList(domain));
Collections.sort(columnsListForSorting);
String firstFieldToSortBy = this.getTranslatedFieldName(domain.getClass().getCanonicalName(), sortingInfo.getSortedColumn());
if (!columnsListForSorting.contains(firstFieldToSortBy)){
throw new ConstraintViolationException(<what here?...>);
}
Thanks.
谢谢。
采纳答案by Morfic
In my opinion, the simplest way would be to mock your service into throwing the constraint violation in your test. You can do it manually by extending the class for example, or you can use a mocking framework such as mockito. I prefer mocking frameworks because they simplify things a lot as you neither have to create and maintain additional classes nor have to deal with injecting them in your objects under test.
在我看来,最简单的方法是模拟您的服务在测试中抛出约束违规。例如,您可以通过扩展类来手动完成,也可以使用mockito等模拟框架。我更喜欢模拟框架,因为它们简化了很多事情,因为您既不必创建和维护额外的类,也不必处理将它们注入被测对象中的问题。
Taking mockito as a starting point you'd probably write something similar to:
以 mockito 为起点,您可能会编写类似于以下内容的内容:
import org.hibernate.exception.ConstraintViolationException;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.when;
public class MyTest {
@Mock /* service mock */
private MyService myService;
@InjectMocks /* inject the mocks in the object under test */
private ServiceCaller serviceCaller;
@Test
public void shouldHandleConstraintViolation() {
// make the mock throw the exception when called
when(myService.someMethod(...)).thenThrow(new ConstraintViolationException(...))
// get the operation result
MyResult result = serviceCaller.doSomeStuffWhichInvokesTheServiceMethodThrowingConstraintViolation();
// verify all went according to plan
assertWhatever(result);
}
}
回答by Hardy
A couple of things here:
这里有几件事:
ConstraintViolationis an interface, so you could just implement your own version
Hibernate Validator uses its own internal implementation of this interface - org.hibernate.validator.internal.engine.ConstraintViolationImpl. It is a public class, but since it is in an internalpackage you are not encouraged to use it directly. However, you might get an idea what is needed to implement ConstraintViolation.
ConstraintViolation是一个接口,所以你可以实现你自己的版本
Hibernate Validator 使用它自己的这个接口的内部实现 - org.hibernate.validator.internal.engine.ConstraintViolationImpl。它是一个公共类,但由于它位于内部包中,因此不鼓励您直接使用它。但是,您可能会了解实现ConstraintViolation需要什么。
回答by Stefan Haberl
One more reason why I don't like Hibernate Validator that particular. They make it really hardto create a simple violation programmatically, when it should be dead simple. I do havetest code where I need to create a violation to feed to my mocked subsystem.
我不喜欢 Hibernate Validator 的另一个原因。当它应该非常简单时,它们使得以编程方式创建简单的违规变得非常困难。我确实有测试代码,我需要在其中创建违规以提供给我的模拟子系统。
Anyway, short of rolling your own implementation of a violation contraint - here is what I do to create a violation for a field:
无论如何,没有滚动您自己的违规约束实现 - 这是我为字段创建违规所做的工作:
private static final String MESSAGE_TEMPLATE = "{messageTemplate}";
private static final String MESSAGE = "message";
public static <T, A extends Annotation> ConstraintViolation<T> forField(
final T rootBean,
final Class<T> clazz,
final Class<A> annotationClazz,
final Object leafBean,
final String field,
final Object offendingValue) {
ConstraintViolation<T> violation = null;
try {
Field member = clazz.getDeclaredField(field);
A annotation = member.getAnnotation(annotationClazz);
ConstraintDescriptor<A> descriptor = new ConstraintDescriptorImpl<>(
new ConstraintHelper(),
member,
annotation,
ElementType.FIELD);
Path p = PathImpl.createPathFromString(field);
violation = ConstraintViolationImpl.forBeanValidation(
MESSAGE_TEMPLATE,
MESSAGE,
clazz,
rootBean,
leafBean,
offendingValue,
p,
descriptor,
ElementType.FIELD);
} catch (NoSuchFieldException ignore) {}
return violation;
}
HTH
HTH
回答by headstar
Why not inject the Validator
in your test and create an object triggering the validation errors you want?
为什么不在Validator
您的测试中注入并创建一个触发您想要的验证错误的对象?
Set<ConstraintViolation<T>> res = validator.validate(object);
回答by ronc
I encountered this issue several times already and came up with this little solution.
It is based on the validateValue method of the Validator and using a helper-validator in the test class, which is used to generate in a one liner a Set<ConstraintViolation<T>>
object.
我已经多次遇到这个问题并提出了这个小解决方案。它基于Validator 的validateValue 方法,并在测试类中使用了一个helper-validator,用于在一个单行中生成一个Set<ConstraintViolation<T>>
对象。
suppose you are testing a class that internally uses a Validator, mocked in our test, on an object "Data data" which has Bean Validation annotations, for example the field "sessionId" is annotated with @NotNull.
假设您正在测试一个在内部使用验证器的类,在我们的测试中模拟,对象“数据数据”具有 Bean 验证注释,例如字段“sessionId”用@NotNull 注释。
Your test class would then have at least these two members:
您的测试类将至少有以下两个成员:
@Mock
private Validator validator;
private Validator violationCreatorValidator;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
violationsGenerator.Validation.buildDefaultValidatorFactory().getValidator();
}
And then in the test case:
然后在测试用例中:
when(validator.validate(data))
.thenReturn(violationsGenerator.validateValue(Data.class, "sessionId", null));
Thats it. No need to a implement the ConstraintViolation interface or call the monstrous ConstraintViolationImpl.forBeanValidation. Let the Validator do the job for you.
就是这样。无需实现 ConstraintViolation 接口或调用可怕的 ConstraintViolationImpl.forBeanValidation。让验证器为您完成工作。