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

spoon.processing.XMLAnnotationProcessor Maven / Gradle / Ivy

/* 
 * Spoon - http://spoon.gforge.inria.fr/
 * Copyright (C) 2006 INRIA Futurs 
 * 
 * 
 * This software is governed by the CeCILL-C License under French law and
 * abiding by the rules of distribution of free software. You can use, modify 
 * and/or redistribute the software under the terms of the CeCILL-C license as 
 * circulated by CEA, CNRS and INRIA at http://www.cecill.info. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
 *  
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL-C license and that you accept its terms.
 */

package spoon.processing;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import spoon.Launcher;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtExecutable;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtSimpleType;
import spoon.reflect.declaration.CtType;
import spoon.reflect.reference.CtTypeReference;
import spoon.support.processing.XmlProcessorProperties;

/**
 * A processor to add/replace/override/remove annotations described in an XML
 * file. This version is based on java.util.regexp, but it can be subclassed to
 * implement other types of matchings. Note that the used XML file is defined by
 * the property {@link #xmlPath}, which can be defined in a property file or a
 * Spoonlet file (spoon.xml) depending on your environment.
 * 
 * @author Didier Donsez
 * @author Renaud Pawlak
 */
public class XMLAnnotationProcessor extends AbstractManualProcessor {

	/**
	 * This property contains the path of the XML file that describes the
	 * annotations of the processed program. By default, the file is the
	 * annotations.xml file contained in the current directory.
	 */
	@Property
	public String xmlPath = "annotations.xml";

	private Document document;

	/**
	 * Creates a new XMLAnnotationProcessor.
	 */
	public XMLAnnotationProcessor() {
	}

	@Override
	final public void init() {
		// Initiate DocumentBuilderFactory
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

		// To get a validating parser
		factory.setValidating(false); // since no DTD/XML Schema is defined
		// To get one that understands namespaces
		factory.setNamespaceAware(true);

		try {
			// Get DocumentBuilder
			DocumentBuilder builder = factory.newDocumentBuilder();
			// Parse and load into memory the Document
			document = builder.parse(getClass().getClassLoader()
					.getResourceAsStream(xmlPath));
		} catch (SAXParseException spe) {
			// Error generated by the parser
			getEnvironment().report(
					this,
					Severity.ERROR,
					"XML parsing error line " + spe.getLineNumber() + ", uri "
							+ spe.getSystemId());
			// Use the contained exception, if any
			Exception x = spe;
			if (spe.getException() != null)
				x = spe.getException();
			Launcher.logger.error(x.getMessage(), x);
		} catch (SAXException sxe) {
			// Error generated during parsing
			Exception x = sxe;
			if (sxe.getException() != null)
				x = sxe.getException();
			Launcher.logger.error(x.getMessage(), x);
		} catch (ParserConfigurationException pce) {
			// Parser with specified options can't be built
			Launcher.logger.error(pce.getMessage(), pce);
		} catch (IOException ioe) {
			// I/O error
			Launcher.logger.error(ioe.getMessage(), ioe);
		}
	}

	/**
	 * Override this method to create other types of matchings than the defaut
	 * one (java.util.regexp).
	 * 
	 * @param type
	 *            the canditate type
	 * @param typeExpression
	 *            and expression to match the type against.
	 * @return true if the type matches the expression
	 * @see CtElement#getSignature()
	 */
	protected boolean isTypeMatching(CtSimpleType type, String typeExpression) {
		return java.util.regex.Pattern.matches(typeExpression,
				type.getQualifiedName());
	}

	/**
	 * Override this method to create other types of matchings than the defaut
	 * one (java.util.regexp).
	 * 
	 * @param executable
	 *            the canditate executable
	 * @param executableExpression
	 *            and expression to match the executable against.
	 * @return true if the executable matches the expression
	 * @see CtElement#getSignature()
	 */
	protected boolean isExecutableMatching(CtExecutable executable,
			String executableExpression) {
		String signature = executable.getSignature();
		return java.util.regex.Pattern.matches(executableExpression, signature);
	}

	/**
	 * Override this method to create other types of matchings than the defaut
	 * one (java.util.regexp).
	 * 
	 * @param field
	 *            the canditate field
	 * @param fieldExpression
	 *            and expression to match the field against.
	 * @return true if the field matches the expression
	 * @see CtElement#getSignature()
	 */
	protected boolean isFieldMatching(CtField field, String fieldExpression) {
		String signature = field.getSignature();
		return java.util.regex.Pattern.matches(fieldExpression, signature);
	}

	final public void process() {
		// Get the XML root node
		Element root = document.getDocumentElement();

		NodeList nodeList = root.getElementsByTagName("class");
		int len = nodeList.getLength();
		for (int i = 0; i < len; i++) {
			Element clazz = (Element) nodeList.item(i);
			String nameExpr = clazz.getAttribute("expr");
			for (CtSimpleType t : getFactory().Type().getAll(true)) {
				// CtSimpleType t = getType(name);
				if (!isTypeMatching(t, nameExpr))
					continue;
				try {
					annotateElement(t, clazz);
				} catch (Exception e) {
					Launcher.logger.error(e.getMessage(), e);
				}

				NodeList nodeList3 = clazz.getElementsByTagName("field");
				for (int j = 0; j < nodeList3.getLength(); j++) {
					Element fieldElt = (Element) nodeList3.item(j);
					if (fieldElt.getParentNode() != clazz)
						continue;
					String fieldExpr = fieldElt.getAttribute("expr");

					for (CtField field : t.getFields()) {
						if (!isFieldMatching(field, fieldExpr))
							continue;
						try {
							annotateElement(field, fieldElt);
						} catch (Exception e) {
							Launcher.logger.error(e.getMessage(), e);
						}
					}
				}

				if (!(t instanceof CtType))
					continue;

				List> executables = new ArrayList>();
				executables.addAll(((CtType) t).getMethods());
				if (t instanceof CtClass) {
					executables.addAll(((CtClass) t).getConstructors());
				}

				NodeList nodeList2 = clazz.getElementsByTagName("executable");
				for (int j = 0; j < nodeList2.getLength(); j++) {
					Element executableElt = (Element) nodeList2.item(j);
					if (executableElt.getParentNode() != clazz)
						continue;
					String executableExpr = executableElt.getAttribute("expr");

					for (CtExecutable executable : executables) {

						if (!isExecutableMatching(executable, executableExpr))
							continue;
						try {
							annotateElement(executable, executableElt);
						} catch (Exception e) {
							Launcher.logger.error(e.getMessage(), e);
						}

						// NodeList paramList = method
						// .getElementsByTagName("parameter");
						// for (int k = 0; k < paramList.getLength(); k++) {
						// Element param = (Element) paramList.item(k);
						// if (param.getParentNode() != method)
						// continue;
						// String paramName = param.getAttribute("name");
						// CtParameter parameter = getParameter(exec,
						// paramName);
						// if (parameter != null) {
						// try {
						// annotateElement(parameter, param);
						// } catch (Exception e) {
						// Launcher.logger.error(e.getMessage(), e);
						// }
						// }
						// }

					}
				}

			}
		}
	}

	// private CtSimpleType getType(String name) {
	// CtTypeReference ref = getFactory().Type().createReference(name);
	// CtSimpleType t = ref.getDeclaration();
	// return t;
	// }
	//
	// private CtExecutable getExecutable(String signature) {
	// CtExecutableReference ref = getFactory().Executable()
	// .createReference(signature);
	// CtExecutable t = ref.getDeclaration();
	// return t;
	// }
	//
	// private CtField getField(String signature) {
	// CtFieldReference ref = getFactory().Field().createReference(
	// signature);
	// CtField t = ref.getDeclaration();
	// return t;
	// }
	//
	// private CtParameter getParameter(CtExecutable exec, String name) {
	// for (CtParameter p : exec.getParameters()) {
	// if (p.getSimpleName().equals(name)) {
	// return p;
	// }
	// }
	// return null;
	// }

	private void annotateElement(CtElement javaElt, Element xmlNode)
			throws Exception {
		NodeList annNodeList = xmlNode.getElementsByTagName("annotation");
		for (int i = 0; i < annNodeList.getLength(); i++) {
			Element annotationNode = (Element) annNodeList.item(i);
			if (annotationNode.getParentNode() != xmlNode)
				continue;
			String name = annotationNode.getAttribute("name");
			CtTypeReference aref = getFactory()
					.Annotation().createReference(name);
			getFactory().Annotation().annotate(javaElt, aref);
			NodeList fieldNodeList = annotationNode
					.getElementsByTagName("element");
			for (int f = 0; f < fieldNodeList.getLength(); f++) {
				Element fieldNode = (Element) fieldNodeList.item(f);
				String fieldName = fieldNode.getAttribute("name");
				String fieldValue = fieldNode.getAttribute("value");
				Class type = aref.getActualClass().getMethod(fieldName)
						.getReturnType();
				Object v = ((XmlProcessorProperties) getEnvironment().getProcessorProperties(this.getClass().getName())).convert(type, fieldValue);
				getFactory().Annotation().annotate(javaElt, aref, fieldName, v);
			}
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy