001package ball.annotation.processing; 002/*- 003 * ########################################################################## 004 * Utilities 005 * $Id: AbstractProcessor.java 7479 2021-02-14 02:19:05Z ball $ 006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-util/trunk/src/main/java/ball/annotation/processing/AbstractProcessor.java $ 007 * %% 008 * Copyright (C) 2008 - 2021 Allen D. Ball 009 * %% 010 * Licensed under the Apache License, Version 2.0 (the "License"); 011 * you may not use this file except in compliance with the License. 012 * You may obtain a copy of the License at 013 * 014 * http://www.apache.org/licenses/LICENSE-2.0 015 * 016 * Unless required by applicable law or agreed to in writing, software 017 * distributed under the License is distributed on an "AS IS" BASIS, 018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 019 * See the License for the specific language governing permissions and 020 * limitations under the License. 021 * ########################################################################## 022 */ 023import ball.activation.ThrowableDataSource; 024import ball.lang.reflect.JavaLangReflectMethods; 025import ball.tools.javac.AbstractTaskListener; 026import com.sun.source.util.JavacTask; 027import com.sun.source.util.TaskEvent; 028import java.util.Collections; 029import java.util.LinkedHashSet; 030import java.util.Set; 031import java.util.function.Consumer; 032import java.util.function.Predicate; 033import javax.annotation.processing.Completion; 034import javax.annotation.processing.Filer; 035import javax.annotation.processing.ProcessingEnvironment; 036import javax.annotation.processing.Processor; 037import javax.annotation.processing.RoundEnvironment; 038import javax.annotation.processing.SupportedOptions; 039import javax.lang.model.SourceVersion; 040import javax.lang.model.element.AnnotationMirror; 041import javax.lang.model.element.AnnotationValue; 042import javax.lang.model.element.Element; 043import javax.lang.model.element.ExecutableElement; 044import javax.lang.model.element.TypeElement; 045import javax.tools.Diagnostic; 046import lombok.NoArgsConstructor; 047import lombok.Synchronized; 048import lombok.ToString; 049 050import static javax.tools.Diagnostic.Kind.ERROR; 051import static lombok.AccessLevel.PROTECTED; 052 053/** 054 * Provides abstract base class for {@link Processor} by providing a 055 * {@link #getSupportedSourceVersion()} implementation, methods to report 056 * {@link javax.tools.Diagnostic.Kind#ERROR}s and 057 * {@link javax.tools.Diagnostic.Kind#WARNING}s, and access to 058 * {@link ProcessingEnvironment#getFiler()}, 059 * {@link ProcessingEnvironment#getElementUtils()}, and 060 * {@link ProcessingEnvironment#getTypeUtils()}. 061 * 062 * {@bean.info} 063 * 064 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 065 * @version $Revision: 7479 $ 066 */ 067@NoArgsConstructor(access = PROTECTED) @ToString 068public abstract class AbstractProcessor extends JavaxLangModelUtilities 069 implements Processor, 070 JavaLangReflectMethods { 071 private final Set<String> options = new LinkedHashSet<>(); 072 private ProcessingEnvironment processingEnv = null; 073 /** See {@link JavacTask#instance(ProcessingEnvironment)}. */ 074 protected JavacTask javac = null; 075 /** See {@link ProcessingEnvironment#getFiler()}. */ 076 protected Filer filer = null; 077 078 { 079 SupportedOptions annotation = 080 getClass().getAnnotation(SupportedOptions.class); 081 082 if (annotation != null) { 083 Collections.addAll(options, annotation.value()); 084 } 085 } 086 087 @Override 088 public Set<String> getSupportedOptions() { return options; } 089 090 @Override 091 public abstract Set<String> getSupportedAnnotationTypes(); 092 093 @Override 094 public SourceVersion getSupportedSourceVersion() { 095 SourceVersion[] values = SourceVersion.values(); 096 097 return values[values.length - 1]; 098 } 099 100 @Synchronized 101 @Override 102 public void init(ProcessingEnvironment processingEnv) { 103 this.processingEnv = processingEnv; 104 105 try { 106 filer = processingEnv.getFiler(); 107 elements = processingEnv.getElementUtils(); 108 types = processingEnv.getTypeUtils(); 109 110 javac = JavacTask.instance(processingEnv); 111 112 if (javac != null) { 113 javac.addTaskListener(new WhenAnnotationProcessingFinished()); 114 } 115 116 if (fm == null) { 117 fm = Shims.getJavaFileManager(processingEnv); 118 } 119 } catch (Exception exception) { 120 print(ERROR, exception); 121 } 122 } 123 124 @Override 125 public abstract boolean process(Set<? extends TypeElement> annotations, 126 RoundEnvironment roundEnv); 127 128 @Override 129 public Iterable<? extends Completion> getCompletions(Element element, 130 AnnotationMirror annotation, 131 ExecutableElement member, 132 String text) { 133 return Collections.emptyList(); 134 } 135 136 /** 137 * Callback method to signal 138 * {@link com.sun.source.util.TaskEvent.Kind#ANNOTATION_PROCESSING} is 139 * finished. 140 */ 141 protected void whenAnnotationProcessingFinished() { } 142 143 /** 144 * Method to print a diagnostic message. 145 * 146 * @param kind The {@link javax.tools.Diagnostic.Kind}. 147 * @param format The message format {@link String}. 148 * @param argv Optional arguments to the message format 149 * {@link String}. 150 * 151 * @see javax.annotation.processing.Messager#printMessage(Diagnostic.Kind,CharSequence) 152 */ 153 protected void print(Diagnostic.Kind kind, String format, Object... argv) { 154 processingEnv.getMessager() 155 .printMessage(kind, String.format(format, argv)); 156 } 157 158 /** 159 * Method to print a diagnostic message. 160 * 161 * @param kind The {@link javax.tools.Diagnostic.Kind}. 162 * @param element The offending {@link Element}. 163 * @param format The message format {@link String}. 164 * @param argv Optional arguments to the message format 165 * {@link String}. 166 * 167 * @see javax.annotation.processing.Messager#printMessage(Diagnostic.Kind,CharSequence,Element) 168 */ 169 protected void print(Diagnostic.Kind kind, Element element, 170 String format, Object... argv) { 171 processingEnv.getMessager() 172 .printMessage(kind, String.format(format, argv), 173 element); 174 } 175 176 /** 177 * Method to print a diagnostic message. 178 * 179 * @param kind The {@link javax.tools.Diagnostic.Kind}. 180 * @param element The offending {@link Element}. 181 * @param annotation The offending {@link AnnotationMirror}. 182 * @param format The message format {@link String}. 183 * @param argv Optional arguments to the message format 184 * {@link String}. 185 * 186 * @see javax.annotation.processing.Messager#printMessage(Diagnostic.Kind,CharSequence,Element,AnnotationMirror) 187 */ 188 protected void print(Diagnostic.Kind kind, 189 Element element, AnnotationMirror annotation, 190 String format, Object... argv) { 191 processingEnv.getMessager() 192 .printMessage(kind, String.format(format, argv), 193 element, annotation); 194 } 195 196 /** 197 * Method to print a diagnostic message. 198 * 199 * @param kind The {@link javax.tools.Diagnostic.Kind}. 200 * @param element The offending {@link Element}. 201 * @param annotation The offending {@link AnnotationMirror}. 202 * @param value The offending {@link AnnotationValue}. 203 * @param format The message format {@link String}. 204 * @param argv Optional arguments to the message format 205 * {@link String}. 206 * 207 * @see javax.annotation.processing.Messager#printMessage(Diagnostic.Kind,CharSequence,Element,AnnotationMirror,AnnotationValue) 208 */ 209 protected void print(Diagnostic.Kind kind, 210 Element element, 211 AnnotationMirror annotation, AnnotationValue value, 212 String format, Object... argv) { 213 processingEnv.getMessager() 214 .printMessage(kind, String.format(format, argv), 215 element, annotation, value); 216 } 217 218 /** 219 * Method to print a {@link Throwable}. 220 * 221 * @param kind The {@link javax.tools.Diagnostic.Kind}. 222 * @param throwable The {@link Throwable}. 223 */ 224 protected void print(Diagnostic.Kind kind, Throwable throwable) { 225 print(kind, new ThrowableDataSource(throwable).toString()); 226 } 227 228 /** 229 * Abstract {@link Criterion} base class. 230 */ 231 @NoArgsConstructor(access = PROTECTED) @ToString 232 protected abstract class Criterion<T extends Element> implements Predicate<T> { } 233 234 /** 235 * Abstract {@link Check} base class. 236 */ 237 @NoArgsConstructor(access = PROTECTED) @ToString 238 protected abstract class Check<T extends Element> implements Consumer<T> { } 239 240 @NoArgsConstructor @ToString 241 private class WhenAnnotationProcessingFinished extends AbstractTaskListener { 242 @Override 243 public void finished(TaskEvent event) { 244 switch (event.getKind()) { 245 case ANNOTATION_PROCESSING: 246 javac.removeTaskListener(this); 247 whenAnnotationProcessingFinished(); 248 break; 249 250 default: 251 break; 252 } 253 } 254 } 255}