1 /* 2 * Copyright (c) 2005, 2006, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.annotation.processing; 27 28 import java.util.Set; 29 import java.util.HashSet; 30 import java.util.Collections; 31 import javax.lang.model.element.*; 32 import javax.lang.model.SourceVersion; 33 import javax.tools.Diagnostic; 34 35 /** 36 * An abstract annotation processor designed to be a convenient 37 * superclass for most concrete annotation processors. This class 38 * examines annotation values to compute the {@linkplain 39 * #getSupportedOptions options}, {@linkplain 40 * #getSupportedAnnotationTypes annotations}, and {@linkplain 41 * #getSupportedSourceVersion source version} supported by its 42 * subtypes. 43 * 44 * <p>The getter methods may {@linkplain Messager#printMessage issue 45 * warnings} about noteworthy conditions using the facilities available 46 * after the processor has been {@linkplain #isInitialized 47 * initialized}. 48 * 49 * <p>Subclasses are free to override the implementation and 50 * specification of any of the methods in this class as long as the 51 * general {@link javax.annotation.processing.Processor Processor} 52 * contract for that method is obeyed. 53 * 54 * @author Joseph D. Darcy 55 * @author Scott Seligman 56 * @author Peter von der Ahé 57 * @since 1.6 58 */ 59 public abstract class AbstractProcessor implements Processor { 60 /** 61 * Processing environment providing by the tool framework. 62 */ 63 protected ProcessingEnvironment processingEnv; 64 private boolean initialized = false; 65 66 /** 67 * Constructor for subclasses to call. 68 */ 69 protected AbstractProcessor() {} 70 71 /** 72 * If the processor class is annotated with {@link 73 * SupportedOptions}, return an unmodifiable set with the same set 74 * of strings as the annotation. If the class is not so 75 * annotated, an empty set is returned. 76 * 77 * @return the options recognized by this processor, or an empty 78 * set if none 79 */ 80 public Set<String> getSupportedOptions() { 81 SupportedOptions so = this.getClass().getAnnotation(SupportedOptions.class); 82 if (so == null) 83 return Collections.emptySet(); 84 else 85 return arrayToSet(so.value()); 86 } 87 88 /** 89 * If the processor class is annotated with {@link 90 * SupportedAnnotationTypes}, return an unmodifiable set with the 91 * same set of strings as the annotation. If the class is not so 92 * annotated, an empty set is returned. 93 * 94 * @return the names of the annotation types supported by this 95 * processor, or an empty set if none 96 */ 97 public Set<String> getSupportedAnnotationTypes() { 98 SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class); 99 if (sat == null) { 100 if (isInitialized()) 101 processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, 102 "No SupportedAnnotationTypes annotation " + 103 "found on " + this.getClass().getName() + 104 ", returning an empty set."); 105 return Collections.emptySet(); 106 } 107 else 108 return arrayToSet(sat.value()); 109 } 110 111 /** 112 * If the processor class is annotated with {@link 113 * SupportedSourceVersion}, return the source version in the 114 * annotation. If the class is not so annotated, {@link 115 * SourceVersion#RELEASE_6} is returned. 116 * 117 * @return the latest source version supported by this processor 118 */ 119 public SourceVersion getSupportedSourceVersion() { 120 SupportedSourceVersion ssv = this.getClass().getAnnotation(SupportedSourceVersion.class); 121 SourceVersion sv = null; 122 if (ssv == null) { 123 sv = SourceVersion.RELEASE_6; 124 if (isInitialized()) 125 processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, 126 "No SupportedSourceVersion annotation " + 127 "found on " + this.getClass().getName() + 128 ", returning " + sv + "."); 129 } else 130 sv = ssv.value(); 131 return sv; 132 } 133 134 135 /** 136 * Initializes the processor with the processing environment by 137 * setting the {@code processingEnv} field to the value of the 138 * {@code processingEnv} argument. An {@code 139 * IllegalStateException} will be thrown if this method is called 140 * more than once on the same object. 141 * 142 * @param processingEnv environment to access facilities the tool framework 143 * provides to the processor 144 * @throws IllegalStateException if this method is called more than once. 145 */ 146 public synchronized void init(ProcessingEnvironment processingEnv) { 147 if (initialized) 148 throw new IllegalStateException("Cannot call init more than once."); 149 if (processingEnv == null) 150 throw new NullPointerException("Tool provided null ProcessingEnvironment"); 151 152 this.processingEnv = processingEnv; 153 initialized = true; 154 } 155 156 /** 157 * {@inheritDoc} 158 */ 159 public abstract boolean process(Set<? extends TypeElement> annotations, 160 RoundEnvironment roundEnv); 161 162 /** 163 * Returns an empty iterable of completions. 164 * 165 * @param element {@inheritDoc} 166 * @param annotation {@inheritDoc} 167 * @param member {@inheritDoc} 168 * @param userText {@inheritDoc} 169 */ 170 public Iterable<? extends Completion> getCompletions(Element element, 171 AnnotationMirror annotation, 172 ExecutableElement member, 173 String userText) { 174 return Collections.emptyList(); 175 } 176 177 /** 178 * Returns {@code true} if this object has been {@linkplain #init 179 * initialized}, {@code false} otherwise. 180 * 181 * @return {@code true} if this object has been initialized, 182 * {@code false} otherwise. 183 */ 184 protected synchronized boolean isInitialized() { 185 return initialized; 186 } 187 188 private static Set<String> arrayToSet(String[] array) { 189 assert array != null; 190 Set<String> set = new HashSet<String>(array.length); 191 for (String s : array) 192 set.add(s); 193 return Collections.unmodifiableSet(set); 194 } 195 }