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

org.jvnet.jaxb.annox.parser.XAnnotationParser Maven / Gradle / Ivy

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

import com.github.javaparser.ParseException;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.MarkerAnnotationExpr;
import com.github.javaparser.ast.expr.MemberValuePair;
import com.github.javaparser.ast.expr.NormalAnnotationExpr;
import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jvnet.jaxb.annox.Constants;
import org.jvnet.jaxb.annox.annotation.AnnotationClassNotFoundException;
import org.jvnet.jaxb.annox.annotation.NoSuchAnnotationFieldException;
import org.jvnet.jaxb.annox.javaparser.AnnotationExprParser;
import org.jvnet.jaxb.annox.javaparser.ast.visitor.AbstractGenericExpressionVisitor;
import org.jvnet.jaxb.annox.model.XAnnotation;
import org.jvnet.jaxb.annox.model.annotation.field.XAnnotationField;
import org.jvnet.jaxb.annox.parser.exception.AnnotationElementParseException;
import org.jvnet.jaxb.annox.parser.exception.AnnotationExpressionParseException;
import org.jvnet.jaxb.annox.parser.exception.AnnotationStringParseException;
import org.jvnet.jaxb.annox.util.ClassUtils;
import org.jvnet.jaxb.annox.util.StringUtils;
import org.jvnet.jaxb.annox.util.Validate;
import org.w3c.dom.Element;

public class XAnnotationParser {

	public static final XAnnotationParser INSTANCE = new XAnnotationParser();

	private final ClassLoader classLoader;
    private final Logger logger = Logger.getLogger(getClass().getName());

	/**
	 * Default constructor.
	 */
	public XAnnotationParser() {
		classLoader = this.getClass().getClassLoader();
	}

	/**
	 * Constructor with a specified class loader.
	 *
	 * @param classLoader
	 *            the class loader which should be used to get classes (like
	 *            annotations)
	 */
	public XAnnotationParser(ClassLoader classLoader) {
		super();
		this.classLoader = classLoader;
	}

	public XAnnotation parse(final Annotation annotation) {
		Objects.requireNonNull(annotation, "Annotation must not be null.");

		final Class annotationClass = annotation
				.annotationType();

		final XAnnotationField[] fields = parseFields(annotation,
				annotationClass);

		@SuppressWarnings({ "rawtypes", "unchecked" })
		final XAnnotation xannotation = new XAnnotation(annotationClass,
				fields);
		return xannotation;

	}

	public XAnnotation[] parse(final Annotation[] annotations) {
		Validate.noNullElements(annotations,
				"Annotations must not contain nulls.");
		final XAnnotation[] xannotations = new XAnnotation[annotations.length];
		for (int index = 0; index < annotations.length; index++) {
			final Annotation annotation = annotations[index];
			xannotations[index] = parse(annotation);
		}
		return xannotations;
	}

	@SuppressWarnings("unchecked")
	public XAnnotation parse(final Element annotationElement)
			throws AnnotationElementParseException {
        Objects.requireNonNull(annotationElement,
				"Annotation element must not be null.");

		final String name = annotationElement.getLocalName();

		final String classAttribute = annotationElement.getAttributeNS(
				Constants.NAMESPACE_URI, "class");
        final String legacyClassAttribute = annotationElement.getAttributeNS(
            Constants.LEGACY_NAMESPACE_URI, "class");

		final String className;
		if (!StringUtils.isEmpty(classAttribute)) {
			className = classAttribute;
		} else if (!StringUtils.isEmpty(legacyClassAttribute)) {
            logger.log(Level.WARNING, "Please migrate your namespace in xsd / xjb from " + Constants.LEGACY_NAMESPACE_URI + " to " + Constants.NAMESPACE_URI);
            className = legacyClassAttribute;
        } else {
			final String namespaceURI = annotationElement.getNamespaceURI();

			if (namespaceURI != null
					&& namespaceURI.startsWith(Constants.NAMESPACE_URI_PREFIX)) {
				final String containerPrefix = namespaceURI
						.substring(Constants.NAMESPACE_URI_PREFIX.length());
				className = containerPrefix + "." + name.replace('.', '$');
			} else if (namespaceURI != null
                && namespaceURI.startsWith(Constants.LEGACY_NAMESPACE_URI_PREFIX)) {
                logger.log(Level.WARNING, "Please migrate your namespace in xsd / xjb from " + Constants.LEGACY_NAMESPACE_URI_PREFIX + " to " + Constants.NAMESPACE_URI_PREFIX);
                final String containerPrefix = namespaceURI
                    .substring(Constants.LEGACY_NAMESPACE_URI_PREFIX.length());
                className = containerPrefix + "." + name.replace('.', '$');
            } else {
				className = name;
			}
		}

		try {
			final Class draftClass = classLoader.loadClass(className);

			if (!Annotation.class.isAssignableFrom(draftClass))
				throw new AnnotationElementParseException(annotationElement,
						new IllegalArgumentException(MessageFormat.format(
								"The class [{0}] is not an annotation class.",
								draftClass.getName())));

			final Class annotationClass = (Class) draftClass;

			final XAnnotationField[] fields = parseFields(annotationElement,
					annotationClass);
			@SuppressWarnings("rawtypes")
			final XAnnotation xannotation = new XAnnotation(annotationClass,
					fields);
			return xannotation;
		} catch (ClassNotFoundException cnfex) {
			throw new AnnotationElementParseException(annotationElement,
					new AnnotationClassNotFoundException(className, cnfex));
		} catch (AnnotationElementParseException cnfex) {
			throw new AnnotationElementParseException(annotationElement,
					new AnnotationClassNotFoundException(className, cnfex));
		}

	}

	public XAnnotation[] parse(final Element[] annotationElements)
			throws AnnotationElementParseException {
		Validate.noNullElements(annotationElements,
				"Annotation elements must not contain null.");
		final XAnnotation[] xannotations = new XAnnotation[annotationElements.length];
		for (int index = 0; index < annotationElements.length; index++) {
			final Element annotationElement = annotationElements[index];
			try {
				xannotations[index] = parse(annotationElement);
			} catch (AnnotationElementParseException aepex) {
				throw new AnnotationElementParseException(annotationElement,
						aepex);
			}
		}
		return xannotations;
	}

	public XAnnotation parse(final String annotationString)
			throws AnnotationStringParseException,
			AnnotationExpressionParseException {
		final AnnotationExpr expression = parseAnnotationExpr(annotationString);
		return parse(expression);
	}

	public XAnnotation[] parse(final String[] annotationStrings)
			throws AnnotationStringParseException,
			AnnotationExpressionParseException {
		Validate.noNullElements(annotationStrings);
		final List allAnnotationExprs = new ArrayList(
				annotationStrings.length);
		for (String annotationString : annotationStrings) {
			allAnnotationExprs.addAll(parseAnnotationExprs(annotationString));
		}
		final AnnotationExpr[] annotationExprs = new AnnotationExpr[allAnnotationExprs
				.size()];
		allAnnotationExprs.toArray(annotationExprs);
		return parse(annotationExprs);
	}

	private AnnotationExpr parseAnnotationExpr(final String annotationString)
			throws AnnotationStringParseException {
		List annotationExprs = parseAnnotationExprs(annotationString);

		if (annotationExprs.isEmpty()) {
			throw new AnnotationStringParseException(
					MessageFormat.format(
							"Could not parse the annotation [{0}], this expression apparently contains no annotations.",
							annotationString), annotationString);
		} else if (annotationExprs.size() > 1) {
			throw new AnnotationStringParseException(
					MessageFormat.format(
							"Could not parse the annotation [{0}], this expression apparently more than one annotation.",
							annotationString), annotationString);
		} else {
			return annotationExprs.get(0);
		}
	}

	private List parseAnnotationExprs(
			final String annotationString)
			throws AnnotationStringParseException {
		final AnnotationExprParser parser = new AnnotationExprParser();

		try {

			final List annotations = parser
					.parse(annotationString);

			return annotations;
		} catch (ParseException pex) {
			throw new AnnotationStringParseException(MessageFormat.format(
					"Could not parse the annotation [{0}].", annotationString),
					annotationString, pex);
		}
	}

	@SuppressWarnings("unchecked")
	public XAnnotation parse(final AnnotationExpr annotationElement)
			throws AnnotationExpressionParseException {
        Objects.requireNonNull(annotationElement,
				"Annotation expression must not be null.");
		final String className = annotationElement.getName().toString();

		try {

			final Class draftClass = ClassUtils.getClass(classLoader, className);

			if (!Annotation.class.isAssignableFrom(draftClass))
				throw new AnnotationExpressionParseException(annotationElement,
						new IllegalArgumentException(MessageFormat.format(
								"The class [{0}] is not an annotation class.",
								draftClass.getName())));

			final Class annotationClass = (Class) draftClass;

			final XAnnotationField[] fields = parseFields(annotationElement,
					annotationClass);
			@SuppressWarnings("rawtypes")
			final XAnnotation xannotation = new XAnnotation(annotationClass,
					fields);
			return xannotation;
		} catch (ClassNotFoundException cnfex) {
			throw new AnnotationExpressionParseException(annotationElement,
					new AnnotationClassNotFoundException(className, cnfex));
		}
	}

	public XAnnotation[] parse(final AnnotationExpr[] annotationElements)
			throws AnnotationExpressionParseException {
		Validate.noNullElements(annotationElements,
				"Annotation elements must not contain null.");
		final XAnnotation[] xannotations = new XAnnotation[annotationElements.length];
		for (int index = 0; index < annotationElements.length; index++) {
			final AnnotationExpr annotationElement = annotationElements[index];
			try {
				xannotations[index] = parse(annotationElement);
			} catch (AnnotationExpressionParseException aepex) {
				throw new AnnotationExpressionParseException(annotationElement,
						aepex);
			}
		}
		return xannotations;
	}

	public XAnnotationField[] parseFields(Element annotationElement,
			Class annotationClass)
			throws AnnotationElementParseException {

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

		final Map> fieldsMap = new HashMap>();

		for (final Method method : methods) {
			if (!Annotation.class.equals(method.getDeclaringClass())) {
				final String name = method.getName();
				final Class type = method.getReturnType();
				fieldsMap.put(name, type);
			}
		}

		final List> fields = new ArrayList>(
				fieldsMap.size());

		for (Entry> entry : fieldsMap.entrySet()) {
			final String name = entry.getKey();
			final Class type = entry.getValue();
			try {
				final XAnnotationField field = parseField(annotationElement,
						name, type);
				if (field != null) {
					fields.add(field);
				}
			} catch (AnnotationElementParseException aepex) {
				throw new AnnotationElementParseException(annotationElement,
						aepex);

			}

		}
		return fields.toArray(new XAnnotationField[fields.size()]);
	}

	public XAnnotationField[] parseFields(Annotation annotation,
			Class annotationClass) {

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

		final List> fields = new ArrayList>(
				methods.length);

		for (final Method method : methods) {
			if (!Annotation.class.equals(method.getDeclaringClass())) {
				final String name = method.getName();
				final Class type = method.getReturnType();
				try {
					fields.add(parseField(annotation, name, type));
				} catch (NoSuchAnnotationFieldException nsafex) {
					// We're sure that method exists, exception can not happen
					throw new AssertionError(nsafex);
				}
			}
		}
		return fields.toArray(new XAnnotationField[fields.size()]);
	}

	public XAnnotationField[] parseFields(AnnotationExpr annotationExpr,
			Class annotationClass)
			throws AnnotationExpressionParseException {
		final List pairs = annotationExpr
				.accept(new AbstractGenericExpressionVisitor, Void>() {
					@Override
					public List visitDefault(Node n, Void arg) {
						throw new IllegalArgumentException();
					}

					@Override
					public List visit(NormalAnnotationExpr n,
							Void arg) {
						return n.getPairs();
					}

					@Override
					public List visit(MarkerAnnotationExpr n,
							Void arg) {
						return Collections.emptyList();
					}

					@Override
					public List visit(
							SingleMemberAnnotationExpr n, Void arg) {
						return Collections.singletonList(new MemberValuePair(
								"value", n.getMemberValue()));
					}
				}, null);

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

		final Map> fieldsMap = new HashMap>();

		for (final Method method : methods) {
			if (!Annotation.class.equals(method.getDeclaringClass())) {
				final String name = method.getName();
				final Class type = method.getReturnType();
				fieldsMap.put(name, type);
			}
		}

		final List> fields = new ArrayList>(
				fieldsMap.size());

		for (MemberValuePair memberValuePair : pairs) {
			final String name = memberValuePair.getNameAsString();
			final Expression value = memberValuePair.getValue();
			final Class type = fieldsMap.get(name);
			if (type != null) {
				fields.add(parseField(value, name, type));
			} else {
				// TODO
			}
		}
		return fields.toArray(new XAnnotationField[fields.size()]);
	}

	@SuppressWarnings("unchecked")
	public XAnnotationField parseField(Expression annotationExpression,
			String name, Class type)
			throws AnnotationExpressionParseException {

		final XAnnotationField field = XGenericFieldParser.GENERIC.parse(
				annotationExpression, name, type);
		return field;
	}

	@SuppressWarnings("unchecked")
	public XAnnotationField parseField(Element annotationElement,
			String name, Class type) throws AnnotationElementParseException {

		final XAnnotationField field = XGenericFieldParser.GENERIC.parse(
				annotationElement, name, type);
		return field;
	}

	@SuppressWarnings("unchecked")
	public XAnnotationField parseField(Annotation annotation, String name,
			Class type) throws NoSuchAnnotationFieldException {

		final XAnnotationField field = XGenericFieldParser.GENERIC.parse(
				annotation, name, type);
		return field;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy