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

org.jvnet.jaxb.annox.model.XAnnotation Maven / Gradle / Ivy

The newest version!
package org.jvnet.jaxb.annox.model;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jvnet.jaxb.annox.model.annotation.field.XAnnotationField;
import org.jvnet.jaxb.annox.parser.XGenericFieldParser;
import org.jvnet.jaxb.annox.util.Validate;

/**
 * Defines an xannotation.
 *
 * @author Aleksei Valikov
 *
 */
public class XAnnotation {

	/**
	 * Empty array of annotations.
	 */
	public static XAnnotation[] EMPTY_ARRAY = new XAnnotation[0];

	/**
	 * Class of the annotation.
	 */
	final Class annotationClass;

	/**
	 * Map of the xannotation fields.
	 */
	private final Map> fieldsMap;

	/**
	 * Set of the xannotation fields.
	 */
	private final Set> fieldsSet;

	/**
	 * List of the xannotation fields.
	 */
	private final List> fieldsList;

	/**
	 * Constructs an xannotation for the given annotation class.
	 *
	 * @param annotationClass
	 *            annotation class, must not be null
	 * @param fields
	 *            fields of the xannotation.
	 * @throws IllegalArgumentException
	 *             If annotation class is null, some required
	 *             annotation fields are missing or some annotation fields have
	 *             mismatching types.
	 */
	public XAnnotation(final Class annotationClass,
			final XAnnotationField... fields)
			throws IllegalArgumentException {
		Validate.notNull(annotationClass, "Annotation class must not be null.");
		this.annotationClass = annotationClass;
		final List> fieldsList = Collections
				.unmodifiableList(toFieldsList(fields));

		final Map> fieldsMap = Collections
				.unmodifiableMap(toFieldsMap(annotationClass.getMethods(),
						fieldsList));
		checkFieldsMap(fieldsMap);

		this.fieldsList = fieldsList;
		this.fieldsMap = fieldsMap;
		this.fieldsSet = Collections
				.unmodifiableSet(new HashSet>(fieldsMap
						.values()));
	}

	private static List> toFieldsList(
			final XAnnotationField[] fields) {
		if (fields == null) {
			return Collections.emptyList();
		} else {
			final List> fieldsList = new ArrayList>(
					fields.length);

			for (XAnnotationField field : fields) {
				if (field != null) {
					fieldsList.add(field);
				}
			}
			return fieldsList;
		}
	}

	@SuppressWarnings("unchecked")
	private static Map> toFieldsMap(
			final Method[] methods, final List> fieldsList) {
		final Map> definedFieldsMap = new HashMap>();
		if (fieldsList != null) {
			for (XAnnotationField definedField : fieldsList) {
				if (definedField == null)
					throw new IllegalArgumentException(
							"Fields array must not contain null entries.");
				definedFieldsMap.put(definedField.getName(), definedField);
			}
		}

		final Map> fieldsMap = new HashMap>();

		for (final Method method : methods) {
			if (Annotation.class.equals(method.getDeclaringClass())) {
				// Annotation class methods are ignored
			} else {
				final String name = method.getName();
				final Class fieldType = method.getReturnType();
				final XAnnotationField field;

				final XAnnotationField definedField = definedFieldsMap
						.get(name);
				if (definedField == null) {
					final Object defaultValue = method.getDefaultValue();
					if (defaultValue == null) {
						throw new IllegalArgumentException(
								"Field ["
										+ name
										+ "] is not defined and it has no default value.");
					} else {
						try {
							field = XGenericFieldParser.GENERIC.construct(
									name, defaultValue, fieldType);
						} catch (Exception ex) {
							throw new IllegalArgumentException("Field [" + name
									+ "] could not be parsed.", ex);
						}
					}
				} else {
					final Class definedFieldType = definedField.getType();
					if (!fieldType.equals(definedFieldType)) {
						throw new IllegalArgumentException("Field [" + name
								+ "] has the wrong type [" + definedFieldType
								+ "] instead of expected [" + fieldType + "].");
					} else {
						field = definedField;
					}
				}

				fieldsMap.put(field.getName(), field);
			}
		}
		return fieldsMap;
	}

	private void checkFieldsMap(Map> fieldsMap) {

		final Method[] methods = annotationClass.getMethods();

		for (final Method method : methods) {
			if (!Annotation.class.equals(method.getDeclaringClass())) {
				final String name = method.getName();
				final Class type = method.getReturnType();
				final XAnnotationField field = fieldsMap.get(name);
				if (field == null) {
					throw new IllegalArgumentException("Field [" + name
							+ "] is not defined.");
				}
				final Class fieldType = field.getType();
				if (!type.equals(fieldType)) {
					throw new IllegalArgumentException("Field [" + name
							+ "] has the wrong type [" + field.getType()
							+ "] instead of expected [" + type + "].");
				}
			}
		}

	}

	/**
	 * Returns the annotation class.
	 *
	 * @return annotation class.
	 */
	public Class getAnnotationClass() {
		return annotationClass;
	}

	public String getAnnotationClassName() {
		return annotationClass.getName();
	}

	/**
	 * Returns the list of the fields.
	 *
	 * @return list of the fields.
	 */
	public List> getFieldsList() {
		return fieldsList;
	}

	/**
	 * Returns the map of the fields.
	 *
	 * @return map of the fields.
	 */
	public Map> getFieldsMap() {
		return fieldsMap;
	}

	@Override
	public int hashCode() {
		int hash = 0;
		hash = hash * 37 + annotationClass.hashCode();
		hash = hash * 37 + fieldsSet.hashCode();
		return hash;
	}

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof XAnnotation)) {
			return false;
		}
		if (this == obj) {
			return true;
		}
		final XAnnotation other = (XAnnotation) obj;
		return annotationClass.equals(other.annotationClass)
				&& fieldsSet.equals(other.fieldsSet);
	}

	@Override
	public String toString() {
		final StringBuffer sb = new StringBuffer();
		sb.append("@");
		sb.append(getAnnotationClass().getName());

		sb.append("(");
		for (int index = 0; index < fieldsList.size(); index++) {
			final XAnnotationField field = fieldsList.get(index);
			if (index > 0) {
				sb.append(", ");
			}
			sb.append(field);
		}
		sb.append(")");
		return sb.toString();
	}

	/**
	 * Returns the instance of the annotation for this xannotation.
	 *
	 * @return Instance of the annotation for this xannotation.
	 */
	public A getResult() {
		final InvocationHandler handler = new XAnnotationInvocationHandler(this);

		@SuppressWarnings("unchecked")
		final A annotation = (A) Proxy.newProxyInstance(
				annotationClass.getClassLoader(),
				new Class[] { annotationClass }, handler);

		return annotation;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy