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