Package jodd.vtor

Source Code of jodd.vtor.ValidationContext

// Copyright (c) 2003-2014, Jodd Team (jodd.org). All Rights Reserved.

package jodd.vtor;

import jodd.introspector.ClassDescriptor;
import jodd.introspector.ClassIntrospector;
import jodd.introspector.FieldDescriptor;
import jodd.introspector.MethodDescriptor;
import jodd.introspector.PropertyDescriptor;
import jodd.util.ReflectUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Validation context is set of all checks that can be applied on one target.
* Checks can be added manually or by parsing the class.
*/
public class ValidationContext {

  private static final String ANN_SEVERITY = "severity";
  private static final String ANN_PROFILES = "profiles";

  // ---------------------------------------------------------------- define constraints

  protected final Map<String, List<Check>> map = new HashMap<String, List<Check>>();

  /**
   * Adds validation checks.
   */
  public void add(Check check) {
    String name = check.getName();
    List<Check> list = map.get(name);
    if (list == null) {
      list = new ArrayList<Check>();
      map.put(name, list);
    }
    list.add(check);
  }

  /**
   * Adds all checks from provided list.
   */
  public void addAll(List<Check> checkList) {
    for (Check check : checkList) {
      add(check);
    }
  }


  // ---------------------------------------------------------------- annotation resolver

  private static Map<Class, List<Check>> cache = new HashMap<Class, List<Check>>();

  /**
   * Resolve validation context for provided target class.
   * @see #addClassChecks(Class)
   */
  public static ValidationContext resolveFor(Class<?> target) {
    ValidationContext vc = new ValidationContext();
    vc.addClassChecks(target);
    return vc;
  }

  /**
   * Parses class annotations and adds all checks.
   * @see #resolveFor(Class)
   */
  public void addClassChecks(Class target) {
    List<Check> list = cache.get(target);
    if (list == null) {
      list = new ArrayList<Check>();
      ClassDescriptor cd = ClassIntrospector.lookup(target);

      PropertyDescriptor[] allProperties = cd.getAllPropertyDescriptors();
      for (PropertyDescriptor propertyDescriptor : allProperties) {
        collectPropertyAnnotationChecks(list, propertyDescriptor);
      }

      cache.put(target, list);
    }
    addAll(list);
  }

  /**
   * Process all annotations of provided properties.
   */
  protected void collectPropertyAnnotationChecks(List<Check> annChecks, PropertyDescriptor propertyDescriptor) {
    FieldDescriptor fd = propertyDescriptor.getFieldDescriptor();

    if (fd != null) {
      Annotation[] annotations = fd.getField().getAnnotations();
      collectAnnotationChecks(annChecks, propertyDescriptor.getType(), propertyDescriptor.getName(), annotations);
    }

    MethodDescriptor md = propertyDescriptor.getReadMethodDescriptor();
    if (md != null) {
      Annotation[] annotations = md.getMethod().getAnnotations();
      collectAnnotationChecks(annChecks, propertyDescriptor.getType(), propertyDescriptor.getName(), annotations);
    }

    md = propertyDescriptor.getWriteMethodDescriptor();
    if (md != null) {
      Annotation[] annotations = md.getMethod().getAnnotations();
      collectAnnotationChecks(annChecks, propertyDescriptor.getType(), propertyDescriptor.getName(), annotations);
    }
  }

  /**
   * Collect annotations for some target.
   */
  @SuppressWarnings({"unchecked"})
  protected void collectAnnotationChecks(List<Check> annChecks, Class targetType, String targetName, Annotation[] annotations) {
    for (Annotation annotation : annotations) {
      Constraint c = annotation.annotationType().getAnnotation(Constraint.class);
      if (c == null) {
        continue;
      }

      Class<? extends ValidationConstraint> constraintClass = c.value();
      ValidationConstraint vc;
      try {
        vc = newConstraint(constraintClass, targetType);
      } catch (Exception ex) {
        throw new VtorException("Invalid constraint: " + constraintClass.getClass().getName(), ex);
      }
      vc.configure(annotation);
      Check check = new Check(targetName, vc);
      copyDefaultCheckProperties(check, annotation);
      annChecks.add(check);
    }
  }


  /**
   * Create new constraint. The following rules are used:
   * <ul>
   * <li>use default constructor if exist.</li>
   * <li>otherwise, use constructor with ValidationContext parameter.</li>
   * </ul>
   */
  protected <V extends ValidationConstraint> V newConstraint(Class<V> constraint, Class targetType) throws Exception {
    Constructor<V> ctor;
    try {
      ctor = constraint.getConstructor();
      return ctor.newInstance();
    } catch (NoSuchMethodException ignore) {
      ctor = constraint.getConstructor(ValidationContext.class);
      return ctor.newInstance(resolveFor(targetType));
    }
  }



  /**
   * Copies default properties from annotation to the check.
   */
  protected void copyDefaultCheckProperties(Check destCheck, Annotation annotation) {
    Integer severity = (Integer) ReflectUtil.readAnnotationValue(annotation, ANN_SEVERITY);
    destCheck.setSeverity(severity.intValue());

    String[] profiles = (String[]) ReflectUtil.readAnnotationValue(annotation, ANN_PROFILES);
    destCheck.setProfiles(profiles);
  }

}
TOP

Related Classes of jodd.vtor.ValidationContext

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.