| /******************************************************************************* |
| * Copyright (c) 2007, 2011 BEA Systems, Inc. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * wharley@bea.com - initial API and implementation |
| * |
| *******************************************************************************/ |
| |
| package org.eclipse.jdt.internal.compiler.apt.dispatch; |
| |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager; |
| import org.eclipse.jdt.internal.compiler.Compiler; |
| import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; |
| import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; |
| import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; |
| |
| /** |
| * This class is the central dispatch point for Java 6 annotation processing. |
| * This is created and configured by the JDT core; specifics depend on how |
| * compilation is being performed, ie from the command line, via the Tool |
| * interface, or within the IDE. This class manages the discovery of annotation |
| * processors and other information spanning multiple rounds of processing; |
| * context that is valid only within a single round is managed by |
| * {@link RoundDispatcher}. There may be multiple instances of this class; |
| * there is in general one of these for every Compiler that has annotation |
| * processing enabled. Within the IDE there will typically be one for every |
| * Java project, because each project potentially has a separate processor path. |
| * |
| * TODO: do something useful with _supportedOptions and _supportedAnnotationTypes. |
| */ |
| public abstract class BaseAnnotationProcessorManager extends AbstractAnnotationProcessorManager |
| implements IProcessorProvider |
| { |
| |
| protected PrintWriter _out; |
| protected PrintWriter _err; |
| protected BaseProcessingEnvImpl _processingEnv; |
| protected boolean _isFirstRound = true; |
| |
| /** |
| * The list of processors that have been loaded so far. A processor on this |
| * list has been initialized, but may not yet have been called to process(). |
| */ |
| protected List<ProcessorInfo> _processors = new ArrayList<ProcessorInfo>(); |
| |
| // Tracing |
| protected boolean _printProcessorInfo = false; |
| protected boolean _printRounds = false; |
| protected int _round; |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#configure(org.eclipse.jdt.internal.compiler.batch.Main, java.lang.String[]) |
| */ |
| @Override |
| public void configure(Object batchCompiler, String[] options) { |
| // Implemented by BatchAnnotationProcessorManager. |
| throw new UnsupportedOperationException(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#configureFromPlatform(org.eclipse.jdt.internal.compiler.Compiler, java.lang.Object) |
| */ |
| @Override |
| public void configureFromPlatform(Compiler compiler, Object compilationUnitLocator, Object javaProject) { |
| // Implemented by IdeAnnotationProcessorManager. |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public List<ProcessorInfo> getDiscoveredProcessors() { |
| return _processors; |
| } |
| |
| @Override |
| public ICompilationUnit[] getDeletedUnits() { |
| return _processingEnv.getDeletedUnits(); |
| } |
| |
| @Override |
| public ICompilationUnit[] getNewUnits() { |
| return _processingEnv.getNewUnits(); |
| } |
| |
| @Override |
| public ReferenceBinding[] getNewClassFiles() { |
| return _processingEnv.getNewClassFiles(); |
| } |
| |
| @Override |
| public void reset() { |
| _processingEnv.reset(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setErr(java.io.PrintWriter) |
| */ |
| @Override |
| public void setErr(PrintWriter err) { |
| _err = err; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setOut(java.io.PrintWriter) |
| */ |
| @Override |
| public void setOut(PrintWriter out) { |
| _out = out; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setProcessors(java.lang.Object[]) |
| */ |
| @Override |
| public void setProcessors(Object[] processors) { |
| // Only meaningful in batch mode. |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * A single "round" of processing, in the sense implied in |
| * {@link javax.annotation.processing.Processor}. |
| * <p> |
| * The Java 6 Processor spec contains ambiguities about how processors that support "*" are |
| * handled. Eclipse tries to match Sun's implementation in javac. What that actually does is |
| * analogous to inspecting the set of annotions found in the root units and adding an |
| * "imaginary" annotation if the set is empty. Processors are then called in order of discovery; |
| * for each processor, the intersection between the set of root annotations and the set of |
| * annotations the processor supports is calculated, and if it is non-empty, the processor is |
| * called. If the processor returns <code>true</code> then the intersection (including the |
| * imaginary annotation if one exists) is removed from the set of root annotations and the loop |
| * continues, until the set is empty. Of course, the imaginary annotation is not actually |
| * included in the set of annotations passed in to the processor. A processor's process() method |
| * is not called until its intersection set is non-empty, but thereafter it is called on every |
| * round. Note that even if a processor is not called in the first round, if it is called in |
| * subsequent rounds, it will be called in the order in which the processors were discovered, |
| * rather than being added to the end of the list. |
| */ |
| @Override |
| public void processAnnotations(CompilationUnitDeclaration[] units, ReferenceBinding[] referenceBindings, boolean isLastRound) { |
| RoundEnvImpl roundEnv = new RoundEnvImpl(units, referenceBindings, isLastRound, _processingEnv); |
| if (_isFirstRound) { |
| _isFirstRound = false; |
| } |
| |
| PrintWriter traceProcessorInfo = _printProcessorInfo ? _out : null; |
| PrintWriter traceRounds = _printRounds ? _out : null; |
| if (traceRounds != null) { |
| traceRounds.println("Round " + ++_round + ':'); //$NON-NLS-1$ |
| } |
| RoundDispatcher dispatcher = new RoundDispatcher( |
| this, roundEnv, roundEnv.getRootAnnotations(), traceProcessorInfo, traceRounds); |
| dispatcher.round(); |
| } |
| |
| } |