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