src/share/classes/com/sun/source/util/AbstractTypeProcessor.java

changeset 309
664edca41e34
child 554
9d9f26857129
equal deleted inserted replaced
308:03944ee4fac4 309:664edca41e34
1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package com.sun.source.util;
27
28 import java.util.ArrayList;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Set;
32
33 import javax.annotation.processing.*;
34 import javax.lang.model.element.Name;
35 import javax.lang.model.element.TypeElement;
36 import javax.lang.model.util.ElementFilter;
37
38 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
39 import com.sun.tools.javac.util.Context;
40 import com.sun.tools.javac.util.Log;
41
42 import com.sun.source.tree.ClassTree;
43
44 /**
45 * This class is an abstract annotation processor designed to be a
46 * convenient superclass for concrete "type processors", processors that
47 * require the type information in the processed source.
48 *
49 * <p>Type processing occurs in one round after the tool (e.g. java compiler)
50 * analyzes the source (all sources taken as input to the tool and sources
51 * generated by other annotation processors).
52 *
53 * <p>The tool infrastructure will interact with classes extending this abstract
54 * class as follows:
55 *
56 * <ol>
57 * [1-3: Identical to {@link Processor} life cycle]
58 *
59 * <li>If an existing {@code Processor} object is not being used, to
60 * create an instance of a processor the tool calls the no-arg
61 * constructor of the processor class.
62 *
63 * <li>Next, the tool calls the {@link #init init} method with
64 * an appropriate {@code ProcessingEnvironment}.
65 *
66 * <li>Afterwards, the tool calls {@link #getSupportedAnnotationTypes
67 * getSupportedAnnotationTypes}, {@link #getSupportedOptions
68 * getSupportedOptions}, and {@link #getSupportedSourceVersion
69 * getSupportedSourceVersion}. These methods are only called once per
70 * run, not on each round.
71 *
72 * [4-5Unique to {@code AbstractTypeProcessor} subclasses]
73 *
74 * <li>For each class containing a supported annotation, the tool calls
75 * {@link #typeProcess(TypeElement, TreePath) typeProcess} method on the
76 * {@code Processor}. The class is guaranteed to be type-checked Java code
77 * and all the tree type and symbol information is resolved.
78 *
79 * <li>Finally, the tools calls the
80 * {@link #typeProcessingOver() typeProcessingOver} method
81 * on the {@code Processor}.
82 *
83 * </ol>
84 *
85 * <p>The tool is permitted to ask type processors to process a class once
86 * it is analyzed before the rest of classes are analyzed. The tool is also
87 * permitted to stop type processing immediately if any errors are raised,
88 * without invoking {@code typeProcessingOver}
89 *
90 * <p>A subclass may override any of the methods in this class, as long as the
91 * general {@link javax.annotation.processing.Processor Processor}
92 * contract is obeyed, with one notable exception.
93 * {@link #process(Set, RoundEnvironment)} may not be overridden, as it
94 * is called during the regular annotation phase before classes are analyzed.
95 *
96 * @author Mahmood Ali
97 * @since 1.7
98 */
99 public abstract class AbstractTypeProcessor extends AbstractProcessor {
100 private final Set<Name> elements = new HashSet<Name>();
101 private boolean hasInvokedTypeProcessingOver = false;
102 private JavacProcessingEnvironment env;
103 private final AttributionTaskListener listener = new AttributionTaskListener();
104
105 /**
106 * Constructor for subclasses to call.
107 */
108 protected AbstractTypeProcessor() { }
109
110 /**
111 * {@inheritDoc}
112 */
113 @Override
114 public void init(ProcessingEnvironment env) {
115 super.init(env);
116 this.env = (JavacProcessingEnvironment)env;
117 prepareContext(this.env.getContext());
118 }
119
120 /**
121 * The use of this method is obsolete in type processors. The method is
122 * called during regular annotation processing phase only.
123 */
124 @Override
125 public final boolean process(Set<? extends TypeElement> annotations,
126 RoundEnvironment roundEnv) {
127 for (TypeElement elem : ElementFilter.typesIn(roundEnv.getRootElements())) {
128 elements.add(elem.getQualifiedName());
129 }
130 return false;
131 }
132
133 /**
134 * Processes a fully analyzed class that contains a supported annotation
135 * (look {@link #getSupportedAnnotationTypes()}).
136 *
137 * <p>The passed class is always a valid type-checked Java code.
138 *
139 * @param element element of the analyzed class
140 * @param tree the tree path to the element, with the leaf being a
141 * {@link ClassTree}
142 */
143 public abstract void typeProcess(TypeElement element, TreePath tree);
144
145 /**
146 * A method to be called once all the classes are processed and no error
147 * is reported.
148 *
149 * <p>Subclasses may override this method to do any aggregate analysis
150 * (e.g. generate report, persistence) or resource deallocation.
151 *
152 * <p>If an error (a Java error or a processor error) is reported, this
153 * method is not guaranteed to be invoked.
154 */
155 public void typeProcessingOver() { }
156
157 /**
158 * adds a listener for attribution.
159 */
160 private void prepareContext(Context context) {
161 TaskListener otherListener = context.get(TaskListener.class);
162 if (otherListener == null) {
163 context.put(TaskListener.class, listener);
164 } else {
165 // handle cases of multiple listeners
166 context.put(TaskListener.class, (TaskListener)null);
167 TaskListeners listeners = new TaskListeners();
168 listeners.add(otherListener);
169 listeners.add(listener);
170 context.put(TaskListener.class, listeners);
171 }
172 }
173
174 /**
175 * A task listener that invokes the processor whenever a class is fully
176 * analyzed.
177 */
178 private final class AttributionTaskListener implements TaskListener {
179
180 @Override
181 public void finished(TaskEvent e) {
182 Log log = Log.instance(env.getContext());
183
184 if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
185 typeProcessingOver();
186 hasInvokedTypeProcessingOver = true;
187 }
188
189 if (e.getKind() != TaskEvent.Kind.ANALYZE)
190 return;
191
192 if (e.getTypeElement() == null)
193 throw new AssertionError("event task without a type element");
194 if (e.getCompilationUnit() == null)
195 throw new AssertionError("even task without compilation unit");
196
197 if (!elements.remove(e.getTypeElement().getQualifiedName()))
198 return;
199
200 if (log.nerrors != 0)
201 return;
202
203 TypeElement elem = e.getTypeElement();
204 TreePath p = Trees.instance(env).getPath(elem);
205
206 typeProcess(elem, p);
207
208 if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) {
209 typeProcessingOver();
210 hasInvokedTypeProcessingOver = true;
211 }
212 }
213
214 @Override
215 public void started(TaskEvent e) { }
216
217 }
218
219 /**
220 * A task listener multiplexer.
221 */
222 private static class TaskListeners implements TaskListener {
223 private final List<TaskListener> listeners = new ArrayList<TaskListener>();
224
225 public void add(TaskListener listener) {
226 listeners.add(listener);
227 }
228
229 public void remove(TaskListener listener) {
230 listeners.remove(listener);
231 }
232
233 @Override
234 public void finished(TaskEvent e) {
235 for (TaskListener listener : listeners)
236 listener.finished(e);
237 }
238
239 @Override
240 public void started(TaskEvent e) {
241 for (TaskListener listener : listeners)
242 listener.started(e);
243 }
244 }
245 }

mercurial