io.dropwizard.jersey.validation.DropwizardConfiguredValidator Maven / Gradle / Ivy
The newest version!
package io.dropwizard.jersey.validation;
import io.dropwizard.validation.ConstraintViolations;
import io.dropwizard.validation.Validated;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
import jakarta.validation.executable.ExecutableValidator;
import jakarta.validation.groups.Default;
import jakarta.validation.metadata.BeanDescriptor;
import jakarta.ws.rs.WebApplicationException;
import org.glassfish.jersey.server.internal.inject.ConfiguredValidator;
import org.glassfish.jersey.server.model.Invocable;
import org.glassfish.jersey.server.model.Parameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static java.util.Objects.requireNonNull;
public class DropwizardConfiguredValidator implements ConfiguredValidator {
private static final Logger LOGGER = LoggerFactory.getLogger(DropwizardConfiguredValidator.class);
private final Validator validator;
public DropwizardConfiguredValidator(Validator validator) {
this.validator = requireNonNull(validator);
}
@Override
public void validateResourceAndInputParams(Object resource, final Invocable invocable, Object[] objects)
throws ConstraintViolationException {
final Class>[] groups = getGroup(invocable);
final Set> violations = new HashSet<>();
final BeanDescriptor beanDescriptor = getConstraintsForClass(resource.getClass());
if (beanDescriptor.isBeanConstrained()) {
violations.addAll(validate(resource, groups));
}
violations.addAll(forExecutables().validateParameters(resource, invocable.getHandlingMethod(), objects, groups));
if (!violations.isEmpty()) {
throw new JerseyViolationException(violations, invocable);
}
}
/**
* If the request entity is annotated with {@link Validated} then run
* validations in the specified constraint group else validate with the
* {@link Default} group
*/
private Class>[] getGroup(Invocable invocable) {
final List[]> groups = new ArrayList<>();
for (Parameter parameter : invocable.getParameters()) {
if (parameter.isAnnotationPresent(Validated.class)) {
groups.add(parameter.getAnnotation(Validated.class).value());
}
}
switch (groups.size()) {
// No parameters were annotated with Validated, so validate under the default group
case 0: return new Class>[] {Default.class};
// A single parameter was annotated with Validated, so use their group
case 1: return groups.get(0);
// Multiple parameters were annotated with Validated, so we must check if
// all groups are equal to each other, if not, throw an exception because
// the validator is unable to handle parameters validated under different
// groups. If the parameters have the same group, we can grab the first
// group.
default:
for (int i = 0; i < groups.size(); i++) {
for (int j = i; j < groups.size(); j++) {
if (!Arrays.deepEquals(groups.get(i), groups.get(j))) {
throw new WebApplicationException("Parameters must have the same validation groups in " +
invocable.getHandlingMethod().getName(), 500);
}
}
}
return groups.get(0);
}
}
@Override
public void validateResult(Object resource, Invocable invocable, Object returnValue)
throws ConstraintViolationException {
// If the Validated annotation is on a method, then validate the response with
// the specified constraint group.
final Class>[] groups;
if (invocable.getHandlingMethod().isAnnotationPresent(Validated.class)) {
groups = invocable.getHandlingMethod().getAnnotation(Validated.class).value();
} else {
groups = new Class>[]{Default.class};
}
final Set> violations =
forExecutables().validateReturnValue(resource, invocable.getHandlingMethod(), returnValue, groups);
if (!violations.isEmpty()) {
LOGGER.trace("Response validation failed: {}", ConstraintViolations.copyOf(violations));
throw new JerseyViolationException(violations, invocable);
}
}
@Override
public Set> validate(T t, Class>... classes) {
return validator.validate(t, classes);
}
@Override
public Set> validateProperty(T t, String s, Class>... classes) {
return validator.validateProperty(t, s, classes);
}
@Override
public Set> validateValue(Class aClass, String s, Object o, Class>... classes) {
return validator.validateValue(aClass, s, o, classes);
}
@Override
public BeanDescriptor getConstraintsForClass(Class> aClass) {
return validator.getConstraintsForClass(aClass);
}
@Override
public T unwrap(Class aClass) {
return validator.unwrap(aClass);
}
@Override
public ExecutableValidator forExecutables() {
return validator.forExecutables();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy