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