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

jodd.vtor.ValidationContext Maven / Gradle / Ivy

There is a newer version: 5.3.0
Show newest version
// 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> map = new HashMap>();

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

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


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

	private static Map> cache = new HashMap>();

	/**
	 * 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 list = cache.get(target);
		if (list == null) {
			list = new ArrayList();
			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 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 annChecks, Class targetType, String targetName, Annotation[] annotations) {
		for (Annotation annotation : annotations) {
			Constraint c = annotation.annotationType().getAnnotation(Constraint.class);
			if (c == null) {
				continue;
			}

			Class 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:
	 * 
    *
  • use default constructor if exist.
  • *
  • otherwise, use constructor with ValidationContext parameter.
  • *
*/ protected V newConstraint(Class constraint, Class targetType) throws Exception { Constructor 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); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy