All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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