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 }
|