001package ball.annotation.processing; 002/*- 003 * ########################################################################## 004 * Utilities 005 * $Id: AbstractProcessor.java 6125 2020-06-06 15:01:50Z 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 - 2020 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.beans.PropertyMethodEnum; 025import ball.lang.reflect.JavaLangReflectMethods; 026import ball.tools.javac.AbstractTaskListener; 027import com.sun.source.util.JavacTask; 028import com.sun.source.util.TaskEvent; 029import com.sun.source.util.Trees; 030import com.sun.tools.javac.processing.JavacProcessingEnvironment; 031import com.sun.tools.javac.util.Context; 032import java.lang.annotation.Annotation; 033import java.lang.reflect.Method; 034import java.net.URLClassLoader; 035import java.nio.file.Path; 036import java.nio.file.Paths; 037import java.util.Arrays; 038import java.util.Collection; 039import java.util.EnumSet; 040import java.util.List; 041import java.util.Objects; 042import java.util.Optional; 043import java.util.Set; 044import java.util.TreeSet; 045import java.util.function.Consumer; 046import java.util.function.Function; 047import java.util.function.Predicate; 048import java.util.regex.Pattern; 049import java.util.stream.IntStream; 050import java.util.stream.Stream; 051import javax.annotation.processing.Filer; 052import javax.annotation.processing.ProcessingEnvironment; 053import javax.annotation.processing.RoundEnvironment; 054import javax.lang.model.SourceVersion; 055import javax.lang.model.element.AnnotationMirror; 056import javax.lang.model.element.AnnotationValue; 057import javax.lang.model.element.Element; 058import javax.lang.model.element.ExecutableElement; 059import javax.lang.model.element.Modifier; 060import javax.lang.model.element.PackageElement; 061import javax.lang.model.element.TypeElement; 062import javax.lang.model.type.TypeKind; 063import javax.lang.model.type.TypeMirror; 064import javax.lang.model.util.Elements; 065import javax.lang.model.util.Types; 066import javax.tools.Diagnostic; 067import javax.tools.FileObject; 068import javax.tools.JavaFileManager; 069import lombok.NoArgsConstructor; 070import lombok.ToString; 071 072import static java.util.Collections.disjoint; 073import static java.util.stream.Collectors.toList; 074import static javax.lang.model.element.ElementKind.CONSTRUCTOR; 075import static javax.lang.model.element.ElementKind.METHOD; 076import static javax.lang.model.element.Modifier.PRIVATE; 077import static javax.lang.model.element.Modifier.STATIC; 078import static javax.lang.model.util.ElementFilter.constructorsIn; 079import static javax.lang.model.util.ElementFilter.methodsIn; 080import static javax.tools.Diagnostic.Kind.ERROR; 081import static javax.tools.StandardLocation.CLASS_PATH; 082import static lombok.AccessLevel.PROTECTED; 083 084/** 085 * Extends {@link javax.annotation.processing.AbstractProcessor} by 086 * providing a {@link #getSupportedSourceVersion()} implementation, methods 087 * to report {@link javax.tools.Diagnostic.Kind#ERROR}s and 088 * {@link javax.tools.Diagnostic.Kind#WARNING}s, and access to 089 * {@link ProcessingEnvironment#getFiler()}, 090 * {@link ProcessingEnvironment#getElementUtils()}, and 091 * {@link ProcessingEnvironment#getTypeUtils()}. 092 * 093 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 094 * @version $Revision: 6125 $ 095 */ 096@NoArgsConstructor(access = PROTECTED) @ToString 097public abstract class AbstractProcessor 098 extends javax.annotation.processing.AbstractProcessor 099 implements JavaLangReflectMethods { 100 /** See {@link JavacTask#instance(ProcessingEnvironment)}. */ 101 protected JavacTask javac = null; 102 /** {@link JavacTask} {@link JavaFileManager} instance. */ 103 protected JavaFileManager fm = null; 104 /** See {@link Trees#instance(ProcessingEnvironment)}. */ 105 protected Trees trees = null; 106 /** See {@link ProcessingEnvironment#getFiler()}. */ 107 protected Filer filer = null; 108 /** See {@link ProcessingEnvironment#getElementUtils()}. */ 109 protected Elements elements = null; 110 /** See {@link ProcessingEnvironment#getTypeUtils()}. */ 111 protected Types types = null; 112 113 @Override 114 public SourceVersion getSupportedSourceVersion() { 115 SourceVersion[] values = SourceVersion.values(); 116 117 return values[values.length - 1]; 118 } 119 120 @Override 121 public void init(ProcessingEnvironment processingEnv) { 122 super.init(processingEnv); 123 124 try { 125 filer = processingEnv.getFiler(); 126 elements = processingEnv.getElementUtils(); 127 types = processingEnv.getTypeUtils(); 128 129 javac = JavacTask.instance(processingEnv); 130 131 if (javac != null) { 132 javac.addTaskListener(new WhenAnnotationProcessingFinished()); 133 } 134 135 if (processingEnv instanceof JavacProcessingEnvironment) { 136 Context context = 137 ((JavacProcessingEnvironment) processingEnv).getContext(); 138 139 if (context != null) { 140 fm = context.get(JavaFileManager.class); 141 } 142 } 143 144 trees = Trees.instance(processingEnv); 145 } catch (Exception exception) { 146 print(ERROR, exception); 147 } 148 } 149 150 @Override 151 public abstract boolean process(Set<? extends TypeElement> annotations, 152 RoundEnvironment roundEnv); 153 154 /** 155 * Callback method to signal 156 * {@link com.sun.source.util.TaskEvent.Kind#ANNOTATION_PROCESSING} is 157 * finished. 158 */ 159 protected void whenAnnotationProcessingFinished() { } 160 161 /** 162 * See {@link JavaFileManager#getClassLoader(javax.tools.JavaFileManager.Location) JavaFileManager.getClassLoader(CLASS_PATH)}. 163 * 164 * @param fm The {@link JavaFileManager}. 165 * 166 * @return The {@link ClassLoader}. 167 */ 168 protected ClassLoader getClassPathClassLoader(JavaFileManager fm) { 169 ClassLoader loader = null; 170 171 if (fm != null) { 172 loader = fm.getClassLoader(CLASS_PATH); 173 174 if (loader instanceof URLClassLoader) { 175 loader = 176 URLClassLoader 177 .newInstance(((URLClassLoader) loader).getURLs(), 178 getClass().getClassLoader()); 179 } 180 } 181 182 return loader; 183 } 184 185 /** 186 * Method to get a {@link TypeElement} for a {@link Class}. 187 * 188 * @param type The {@link Class}. 189 * 190 * @return The {@link TypeElement} for the {@link Class}. 191 */ 192 protected TypeElement asTypeElement(Class<?> type) { 193 TypeElement element = null; 194 195 try { 196 element = elements.getTypeElement(type.getCanonicalName()); 197 } catch (Exception exception) { 198 throw new IllegalArgumentException("type=" + type, exception); 199 } 200 201 return element; 202 } 203 204 /** 205 * Method to get a {@link TypeMirror} for a {@link Class}. 206 * 207 * @param type The {@link Class}. 208 * 209 * @return The {@link TypeMirror} for the {@link Class}. 210 */ 211 protected TypeMirror asTypeMirror(Class<?> type) { 212 TypeMirror mirror = null; 213 214 if (type.isArray()) { 215 mirror = types.getArrayType(asTypeMirror(type.getComponentType())); 216 } else if (type.isPrimitive()) { 217 mirror = asTypeMirror(TypeKind.valueOf(type.getName().toUpperCase())); 218 } else { 219 mirror = asTypeElement(type).asType(); 220 } 221 222 return mirror; 223 } 224 225 private TypeMirror asTypeMirror(TypeKind type) { 226 return type.isPrimitive() ? types.getPrimitiveType(type) : types.getNoType(type); 227 } 228 229 /** 230 * Method to get a {@link List} of {@link TypeMirror}s for an array of 231 * {@link Class}es. 232 * 233 * @param types The array of {@link Class}es. 234 * 235 * @return The {@link List} of {@link TypeMirror}s. 236 */ 237 protected List<TypeMirror> asTypeMirrorList(Class<?>... types) { 238 return Stream.of(types).map(t -> asTypeMirror(t)).collect(toList()); 239 } 240 241 /** 242 * Constructor to get an {@link ExecutableElement} for a {@link Class} 243 * {@link java.lang.reflect.Constructor} by parameter list. 244 * 245 * @param type The {@link TypeElement}. 246 * @param parameters The constructor parameter types. 247 * 248 * @return The {@link ExecutableElement} for the constructor. 249 */ 250 protected ExecutableElement getConstructor(TypeElement type, 251 List<TypeMirror> parameters) { 252 Element element = 253 constructorsIn(type.getEnclosedElements()) 254 .stream() 255 .filter(hasSameSignatureAs(parameters)) 256 .findFirst().orElse(null); 257 258 return (ExecutableElement) element; 259 } 260 261 /** 262 * Method to get an {@link ExecutableElement} for a {@link Method} 263 * prototype. 264 * 265 * @param method The prototype {@link Method}. 266 * 267 * @return The {@link ExecutableElement} for the method. 268 */ 269 protected ExecutableElement getMethod(Method method) { 270 return getMethod(asTypeElement(method.getDeclaringClass()), method); 271 } 272 273 /** 274 * Method to get an {@link ExecutableElement} for a {@link Method} 275 * prototype. 276 * 277 * @param type The {@link TypeElement}. 278 * @param method The prototype {@link Method}. 279 * 280 * @return The {@link ExecutableElement} for the method. 281 */ 282 protected ExecutableElement getMethod(TypeElement type, Method method) { 283 Element element = 284 methodsIn(type.getEnclosedElements()) 285 .stream() 286 .filter(hasSameSignatureAs(method)) 287 .findFirst().orElse(null); 288 289 return (ExecutableElement) element; 290 } 291 292 /** 293 * Method to return the {@link ExecutableElement} 294 * ({@link java.lang.reflect.Method}) the argument 295 * {@link ExecutableElement} overrides (if any). 296 * 297 * @param overrider The {@link ExecutableElement}. 298 * 299 * @return The overridden {@link ExecutableElement} if any; 300 * {@code null} otherwise. 301 * 302 * @see Elements#overrides(ExecutableElement,ExecutableElement,TypeElement) 303 */ 304 protected ExecutableElement overrides(ExecutableElement overrider) { 305 TypeElement type = (TypeElement) overrider.getEnclosingElement(); 306 ExecutableElement element = 307 types.directSupertypes(type.asType()) 308 .stream() 309 .map(t -> overrides(overrider, types.asElement(t))) 310 .filter(Objects::nonNull) 311 .findFirst().orElse(null); 312 313 return element; 314 } 315 316 private ExecutableElement overrides(ExecutableElement overrider, 317 Element type) { 318 ExecutableElement overridden = null; 319 320 if (type != null) { 321 switch (type.getKind()) { 322 case CLASS: 323 case INTERFACE: 324 overridden = overridden(overrider, (TypeElement) type); 325 break; 326 327 default: 328 break; 329 } 330 } 331 332 return overridden; 333 } 334 335 private ExecutableElement overridden(ExecutableElement overrider, 336 TypeElement type) { 337 ExecutableElement element = 338 methodsIn(type.getEnclosedElements()) 339 .stream() 340 .filter(withoutModifiers(PRIVATE, STATIC)) 341 .filter(t -> elements.overrides(overrider, t, type)) 342 .findFirst().orElse(null); 343 344 if (element == null) { 345 element = 346 overrides(overrider, types.asElement(type.getSuperclass())); 347 } 348 349 return element; 350 } 351 352 /** 353 * Method to determine if a {@link ExecutableElement} 354 * ({@link java.lang.reflect.Method}) overrides another 355 * {@link ExecutableElement}. 356 * 357 * @param overrider The (possibly) overriding 358 * {@link ExecutableElement}. 359 * @param overridden The overridden {@link ExecutableElement}. 360 * 361 * @return {@code true} if {@code overrider} overrides 362 * {@code overridden}; {@code false} otherwise. 363 * 364 * @see Elements#overrides(ExecutableElement,ExecutableElement,TypeElement) 365 */ 366 protected boolean overrides(ExecutableElement overrider, 367 ExecutableElement overridden) { 368 TypeElement type = (TypeElement) overridden.getEnclosingElement(); 369 370 return elements.overrides(overrider, overridden, type); 371 } 372 373 /** 374 * Method to return the {@link ExecutableElement} 375 * ({@link java.lang.reflect.Method}) the argument 376 * {@link ExecutableElement} is overriden by (if any). 377 * 378 * @param overridden The {@link ExecutableElement}. 379 * @param type The {@link TypeElement}. 380 * 381 * @return The overriding {@link ExecutableElement} if any; 382 * {@code null} otherwise. 383 * 384 * @see #overrides(ExecutableElement) 385 */ 386 protected ExecutableElement implementationOf(ExecutableElement overridden, 387 TypeElement type) { 388 ExecutableElement element = null; 389 390 if (type != null) { 391 element = 392 methodsIn(type.getEnclosedElements()) 393 .stream() 394 .filter(t -> overrides(t, overridden)) 395 .findFirst().orElse(null); 396 397 if (element == null) { 398 element = 399 Optional.ofNullable(type.getSuperclass()) 400 .map(t -> (TypeElement) types.asElement(t)) 401 .filter(Objects::nonNull) 402 .map(t -> implementationOf(overridden, t)) 403 .orElse(null); 404 } 405 } 406 407 return element; 408 } 409 410 /** 411 * Method to return the {@link ExecutableElement} 412 * ({@link java.lang.reflect.Method}) the argument 413 * {@link ExecutableElement} is specified by (if any). 414 * 415 * @param method The {@link ExecutableElement}. 416 * 417 * @return The specification {@link ExecutableElement} if any; 418 * {@code null} otherwise. 419 * 420 * @see #overrides(ExecutableElement) 421 */ 422 protected ExecutableElement specifiedBy(ExecutableElement method) { 423 ExecutableElement specification = overrides(method); 424 425 if (specification != null) { 426 for (;;) { 427 ExecutableElement overridden = overrides(specification); 428 429 if (overridden != null) { 430 specification = overridden; 431 } else { 432 break; 433 } 434 } 435 } 436 437 return specification; 438 } 439 440 /** 441 * Method to get an {@link Element}'s {@link AnnotationMirror}. 442 * 443 * @param element The annotated {@link Element}. 444 * @param type The {@link Annotation} type ({@link Class}). 445 * 446 * @return The {@link AnnotationMirror} if the {@link Element} is 447 * annotated with the argument annotation; {@code null} 448 * otherwise. 449 * 450 * @see Element#getAnnotationMirrors() 451 */ 452 protected AnnotationMirror getAnnotationMirror(Element element, 453 Class<? extends Annotation> type) { 454 return getAnnotationMirror(element, type.getName()); 455 } 456 457 /** 458 * Method to get an {@link Element}'s {@link AnnotationMirror}. 459 * 460 * @param element The annotated {@link Element}. 461 * @param type The {@link Annotation} type 462 * ({@link TypeElement}). 463 * 464 * @return The {@link AnnotationMirror} if the {@link Element} is 465 * annotated with the argument annotation; {@code null} 466 * otherwise. 467 * 468 * @see Element#getAnnotationMirrors() 469 */ 470 protected AnnotationMirror getAnnotationMirror(Element element, 471 TypeElement type) { 472 return getAnnotationMirror(element, 473 type.getQualifiedName().toString()); 474 } 475 476 private AnnotationMirror getAnnotationMirror(Element element, 477 String name) { 478 AnnotationMirror mirror = 479 element.getAnnotationMirrors() 480 .stream() 481 .filter(t -> t.getAnnotationType().toString().equals(name)) 482 .map(t -> (AnnotationMirror) t) 483 .findFirst().orElse(null); 484 485 return mirror; 486 } 487 488 /** 489 * Method to get an {@link AnnotationMirror} element's 490 * {@link AnnotationValue}. 491 * 492 * @param annotation The {@link AnnotationMirror}. 493 * @param name The simple name of the element. 494 * 495 * @return The {@link AnnotationValue} if it is defined; {@code null} 496 * otherwise. 497 * 498 * @see Elements#getElementValuesWithDefaults(AnnotationMirror) 499 */ 500 protected AnnotationValue getAnnotationValue(AnnotationMirror annotation, String name) { 501 AnnotationValue value = 502 elements.getElementValuesWithDefaults(annotation).entrySet() 503 .stream() 504 .filter(t -> named(name).test(t.getKey())) 505 .map(t -> t.getValue()) 506 .findFirst().orElse(null); 507 508 return value; 509 } 510 511 /** 512 * Method to determine if an {@link AnnotationValue} is "empty": 513 * {@code null} or an empty array. 514 * 515 * @param value The {@link AnnotationValue}. 516 * 517 * @return {@code true} if empty; {code false} otherwise. 518 */ 519 protected boolean isEmptyArray(AnnotationValue value) { 520 List<?> list = (List<?>) ((value != null) ? value.getValue() : null); 521 522 return (list == null || list.isEmpty()); 523 } 524 525 /** 526 * Method to get bean property name from an {@link ExecutableElement}. 527 * 528 * @param element The {@link ExecutableElement}. 529 * 530 * @return the name {@link String} if the {@link ExecutableElement} 531 * is a getter or setter method; {@code null} otherwise. 532 */ 533 protected String getPropertyName(ExecutableElement element) { 534 String string = 535 Stream.of(PropertyMethodEnum.values()) 536 .filter(t -> t.getPropertyName(element.getSimpleName().toString()) != null) 537 .filter(t -> isAssignableTo(t.getReturnType(), 538 e -> ((ExecutableElement) e).getReturnType()).test(element)) 539 .filter(t -> withParameters(t.getParameterTypes()).test(element)) 540 .map(t -> t.getPropertyName(element.getSimpleName().toString())) 541 .findFirst().orElse(null); 542 543 return string; 544 } 545 546 /** 547 * Method to determine if an {@link ExecutableElement} is a bean getter. 548 * 549 * @param element The {@link ExecutableElement}. 550 * 551 * @return {@code true} if the {@link Element} has a non-private getter 552 * method; {@code false} otherwise. 553 */ 554 protected boolean isGetterMethod(ExecutableElement element) { 555 Optional <PropertyMethodEnum> optional = 556 Stream.of(PropertyMethodEnum.GET, PropertyMethodEnum.IS) 557 .filter(t -> t.getPropertyName(element.getSimpleName().toString()) != null) 558 .filter(t -> withoutModifiers(PRIVATE).test(element)) 559 .filter(t -> isAssignableTo(t.getReturnType(), 560 e -> ((ExecutableElement) e).getReturnType()).test(element)) 561 .filter(t -> withParameters(t.getParameterTypes()).test(element)) 562 .findFirst(); 563 564 return optional.isPresent(); 565 } 566 567 /** 568 * Method to get the {@link Set} of bean property names for the 569 * specified {@link TypeElement}. 570 * 571 * @param type The {@link TypeElement} to analyze. 572 * 573 * @return The {@link Set} of bean property names. 574 */ 575 protected Set<String> getPropertyNames(TypeElement type) { 576 return getPropertyNames(new TreeSet<>(), type); 577 } 578 579 private Set<String> getPropertyNames(Set<String> set, TypeElement type) { 580 for (ExecutableElement element : 581 methodsIn(type.getEnclosedElements())) { 582 if (withoutModifiers(PRIVATE).test(element)) { 583 Stream.of(PropertyMethodEnum.values()) 584 .filter(t -> t.getPropertyName(element.getSimpleName().toString()) != null) 585 .filter(t -> isAssignableTo(t.getReturnType(), 586 e -> ((ExecutableElement) e).getReturnType()).test(element)) 587 .filter(t -> withParameters(t.getParameterTypes()).test(element)) 588 .map(t -> t.getPropertyName(element.getSimpleName().toString())) 589 .forEach(t -> set.add(t)); 590 } 591 } 592 593 Element superclass = types.asElement(type.getSuperclass()); 594 595 if (superclass != null) 596 switch (superclass.getKind()) { 597 case CLASS: 598 getPropertyNames(set, (TypeElement) superclass); 599 break; 600 601 default: 602 break; 603 } 604 605 return set; 606 } 607 /* 608 * Element Predicate Calculus 609 */ 610 protected <E extends Enum<E>> EnumSet<E> toEnumSet(E[] array) { 611 return EnumSet.copyOf(Arrays.asList(array)); 612 } 613 614 private <E extends Enum<E>> Predicate<Element> is(E e, Function<? super Element,E> extractor) { 615 return t -> e.equals(extractor.apply(t)); 616 } 617 618 protected Predicate<Element> hasSameSignatureAs(List<TypeMirror> parameters) { 619 return is(CONSTRUCTOR, Element::getKind).and(withParameters(parameters)); 620 } 621 622 protected Predicate<Element> hasSameSignatureAs(Method method) { 623 return hasSameSignatureAs(method.getName(), 624 method.getParameterTypes()); 625 } 626 627 protected Predicate<Element> hasSameSignatureAs(CharSequence name, 628 Class<?>[] parameters) { 629 return is(METHOD, Element::getKind).and(named(name).and(withParameters(parameters))); 630 } 631 632 protected Predicate<Element> isAssignableTo(Class<?> type) { 633 return isAssignableTo(type, t -> t.asType()); 634 } 635 636 protected Predicate<Element> isAssignableTo(TypeMirror type) { 637 return isAssignableTo(type, t -> t.asType()); 638 } 639 640 protected Predicate<Element> isAssignableTo(Class<?> type, 641 Function<? super Element,TypeMirror> extractor) { 642 return isAssignableTo(asTypeMirror(type), extractor); 643 } 644 645 protected Predicate<Element> isAssignableTo(TypeMirror type, 646 Function<? super Element,TypeMirror> extractor) { 647 return t -> types.isAssignable(extractor.apply(t), type); 648 } 649 650 protected Predicate<Element> named(CharSequence name) { 651 return t -> t.getSimpleName().contentEquals(name); 652 } 653 654 protected Predicate<Element> withParameters(Class<?>[] parameters) { 655 return withParameters(asTypeMirrorList(parameters)); 656 } 657 658 protected Predicate<Element> withParameters(List<TypeMirror> parameters) { 659 return new Predicate<Element>() { 660 @Override 661 public boolean test(Element element) { 662 boolean match = 663 parameters.size() == ((ExecutableElement) element).getParameters().size(); 664 665 if (match) { 666 match &= 667 IntStream.range(0, parameters.size()) 668 .allMatch(i -> isAssignableTo(parameters.get(i), 669 t -> types.erasure(((ExecutableElement) t) 670 .getParameters().get(i).asType())) 671 .test(element)); 672 } 673 674 return match; 675 } 676 }; 677 } 678 679 protected Predicate<Element> withModifiers(Modifier... modifiers) { 680 return withModifiers(toEnumSet(modifiers)); 681 } 682 683 protected Predicate<Element> withModifiers(Set<Modifier> modifiers) { 684 return with(modifiers, t -> t.getModifiers()); 685 } 686 687 protected Predicate<Element> withoutModifiers(Modifier... modifiers) { 688 return withoutModifiers(toEnumSet(modifiers)); 689 } 690 691 protected Predicate<Element> withoutModifiers(Set<Modifier> modifiers) { 692 return without(modifiers, t -> t.getModifiers()); 693 } 694 695 protected <E> Predicate<Element> with(Set<E> set, 696 Function<Element,Collection<E>> extractor) { 697 return t -> extractor.apply(t).containsAll(set); 698 } 699 700 protected <E> Predicate<Element> without(Set<E> set, 701 Function<Element,Collection<E>> extractor) { 702 return t -> disjoint(set, extractor.apply(t)); 703 } 704 705 /** 706 * Method to print a diagnostic message. 707 * 708 * @param kind The {@link javax.tools.Diagnostic.Kind}. 709 * @param format The message format {@link String}. 710 * @param argv Optional arguments to the message format 711 * {@link String}. 712 * 713 * @see javax.annotation.processing.Messager#printMessage(Diagnostic.Kind,CharSequence) 714 */ 715 protected void print(Diagnostic.Kind kind, String format, Object... argv) { 716 processingEnv.getMessager() 717 .printMessage(kind, String.format(format, argv)); 718 } 719 720 /** 721 * Method to print a diagnostic message. 722 * 723 * @param kind The {@link javax.tools.Diagnostic.Kind}. 724 * @param element The offending {@link Element}. 725 * @param format The message format {@link String}. 726 * @param argv Optional arguments to the message format 727 * {@link String}. 728 * 729 * @see javax.annotation.processing.Messager#printMessage(Diagnostic.Kind,CharSequence,Element) 730 */ 731 protected void print(Diagnostic.Kind kind, Element element, 732 String format, Object... argv) { 733 processingEnv.getMessager() 734 .printMessage(kind, String.format(format, argv), 735 element); 736 } 737 738 /** 739 * Method to print a diagnostic message. 740 * 741 * @param kind The {@link javax.tools.Diagnostic.Kind}. 742 * @param element The offending {@link Element}. 743 * @param annotation The offending {@link AnnotationMirror}. 744 * @param format The message format {@link String}. 745 * @param argv Optional arguments to the message format 746 * {@link String}. 747 * 748 * @see javax.annotation.processing.Messager#printMessage(Diagnostic.Kind,CharSequence,Element,AnnotationMirror) 749 */ 750 protected void print(Diagnostic.Kind kind, 751 Element element, AnnotationMirror annotation, 752 String format, Object... argv) { 753 processingEnv.getMessager() 754 .printMessage(kind, String.format(format, argv), 755 element, annotation); 756 } 757 758 /** 759 * Method to print a diagnostic message. 760 * 761 * @param kind The {@link javax.tools.Diagnostic.Kind}. 762 * @param element The offending {@link Element}. 763 * @param annotation The offending {@link AnnotationMirror}. 764 * @param value The offending {@link AnnotationValue}. 765 * @param format The message format {@link String}. 766 * @param argv Optional arguments to the message format 767 * {@link String}. 768 * 769 * @see javax.annotation.processing.Messager#printMessage(Diagnostic.Kind,CharSequence,Element,AnnotationMirror,AnnotationValue) 770 */ 771 protected void print(Diagnostic.Kind kind, 772 Element element, 773 AnnotationMirror annotation, AnnotationValue value, 774 String format, Object... argv) { 775 processingEnv.getMessager() 776 .printMessage(kind, String.format(format, argv), 777 element, annotation, value); 778 } 779 780 /** 781 * Method to print a {@link Throwable}. 782 * 783 * @param kind The {@link javax.tools.Diagnostic.Kind}. 784 * @param throwable The {@link Throwable}. 785 */ 786 protected void print(Diagnostic.Kind kind, Throwable throwable) { 787 print(kind, new ThrowableDataSource(throwable).toString()); 788 } 789 790 /** 791 * Abstract {@link Criterion} base class. 792 */ 793 @NoArgsConstructor(access = PROTECTED) @ToString 794 protected abstract class Criterion<T extends Element> implements Predicate<T> { } 795 796 /** 797 * Abstract {@link Check} base class. 798 */ 799 @NoArgsConstructor(access = PROTECTED) @ToString 800 protected abstract class Check<T extends Element> implements Consumer<T> { } 801 802 @NoArgsConstructor @ToString 803 private class WhenAnnotationProcessingFinished extends AbstractTaskListener { 804 @Override 805 public void finished(TaskEvent event) { 806 switch (event.getKind()) { 807 case ANNOTATION_PROCESSING: 808 javac.removeTaskListener(this); 809 whenAnnotationProcessingFinished(); 810 break; 811 812 default: 813 break; 814 } 815 } 816 } 817}