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.Utils.*;
020import static org.apache.juneau.internal.ConsumerUtils.*;
021
022import java.beans.*;
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 * Lightweight utility class for introspecting information about a method.
033 *
034 * <h5 class='section'>See Also:</h5><ul>
035 * </ul>
036 */
037public class MethodInfo extends ExecutableInfo implements Comparable<MethodInfo> {
038
039   //-----------------------------------------------------------------------------------------------------------------
040   // Static
041   //-----------------------------------------------------------------------------------------------------------------
042
043   /**
044    * Convenience method for instantiating a {@link MethodInfo};
045    *
046    * @param declaringClass The class that declares this method.
047    * @param m The method being wrapped.
048    * @return A new {@link MethodInfo} object, or <jk>null</jk> if the method was null;
049    */
050   public static MethodInfo of(ClassInfo declaringClass, Method m) {
051      if (m == null)
052         return null;
053      return declaringClass.getMethodInfo(m);
054   }
055
056   /**
057    * Convenience method for instantiating a {@link MethodInfo};
058    *
059    * @param declaringClass The class that declares this method.
060    * @param m The method being wrapped.
061    * @return A new {@link MethodInfo} object, or <jk>null</jk> if the method was null;
062    */
063   public static MethodInfo of(Class<?> declaringClass, Method m) {
064      if (m == null)
065         return null;
066      return ClassInfo.of(declaringClass).getMethodInfo(m);
067   }
068
069   /**
070    * Convenience method for instantiating a {@link MethodInfo};
071    *
072    * @param m The method being wrapped.
073    * @return A new {@link MethodInfo} object, or <jk>null</jk> if the method was null;
074    */
075   public static MethodInfo of(Method m) {
076      if (m == null)
077         return null;
078      return ClassInfo.of(m.getDeclaringClass()).getMethodInfo(m);
079   }
080
081   //-----------------------------------------------------------------------------------------------------------------
082   // Instance
083   //-----------------------------------------------------------------------------------------------------------------
084
085   private final Method m;
086   private volatile ClassInfo returnType;
087   private volatile MethodInfo[] matching;
088
089   /**
090    * Constructor.
091    *
092    * @param declaringClass The class that declares this method.
093    * @param m The method being wrapped.
094    */
095   protected MethodInfo(ClassInfo declaringClass, Method m) {
096      super(declaringClass, m);
097      this.m = m;
098   }
099
100   /**
101    * Returns the wrapped method.
102    *
103    * @return The wrapped method.
104    */
105   public Method inner() {
106      return m;
107   }
108
109   //-----------------------------------------------------------------------------------------------------------------
110   // Matching methods.
111   //-----------------------------------------------------------------------------------------------------------------
112
113   /**
114    * Returns <jk>true</jk> if this constructor can accept the specified arguments in the specified order.
115    *
116    * @param args The arguments to check.
117    * @return <jk>true</jk> if this constructor can accept the specified arguments in the specified order.
118    */
119   public boolean canAccept(Object...args) {
120      Class<?>[] pt = m.getParameterTypes();
121      if (pt.length != args.length)
122         return false;
123      for (int i = 0; i < pt.length; i++)
124         if (! pt[i].isInstance(args[i]))
125            return false;
126      return true;
127   }
128
129   /**
130    * Returns the number of matching arguments for this method.
131    *
132    * @param args The arguments to check.
133    * @return the number of matching arguments for this method.
134    */
135   public int canAcceptFuzzy(Object...args) {
136      int matches = 0;
137      outer: for (ClassInfo pi : _getParameterTypes()) {
138         for (Object a : args) {
139            if (pi.canAcceptArg(a)) {
140               matches++;
141               continue outer;
142            }
143         }
144         return -1;
145      }
146      return matches;
147   }
148
149   /**
150    * Performs an action on all matching declared methods with the same name and arguments on all superclasses and interfaces.
151    *
152    * <p>
153    * Methods are accessed from child-to-parent order.
154    *
155    * @param filter A predicate to apply to the entries to determine if action should be performed.  Can be <jk>null</jk>.
156    * @param action An action to perform on the entry.
157    * @return This object.
158    */
159   public MethodInfo forEachMatching(Predicate<MethodInfo> filter, Consumer<MethodInfo> action) {
160      for (MethodInfo m : _getMatching())
161         consume(filter, action, m);
162      return this;
163   }
164
165   /**
166    * Performs an action on all matching declared methods with the same name and arguments on all superclasses and interfaces.
167    *
168    * <p>
169    * Methods are accessed from parent-to-child order.
170    *
171    * @param filter A predicate to apply to the entries to determine if action should be performed.  Can be <jk>null</jk>.
172    * @param action An action to perform on the entry.
173    * @return This object.
174    */
175   public MethodInfo forEachMatchingParentFirst(Predicate<MethodInfo> filter, Consumer<MethodInfo> action) {
176      MethodInfo[] m = _getMatching();
177      for (int i = m.length-1; i >= 0; i--)
178         consume(filter, action, m[i]);
179      return this;
180   }
181
182   private static List<MethodInfo> findMatching(List<MethodInfo> l, MethodInfo m, ClassInfo c) {
183      for (MethodInfo m2 : c._getDeclaredMethods())
184         if (m.hasName(m2.getName()) && Arrays.equals(m._getParameterTypes(), m2._getParameterTypes()))
185            l.add(m2);
186      ClassInfo pc = c.getSuperclass();
187      if (pc != null)
188         findMatching(l, m, pc);
189      for (ClassInfo ic : c._getDeclaredInterfaces())
190         findMatching(l, m, ic);
191      return l;
192   }
193
194   private MethodInfo findMatchingOnClass(ClassInfo c) {
195      for (MethodInfo m2 : c._getDeclaredMethods())
196         if (hasName(m2.getName()) && Arrays.equals(_getParameterTypes(), m2._getParameterTypes()))
197            return m2;
198      return null;
199   }
200
201   MethodInfo[] _getMatching() {
202      if (matching == null) {
203         synchronized(this) {
204            List<MethodInfo> l = findMatching(list(), this, getDeclaringClass());
205            matching = l.toArray(new MethodInfo[l.size()]);
206         }
207      }
208      return matching;
209   }
210
211   //-----------------------------------------------------------------------------------------------------------------
212   // Annotations
213   //-----------------------------------------------------------------------------------------------------------------
214
215   /**
216    * Finds the annotation of the specified type defined on this method.
217    *
218    * <p>
219    * If this is a method and the annotation cannot be found on the immediate method, searches methods with the same
220    * signature on the parent classes or interfaces.
221    * <br>The search is performed in child-to-parent order.
222    *
223    * @param <A> The annotation type to look for.
224    * @param type The annotation to look for.
225    * @return The annotation if found, or <jk>null</jk> if not.
226    */
227   public <A extends Annotation> A getAnnotation(Class<A> type) {
228      return getAnnotation(AnnotationProvider.DEFAULT, type);
229   }
230
231   /**
232    * Finds the annotation of the specified type defined on this method.
233    *
234    * <p>
235    * Searches all methods with the same signature on the parent classes or interfaces
236    * and the return type on the method.
237    *
238    * @param <A> The annotation type to look for.
239    * @param annotationProvider The annotation provider.
240    * @param type The annotation to look for.
241    * @return The first annotation found, or <jk>null</jk> if it doesn't exist.
242    */
243   public <A extends Annotation> A getAnnotation(AnnotationProvider annotationProvider, Class<A> type) {
244      if (type == null)
245         return null;
246      Value<A> t = Value.empty();
247      for (MethodInfo m2 : _getMatching()) {
248         annotationProvider.forEachAnnotation(type, m2.inner(), x -> true, x -> t.set(x));
249         if (t.isPresent())
250            return t.get();
251      }
252      return null;
253   }
254
255   /**
256    * Returns <jk>true</jk> if the specified annotation is present on this method.
257    *
258    * @param <A> The annotation type to look for.
259    * @param type The annotation to look for.
260    * @return <jk>true</jk> if the specified annotation is present on this method.
261    */
262   public <A extends Annotation> boolean hasAnnotation(Class<A> type) {
263      return hasAnnotation(AnnotationProvider.DEFAULT, type);
264   }
265
266   /**
267    * Returns <jk>true</jk> if the specified annotation is present on this method.
268    *
269    * @param <A> The annotation type to look for.
270    * @param annotationProvider The annotation provider.
271    * @param type The annotation to look for.
272    * @return <jk>true</jk> if the specified annotation is present on this method.
273    */
274   public <A extends Annotation> boolean hasAnnotation(AnnotationProvider annotationProvider, Class<A> type) {
275      for (MethodInfo m2 : _getMatching())
276         if (annotationProvider.firstAnnotation(type, m2.inner(), x -> true) != null)
277            return true;
278      return false;
279   }
280
281   /**
282    * Returns <jk>true</jk> if the specified annotation is not present on this method.
283    *
284    * @param <A> The annotation type to look for.
285    * @param annotationProvider The annotation provider.
286    * @param type The annotation to look for.
287    * @return <jk>true</jk> if the specified annotation is not present on this method.
288    */
289   public <A extends Annotation> boolean hasNoAnnotation(AnnotationProvider annotationProvider, Class<A> type) {
290      return ! hasAnnotation(annotationProvider, type);
291   }
292
293   /**
294    * Returns <jk>true</jk> if the specified annotation is not present on this method.
295    *
296    * @param <A> The annotation type to look for.
297    * @param type The annotation to look for.
298    * @return <jk>true</jk> if the specified annotation is not present on this method.
299    */
300   public <A extends Annotation> boolean hasNoAnnotation(Class<A> type) {
301      return getAnnotation(type) == null;
302   }
303
304   /**
305    * Returns <jk>true</jk> if at least one of the specified annotation is present on this method.
306    *
307    * @param types The annotation to look for.
308    * @return <jk>true</jk> if at least one of the specified annotation is present on this method.
309    */
310   @SafeVarargs
311   public final boolean hasAnyAnnotations(Class<? extends Annotation>...types) {
312      for (Class<? extends Annotation> a : types)
313         if (hasAnnotation(a))
314            return true;
315      return false;
316   }
317
318   /**
319    * Performs an action on all matching annotations defined on this method.
320    *
321    * <p>
322    * Searches all methods with the same signature on the parent classes or interfaces
323    * and the return type on the method.
324    * <br>Results are parent-to-child ordered.
325    *
326    * @param <A> The annotation type to look for.
327    * @param type The annotation to look for.
328    * @param filter A predicate to apply to the entries to determine if action should be performed.  Can be <jk>null</jk>.
329    * @param action An action to perform on the entry.
330    * @return This object.
331    */
332   public <A extends Annotation> MethodInfo forEachAnnotation(Class<A> type, Predicate<A> filter, Consumer<A> action) {
333      return forEachAnnotation(AnnotationProvider.DEFAULT, type, filter, action);
334   }
335
336   /**
337    * Performs an action on all matching annotations defined on this method.
338    *
339    * <p>
340    * Searches all methods with the same signature on the parent classes or interfaces
341    * and the return type on the method.
342    * <br>Results are parent-to-child ordered.
343    *
344    * @param <A> The annotation type to look for.
345    * @param annotationProvider The annotation provider.
346    * @param type The annotation type.
347    * @param filter A predicate to apply to the entries to determine if action should be performed.  Can be <jk>null</jk>.
348    * @param action An action to perform on the entry.
349    * @return This object.
350    */
351   public <A extends Annotation> MethodInfo forEachAnnotation(AnnotationProvider annotationProvider, Class<A> type, Predicate<A> filter, Consumer<A> action) {
352      declaringClass.forEachAnnotation(annotationProvider, type, filter, action);
353      MethodInfo[] m = _getMatching();
354      for (int i = m.length-1; i >= 0; i--)
355         for (Annotation a2 : m[i]._getDeclaredAnnotations())
356            consume(type, filter, action, a2);
357      getReturnType().unwrap(Value.class,Optional.class).forEachAnnotation(annotationProvider, type, filter, action);
358      return this;
359   }
360
361   /**
362    * Returns the first annotation in the specified list on this method.
363    *
364    * @param types The annotations to look for.
365    * @return The first matching annotation.
366    */
367   @SafeVarargs
368   public final Annotation getAnyAnnotation(Class<? extends Annotation>...types) {
369      for (Class<? extends Annotation> cc : types) {
370         Annotation a = getAnnotation(cc);
371         if (a != null)
372            return a;
373      }
374      return null;
375   }
376
377   /**
378    * Constructs an {@link AnnotationList} of all annotations found on this method.
379    *
380    * <p>
381    * Annotations are appended in the following orders:
382    * <ol>
383    *    <li>On the package of this class.
384    *    <li>On interfaces ordered parent-to-child.
385    *    <li>On parent classes ordered parent-to-child.
386    *    <li>On this class.
387    *    <li>On this method and matching methods ordered parent-to-child.
388    * </ol>
389    *
390    * @return A new {@link AnnotationList} object on every call.
391    */
392   public AnnotationList getAnnotationList() {
393      return getAnnotationList(x -> true);
394   }
395
396   /**
397    * Constructs an {@link AnnotationList} of all matching annotations found on this method.
398    *
399    * <p>
400    * Annotations are appended in the following orders:
401    * <ol>
402    *    <li>On the package of this class.
403    *    <li>On interfaces ordered parent-to-child.
404    *    <li>On parent classes ordered parent-to-child.
405    *    <li>On this class.
406    *    <li>On this method and matching methods ordered parent-to-child.
407    * </ol>
408    *
409    * @param filter A predicate to apply to the entries to determine if value should be added.  Can be <jk>null</jk>.
410    * @return A new {@link AnnotationList} object on every call.
411    */
412   public AnnotationList getAnnotationList(Predicate<AnnotationInfo<?>> filter) {
413      AnnotationList al = new AnnotationList();
414      forEachAnnotationInfo(filter, x -> al.add(x));
415      return al;
416   }
417
418   /**
419    * Same as {@link #getAnnotationList(Predicate)} except only returns annotations defined on methods.
420    *
421    * @param filter A predicate to apply to the entries to determine if value should be added.  Can be <jk>null</jk>.
422    * @return A new {@link AnnotationList} object on every call.
423    */
424   public AnnotationList getAnnotationListMethodOnly(Predicate<AnnotationInfo<?>> filter) {
425      AnnotationList al = new AnnotationList();
426      forEachAnnotationInfoMethodOnly(filter, x -> al.add(x));
427      return al;
428   }
429
430   /**
431    * Perform an action on all matching annotations on this method.
432    *
433    * @param filter A predicate to apply to the entries to determine if action should be performed.  Can be <jk>null</jk>.
434    * @param action An action to perform on the entry.
435    * @return This object.
436    */
437   public MethodInfo forEachAnnotationInfo(Predicate<AnnotationInfo<?>> filter, Consumer<AnnotationInfo<?>> action) {
438      ClassInfo c = this.declaringClass;
439      forEachDeclaredAnnotationInfo(c.getPackage(), filter, action);
440      ClassInfo[] interfaces = c._getInterfaces();
441      for (int i = interfaces.length-1; i >= 0; i--) {
442         forEachDeclaredAnnotationInfo(interfaces[i], filter, action);
443         forEachDeclaredMethodAnnotationInfo(interfaces[i], filter, action);
444      }
445      ClassInfo[] parents = c._getParents();
446      for (int i = parents.length-1; i >= 0; i--) {
447         forEachDeclaredAnnotationInfo(parents[i], filter, action);
448         forEachDeclaredMethodAnnotationInfo(parents[i], filter, action);
449      }
450      return this;
451   }
452
453   private void forEachAnnotationInfoMethodOnly(Predicate<AnnotationInfo<?>> filter, Consumer<AnnotationInfo<?>> action) {
454      ClassInfo c = this.declaringClass;
455      ClassInfo[] interfaces = c._getInterfaces();
456      for (int i = interfaces.length-1; i >= 0; i--)
457         forEachDeclaredMethodAnnotationInfo(interfaces[i], filter, action);
458      ClassInfo[] parents = c._getParents();
459      for (int i = parents.length-1; i >= 0; i--)
460         forEachDeclaredMethodAnnotationInfo(parents[i], filter, action);
461   }
462
463   private void forEachDeclaredAnnotationInfo(Package p, Predicate<AnnotationInfo<?>> filter, Consumer<AnnotationInfo<?>> action) {
464      if (p != null)
465         for (Annotation a : p.getDeclaredAnnotations())
466            AnnotationInfo.of(p, a).accept(filter, action);
467   }
468
469   private void forEachDeclaredAnnotationInfo(ClassInfo ci, Predicate<AnnotationInfo<?>> filter, Consumer<AnnotationInfo<?>> action) {
470      if (ci != null)
471         for (Annotation a : ci._getDeclaredAnnotations())
472            AnnotationInfo.of(ci, a).accept(filter, action);
473   }
474
475   private void forEachDeclaredMethodAnnotationInfo(ClassInfo ci, Predicate<AnnotationInfo<?>> filter, Consumer<AnnotationInfo<?>> action) {
476      MethodInfo m = findMatchingOnClass(ci);
477      if (m != null)
478         for (Annotation a : m._getDeclaredAnnotations())
479            AnnotationInfo.of(m, a).accept(filter, action);
480   }
481
482   //-----------------------------------------------------------------------------------------------------------------
483   // Return type.
484   //-----------------------------------------------------------------------------------------------------------------
485
486   /**
487    * Returns the generic return type of this method as a {@link ClassInfo} object.
488    *
489    * @return The generic return type of this method.
490    */
491   public ClassInfo getReturnType() {
492      if (returnType == null) {
493         synchronized(this) {
494            returnType = ClassInfo.of(m.getReturnType(), m.getGenericReturnType());
495         }
496      }
497      return returnType;
498   }
499
500   /**
501    * Returns <jk>true</jk> if this method has this return type.
502    *
503    * @param c The return type to test for.
504    * @return <jk>true</jk> if this method has this return type.
505    */
506   public boolean hasReturnType(Class<?> c) {
507      return m.getReturnType() == c;
508   }
509
510   /**
511    * Returns <jk>true</jk> if this method has this return type.
512    *
513    * @param ci The return type to test for.
514    * @return <jk>true</jk> if this method has this return type.
515    */
516   public boolean hasReturnType(ClassInfo ci) {
517      return hasReturnType(ci.inner());
518   }
519
520   /**
521    * Returns <jk>true</jk> if this method has this parent return type.
522    *
523    * @param c The return type to test for.
524    * @return <jk>true</jk> if this method has this parent return type.
525    */
526   public boolean hasReturnTypeParent(Class<?> c) {
527      return ClassInfo.of(c).isParentOf(m.getReturnType());
528   }
529
530   /**
531    * Returns <jk>true</jk> if this method has this parent return type.
532    *
533    * @param ci The return type to test for.
534    * @return <jk>true</jk> if this method has this parent return type.
535    */
536   public boolean hasReturnTypeParent(ClassInfo ci) {
537      return hasReturnTypeParent(ci.inner());
538   }
539
540   //-----------------------------------------------------------------------------------------------------------------
541   // Other methods
542   //-----------------------------------------------------------------------------------------------------------------
543
544   /**
545    * Returns <jk>true</jk> if this object passes the specified predicate test.
546    *
547    * @param test The test to perform.
548    * @return <jk>true</jk> if this object passes the specified predicate test.
549    */
550   public boolean matches(Predicate<MethodInfo> test) {
551      return test(test, this);
552   }
553
554   /**
555    * Performs an action on this object if the specified predicate test passes.
556    *
557    * @param test A test to apply to determine if action should be executed.  Can be <jk>null</jk>.
558    * @param action An action to perform on this object.
559    * @return This object.
560    */
561   public MethodInfo accept(Predicate<MethodInfo> test, Consumer<MethodInfo> action) {
562      if (matches(test))
563         action.accept(this);
564      return this;
565   }
566
567   /**
568    * Shortcut for calling the invoke method on the underlying method.
569    *
570    * @param <T> The method return type.
571    * @param obj the object the underlying method is invoked from.
572    * @param args the arguments used for the method call
573    * @return The object returned from the method.
574    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
575    */
576   @SuppressWarnings("unchecked")
577   public <T> T invoke(Object obj, Object...args) throws ExecutableException {
578      try {
579         return (T)m.invoke(obj, args);
580      } catch (IllegalAccessException e) {
581         throw new ExecutableException(e);
582      } catch (InvocationTargetException e) {
583         throw new ExecutableException(e.getTargetException());
584      }
585   }
586
587   /**
588    * Invokes the specified method using fuzzy-arg matching.
589    *
590    * <p>
591    * Arguments will be matched to the parameters based on the parameter types.
592    * <br>Arguments can be in any order.
593    * <br>Extra arguments will be ignored.
594    * <br>Missing arguments will be left <jk>null</jk>.
595    *
596    * <p>
597    * Note that this only works for methods that have distinguishable argument types.
598    * <br>It's not going to work on methods with generic argument types like <c>Object</c>
599    *
600    * @param pojo
601    *    The POJO the method is being called on.
602    *    <br>Can be <jk>null</jk> for static methods.
603    * @param args
604    *    The arguments to pass to the method.
605    * @return
606    *    The results of the method invocation.
607    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
608    */
609   public Object invokeFuzzy(Object pojo, Object...args) throws ExecutableException {
610      try {
611         return m.invoke(pojo, ClassUtils.getMatchingArgs(m.getParameterTypes(), args));
612      } catch (IllegalAccessException | InvocationTargetException e) {
613         throw new ExecutableException(e);
614      }
615   }
616
617   /**
618    * Returns the signature of this method.
619    *
620    * <p>
621    * For no-arg methods, the signature will be a simple string such as <js>"toString"</js>.
622    * For methods with one or more args, the arguments will be fully-qualified class names (e.g.
623    * <js>"append(java.util.StringBuilder,boolean)"</js>)
624    *
625    * @return The methods signature.
626    */
627   public String getSignature() {
628      StringBuilder sb = new StringBuilder(128);
629      sb.append(m.getName());
630      Class<?>[] pt = _getRawParamTypes();
631      if (pt.length > 0) {
632         sb.append('(');
633         List<ParamInfo> mpi = getParams();
634         for (int i = 0; i < pt.length; i++) {
635            if (i > 0)
636               sb.append(',');
637            mpi.get(i).getParameterType().appendFullName(sb);
638         }
639         sb.append(')');
640      }
641      return sb.toString();
642   }
643
644   /**
645    * Returns the bean property name if this is a getter or setter.
646    *
647    * @return The bean property name, or <jk>null</jk> if this isn't a getter or setter.
648    */
649   public String getPropertyName() {
650      String n = m.getName();
651      if ((n.startsWith("get") || n.startsWith("set")) && n.length() > 3)
652         return Introspector.decapitalize(n.substring(3));
653      if (n.startsWith("is") && n.length() > 2)
654         return Introspector.decapitalize(n.substring(2));
655      return n;
656   }
657
658   /**
659    * Returns <jk>true</jk> if the parameters on the method only consist of the types specified in the list.
660    *
661    * <h5 class='figure'>Example:</h5>
662    * <p class='bjava'>
663    *
664    *    <jc>// Example method:</jc>
665    *    <jk>public void</jk> foo(String <jv>bar</jv>, Integer <jv>baz</jv>);
666    *
667    *    argsOnlyOfType(<jv>fooMethod</jv>, String.<jk>class</jk>, Integer.<jk>class</jk>);  <jc>// True.</jc>
668    *    argsOnlyOfType(<jv>fooMethod</jv>, String.<jk>class</jk>, Integer.<jk>class</jk>, Map.<jk>class</jk>);  <jc>// True.</jc>
669    *    argsOnlyOfType(<jv>fooMethod</jv>, String.<jk>class</jk>);  <jc>// False.</jc>
670    * </p>
671    *
672    * @param args The valid class types (exact) for the arguments.
673    * @return <jk>true</jk> if the method parameters only consist of the types specified in the list.
674    */
675   public boolean argsOnlyOfType(Class<?>...args) {
676      for (Class<?> c1 : _getRawParamTypes()) {
677         boolean foundMatch = false;
678         for (Class<?> c2 : args)
679            if (c1 == c2)
680               foundMatch = true;
681         if (! foundMatch)
682            return false;
683      }
684      return true;
685   }
686
687   /**
688    * Returns <jk>true</jk> if this method has at least the specified parameters.
689    *
690    * <p>
691    * Method may or may not have additional parameters besides those specified.
692    *
693    * @param requiredParams The parameter types to check for.
694    * @return <jk>true</jk> if this method has at least the specified parameters.
695    */
696   public boolean hasAllArgs(Class<?>...requiredParams) {
697      List<Class<?>> rawParamTypes = getRawParamTypes();
698
699      for (Class<?> c : requiredParams)
700         if (! rawParamTypes.contains(c))
701            return false;
702
703      return true;
704   }
705
706   /**
707    * Returns <jk>true</jk> if this method has the specified parameter.
708    *
709    * <p>
710    * Method may or may not have additional parameters besides the one specified.
711    *
712    * @param requiredParam The parameter type to check for.
713    * @return <jk>true</jk> if this method has at least the specified parameter.
714    */
715   public boolean hasArg(Class<?> requiredParam) {
716      return hasAllArgs(requiredParam);
717   }
718
719   /**
720    * Returns <jk>true</jk> if this method is a bridge method.
721    *
722    * @return <jk>true</jk> if this method is a bridge method.
723    */
724   public boolean isBridge() {
725      return m.isBridge();
726   }
727
728   /**
729    * Returns the name of this method.
730    *
731    * @return The name of this method
732    */
733   public String getName() {
734      return m.getName();
735   }
736
737   @Override
738   public int compareTo(MethodInfo o) {
739      int i = getSimpleName().compareTo(o.getSimpleName());
740      if (i == 0) {
741         i = _getRawParamTypes().length - o._getRawParamTypes().length;
742         if (i == 0) {
743            for (int j = 0; j < _getRawParamTypes().length && i == 0; j++) {
744               i = _getRawParamTypes()[j].getName().compareTo(o._getRawParamTypes()[j].getName());
745            }
746         }
747      }
748      return i;
749   }
750   @Override /* Overridden from ExecutableInfo */
751   public MethodInfo accessible() {
752      super.accessible();
753      return this;
754   }
755}