001: /*
002: * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package javax.annotation.processing;
027:
028: import java.util.Set;
029: import java.util.HashSet;
030: import java.util.Collections;
031: import javax.lang.model.element.*;
032: import javax.lang.model.SourceVersion;
033: import javax.tools.Diagnostic;
034:
035: /**
036: * An abstract annotation processor designed to be a convenient
037: * superclass for most concrete annotation processors. This class
038: * examines annotation values to compute the {@linkplain
039: * #getSupportedOptions options}, {@linkplain
040: * #getSupportedAnnotationTypes annotations}, and {@linkplain
041: * #getSupportedSourceVersion source version} supported by its
042: * subtypes.
043: *
044: * <p>The getter methods may {@linkplain Messager#printMessage issue
045: * warnings} about noteworthy conditions using the facilities available
046: * after the processor has been {@linkplain #isInitialized
047: * initialized}.
048: *
049: * <p>Subclasses are free to override the implementation and
050: * specification of any of the methods in this class as long as the
051: * general {@link javax.annotation.processing.Processor Processor}
052: * contract for that method is obeyed.
053: *
054: * @author Joseph D. Darcy
055: * @author Scott Seligman
056: * @author Peter von der Ahé
057: * @version 1.14 07/05/05
058: * @since 1.6
059: */
060: public abstract class AbstractProcessor implements Processor {
061: /**
062: * Processing environment providing by the tool framework.
063: */
064: protected ProcessingEnvironment processingEnv;
065: private boolean initialized = false;
066:
067: /**
068: * Constructor for subclasses to call.
069: */
070: protected AbstractProcessor() {
071: }
072:
073: /**
074: * If the processor class is annotated with {@link
075: * SupportedOptions}, return an unmodifiable set with the same set
076: * of strings as the annotation. If the class is not so
077: * annotated, an empty set is returned.
078: *
079: * @return the options recognized by this processor, or an empty
080: * set if none
081: */
082: public Set<String> getSupportedOptions() {
083: SupportedOptions so = this .getClass().getAnnotation(
084: SupportedOptions.class);
085: if (so == null)
086: return Collections.emptySet();
087: else
088: return arrayToSet(so.value());
089: }
090:
091: /**
092: * If the processor class is annotated with {@link
093: * SupportedAnnotationTypes}, return an unmodifiable set with the
094: * same set of strings as the annotation. If the class is not so
095: * annotated, an empty set is returned.
096: *
097: * @return the names of the annotation types supported by this
098: * processor, or an empty set if none
099: */
100: public Set<String> getSupportedAnnotationTypes() {
101: SupportedAnnotationTypes sat = this .getClass().getAnnotation(
102: SupportedAnnotationTypes.class);
103: if (sat == null) {
104: if (isInitialized())
105: processingEnv.getMessager().printMessage(
106: Diagnostic.Kind.WARNING,
107: "No SupportedAnnotationTypes annotation "
108: + "found on "
109: + this .getClass().getName()
110: + ", returning an empty set.");
111: return Collections.emptySet();
112: } else
113: return arrayToSet(sat.value());
114: }
115:
116: /**
117: * If the processor class is annotated with {@link
118: * SupportedSourceVersion}, return the source version in the
119: * annotation. If the class is not so annotated, {@link
120: * SourceVersion#RELEASE_6} is returned.
121: *
122: * @return the latest source version supported by this processor
123: */
124: public SourceVersion getSupportedSourceVersion() {
125: SupportedSourceVersion ssv = this .getClass().getAnnotation(
126: SupportedSourceVersion.class);
127: SourceVersion sv = null;
128: if (ssv == null) {
129: sv = SourceVersion.RELEASE_6;
130: if (isInitialized())
131: processingEnv.getMessager().printMessage(
132: Diagnostic.Kind.WARNING,
133: "No SupportedSourceVersion annotation "
134: + "found on "
135: + this .getClass().getName()
136: + ", returning " + sv + ".");
137: } else
138: sv = ssv.value();
139: return sv;
140: }
141:
142: /**
143: * Initializes the processor with the processing environment by
144: * setting the {@code processingEnv} field to the value of the
145: * {@code processingEnv} argument. An {@code
146: * IllegalStateException} will be thrown if this method is called
147: * more than once on the same object.
148: *
149: * @param processingEnv environment to access facilities the tool framework
150: * provides to the processor
151: * @throws IllegalStateException if this method is called more than once.
152: */
153: public synchronized void init(ProcessingEnvironment processingEnv) {
154: if (initialized)
155: throw new IllegalStateException(
156: "Cannot call init more than once.");
157: if (processingEnv == null)
158: throw new NullPointerException(
159: "Tool provided null ProcessingEnvironment");
160:
161: this .processingEnv = processingEnv;
162: initialized = true;
163: }
164:
165: /**
166: * {@inheritDoc}
167: */
168: public abstract boolean process(
169: Set<? extends TypeElement> annotations,
170: RoundEnvironment roundEnv);
171:
172: /**
173: * Returns an empty iterable of completions.
174: *
175: * @param element {@inheritDoc}
176: * @param annotation {@inheritDoc}
177: * @param member {@inheritDoc}
178: * @param userText {@inheritDoc}
179: */
180: public Iterable<? extends Completion> getCompletions(
181: Element element, AnnotationMirror annotation,
182: ExecutableElement member, String userText) {
183: return Collections.emptyList();
184: }
185:
186: /**
187: * Returns {@code true} if this object has been {@linkplain #init
188: * initialized}, {@code false} otherwise.
189: *
190: * @return {@code true} if this object has been initialized,
191: * {@code false} otherwise.
192: */
193: protected synchronized boolean isInitialized() {
194: return initialized;
195: }
196:
197: private static Set<String> arrayToSet(String[] array) {
198: assert array != null;
199: Set<String> set = new HashSet<String>(array.length);
200: for (String s : array)
201: set.add(s);
202: return Collections.unmodifiableSet(set);
203: }
204: }
|