Reputation: 16636
According to this link:
If you need to validate entities outside of resource endpoints, the validator can be accessed in the Environment when the application is first ran.
Which means that the @Valid
below won't work and I have to programatically use the validator on the profile
object and do something with the errors that come back:
public class ProfilesManager {
...
public void createProfile(@Valid Profile profile) {
Set<ConstraintViolation<Profile>> errors = validator.validate(profile);
...
}
}
In Spring Boot, all I have to do is annotate it with @Validated
and a ConstraintViolationException
will automatically be thrown:
@Validated
@Component
public class ProfilesManager {
public void createProfile(@Valid Profile profile) {
// if invalid, exception thrown before getting here
}
}
Is there an equivalent solution for Dropwizard, official or 3rd party?
Upvotes: 0
Views: 450
Reputation: 208984
It is easy to implement this on your own using HK2's interception service. All you need to do is provide a MethodInteceptor
that inspects the method parameters for the @Valid
annotation and validate those parameters with the Validator
public class ValidationMethodInterceptor implements MethodInterceptor {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[] args = invocation.getArguments();
for (int i = 0; i < args.length; i++) {
Parameter parameter = invocation.getMethod().getParameters()[i];
if (parameter.getAnnotation(Valid.class) != null) {
handleValidation(args[i]);
}
}
return invocation.proceed();
}
private void handleValidation(Object arg) {
Set<ConstraintViolation<Object>> constraintViolations
= validator.validate(arg);
if (!constraintViolations.isEmpty()) {
throw new IllegalArgumentException(
"constraint violations in bean argument");
}
}
}
In your InterceptionService
implementation, you can decide which services should be validated with a custom Filter
that looks for a custom @Validated
annotation on the service class
public class ValidatedFilter implements Filter {
@Override
public boolean matches(Descriptor descriptor) {
try {
return Class.forName(descriptor.getImplementation())
.isAnnotationPresent(Validated.class);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
public class ValidationInterceptionService implements InterceptionService {
private final static MethodInterceptor METHOD_INTERCEPTOR = new ValidationMethodInterceptor();
private final static List<MethodInterceptor> METHOD_LIST = Collections.singletonList(METHOD_INTERCEPTOR);
@Override
public Filter getDescriptorFilter() {
return new ValidatedFilter();
}
@Override
public List<MethodInterceptor> getMethodInterceptors(Method method) {
for (Parameter parameter: method.getParameters()) {
if (parameter.isAnnotationPresent(Valid.class)) {
return METHOD_LIST;
}
}
return null;
}
@Override
public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> c) {
return null;
}
}
See complete example with test case in this GitHub repository.
Upvotes: 1