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}