/*
* @(#)AbstractProcessor.java 1.8 06/07/17
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package javax.annotation.processing;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;
import javax.lang.model.element.*;
import javax.lang.model.SourceVersion;
import javax.tools.Diagnostic;
/**
* An abstract annotation processor designed to be a convenient
* superclass for most concrete annotation processors. This class
* examines annotation values to compute the {@linkplain
* #getSupportedOptions options}, {@linkplain
* #getSupportedAnnotationTypes annotations}, and {@linkplain
* #getSupportedSourceVersion source version} supported by its
* subtypes.
*
* <p>The getter methods may {@linkplain Messager#printMessage issue
* warnings} about noteworthy conditions using the facilities available
* after the processor has been {@linkplain #isInitialized
* initialized}.
*
* <p>Subclasses are free to override the implementation and
* specification of any of the methods in this class as long as the
* general {@link javax.annotation.processing.Processor Processor}
* contract for that method is obeyed.
*
* @author Joseph D. Darcy
* @author Scott Seligman
* @author Peter von der Ahé
* @version 1.8 06/07/17
* @since 1.6
*/
public abstract class AbstractProcessor implements Processor {
/**
* Processing environment providing by the tool framework.
*/
protected ProcessingEnvironment processingEnv;
private boolean initialized = false;
/**
* Constructor for subclasses to call.
*/
protected AbstractProcessor() {}
/**
* If the processor class is annotated with {@link
* SupportedOptions}, return an unmodifiable set with the same set
* of strings as the annotation. If the class is not so
* annotated, an empty set is returned.
*
* @return the options recognized by this processor, or an empty
* set if none
*/
public Set<String> getSupportedOptions() {
SupportedOptions so = this.getClass().getAnnotation(SupportedOptions.class);
if (so == null)
return Collections.emptySet();
else
return arrayToSet(so.value());
}
/**
* If the processor class is annotated with {@link
* SupportedAnnotationTypes}, return an unmodifiable set with the
* same set of strings as the annotation. If the class is not so
* annotated, an empty set is returned.
*
* @return the names of the annotation types supported by this
* processor, or an empty set if none
*/
public Set<String> getSupportedAnnotationTypes() {
SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class);
if (sat == null) {
if (isInitialized())
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
"No SupportedAnnotationTypes annotation " +
"found on " + this.getClass().getName() +
", returning an empty set.");
return Collections.emptySet();
}
else
return arrayToSet(sat.value());
}
/**
* If the processor class is annotated with {@link
* SupportedSourceVersion}, return the source version in the
* annotation. If the class is not so annotated, {@link
* SourceVersion#RELEASE_6} is returned.
*
* @return the latest source version supported by this processor
*/
public SourceVersion getSupportedSourceVersion() {
SupportedSourceVersion ssv = this.getClass().getAnnotation(SupportedSourceVersion.class);
SourceVersion sv = null;
if (ssv == null) {
sv = SourceVersion.RELEASE_6;
if (isInitialized())
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
"No SupportedSourceVersion annotation " +
"found on " + this.getClass().getName() +
", returning " + sv + ".");
} else
sv = ssv.value();
return sv;
}
/**
* Initializes the processor with the processing environment by
* setting the {@code processingEnv} field to the value of the
* {@code processingEnv} argument. An {@code
* IllegalStateException} will be thrown if this method is called
* more than once on the same object.
*
* @param processingEnv environment to access facilities the tool framework
* provides to the processor
* @throws IllegalStateException if this method is called more than once.
*/
public synchronized void init(ProcessingEnvironment processingEnv) {
if (initialized)
throw new IllegalStateException("Cannot call init more than once.");
if (processingEnv == null)
throw new NullPointerException("Tool provided null ProcessingEnvironment");
this.processingEnv = processingEnv;
initialized = true;
}
/**
* {@inheritDoc}
*/
public abstract boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv);
/**
* Returns an empty iterable of completions.
*
* @param element {@inheritDoc}
* @param annotation {@inheritDoc}
* @param member {@inheritDoc}
* @param userText {@inheritDoc}
*/
public Iterable<? extends Completion> getCompletions(Element element,
AnnotationMirror annotation,
ExecutableElement member,
String userText) {
return Collections.emptyList();
}
/**
* Returns {@code true} if this object has been {@linkplain #init
* initialized}, {@code false} otherwise.
*
* @return {@code true} if this object has been initialized,
* {@code false} otherwise.
*/
protected synchronized boolean isInitialized() {
return initialized;
}
private static Set<String> arrayToSet(String[] array) {
assert array != null;
Set<String> set = new HashSet<String>(array.length);
for (String s : array)
set.add(s);
return Collections.unmodifiableSet(set);
}
}