Bean 验证:如何手动创建约束冲突?

我有一个特定的场景,我只能在流程的稍后时刻手动检查违规条件。

我想做的是抛出一个,并向它提供一个“真实”(当我在堆栈中捕获异常时,我使用和参数)。ConstraintViolationExceptionConstraintViolation object#{validatedValue}violation.getPropertyPath()

我如何在没有框架通过注释为我做这件事的情况下创建一个自己(我使用Hibernate Validator)?ConstraintViolation

代码示例:

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?...>);
}

谢谢。


答案 1

我不喜欢Hibernate Validator的另一个原因。它们使得以编程方式创建简单的违规变得非常困难,而它应该非常简单。我确实测试代码,我需要创建一个冲突来提供给我的模拟子系统。

无论如何,除了滚动你自己的违规约束的实现 - 以下是我为字段创建违规所做的工作:

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;

}

呵呵


答案 2

在我看来,最简单的方法是嘲笑你的服务在测试中抛出约束冲突。例如,您可以通过扩展类来手动执行此操作,也可以使用模拟框架(例如 mockito)。我更喜欢模拟框架,因为它们简化了很多事情,因为你既不必创建和维护额外的类,也不必处理将它们注入到被测试对象中。

以 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);
    }
}

推荐