View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.api.util;
21  
22  
23  import org.apache.directory.api.i18n.I18n;
24  import org.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  
27  import java.lang.reflect.Method;
28  import java.util.Arrays;
29  
30  
31  /**
32   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
33   */
34  public final class MethodUtils
35  {
36      /** The logger. */
37      private static final Logger LOG = LoggerFactory.getLogger( MethodUtils.class );
38  
39  
40      /**
41       * Private constructor.
42       */
43      private MethodUtils()
44      {
45      }
46  
47  
48      /**
49       * A replacement for {@link java.lang.Class#getMethod} with extended capability.
50       * 
51       * <p>
52       * This method returns parameter-list assignment-compatible method as well as
53       * exact-signature matching method.
54       * 
55       * @param clazz The class which will be queried for the method.
56       * @param candidateMethodName Name of the method been looked for.
57       * @param candidateParameterTypes Types of the parameters in the signature of the method being loooked for.
58       * @return The Method found.
59       * @throws NoSuchMethodException when the method cannot be found
60       */
61      public static Method getAssignmentCompatibleMethod( Class<?> clazz,
62          String candidateMethodName,
63          Class<?>[] candidateParameterTypes
64          ) throws NoSuchMethodException
65      {
66          if ( LOG.isDebugEnabled() )
67          {
68              StringBuilder buf = new StringBuilder();
69              buf.append( "call to getAssignmentCompatibleMethod(): \n\tclazz = " );
70              buf.append( clazz.getName() );
71              buf.append( "\n\tcandidateMethodName = " );
72              buf.append( candidateMethodName );
73              buf.append( "\n\tcandidateParameterTypes = " );
74  
75              for ( Class<?> argClass : candidateParameterTypes )
76              {
77                  buf.append( "\n\t\t" );
78                  buf.append( argClass.getName() );
79              }
80  
81              if ( LOG.isDebugEnabled() )
82              {
83                  LOG.debug( buf.toString() );
84              }
85          }
86  
87          try
88          {
89              // Look for exactly the same signature.
90              Method exactMethod = clazz.getMethod( candidateMethodName, candidateParameterTypes );
91  
92              if ( exactMethod != null )
93              {
94                  return exactMethod;
95              }
96          }
97          catch ( Exception e )
98          {
99              if ( LOG.isInfoEnabled() )
100             {
101                 LOG.info( I18n.msg( I18n.MSG_17009_NO_EXACT_MATCH, candidateMethodName, e ) );
102             }
103         }
104 
105         /**
106          * Look for the assignment-compatible signature.
107          */
108 
109         // Get all methods of the class.
110         Method[] methods = clazz.getMethods();
111 
112         // For each method of the class...
113         for ( int mx = 0; mx < methods.length; mx++ )
114         {
115             // If the method name does not match...
116             if ( !candidateMethodName.equals( methods[mx].getName() ) )
117             {
118                 // ... Go on with the next method.
119                 continue;
120             }
121 
122             // ... Get parameter types list.
123             Class<?>[] parameterTypes = methods[mx].getParameterTypes();
124 
125             // If parameter types list length mismatch...
126             if ( parameterTypes.length != candidateParameterTypes.length )
127             {
128                 // ... Go on with the next method.
129                 continue;
130             }
131             // If parameter types list length is OK...
132             // ... For each parameter of the method...
133             for ( int px = 0; px < parameterTypes.length; px++ )
134             {
135                 // ... If the parameter is not assignment-compatible with the candidate parameter type...
136                 if ( !parameterTypes[px].isAssignableFrom( candidateParameterTypes[px] ) )
137                 {
138                     // ... Go on with the next method.
139                     break;
140                 }
141             }
142 
143             // Return the only one possible and found method.
144             return methods[mx];
145         }
146 
147         throw new NoSuchMethodException( clazz.getName() + "." + candidateMethodName
148             + "(" + Arrays.toString( candidateParameterTypes ) + ")" );
149     }
150 }