001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.reflect; 014 015import static org.apache.juneau.internal.StringUtils.*; 016 017import java.lang.annotation.*; 018import java.lang.reflect.*; 019import java.util.*; 020import java.util.concurrent.*; 021 022import org.apache.juneau.*; 023import org.apache.juneau.internal.*; 024 025/** 026 * Contains common methods between {@link ConstructorInfo} and {@link MethodInfo}. 027 */ 028public abstract class ExecutableInfo { 029 030 final ClassInfo declaringClass; 031 final Executable e, re; 032 final boolean isConstructor; 033 034 private List<ParamInfo> params; 035 private List<ClassInfo> paramTypes, exceptionInfos; 036 private Class<?>[] rawParamTypes, rawExceptionTypes; 037 private Type[] rawGenericParamTypes; 038 private Parameter[] rawParameters; 039 private Map<Class<?>,Optional<Annotation>> annotationMap; 040 041 /** 042 * Constructor. 043 * 044 * @param declaringClass The class that declares this method or constructor. 045 * @param e The constructor or method that this info represents. 046 * @param re The "real" constructor if the constructor above is defined against a CGLIB proxy. 047 */ 048 protected ExecutableInfo(ClassInfo declaringClass, Executable e, Executable re) { 049 this.declaringClass = declaringClass; 050 this.e = e; 051 this.re = re == null ? e : re; 052 this.isConstructor = e instanceof Constructor; 053 } 054 055 /** 056 * Returns metadata about the class that declared this method or constructor. 057 * 058 * @return Metadata about the class that declared this method or constructor. 059 */ 060 public final ClassInfo getDeclaringClass() { 061 return declaringClass; 062 } 063 064 /** 065 * Returns <jk>true</jk> if this executable represents a {@link Constructor}. 066 * 067 * @return 068 * <jk>true</jk> if this executable represents a {@link Constructor} and can be cast to {@link ConstructorInfo}. 069 * <jk>false</jk> if this executable represents a {@link Method} and can be cast to {@link MethodInfo}. 070 */ 071 public final boolean isConstructor() { 072 return isConstructor; 073 } 074 075 //----------------------------------------------------------------------------------------------------------------- 076 // Parameters 077 //----------------------------------------------------------------------------------------------------------------- 078 079 /** 080 * Returns the number of parameters in this executable. 081 * 082 * <p> 083 * Same as calling {@link Executable#getParameterCount()}. 084 * 085 * @return The number of parameters in this executable. 086 */ 087 public final int getParamCount() { 088 return e.getParameterCount(); 089 } 090 091 /** 092 * Returns <jk>true</jk> if this executable has at least one parameter. 093 * 094 * <p> 095 * Same as calling {@link Executable#getParameterCount()} and comparing with zero. 096 * 097 * @return <jk>true</jk> if this executable has at least one parameter. 098 */ 099 public final boolean hasParams() { 100 return getParamCount() != 0; 101 } 102 103 /** 104 * Returns <jk>true</jk> if this executable has no parameters. 105 * 106 * <p> 107 * Same as calling {@link Executable#getParameterCount()} and comparing with zero. 108 * 109 * @return <jk>true</jk> if this executable has no parameters. 110 */ 111 public final boolean hasNoParams() { 112 return getParamCount() == 0; 113 } 114 115 /** 116 * Returns <jk>true</jk> if this executable has this number of arguments. 117 * 118 * <p> 119 * Same as calling {@link Executable#getParameterCount()} and comparing the count. 120 * 121 * @param number The number of expected arguments. 122 * @return <jk>true</jk> if this executable has this number of arguments. 123 */ 124 public final boolean hasNumParams(int number) { 125 return getParamCount() == number; 126 } 127 128 /** 129 * Returns the parameters defined on this executable. 130 * 131 * <p> 132 * Same as calling {@link Executable#getParameters()} but wraps the results 133 * 134 * @return An array of parameter information, never <jk>null</jk>. 135 */ 136 public final List<ParamInfo> getParams() { 137 if (params == null) { 138 Parameter[] rp = rawParameters(); 139 List<ParamInfo> l = new ArrayList<>(rp.length); 140 for (int i = 0; i < rp.length; i++) 141 l.add(new ParamInfo(this, rp[i], i)); 142 params = Collections.unmodifiableList(l); 143 } 144 return params; 145 } 146 147 /** 148 * Returns parameter information at the specified index. 149 * 150 * @param index The parameter index. 151 * @return The parameter information, never <jk>null</jk>. 152 */ 153 public final ParamInfo getParam(int index) { 154 checkIndex(index); 155 if (params != null) 156 return params.get(index); 157 return new ParamInfo(this, rawParameters()[index], index); 158 } 159 160 /** 161 * Returns the parameter types on this executable. 162 * 163 * @return The parameter types on this executable. 164 */ 165 public final List<ClassInfo> getParamTypes() { 166 if (paramTypes == null) { 167 Class<?>[] ptc = rawParamTypes(); 168 // Note that due to a bug involving Enum constructors, getGenericParameterTypes() may 169 // always return an empty array. This appears to be fixed in Java 8 b75. 170 Type[] ptt = rawGenericParamTypes(); 171 if (ptt.length != ptc.length) 172 ptt = ptc; 173 List<ClassInfo> l = new ArrayList<>(ptc.length); 174 for (int i = 0; i < ptc.length; i++) 175 l.add(ClassInfo.of(ptc[i], ptt[i])); 176 paramTypes = Collections.unmodifiableList(l); 177 } 178 return paramTypes; 179 } 180 181 /** 182 * Returns the parameter type of the parameter at the specified index. 183 * 184 * @param index The parameter index. 185 * @return The parameter type of the parameter at the specified index. 186 */ 187 public final ClassInfo getParamType(int index) { 188 checkIndex(index); 189 if (paramTypes != null) 190 return getParamTypes().get(index); 191 return ClassInfo.of(getRawParamType(index), getRawGenericParamType(index)); 192 } 193 194 /** 195 * Returns the raw parameter types on this executable. 196 * 197 * @return The raw parameter types on this executable. 198 */ 199 public final Class<?>[] getRawParamTypes() { 200 return rawParamTypes().clone(); 201 } 202 203 /** 204 * Returns the raw parameter type of the parameter at the specified index. 205 * 206 * @param index The parameter index. 207 * @return The raw parameter type of the parameter at the specified index. 208 */ 209 public final Class<?> getRawParamType(int index) { 210 checkIndex(index); 211 return rawParamTypes()[index]; 212 } 213 214 /** 215 * Returns the raw generic parameter types on this executable. 216 * 217 * @return The raw generic parameter types on this executable. 218 */ 219 public final Type[] getRawGenericParamTypes() { 220 return rawGenericParamTypes().clone(); 221 } 222 223 /** 224 * Returns the raw generic parameter type of the parameter at the specified index. 225 * 226 * @param index The parameter index. 227 * @return The raw generic parameter type of the parameter at the specified index. 228 */ 229 public final Type getRawGenericParamType(int index) { 230 checkIndex(index); 231 return rawGenericParamTypes()[index]; 232 } 233 234 /** 235 * Returns an array of raw {@link Parameter} objects that represent all the parameters to the underlying executable represented by this object. 236 * 237 * @return An array of raw {@link Parameter} objects, or an empty array if executable has no parameters. 238 * @see Executable#getParameters() 239 */ 240 public final Parameter[] getRawParameters() { 241 return rawParameters().clone(); 242 } 243 244 /** 245 * Returns the raw {@link Parameter} object that represents the parameter at the specified index. 246 * 247 * @param index The parameter index. 248 * @return The raw {@link Parameter} object that represents the parameter at the specified index. 249 * @see Executable#getParameters() 250 */ 251 public final Parameter getRawParameter(int index) { 252 checkIndex(index); 253 return rawParameters()[index]; 254 } 255 256 Class<?>[] rawParamTypes() { 257 if (rawParamTypes == null) 258 rawParamTypes = e.getParameterTypes(); 259 return rawParamTypes; 260 } 261 262 Type[] rawGenericParamTypes() { 263 if (rawGenericParamTypes == null) 264 rawGenericParamTypes = re.getGenericParameterTypes(); 265 return rawGenericParamTypes; 266 } 267 268 Parameter[] rawParameters() { 269 if (rawParameters == null) 270 rawParameters = re.getParameters(); 271 return rawParameters; 272 } 273 274 private void checkIndex(int index) { 275 int pc = getParamCount(); 276 if (pc == 0) 277 throw new IndexOutOfBoundsException(format("Invalid index ''{0}''. No parameters.", index)); 278 if (index < 0 || index >= pc) 279 throw new IndexOutOfBoundsException(format("Invalid index ''{0}''. Parameter count: {1}", index, pc)); 280 } 281 282 //----------------------------------------------------------------------------------------------------------------- 283 // Annotations 284 //----------------------------------------------------------------------------------------------------------------- 285 286 /** 287 * Returns the parameter annotations on this executable. 288 * 289 * @return The parameter annotations on this executable. 290 */ 291 public final Annotation[][] getParameterAnnotations() { 292 return e.getParameterAnnotations(); 293 } 294 295 /** 296 * Returns the parameter annotations on the parameter at the specified index. 297 * 298 * @param index The parameter index. 299 * @return The parameter annotations on the parameter at the specified index. 300 */ 301 public final Annotation[] getParameterAnnotations(int index) { 302 checkIndex(index); 303 return e.getParameterAnnotations()[index]; 304 } 305 306 /** 307 * Returns <jk>true</jk> if the specified annotation is present on this method. 308 * 309 * @param a The annotation to check for. 310 * @return <jk>true</jk> if the specified annotation is present on this method. 311 */ 312 public final boolean hasAnnotation(Class<? extends Annotation> a) { 313 return getAnnotation(a) != null; 314 } 315 316 /** 317 * Finds the annotation of the specified type defined on this executable. 318 * 319 * <p> 320 * If this is a method and the annotation cannot be found on the immediate method, searches methods with the same 321 * signature on the parent classes or interfaces. 322 * <br>The search is performed in child-to-parent order. 323 * 324 * @param a 325 * The annotation to search for. 326 * @return 327 * The annotation if found, or <jk>null</jk> if not. 328 */ 329 @SuppressWarnings("unchecked") 330 public final <T extends Annotation> T getAnnotation(Class<T> a) { 331 if (a == null) 332 return null; 333 Optional<Annotation> o = annotationMap().get(a); 334 if (o == null) { 335 o = Optional.ofNullable(findAnnotation(a)); 336 annotationMap().put(a, o); 337 } 338 return o.isPresent() ? (T)o.get() : null; 339 } 340 341 /** 342 * Searched for the specified annotation on the method. 343 * 344 * @param a The annotation to search for on the method. 345 * @return The annotation if found. 346 */ 347 protected <T extends Annotation> T findAnnotation(Class<T> a) { 348 return e.getAnnotation(a); 349 } 350 351 private synchronized Map<Class<?>,Optional<Annotation>> annotationMap() { 352 if (annotationMap == null) 353 annotationMap = new ConcurrentHashMap<>(); 354 return annotationMap; 355 } 356 357 //----------------------------------------------------------------------------------------------------------------- 358 // Exceptions 359 //----------------------------------------------------------------------------------------------------------------- 360 361 /** 362 * Returns the exception types on this executable. 363 * 364 * @return The exception types on this executable. 365 */ 366 public final List<ClassInfo> getExceptionTypes() { 367 if (exceptionInfos == null) { 368 Class<?>[] exceptionTypes = rawExceptionTypes(); 369 List<ClassInfo> l = new ArrayList<>(exceptionTypes.length); 370 for (Class<?> et : exceptionTypes) 371 l.add(ClassInfo.of(et)); 372 exceptionInfos = Collections.unmodifiableList(l); 373 } 374 return exceptionInfos; 375 } 376 377 /** 378 * Returns the raw exception types on this executable. 379 * 380 * @return The raw exception types on this executable. 381 */ 382 public final Class<?>[] getRawExceptionTypes() { 383 return rawExceptionTypes().clone(); 384 } 385 386 private Class<?>[] rawExceptionTypes() { 387 if (rawExceptionTypes == null) 388 rawExceptionTypes = e.getExceptionTypes(); 389 return rawExceptionTypes; 390 } 391 392 //----------------------------------------------------------------------------------------------------------------- 393 // Characteristics 394 //----------------------------------------------------------------------------------------------------------------- 395 396 /** 397 * Returns <jk>true</jk> if all specified flags are applicable to this method. 398 * 399 * @param flags The flags to test for. 400 * @return <jk>true</jk> if all specified flags are applicable to this method. 401 */ 402 public final boolean isAll(ReflectFlags...flags) { 403 for (ReflectFlags f : flags) { 404 switch (f) { 405 case DEPRECATED: 406 if (isNotDeprecated()) 407 return false; 408 break; 409 case NOT_DEPRECATED: 410 if (isDeprecated()) 411 return false; 412 break; 413 case HAS_PARAMS: 414 if (hasNoParams()) 415 return false; 416 break; 417 case HAS_NO_PARAMS: 418 if (hasParams()) 419 return false; 420 break; 421 case PUBLIC: 422 if (isNotPublic()) 423 return false; 424 break; 425 case NOT_PUBLIC: 426 if (isPublic()) 427 return false; 428 break; 429 case STATIC: 430 if (isNotStatic()) 431 return false; 432 break; 433 case NOT_STATIC: 434 if (isStatic()) 435 return false; 436 break; 437 case ABSTRACT: 438 if (isNotAbstract()) 439 return false; 440 break; 441 case NOT_ABSTRACT: 442 if (isAbstract()) 443 return false; 444 break; 445 default: 446 throw new RuntimeException("Invalid flag for executable: " + f); 447 } 448 } 449 return true; 450 } 451 452 /** 453 * Returns <jk>true</jk> if all specified flags are applicable to this method. 454 * 455 * @param flags The flags to test for. 456 * @return <jk>true</jk> if all specified flags are applicable to this method. 457 */ 458 public final boolean isAny(ReflectFlags...flags) { 459 for (ReflectFlags f : flags) { 460 switch (f) { 461 case DEPRECATED: 462 if (isDeprecated()) 463 return true; 464 break; 465 case NOT_DEPRECATED: 466 if (isNotDeprecated()) 467 return true; 468 break; 469 case HAS_PARAMS: 470 if (hasParams()) 471 return true; 472 break; 473 case HAS_NO_PARAMS: 474 if (hasNoParams()) 475 return true; 476 break; 477 case PUBLIC: 478 if (isPublic()) 479 return true; 480 break; 481 case NOT_PUBLIC: 482 if (isNotPublic()) 483 return true; 484 break; 485 case STATIC: 486 if (isStatic()) 487 return true; 488 break; 489 case NOT_STATIC: 490 if (isNotStatic()) 491 return true; 492 break; 493 case ABSTRACT: 494 if (isAbstract()) 495 return true; 496 break; 497 case NOT_ABSTRACT: 498 if (isNotAbstract()) 499 return true; 500 break; 501 default: 502 throw new RuntimeException("Invalid flag for executable: " + f); 503 } 504 } 505 return false; 506 } 507 508 /** 509 * Returns <jk>true</jk> if this method has the specified arguments. 510 * 511 * @param args The arguments to test for. 512 * @return <jk>true</jk> if this method has this arguments in the exact order. 513 */ 514 public final boolean hasParamTypes(Class<?>...args) { 515 Class<?>[] pt = rawParamTypes(); 516 if (pt.length == args.length) { 517 for (int i = 0; i < pt.length; i++) 518 if (! pt[i].equals(args[i])) 519 return false; 520 return true; 521 } 522 return false; 523 } 524 525 /** 526 * Returns <jk>true</jk> if this method has the specified arguments. 527 * 528 * @param args The arguments to test for. 529 * @return <jk>true</jk> if this method has this arguments in the exact order. 530 */ 531 public final boolean hasParamTypes(ClassInfo...args) { 532 Class<?>[] pt = rawParamTypes(); 533 if (pt.length == args.length) { 534 for (int i = 0; i < pt.length; i++) 535 if (! pt[i].equals(args[i].inner())) 536 return false; 537 return true; 538 } 539 return false; 540 } 541 542 /** 543 * Returns <jk>true</jk> if this method has the specified argument parent classes. 544 * 545 * @param args The arguments to test for. 546 * @return <jk>true</jk> if this method has this arguments in the exact order. 547 */ 548 public final boolean hasParamTypeParents(Class<?>...args) { 549 Class<?>[] pt = rawParamTypes(); 550 if (pt.length == args.length) { 551 for (int i = 0; i < pt.length; i++) 552 if (! args[i].isAssignableFrom(pt[i])) 553 return false; 554 return true; 555 } 556 return false; 557 } 558 559 /** 560 * Returns <jk>true</jk> if this method has the specified argument parent classes. 561 * 562 * @param args The arguments to test for. 563 * @return <jk>true</jk> if this method has this arguments in the exact order. 564 */ 565 public final boolean hasParamTypeParents(ClassInfo...args) { 566 Class<?>[] pt = rawParamTypes(); 567 if (pt.length == args.length) { 568 for (int i = 0; i < pt.length; i++) 569 if (! args[i].inner().isAssignableFrom(pt[i])) 570 return false; 571 return true; 572 } 573 return false; 574 } 575 576 /** 577 * Returns <jk>true</jk> if this method has at most only this arguments in any order. 578 * 579 * @param args The arguments to test for. 580 * @return <jk>true</jk> if this method has at most only this arguments in any order. 581 */ 582 public final boolean hasFuzzyParamTypes(Class<?>...args) { 583 return ClassUtils.fuzzyArgsMatch(rawParamTypes(), args) != -1; 584 } 585 586 /** 587 * Returns <jk>true</jk> if this method has at most only this arguments in any order. 588 * 589 * @param args The arguments to test for. 590 * @return <jk>true</jk> if this method has at most only this arguments in any order. 591 */ 592 public boolean hasFuzzyParamTypes(ClassInfo...args) { 593 return ClassUtils.fuzzyArgsMatch(rawParamTypes(), args) != -1; 594 } 595 596 /** 597 * Returns <jk>true</jk> if this method has the {@link Deprecated @Deprecated} annotation on it. 598 * 599 * @return <jk>true</jk> if this method has the {@link Deprecated @Deprecated} annotation on it. 600 */ 601 public final boolean isDeprecated() { 602 return e.isAnnotationPresent(Deprecated.class); 603 604 } 605 606 /** 607 * Returns <jk>true</jk> if this method doesn't have the {@link Deprecated @Deprecated} annotation on it. 608 * 609 * @return <jk>true</jk> if this method doesn't have the {@link Deprecated @Deprecated} annotation on it. 610 */ 611 public final boolean isNotDeprecated() { 612 return ! e.isAnnotationPresent(Deprecated.class); 613 614 } 615 616 /** 617 * Returns <jk>true</jk> if this method is abstract. 618 * 619 * @return <jk>true</jk> if this method is abstract. 620 */ 621 public final boolean isAbstract() { 622 return Modifier.isAbstract(e.getModifiers()); 623 } 624 625 /** 626 * Returns <jk>true</jk> if this method is not abstract. 627 * 628 * @return <jk>true</jk> if this method is not abstract. 629 */ 630 public final boolean isNotAbstract() { 631 return ! Modifier.isAbstract(e.getModifiers()); 632 } 633 634 /** 635 * Returns <jk>true</jk> if this method is public. 636 * 637 * @return <jk>true</jk> if this method is public. 638 */ 639 public final boolean isPublic() { 640 return Modifier.isPublic(e.getModifiers()); 641 } 642 643 /** 644 * Returns <jk>true</jk> if this method is not public. 645 * 646 * @return <jk>true</jk> if this method is not public. 647 */ 648 public final boolean isNotPublic() { 649 return ! Modifier.isPublic(e.getModifiers()); 650 } 651 652 /** 653 * Returns <jk>true</jk> if this method is static. 654 * 655 * @return <jk>true</jk> if this method is static. 656 */ 657 public final boolean isStatic() { 658 return Modifier.isStatic(e.getModifiers()); 659 } 660 661 /** 662 * Returns <jk>true</jk> if this method is not static. 663 * 664 * @return <jk>true</jk> if this method is not static. 665 */ 666 public final boolean isNotStatic() { 667 return ! Modifier.isStatic(e.getModifiers()); 668 } 669 670 //----------------------------------------------------------------------------------------------------------------- 671 // Visibility 672 //----------------------------------------------------------------------------------------------------------------- 673 674 /** 675 * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions. 676 * 677 * @return <jk>true</jk> if call was successful. 678 */ 679 public final boolean setAccessible() { 680 try { 681 if (! (e.isAccessible())) 682 e.setAccessible(true); 683 return true; 684 } catch (SecurityException e) { 685 return false; 686 } 687 } 688 689 /** 690 * Identifies if the specified visibility matches this method. 691 * 692 * @param v The visibility to validate against. 693 * @return <jk>true</jk> if this visibility matches the modifier attribute of this method. 694 */ 695 public final boolean isVisible(Visibility v) { 696 return v.isVisible(e); 697 } 698 699 //----------------------------------------------------------------------------------------------------------------- 700 // Labels 701 //----------------------------------------------------------------------------------------------------------------- 702 703 /** 704 * Returns <jk>true</jk> if this method has this name. 705 * 706 * @param name The name to test for. 707 * @return <jk>true</jk> if this method has this name. 708 */ 709 public final boolean hasName(String name) { 710 return getSimpleName().equals(name); 711 } 712 713 /** 714 * Returns <jk>true</jk> if this method has a name in the specified list. 715 * 716 * @param names The names to test for. 717 * @return <jk>true</jk> if this method has one of the names. 718 */ 719 public final boolean hasName(String...names) { 720 for (String n : names) 721 if (getSimpleName().equals(n)) 722 return true; 723 return false; 724 } 725 726 /** 727 * Returns <jk>true</jk> if this method has a name in the specified set. 728 * 729 * @param names The names to test for. 730 * @return <jk>true</jk> if this method has one of the names. 731 */ 732 public final boolean hasName(Set<String> names) { 733 return names.contains(getSimpleName()); 734 } 735 736 //----------------------------------------------------------------------------------------------------------------- 737 // Labels 738 //----------------------------------------------------------------------------------------------------------------- 739 740 /** 741 * Returns the full name of this executable. 742 * 743 * <h5 class='section'>Examples:</h5> 744 * <ul> 745 * <li><js>"com.foo.MyClass.get(java.util.String)"<js> - Method. 746 * <li><js>"com.foo.MyClass(java.util.String)"<js> - Constructor. 747 * </ul> 748 * 749 * @return The underlying executable name. 750 */ 751 public final String getFullName() { 752 StringBuilder sb = new StringBuilder(128); 753 ClassInfo dc = declaringClass; 754 Package p = dc.getPackage(); 755 if (p != null) 756 sb.append(p.getName()).append('.'); 757 dc.appendShortName(sb); 758 if (! isConstructor) 759 sb.append('.').append(getSimpleName()); 760 sb.append('('); 761 List<ClassInfo> pt = getParamTypes(); 762 for (int i = 0; i < pt.size(); i++) { 763 if (i > 0) 764 sb.append(','); 765 pt.get(i).appendFullName(sb); 766 } 767 sb.append(')'); 768 return sb.toString(); 769 } 770 771 /** 772 * Returns the short name of this executable. 773 * 774 * <h5 class='section'>Examples:</h5> 775 * <ul> 776 * <li><js>"MyClass.get(String)"<js> - Method. 777 * <li><js>"MyClass(String)"<js> - Constructor. 778 * </ul> 779 * 780 * @return The underlying executable name. 781 */ 782 public final String getShortName() { 783 StringBuilder sb = new StringBuilder(64); 784 sb.append(getSimpleName()).append('('); 785 Class<?>[] pt = rawParamTypes(); 786 for (int i = 0; i < pt.length; i++) { 787 if (i > 0) 788 sb.append(','); 789 sb.append(pt[i].getSimpleName()); 790 } 791 sb.append(')'); 792 return sb.toString(); 793 } 794 795 /** 796 * Returns the simple name of the underlying class. 797 * 798 * <p> 799 * Returns either {@link Class#getSimpleName()} or {@link Type#getTypeName()} depending on whether 800 * this is a class or type. 801 * 802 * @return The simple name of the underlying class; 803 */ 804 public final String getSimpleName() { 805 return isConstructor ? e.getDeclaringClass().getSimpleName() : e.getName(); 806 } 807 808 @Override 809 public String toString() { 810 return getShortName(); 811 } 812}