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