Package org.apache.bval.jsr303.extensions

Source Code of org.apache.bval.jsr303.extensions.MethodValidatorImpl

/**
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.apache.bval.jsr303.extensions;

import org.apache.bval.MetaBeanFactory;
import org.apache.bval.MetaBeanManager;
import org.apache.bval.jsr303.*;
import org.apache.bval.jsr303.groups.Group;
import org.apache.bval.jsr303.groups.Groups;
import org.apache.bval.model.MetaBean;

import javax.validation.ConstraintViolation;
import javax.validation.metadata.ConstraintDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
* Description: experimental implementation of method-level-validation <br/>
*/
class MethodValidatorImpl extends ClassValidator implements MethodValidator {
  public MethodValidatorImpl(ApacheFactoryContext factoryContext) {
    super(factoryContext);
    patchFactoryContextForMethodValidation(factoryContext);
  }

  /**
   * experimental: replace the Jsr303MetaBeanFactory with a MethodValidatorMetaBeanFactory in the factoryContext.
   */
  private void patchFactoryContextForMethodValidation(ApacheFactoryContext factoryContext) {
    MetaBeanFactory[] factories = ((MetaBeanManager) getMetaBeanFinder()).getBuilder().getFactories();
    for(int i=0;i<factories.length;i++) {
      if(factories[i] instanceof Jsr303MetaBeanFactory && !(factories[i] instanceof MethodValidatorMetaBeanFactory)) {
        factories[i] = new MethodValidatorMetaBeanFactory(factoryContext);
      }
    }
  }

  @Override
  protected BeanDescriptorImpl createBeanDescriptor(MetaBean metaBean) {
    MethodBeanDescriptorImpl descriptor = new MethodBeanDescriptorImpl(factoryContext,
        metaBean, metaBean.getValidations());
    MethodValidatorMetaBeanFactory factory =
        new MethodValidatorMetaBeanFactory(factoryContext);
    factory.buildMethodDescriptor(descriptor);
    return descriptor;
  }

  /**
   * enhancement: method-level-validation not yet completly implemented
   * <pre>example:
   * <code>
   * public @NotNull String saveItem(@Valid @NotNull Item item, @Max(23) BigDecimal
   * </code></pre>
   * spec:
   * The constraints declarations evaluated are the constraints hosted on the
   * parameters of the method or constructor. If @Valid is placed on a parameter,
   * constraints declared on the object itself are considered.
   *
   * @throws IllegalArgumentException enhancement: if the method does not belong to <code>T</code>
   *                                  or if the Object[] does not match the method signature
   */
  public <T> Set<ConstraintViolation<T>> validateParameters(Class<T> clazz, Method method,
                                                            Object[] parameters,
                                                            Class<?>... groupArray) {
    MethodBeanDescriptorImpl beanDesc =
        (MethodBeanDescriptorImpl) getConstraintsForClass(clazz);
    MethodDescriptorImpl methodDescriptor =
        (MethodDescriptorImpl) beanDesc.getConstraintsForMethod(method);
    return validateParameters(methodDescriptor.getMetaBean(),
        methodDescriptor.getParameterDescriptors(), parameters, groupArray);
  }

  public <T> Set<ConstraintViolation<T>> validateParameter(Class<T> clazz, Method method,
                                                           Object parameter,
                                                           int parameterIndex,
                                                           Class<?>... groupArray) {
    MethodBeanDescriptorImpl beanDesc =
        (MethodBeanDescriptorImpl) getConstraintsForClass(clazz);
    MethodDescriptorImpl methodDescriptor =
        (MethodDescriptorImpl) beanDesc.getConstraintsForMethod(method);
    ParameterDescriptorImpl paramDesc = (ParameterDescriptorImpl) methodDescriptor
        .getParameterDescriptors().get(parameterIndex);
    return validateParameter(paramDesc, parameter, groupArray);
  }

  public <T> Set<ConstraintViolation<T>> validateParameters(Class<T> clazz,
                                                            Constructor<T> constructor,
                                                            Object[] parameters,
                                                            Class<?>... groupArray) {
    MethodBeanDescriptorImpl beanDesc =
        (MethodBeanDescriptorImpl) getConstraintsForClass(clazz);
    ConstructorDescriptorImpl constructorDescriptor =
        (ConstructorDescriptorImpl) beanDesc.getConstraintsForConstructor(constructor);
    return validateParameters(constructorDescriptor.getMetaBean(),
        constructorDescriptor.getParameterDescriptors(), parameters, groupArray);
  }

  public <T> Set<ConstraintViolation<T>> validateParameter(Class<T> clazz,
                                                           Constructor<T> constructor,
                                                           Object parameter,
                                                           int parameterIndex,
                                                           Class<?>... groupArray) {
    MethodBeanDescriptorImpl beanDesc =
        (MethodBeanDescriptorImpl) getConstraintsForClass(clazz);
    ConstructorDescriptorImpl methodDescriptor =
        (ConstructorDescriptorImpl) beanDesc.getConstraintsForConstructor(constructor);
    ParameterDescriptorImpl paramDesc = (ParameterDescriptorImpl) methodDescriptor
        .getParameterDescriptors().get(parameterIndex);
    return validateParameter(paramDesc, parameter, groupArray);
  }

  /**
   * If @Valid  is placed on the method, the constraints declared on the object
   * itself are considered.
   */
  public <T> Set<ConstraintViolation<T>> validateReturnedValue(Class<T> clazz, Method method,
                                                               Object returnedValue,
                                                               Class<?>... groupArray) {
    MethodBeanDescriptorImpl beanDesc =
        (MethodBeanDescriptorImpl) getConstraintsForClass(clazz);
    MethodDescriptorImpl methodDescriptor =
        (MethodDescriptorImpl) beanDesc.getConstraintsForMethod(method);
    final GroupValidationContext<ConstraintValidationListener<Object>> context =
        createContext(methodDescriptor.getMetaBean(), returnedValue, null, groupArray);
    validateReturnedValueInContext(context, methodDescriptor);
    ConstraintValidationListener result = context.getListener();
    return result.getConstaintViolations();
  }

  private <T> Set<ConstraintViolation<T>> validateParameters(MetaBean metaBean,
                                                             List<ParameterDescriptor> paramDescriptors,
                                                             Object[] parameters,
                                                             Class<?>... groupArray) {
    if (parameters == null) throw new IllegalArgumentException("cannot validate null");
    if (parameters.length > 0) {
      try {
        GroupValidationContext<ConstraintValidationListener<Object[]>> context =
            createContext(metaBean, null, null, groupArray);
        for (int i = 0; i < parameters.length; i++) {
          ParameterDescriptorImpl paramDesc =
              (ParameterDescriptorImpl) paramDescriptors.get(i);
          context.setBean(parameters[i]);
          validateParameterInContext(context, paramDesc);
        }
        ConstraintValidationListener result = context.getListener();
        return result.getConstaintViolations();
      } catch (RuntimeException ex) {
        throw unrecoverableValidationError(ex, parameters);
      }
    } else {
      return Collections.EMPTY_SET;
    }
  }

  private <T> Set<ConstraintViolation<T>> validateParameter(
      ParameterDescriptorImpl paramDesc, Object parameter, Class<?>... groupArray) {
    try {
      final GroupValidationContext<ConstraintValidationListener<Object>> context =
          createContext(paramDesc.getMetaBean(), parameter, null, groupArray);
      final ConstraintValidationListener result = context.getListener();
      validateParameterInContext(context, paramDesc);
      return result.getConstaintViolations();
    } catch (RuntimeException ex) {
      throw unrecoverableValidationError(ex, parameter);
    }
  }

  /**
   * validate constraints hosted on parameters of a method
   */
  private <T> void validateParameterInContext(
      GroupValidationContext<ConstraintValidationListener<T>> context,
      ParameterDescriptorImpl paramDesc) {

    final Groups groups = context.getGroups();

    for (ConstraintDescriptor consDesc : paramDesc.getConstraintDescriptors()) {
      ConstraintValidation validation = (ConstraintValidation) consDesc;
      // 1. process groups
      for (Group current : groups.getGroups()) {
        context.setCurrentGroup(current);
        validation.validate(context);
      }
      // 2. process sequences
      for (List<Group> eachSeq : groups.getSequences()) {
        for (Group current : eachSeq) {
          context.setCurrentGroup(current);
          validation.validate(context);
          /**
           * if one of the group process in the sequence leads to one or more validation failure,
           * the groups following in the sequence must not be processed
           */
          if (!context.getListener().isEmpty()) break;
        }
      }
    }
    if (paramDesc.isCascaded() && context.getValidatedValue() != null) {
      context.setMetaBean(factoryContext.getMetaBeanFinder().
          findForClass(context.getValidatedValue().getClass()));
      // 1. process groups
      for (Group current : groups.getGroups()) {
        context.setCurrentGroup(current);
        validateContext(context);
      }
      // 2. process sequences
      for (List<Group> eachSeq : groups.getSequences()) {
        for (Group current : eachSeq) {
          context.setCurrentGroup(current);
          validateContext(context);
          /**
           * if one of the group process in the sequence leads to one or more validation failure,
           * the groups following in the sequence must not be processed
           */
          if (!context.getListener().isEmpty()) break;
        }
      }
    }
  }

  /**
   * validate constraints hosted on parameters of a method
   */
  private <T> void validateReturnedValueInContext(
      GroupValidationContext<ConstraintValidationListener<T>> context,
      MethodDescriptorImpl methodDescriptor) {

    final Groups groups = context.getGroups();

    for (ConstraintDescriptor consDesc : methodDescriptor.getConstraintDescriptors()) {
      ConstraintValidation validation = (ConstraintValidation) consDesc;
      // 1. process groups
      for (Group current : groups.getGroups()) {
        context.setCurrentGroup(current);
        validation.validate(context);
      }
      // 2. process sequences
      for (List<Group> eachSeq : groups.getSequences()) {
        for (Group current : eachSeq) {
          context.setCurrentGroup(current);
          validation.validate(context);
          /**
           * if one of the group process in the sequence leads to one or more validation failure,
           * the groups following in the sequence must not be processed
           */
          if (!context.getListener().isEmpty()) break;
        }
      }
    }
    if (methodDescriptor.isCascaded() && context.getValidatedValue() != null) {
      context.setMetaBean(factoryContext.getMetaBeanFinder().
          findForClass(context.getValidatedValue().getClass()));
      // 1. process groups
      for (Group current : groups.getGroups()) {
        context.setCurrentGroup(current);
        validateContext(context);
      }
      // 2. process sequences
      for (List<Group> eachSeq : groups.getSequences()) {
        for (Group current : eachSeq) {
          context.setCurrentGroup(current);
          validateContext(context);
          /**
           * if one of the group process in the sequence leads to one or more validation failure,
           * the groups following in the sequence must not be processed
           */
          if (!context.getListener().isEmpty()) break;
        }
      }
    }
  }
}
TOP

Related Classes of org.apache.bval.jsr303.extensions.MethodValidatorImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.