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