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