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

spoon.processing.AbstractAnnotationProcessor Maven / Gradle / Ivy

Go to download

Spoon is a tool for meta-programming, analysis and transformation of Java programs.

There is a newer version: 11.1.1-beta-14
Show newest version
/*
 * SPDX-License-Identifier: (MIT OR CECILL-C)
 *
 * Copyright (C) 2006-2023 INRIA and contributors
 *
 * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) or the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon.
 */
package spoon.processing;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import spoon.Launcher;
import spoon.reflect.declaration.CtAnnotation;
import spoon.reflect.declaration.CtElement;

/**
 * This class defines an abstract annotation processor to be subclassed by the
 * user for defining new annotation processors including Java 8 annotations.
 */
public abstract class AbstractAnnotationProcessor extends AbstractProcessor implements AnnotationProcessor {

	Map> consumedAnnotationTypes = new TreeMap<>();

	Map> processedAnnotationTypes = new TreeMap<>();

	/**
	 * Empty constructor only for all processors (invoked by Spoon).
	 */
	@SuppressWarnings("unchecked")
	public AbstractAnnotationProcessor() {
		clearProcessedElementType();

		for (Method m : getClass().getMethods()) {
			if ("process".equals(m.getName()) && (m.getParameterTypes().length == 2)) {
				Class c = m.getParameterTypes()[0];
				if (inferConsumedAnnotationType() && (Annotation.class != c)) {
					addConsumedAnnotationType((Class) c);
				}
				c = m.getParameterTypes()[1];
				if (CtElement.class != c) {
					addProcessedElementType((Class) c);
				}
			}
		}
		if (inferConsumedAnnotationType() && processedAnnotationTypes.isEmpty()) {
			addProcessedAnnotationType((Class) Annotation.class);
		}
		if (processedElementTypes.isEmpty()) {
			addProcessedElementType(CtElement.class);
		}
	}

	/**
	 * Adds a consumed annotation type (to be used in subclasses constructors).
	 * A consumed annotation type is also part of the processed annotation
	 * types.
	 */
	protected final void addConsumedAnnotationType(Class annotationType) {
		addProcessedAnnotationType(annotationType);
		consumedAnnotationTypes.put(annotationType.getName(), annotationType);
	}

	/**
	 * Adds a processed annotation type (to be used in subclasses constructors).
	 */
	protected final void addProcessedAnnotationType(Class annotationType) {
		processedAnnotationTypes.put(annotationType.getName(), annotationType);
	}

	/**
	 * Removes a processed annotation type.
	 */
	protected final void removeProcessedAnnotationType(Class annotationType) {
		processedAnnotationTypes.remove(annotationType.getName());
	}

	/**
	 * Clears the processed annotation types.
	 */
	protected final void clearProcessedAnnotationTypes() {
		processedAnnotationTypes.clear();
	}

	/**
	 * Clears the consumed annotation types.
	 */
	protected final void clearConsumedAnnotationTypes() {
		consumedAnnotationTypes.clear();
	}

	/**
	 * Removes a processed annotation type.
	 */
	protected final void removeConsumedAnnotationType(Class annotationType) {
		consumedAnnotationTypes.remove(annotationType.getName());
	}

	@Override
	public final Set> getConsumedAnnotationTypes() {
		return new HashSet<>(consumedAnnotationTypes.values());
	}

	@Override
	public final Set> getProcessedAnnotationTypes() {
		return new HashSet<>(processedAnnotationTypes.values());
	}

	@Override
	public boolean inferConsumedAnnotationType() {
		return true;
	}

	/**
	 * Returns true if the element is annotated with an annotation whose type is
	 * processed.
	 */
	@Override
	public final boolean isToBeProcessed(E element) {
		if ((element != null) && (element.getAnnotations() != null)) {
			for (CtAnnotation a : element.getAnnotations()) {
				if (shouldBeProcessed(a)) {
					return true;
				}
			}
		}

		return false;
	}

	@Override
	@SuppressWarnings("unchecked")
	public final void process(E element) {
		for (CtAnnotation annotation : new ArrayList<>(element.getAnnotations())) {
			if (shouldBeProcessed(annotation)) {
				try {
					process((A) annotation.getActualAnnotation(), element);
				} catch (Exception e) {
					Launcher.LOGGER.error(e.getMessage(), e);
				}
				if (shouldBeConsumed(annotation)) {
					element.removeAnnotation(annotation);
				}
			}
		}
	}

	/**
	 * {@inheritDoc}
	 *
	 * Removes all annotations A on elements E.
	 *
	 * @deprecated use {@link #shouldBeConsumed(CtAnnotation)} instead
	 */
	@Deprecated
	@Override
	public boolean shoudBeConsumed(CtAnnotation annotation) {
		return consumedAnnotationTypes.containsKey(annotation.getAnnotationType().getQualifiedName());
	}

	@Override
	public boolean shouldBeConsumed(CtAnnotation annotation) {
		return consumedAnnotationTypes.containsKey(annotation.getAnnotationType().getQualifiedName());
	}

	private boolean shouldBeProcessed(CtAnnotation annotation) {
		return processedAnnotationTypes.containsKey(annotation.getAnnotationType().getQualifiedName());
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy