1 /* 2 * Copyright (c) 2005, 2013, 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 java.util.Objects; 32 import javax.lang.model.element.*; 33 import javax.lang.model.SourceVersion; 34 import javax.tools.Diagnostic; 35 36 /** 37 * An abstract annotation processor designed to be a convenient 38 * superclass for most concrete annotation processors. This class 39 * examines annotation values to compute the {@linkplain 40 * #getSupportedOptions options}, {@linkplain 41 * #getSupportedAnnotationTypes annotations}, and {@linkplain 42 * #getSupportedSourceVersion source version} supported by its 43 * subtypes. 44 * 45 * <p>The getter methods may {@linkplain Messager#printMessage issue 46 * warnings} about noteworthy conditions using the facilities available 47 * after the processor has been {@linkplain #isInitialized 48 * initialized}. 49 * 50 * <p>Subclasses are free to override the implementation and 51 * specification of any of the methods in this class as long as the 52 * general {@link javax.annotation.processing.Processor Processor} 53 * contract for that method is obeyed. 54 * 55 * @author Joseph D. Darcy 56 * @author Scott Seligman 57 * @author Peter von der Ahé 58 * @since 1.6 59 */ 60 public abstract class AbstractProcessor implements Processor { 61 /** 62 * Processing environment providing by the tool framework. 63 */ 64 protected ProcessingEnvironment processingEnv; 65 private boolean initialized = false; 66 67 /** 68 * Constructor for subclasses to call. 69 */ 70 protected AbstractProcessor() {} 71 72 /** 73 * If the processor class is annotated with {@link 74 * SupportedOptions}, return an unmodifiable set with the same set 75 * of strings as the annotation. If the class is not so 76 * annotated, an empty set is returned. 77 * 78 * @return the options recognized by this processor, or an empty 79 * set if none 80 */ 81 public Set<String> getSupportedOptions() { 82 SupportedOptions so = this.getClass().getAnnotation(SupportedOptions.class); 83 if (so == null) 84 return Collections.emptySet(); 85 else 86 return arrayToSet(so.value()); 87 } 88 89 /** 90 * If the processor class is annotated with {@link 91 * SupportedAnnotationTypes}, return an unmodifiable set with the 92 * same set of strings as the annotation. If the class is not so 93 * annotated, an empty set is returned. 94 * 95 * @return the names of the annotation types supported by this 96 * processor, or an empty set if none 97 */ 98 public Set<String> getSupportedAnnotationTypes() { 99 SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class); 100 if (sat == null) { 101 if (isInitialized()) 102 processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, 103 "No SupportedAnnotationTypes annotation " + 104 "found on " + this.getClass().getName() + 105 ", returning an empty set."); 106 return Collections.emptySet(); 107 } 108 else 109 return arrayToSet(sat.value()); 110 } 111 112 /** 113 * If the processor class is annotated with {@link 114 * SupportedSourceVersion}, return the source version in the 115 * annotation. If the class is not so annotated, {@link 116 * SourceVersion#RELEASE_6} is returned. 117 * 118 * @return the latest source version supported by this processor 119 */ 120 public SourceVersion getSupportedSourceVersion() { 121 SupportedSourceVersion ssv = this.getClass().getAnnotation(SupportedSourceVersion.class); 122 SourceVersion sv = null; 123 if (ssv == null) { 124 sv = SourceVersion.RELEASE_6; 125 if (isInitialized()) 126 processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, 127 "No SupportedSourceVersion annotation " + 128 "found on " + this.getClass().getName() + 129 ", returning " + sv + "."); 130 } else 131 sv = ssv.value(); 132 return sv; 133 } 134 135 136 /** 137 * Initializes the processor with the processing environment by 138 * setting the {@code processingEnv} field to the value of the 139 * {@code processingEnv} argument. An {@code 140 * IllegalStateException} will be thrown if this method is called 141 * more than once on the same object. 142 * 143 * @param processingEnv environment to access facilities the tool framework 144 * provides to the processor 145 * @throws IllegalStateException if this method is called more than once. 146 */ 147 public synchronized void init(ProcessingEnvironment processingEnv) { 148 if (initialized) 149 throw new IllegalStateException("Cannot call init more than once."); 150 Objects.requireNonNull(processingEnv, "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 }