KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > iapi > services > loader > ClassInspector


1 /*
2
3    Derby - Class org.apache.derby.iapi.services.loader.ClassInspector
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.iapi.services.loader;
23
24 import org.apache.derby.iapi.services.sanity.SanityManager;
25
26 import org.apache.derby.iapi.error.StandardException;
27
28 import org.apache.derby.iapi.reference.SQLState;
29
30 import java.lang.reflect.*;
31 import java.util.StringTokenizer JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.ArrayList JavaDoc;
34 import java.util.NoSuchElementException JavaDoc;
35 import java.util.Collections JavaDoc;
36
37 /**
38     Methods to find out relationships between classes and methods within a class.
39     All class names within this interface are treated as java language class names,
40     e.g. int, COM.foo.Myclass, int[], java.lang.Object[]. That is java internal
41     class names as defined in the class file format are not understood.
42 */

43 public final class ClassInspector
44 {
45     private static final String JavaDoc[] primTypeNames =
46         {"boolean", "byte", "char", "short", "int", "long", "float", "double"};
47
48     // collect these as static, instead of each time allocates these new
49
// Strings for every method resolution
50

51     private static final String JavaDoc[] nonPrimTypeNames =
52         {"java.lang.Boolean", "java.lang.Byte", "java.lang.Character",
53          "java.lang.Short", "java.lang.Integer", "java.lang.Long",
54          "java.lang.Float", "java.lang.Double"};
55
56     private final ClassFactory cf;
57
58     /**
59         DO NOT USE! use the method in ClassFactory.
60     */

61     public ClassInspector(ClassFactory cf) {
62         this.cf = cf;
63     }
64     
65     /**
66      * Is the given object an instance of the named class?
67      *
68      * @param className The name of the class
69      * @param obj The object to test to see if it's an instance
70      * of the named class
71      *
72      * @return true if obj is an instanceof className, false if not
73      */

74     public boolean instanceOf(String JavaDoc className, Object JavaDoc obj)
75         throws ClassNotFoundException JavaDoc
76     {
77         Class JavaDoc clazz = getClass(className);
78         // is className an untyped null
79
if (clazz == null)
80             return false;
81
82         return clazz.isInstance(obj);
83     }
84
85     /**
86      * Is one named class assignable to another named class or interface?
87      *
88      * @param fromClassName The name of the class to be assigned
89      * @param toClassName The name of the class to be assigned to
90      *
91      * @return true if an object of type fromClass can be assigned to an
92      * object of type toClass, false if not.
93      */

94     public boolean assignableTo(String JavaDoc fromClassName, String JavaDoc toClassName)
95     {
96         try
97         {
98             Class JavaDoc toClass = getClass(toClassName);
99             // is toClass an untyped null
100
if (toClass == null) {
101                 return false;
102             }
103
104             Class JavaDoc fromClass = getClass(fromClassName);
105
106             // is fromClass an untyped null
107
if (fromClass == null)
108                 return !toClass.isPrimitive() || (toClass == Void.TYPE);
109
110
111             return toClass.isAssignableFrom(fromClass);
112         }
113         catch (ClassNotFoundException JavaDoc cnfe)
114         {
115             /* If either class can't be found, they can't be assigned */
116             return false;
117         }
118     }
119
120     /**
121      * Does the named class exist, and is it accessible?
122      *
123      * @param className The name of the class to test for existence
124      *
125      * @return true if the class exists and is accessible, false if not
126      */

127     public boolean accessible(String JavaDoc className)
128         throws ClassNotFoundException JavaDoc
129     {
130         Class JavaDoc theClass = getClass(className);
131         if (theClass == null)
132             return false;
133
134         /* Classes must be public to be accessible */
135         if (! Modifier.isPublic(theClass.getModifiers()))
136             return false;
137
138         return true;
139     }
140
141
142     /**
143      * Get the Java name of the return type from a Member representing
144      * a method or the type of a Member representing a field.
145      *
146      * @param member A Member representing the method for
147      * which we want the return type.
148      *
149      * @return A Java-language-style string describing the return type of
150      * the method (for example, it returns "int" instead of "I".
151      */

152     public String JavaDoc getType(Member member)
153     {
154         Class JavaDoc type;
155
156         if (member instanceof Method)
157             type = ((Method) member).getReturnType();
158         else if (member instanceof Field)
159             type = ((Field) member).getType();
160         else if (member instanceof Constructor)
161             type = ((Constructor) member).getDeclaringClass();
162         else
163             type = Void.TYPE;
164
165         return ClassInspector.readableClassName(type);
166     }
167
168
169     /**
170      * Find a public method that implements a given signature.
171      * The signature is given using the full Java class names of the types.
172      <BR>
173      * A untyped null paramter is indicated by passing in an empty string ("")
174      * as its class name.
175      <BR>
176      If receiverType respresents an interface then the methods of java.lang.Object
177      arer included in the candidate list.
178      <BR>
179      If the caller is simply checking to see that a public method with the
180      specified name exists, regardless of the signature, exists, then the
181      caller should pass in a null for parmTypes. (This is useful for checking
182      the validity of a method alias when creating one.)
183      <BR>
184      We use a two-pass algorithm to resolve methods. In the first pass, we
185      use all "object" types to try to match a method. If this fails, in the
186      second pass, an array of "primitive" types (if the parameter has one,
187      otherwise the same object type is used) is passed in, as well as the
188      "object" type array. For each parameter of a method, we try to match it
189      against either the "object" type, or the "primitive" type. Of all the
190      qualified candidate methods found, we choose the closest one to the input
191      parameter types. This involves comparing methods whose parameters are
192      mixed "object" and "primitive" types in the second pass. This is
193      eventually handled in classConvertableFromTo.
194      *
195      * @param receiverType The class name of the receiver
196      * @param methodName The name of the method
197      * @param parmTypes An array of class names representing the
198      * parameter types. Pass a zero-element array if
199      * there are no parameters. Pass a null if it is
200      * okay to match any signature.
201      * @param primParmTypes This is used in the second pass of the two-pass
202      * method resolution algorithm. Use primitive type
203      * if it has one, otherwise use same object type
204      * @param isParam Array of booleans telling whether parameter is a ?.
205      * @param staticMethod Find a static method.
206        @param repeatLastParameter If true the last parameter may be repeated any number of times (total count must be greater than one).
207        If false the laste parameter is matched as usual. This also requires an exact match on the last parameter type.
208      *
209      * @return A Member representing the matching method. Returns null
210      * if no such method.
211      *
212      * @exception ClassNotFoundException One or more of the classes does
213      * not exist.
214      * @exception StandardException Thrown on ambiguous method invocation.
215      *
216      * @see Member
217      * @see Modifier
218      */

219     public Member findPublicMethod(String JavaDoc receiverType,
220                                 String JavaDoc methodName,
221                                 String JavaDoc[] parmTypes,
222                                 String JavaDoc[] primParmTypes,
223                                 boolean[] isParam,
224                                 boolean staticMethod,
225                                 boolean repeatLastParameter)
226                     throws ClassNotFoundException JavaDoc, StandardException
227     {
228         Class JavaDoc receiverClass = getClass(receiverType);
229         if (receiverClass == null)
230             return null;
231
232         // primitives don't have methods
233
// note that arrays do since they are objects they have
234
// all the methods of java.lang.Object
235
if (receiverClass.isPrimitive()) {
236             return null;
237         }
238
239         // if parmTypes is null, then the caller is simply
240
// looking to see if any public method with the
241
// specified name exists, regardless of its signature
242
if (parmTypes == null) {
243             Method[] methods = receiverClass.getMethods();
244             
245             for (int index = 0; index < methods.length; index++) {
246                 if (staticMethod) {
247                     if (!Modifier.isStatic(methods[index].getModifiers())) {
248                         continue;
249                     }
250                 }
251
252                 if (methodName.equals(methods[index].getName())) {
253                     // We found a match
254
return methods[index];
255                 }
256             }
257             // No match
258
return null;
259         }
260
261         // convert the parameter types to classes
262
Class JavaDoc[] paramClasses = new Class JavaDoc[parmTypes.length];
263         Class JavaDoc[] primParamClasses = null;
264         if (primParmTypes != null)
265             primParamClasses = new Class JavaDoc[primParmTypes.length];
266         for (int i = 0; i < paramClasses.length; i++)
267         {
268             paramClasses[i] = getClass(parmTypes[i]);
269             if (primParmTypes == null)
270                 continue;
271             if (primParmTypes[i].equals(parmTypes[i])) // no separate primitive
272
primParamClasses[i] = null;
273             else
274                 primParamClasses[i] = getClass(primParmTypes[i]);
275         }
276
277         // no overloading possible if there are no arguments, so perform
278
// an exact match lookup.
279
if (paramClasses.length == 0) {
280
281             try {
282                 Method method = receiverClass.getMethod(methodName, paramClasses);
283
284                 if (staticMethod) {
285                     if (!Modifier.isStatic(method.getModifiers()))
286                         return null;
287                 }
288
289                 return method;
290
291                 } catch (NoSuchMethodException JavaDoc nsme2) {
292
293
294                     // if we are an interface then the method could be defined on Object
295
if (!receiverClass.isInterface())
296                         return null;
297                 }
298         }
299
300         // now the tricky method resolution
301
Member[] methodList = receiverClass.getMethods();
302         // if we have an interface we need to add the methods of Object into the mix
303
if (receiverClass.isInterface()) {
304
305             Member[] objectMethods = java.lang.Object JavaDoc.class.getMethods();
306             if (methodList.length == 0) {
307                 methodList = objectMethods;
308             } else {
309                 Member[] set = new Member[methodList.length + objectMethods.length];
310                 System.arraycopy(methodList, 0, set, 0, methodList.length);
311                 System.arraycopy(objectMethods, 0, set, methodList.length, objectMethods.length);
312                 methodList = set;
313             }
314         }
315
316         return resolveMethod(receiverClass, methodName, paramClasses,
317                         primParamClasses, isParam, staticMethod, repeatLastParameter, methodList);
318     }
319
320
321     /**
322      * Find a public field for a class.
323        This follows the sematics of the java compiler for locating a field.
324        This means if a field fieldName exists in the class with package, private or
325        protected then an error is raised. Even if the field hides a field fieldName
326        in a super-class/super--interface. See the JVM spec on fields.
327      *
328      * @param receiverType The class name of the receiver
329      * @param fieldName The name of the field
330      * @param staticField Find a static field
331      *
332      * @return A Member representing the matching field.
333      * @exception StandardException Class or field does not exist or is not public or a security exception.
334      *
335      * @see Member
336      * @see Modifier
337      */

338     public Member findPublicField(String JavaDoc receiverType,
339                                 String JavaDoc fieldName,
340                                 boolean staticField)
341                     throws StandardException
342     {
343
344         Exception JavaDoc e = null;
345         try {
346
347             Class JavaDoc receiverClass = getClass(receiverType);
348             if (receiverClass == null)
349                 return null;
350             if (receiverClass.isArray() || receiverClass.isPrimitive()) {
351                 // arrays don't have fields (the fake field 'length' is not returned here)
352
return null;
353             }
354   
355             int modifier = staticField ? (Modifier.PUBLIC | Modifier.STATIC) : Modifier.PUBLIC;
356
357             // Look for a public field first
358
Field publicField = receiverClass.getField(fieldName);
359
360             if ((publicField.getModifiers() & modifier) == modifier)
361             {
362                 /*
363                     If the class is an interface then we avoid looking for a declared field
364                     that can hide a super-class's public field and not be accessable. This is because
365                     a interface's fields are always public. This avoids a security check.
366                 */

367                 if (receiverClass.isInterface() || (publicField.getDeclaringClass().equals(receiverClass)))
368                     return publicField;
369
370                 /*
371                     Now check to see if there is a declared field that hides the public field.
372                 */

373
374                 try {
375
376                     Field declaredField = receiverClass.getDeclaredField(fieldName);
377
378                     if (SanityManager.DEBUG) {
379
380                         if ((declaredField.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC)
381                             SanityManager.THROWASSERT("declared field not expected to be public here " + declaredField);
382                     }
383
384                 } catch (NoSuchFieldException JavaDoc nsfe) {
385
386                     // no field hides the public field in the super class
387
return publicField;
388                 }
389             }
390
391         } catch (ClassNotFoundException JavaDoc cnfe) {
392             e = cnfe;
393         } catch (NoSuchFieldException JavaDoc nsfep) {
394             e = nsfep;
395         } catch (SecurityException JavaDoc se) {
396             e = se;
397         }
398
399         throw StandardException.newException(
400             staticField ? SQLState.LANG_NO_STATIC_FIELD_FOUND : SQLState.LANG_NO_FIELD_FOUND,
401                                 e, fieldName, receiverType);
402     }
403
404     /**
405      * Find a public constructor that implements a given signature.
406      * The signature is given using the full Java class names of the types.
407      <BR>
408      * A untyped null paramter is indicated by passing in an empty string ("")
409      * as its class name.
410      *
411      * @param receiverType The class name of the receiver
412      * @param parmTypes An array of class names representing the
413      * parameter types. Pass a zero-element array if
414      * there are no parameters.
415      * @param primParmTypes This is used in the second pass of the two-pass
416      * method resolution algorithm. Use primitive type
417      * if it has one, otherwise use same object type
418      * @param isParam Array of booleans telling whether parameter is a ?.
419      *
420      * @return A Member representing the matching constructor. Returns null
421      * if no such constructor.
422      *
423      * @exception ClassNotFoundException One or more of the classes does
424      * not exist.
425      * @exception StandardException Thrown on ambiguous constructor invocation.
426      *
427      * @see Member
428      * @see Modifier
429      */

430     public Member findPublicConstructor(String JavaDoc receiverType,
431                                     String JavaDoc[] parmTypes,
432                                     String JavaDoc[] primParmTypes,
433                                     boolean[] isParam)
434                         throws ClassNotFoundException JavaDoc, StandardException
435     {
436         Class JavaDoc receiverClass = getClass(receiverType);
437         if (receiverClass == null)
438             return null;
439
440         // arrays, primitives, and interfaces do not have constructors
441
if (receiverClass.isArray() || receiverClass.isPrimitive() || receiverClass.isInterface()) {
442             return null;
443         }
444
445         // convert the parameter types to classes
446
Class JavaDoc[] paramClasses = new Class JavaDoc[parmTypes.length];
447         Class JavaDoc[] primParamClasses = null;
448         if (primParmTypes != null)
449             primParamClasses = new Class JavaDoc[primParmTypes.length];
450         boolean unknownParameters = false;
451         for (int i = 0; i < paramClasses.length; i++) {
452             paramClasses[i] = getClass(parmTypes[i]);
453             if (paramClasses[i] == null)
454                 unknownParameters = true;
455             if (primParmTypes == null)
456                 continue;
457             if (primParmTypes[i].equals(parmTypes[i])) // no separate primitive
458
primParamClasses[i] = null;
459             else
460                 primParamClasses[i] = getClass(primParmTypes[i]);
461         }
462
463         try {
464
465             if (!unknownParameters && (primParmTypes == null)) {
466                 // look for an exact match for first pass
467
Member method = receiverClass.getConstructor(paramClasses);
468
469                 return method;
470             }
471
472         } catch (NoSuchMethodException JavaDoc nsme) {
473
474             // no overloading possible if there are no arguments
475
if (paramClasses.length == 0)
476                 return null;
477
478             // now the tricky method resolution
479
}
480
481         // name is only used for debugging
482
return resolveMethod(receiverClass, "<init>", paramClasses,
483                              primParamClasses, isParam, false, false,
484                              receiverClass.getConstructors());
485     }
486
487     /**
488      * Get the parameter types for a method described by a Member as a String[].
489      *
490      * @param method A Member describing a method
491      *
492      * @return A String[] describing the parameters of the method
493      */

494     public String JavaDoc[] getParameterTypes(Member method)
495     {
496
497         Class JavaDoc[] parameterClasses;
498         if (method instanceof Method) {
499             parameterClasses = ((Method) method).getParameterTypes();
500         } else {
501             parameterClasses = ((Constructor) method).getParameterTypes();
502         }
503
504         String JavaDoc[] parameterTypes = new String JavaDoc[parameterClasses.length];
505
506         for (int i = 0; i < parameterTypes.length; i++) {
507             parameterTypes[i] = ClassInspector.readableClassName(parameterClasses[i]);
508         }
509
510         return parameterTypes;
511     }
512
513     /**
514      * Determine whether a type is a Java primitive, like int or boolean
515      *
516      * @param typeName The name of the Java type
517      *
518      * @return true if it's a primitive type
519      */

520     public static boolean primitiveType(String JavaDoc typeName)
521     {
522         for (int i = 0; i < primTypeNames.length; i++)
523         {
524             if (typeName.equals(primTypeNames[i]))
525                 return true;
526         }
527
528         return false;
529     }
530
531
532     /**
533      * Tricky function to resolve a method. If primParamClasses is null
534      * we know it's first pass. First pass try to match as all "object"
535      * types, second pass try to match any combination of "object" and
536      * "primitive" types. Find the closest match among all the qualified
537      * candidates. If there's a tie, it's ambiguous.
538      *
539      * @param receiverClass the class who holds the methods
540      * @param methodName the name of method
541      * @param paramClasses object type classes of input parameters
542      * @param primParamClasses primitive type classes or null
543      * @param isParam isParam (for ?) array
544      * @param staticMethod static method or not
545      * @param methods method stack
546      * @return the matched method
547      *
548      **/

549     private Member resolveMethod(
550                 Class JavaDoc receiverClass,
551                 String JavaDoc methodName,
552                 Class JavaDoc[] paramClasses,
553                 Class JavaDoc[] primParamClasses,
554                 boolean[] isParam,
555                 boolean staticMethod,
556                 boolean repeatLastParameter,
557                 Member[] methods)
558             throws StandardException
559     {
560
561         if (SanityManager.DEBUG) {
562           if (SanityManager.DEBUG_ON("MethodResolutionInfo"))
563           {
564             SanityManager.DEBUG("MethodResolutionInfo",
565                 "MRI - Begin method resolution trace for " + methodName +
566                 "() with " + paramClasses.length + (repeatLastParameter ? "+" : "") + " parameters");
567
568             for (int parmCtr = 0; parmCtr < paramClasses.length; parmCtr++)
569             {
570                 SanityManager.DEBUG("MethodResolutionInfo",
571                     "MRI - Parameter #" + parmCtr +
572                     " is of type " + (paramClasses[parmCtr] == null ? "null" : paramClasses[parmCtr].getName()));
573             }
574           }
575         }
576             
577         /* Step through all the methods available in this class */
578         int candidateIndex = -1;
579
580         boolean firstTimeAround = true;
581         boolean ambiguous;
582         boolean somethingChanged;
583         do {
584
585             ambiguous = false;
586             somethingChanged = false;
587
588 nextMethod: for (int i = 0; i < methods.length; i++) {
589
590                 Member currentMethod = methods[i];
591
592                 // on second and later times around there will be null entries
593
// also, don't compare ourself to ourself
594
if ((currentMethod == null) ||
595                     (i == candidateIndex))
596                 {
597                     continue;
598                 }
599
600                 // must have the same number of parameters
601
Class JavaDoc[] currentMethodParameters = currentMethod instanceof Method ?
602                     ((Method) currentMethod).getParameterTypes():
603                     ((Constructor) currentMethod).getParameterTypes();
604
605                 // only check the basic stuff once
606
if (firstTimeAround) {
607
608                     if (repeatLastParameter) {
609                         // match any number of parameters greater or equal to
610
// the passed in number, but repeating the last type.
611
if (currentMethodParameters.length < paramClasses.length) {
612                             methods[i] = null; // remove non-applicable methods
613
continue;
614                         }
615
616
617                     } else {
618
619                         // regular match on parameter count
620
if (currentMethodParameters.length != paramClasses.length) {
621                             methods[i] = null; // remove non-applicable methods
622
continue;
623                         }
624                     }
625
626                     /* Look only at methods that match the modifiers */
627                     if (staticMethod && !Modifier.isStatic(currentMethod.getModifiers())) {
628                         methods[i] = null; // remove non-applicable methods
629
continue;
630                     }
631
632                     /* Look only at methods with the right name */
633                     if (!methodName.startsWith("<")) {
634                         if ( ! methodName.equals(currentMethod.getName())) {
635                             methods[i] = null; // remove non-applicable methods
636
continue;
637                         }
638                     }
639
640
641                     if (repeatLastParameter) {
642                         // With N parameters requested check all parameters from N-1 to end are equal
643
// to the requested parameter.
644
for (int pr = paramClasses.length - 1; pr < currentMethodParameters.length; pr++) {
645                             if (!currentMethodParameters[pr].equals(paramClasses[paramClasses.length - 1])) {
646                                 methods[i] = null; // remove non-applicable methods
647
continue nextMethod;
648                             }
649                         }
650                     }
651                 }
652
653                 if (SanityManager.DEBUG) {
654                   if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
655                     SanityManager.DEBUG("MethodResolutionInfo",
656                         "MRI - Considering :" + currentMethod.toString());
657                   }
658                 }
659
660
661                 // can the required signature be converted to those of this method
662
if (!signatureConvertableFromTo(paramClasses, primParamClasses,
663                             currentMethodParameters, isParam, false)) {
664
665                     if (SanityManager.DEBUG) {
666                       if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
667                         SanityManager.DEBUG("MethodResolutionInfo",
668                             "MRI - Skipping :" + currentMethod.toString());
669                       }
670                     }
671
672                     methods[i] = null; // remove non-applicable methods
673
continue;
674                 }
675
676
677             if (SanityManager.DEBUG) {
678                   if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
679                     SanityManager.DEBUG("MethodResolutionInfo", "MRI - Match found ");
680                   }
681                 }
682
683                 /* Is this the first match? */
684                 if (candidateIndex == -1)
685                 {
686                     candidateIndex = i;
687                     if (SanityManager.DEBUG) {
688                       if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
689                         SanityManager.DEBUG("MethodResolutionInfo",
690                         "MRI - Current method is now candidate");
691                       }
692                     }
693                     continue;
694                 }
695
696                 /* Not the first match, so find out which one, if either one,
697                  * has the best match on the parameters. (No narrowing
698                  * conversions.) 15.11 of Java Language Specification.
699                  */

700
701                 Member candidateMethod = methods[candidateIndex];
702
703                 // If the candidate method is more specific than the current
704
// method then the candidate method is still the maximally specific method
705
// Note at this point we could still have a ambiguous situation.
706

707                 boolean candidateMoreOrEqual = isMethodMoreSpecificOrEqual(
708                             candidateMethod, currentMethod, isParam);
709                 boolean currentMoreOrEqual = isMethodMoreSpecificOrEqual(
710                             currentMethod, candidateMethod, isParam);
711                 if (candidateMoreOrEqual && ! currentMoreOrEqual) {
712                     if (SanityManager.DEBUG) {
713                       if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
714                         SanityManager.DEBUG("MethodResolutionInfo",
715                         "MRI - Candidate is still maximally specific");
716                       }
717                     }
718                     methods[i] = null; // remove non-applicable methods
719
continue;
720                 }
721
722                 // if the current method is more specific than the candidiate
723
// method then it becomes the new maximally specific method
724
// Note at this point we could still have a ambiguous situation.
725

726                 if (currentMoreOrEqual && ! candidateMoreOrEqual) {
727                     if (SanityManager.DEBUG) {
728                       if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
729                         SanityManager.DEBUG("MethodResolutionInfo",
730                         "MRI - Current method is now candidate, replaced previous candidate");
731                       }
732                     }
733                     methods[candidateIndex] = null; // remove non-applicable methods
734
candidateIndex = i;
735                     somethingChanged = true;
736                     continue;
737                 }
738
739                 /* We have seen an ambiguous situation; one of the cases may
740                  * tie on each parameter.
741                  */

742                 ambiguous = true;
743
744                 if (SanityManager.DEBUG) {
745                   if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
746                     SanityManager.DEBUG("MethodResolutionInfo", "MRI - Ambiguous match");
747                   }
748                 }
749             }
750             firstTimeAround = false;
751         } while (ambiguous && somethingChanged);
752
753         if (SanityManager.DEBUG) {
754           if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
755             SanityManager.DEBUG("MethodResolutionInfo",
756                 "MRI - End method resolution trace for " + methodName + "()" +
757                 "\nMRI - ");
758           }
759         }
760
761         /* Throw an exception here if the method invocation ambiguous */
762         if (ambiguous)
763         {
764             /* Put the parameter type names into a single string */
765             String JavaDoc parmTypesString = "";
766             for (int i = 0; i < paramClasses.length; i++)
767             {
768                 if (i != 0)
769                     parmTypesString += ", ";
770                 parmTypesString += (paramClasses[i] == null ? "null" : paramClasses[i].getName());
771                 if (primParamClasses != null && primParamClasses[i] != null)
772                     parmTypesString += "(" + primParamClasses[i].getName() + ")";
773             }
774
775             throw StandardException.newException(SQLState.LANG_AMBIGUOUS_METHOD_INVOCATION,
776                                                 receiverClass.getName(),
777                                                 methodName,
778                                                 parmTypesString);
779         }
780
781         if (candidateIndex == -1)
782             return null;
783
784         if (SanityManager.DEBUG) {
785             if (methods[candidateIndex] == null)
786                 SanityManager.THROWASSERT("methods is null at index " + candidateIndex);
787         }
788         return methods[candidateIndex];
789     }
790
791     /**
792         Get (load) the class for the given class name.
793         This method converts any java language class name
794         into a Class object. This includes cases like String[]
795         and primitive types.
796         This will attempt to load the class from the application set.
797
798         @exception ClassNotFoundException Class cannot be found, or
799         a SecurityException or LinkageException was thrown loading the class.
800     */

801     public Class JavaDoc getClass(String JavaDoc className) throws ClassNotFoundException JavaDoc {
802
803         if ((className == null) ||
804             (className.length() == 0))
805         {
806             return null;
807         }
808
809         int arrayDepth = 0;
810         int classNameLength = className.length();
811
812         int position = classNameLength - 2;
813
814         while ((position >= 0) && className.substring(position, position + 2).equals("[]")) {
815             arrayDepth++;
816             position -= 2;
817             classNameLength -= 2;
818         }
819
820         if (classNameLength <= 0) {
821             // a bogus class name, let Class.forName deal with the error.
822
return Class.forName(className);
823         }
824
825         if (arrayDepth != 0)
826             className = className.substring(0, classNameLength);
827
828         Class JavaDoc baseClass = null;
829
830         if (classNameLength >=3 && classNameLength <=7) {
831             if ("int".equals(className))
832                 baseClass = Integer.TYPE;
833             else if ("short".equals(className))
834                 baseClass = Short.TYPE;
835             else if ("boolean".equals(className))
836                 baseClass = Boolean.TYPE;
837             else if ("byte".equals(className))
838                 baseClass = Byte.TYPE;
839             else if ("float".equals(className))
840                 baseClass = Float.TYPE;
841             else if ("double".equals(className))
842                 baseClass = Double.TYPE;
843             else if ("long".equals(className))
844                 baseClass = Long.TYPE;
845             else if ("char".equals(className))
846                 baseClass = Character.TYPE;
847             else if ("void".equals(className))
848                 baseClass = Void.TYPE;
849         }
850         
851         if (baseClass == null) {
852             baseClass = cf.loadApplicationClass(className);
853         }
854
855         if (arrayDepth == 0)
856             return baseClass;
857
858         // need to create an actual instance of the array type
859
// and get its class from that. There is no other documented
860
// way to do this. While a getName() on an array class
861
// returns [[[Lclassname; format it's not consistent
862
// with primitive types, e.g.
863
//
864
// Integer.TYPE.getName() returns "int"
865
// Class.forName(new int[0] returns "[I"
866
//
867

868         if (arrayDepth == 1)
869             return Array.newInstance(baseClass, 0).getClass();
870
871         return Array.newInstance(baseClass, new int[arrayDepth]).getClass();
872     }
873
874
875     /**
876         Is method/constructor T more or equally specific than method U.
877
878         See the Java Language Specification section 15.11.2.2.
879     */

880     private boolean isMethodMoreSpecificOrEqual(Member T, Member U, boolean[] isParam) {
881
882         Class JavaDoc[] TC;
883         Class JavaDoc[] UC;
884
885         if (T instanceof Method) {
886             if (!classConvertableFromTo(T.getDeclaringClass(), U.getDeclaringClass(), true))
887                 return false;
888
889             TC = ((Method) T).getParameterTypes();
890             UC = ((Method) U).getParameterTypes();
891         } else {
892             TC = ((Constructor) T).getParameterTypes();
893             UC = ((Constructor) U).getParameterTypes();
894         }
895
896         return signatureConvertableFromTo(TC, null, UC, isParam, true);
897     }
898
899     /**
900      * Can we convert a signature from fromTypes(primFromTypes) to toTypes.
901      * "mixTypes" is a flag to show if object/primitive type conversion is
902      * possible; this is used for comparing two candidate methods in the
903      * second pass of the two pass method resolution.
904      *
905      * @param fromTypes from types' classes
906      * @param primFromTypes primitive from types or null
907      * @param toTypes to types' classes
908      * @param isParam is parameter (?) or not
909      * @param mixTypes mixing object/primitive types for comparison
910      **/

911     private boolean signatureConvertableFromTo(Class JavaDoc[] fromTypes, Class JavaDoc[] primFromTypes,
912                                                  Class JavaDoc[] toTypes, boolean[] isParam,
913                                                  boolean mixTypes) {
914
915         // In the case repeatLastParameter was true, then the two methods may have
916
// different numbers of parameters. We need to compare only the non-repeated
917
// parameters, which is the number of input parameters.
918

919         int checkCount = fromTypes.length;
920         if (toTypes.length < checkCount)
921             checkCount = toTypes.length;
922
923         for (int i = 0; i < checkCount; i++) {
924
925             Class JavaDoc fromClass = fromTypes[i];
926             Class JavaDoc toClass = toTypes[i];
927
928             // this means an untyped null was passed in. Can only ever be in the
929
// from side as the null can only be in the signature passed in by
930
// the caller of findPublicMethod. Any signatures of existing methods
931
// are always typed.
932
if (fromClass == null) {
933
934                 // primitive types are only considered on
935
// the 2nd pass
936
if (toClass.isPrimitive())
937                 {
938                     if ((primFromTypes == null) // first pass
939
|| (isParam != null && ! isParam[i]))
940                     {
941                         return false;
942                     }
943                 }
944                 continue;
945             }
946
947
948             if ((!classConvertableFromTo(fromClass, toClass, mixTypes)) &&
949                 // primitive type, if any, also doesn't work
950
((primFromTypes == null) || (primFromTypes[i] == null) ||
951                  (!classConvertableFromTo(primFromTypes[i], toClass, mixTypes))
952                 ))
953                 return false;
954         }
955
956         return true;
957     }
958
959     /**
960      * Can we convert a fromClass to toClass.
961      * "mixTypes" is a flag to show if object/primitive type conversion is
962      * possible; this is used for comparing two candidate methods in the
963      * second pass of the two pass method resolution.
964      *
965      * @param fromClass from class
966      * @param toClass to class
967      * @param mixTypes mixing object/primitive types for comparison
968      **/

969     protected boolean classConvertableFromTo(Class JavaDoc fromClass, Class JavaDoc toClass, boolean mixTypes) {
970
971         if (toClass.isAssignableFrom(fromClass)) {
972             return true;
973         }
974
975         // When comparing two candidate methods to see which one is closer,
976
// we want to mix object type and primitive type, because they could
977
// both be chosen in the second pass. But when deciding if a method
978
// is qualified (to be a candidate), we do not want to mix types at
979
// any time, the reason is that we can NOT do more than one step
980
// conversion: for example, input parameter is BigDecimal, we convert
981
// it to double for method resolution, we can NOT convert it again to
982
// Double to match a method. "(paramTypes, primParamTypes)" already
983
// includes all the one-step conversions. But at any time we do want
984
// to see if two primitives are convertable.
985
if ((!(toClass.isPrimitive() && fromClass.isPrimitive())) && (!mixTypes))
986             return false;
987
988         // There are nine predefined Class objects to represent the eight
989
// primitive Java types and void. We also handle prim vs. non-prim
990
// conversion of the same type. boolean and double are only convertable
991
// to themseleves. void should never be seen here. In the second pass
992
// we treat primitive type and the corrsponding non-primitive type
993
// uniformly
994

995         String JavaDoc fromName = fromClass.getName(), toName = toClass.getName();
996         if ((fromClass == Boolean.TYPE) || fromName.equals(nonPrimTypeNames[0]))
997         {
998             if ((toClass == Boolean.TYPE) || toName.equals(nonPrimTypeNames[0]))
999                 return true;
1000        } else if ((fromClass == Byte.TYPE) || fromName.equals(nonPrimTypeNames[1]))
1001        {
1002            if ((toClass == Byte.TYPE) || toName.equals(nonPrimTypeNames[1]) ||
1003                // we never need to see if toClass is of wider "object" type,
1004
// because a wider "object" type and a narrower "primitive"
1005
// type can never both be candidate, eg, "int" and "Long" can
1006
// never both accomodate the same parameter; while "long" and
1007
// "Integer" can.
1008
(toClass == Short.TYPE) ||
1009                (toClass == Integer.TYPE) ||
1010                (toClass == Long.TYPE) ||
1011                (toClass == Float.TYPE) ||
1012                (toClass == Double.TYPE) )
1013                return true;
1014        } else if ((fromClass == Character.TYPE) || fromName.equals(nonPrimTypeNames[2]))
1015        {
1016            if ((toClass == Character.TYPE) || toName.equals(nonPrimTypeNames[2]) ||
1017                (toClass == Integer.TYPE) ||
1018                (toClass == Long.TYPE) ||
1019                (toClass == Float.TYPE) ||
1020                (toClass == Double.TYPE) )
1021                return true;
1022        } else if ((fromClass == Short.TYPE) || fromName.equals(nonPrimTypeNames[3]))
1023            {
1024            if ((toClass == Short.TYPE) || toName.equals(nonPrimTypeNames[3]) ||
1025                (toClass == Integer.TYPE) ||
1026                (toClass == Long.TYPE) ||
1027                (toClass == Float.TYPE) ||
1028                (toClass == Double.TYPE) )
1029                return true;
1030        } else if ((fromClass == Integer.TYPE) || fromName.equals(nonPrimTypeNames[4]))
1031        {
1032            if ((toClass == Integer.TYPE) || toName.equals(nonPrimTypeNames[4]) ||
1033                (toClass == Long.TYPE) ||
1034                (toClass == Float.TYPE) ||
1035                (toClass == Double.TYPE) )
1036                return true;
1037        } else if ((fromClass == Long.TYPE) || fromName.equals(nonPrimTypeNames[5]))
1038        {
1039            if ((toClass == Long.TYPE) || toName.equals(nonPrimTypeNames[5]) ||
1040                (toClass == Float.TYPE) ||
1041                (toClass == Double.TYPE) )
1042                return true;
1043        } else if ((fromClass == Float.TYPE) || fromName.equals(nonPrimTypeNames[6]))
1044        {
1045            if ((toClass == Float.TYPE) || toName.equals(nonPrimTypeNames[6]) ||
1046                (toClass == Double.TYPE) )
1047                return true;
1048        } else if ((fromClass == Double.TYPE) || fromName.equals(nonPrimTypeNames[7]))
1049        {
1050            if ((toClass == Double.TYPE) || toName.equals(nonPrimTypeNames[7]))
1051                return true;
1052        }
1053
1054        return false;
1055    }
1056
1057    /**
1058     * Translate a JVM-style type descriptor to a Java-language-style type
1059     * name.
1060     *
1061     * @param clazz The String that contains the JVM type name
1062     *
1063     * @return The Java-language-style type name
1064     */

1065    public static String JavaDoc readableClassName(Class JavaDoc clazz)
1066    {
1067        if (!clazz.isArray())
1068            return clazz.getName();
1069
1070        int arrayDepth = 0;
1071        do {
1072            arrayDepth++;
1073            clazz = clazz.getComponentType();
1074        } while (clazz.isArray());
1075
1076        StringBuffer JavaDoc sb = new StringBuffer JavaDoc(clazz.getName());
1077
1078        for (int i = 0; i < arrayDepth; i++) {
1079            sb.append("[]");
1080        }
1081
1082        return sb.toString();
1083    }
1084
1085    /**
1086     * Determine whether or not the received class can be
1087     * loaded.
1088     *
1089     * @param className The name of the class in question
1090     * @return True if className can be loaded, false otherwise
1091     */

1092    public static boolean classIsLoadable(String JavaDoc className)
1093    {
1094        try {
1095
1096            Class.forName(className);
1097            return true;
1098
1099        } catch (ClassNotFoundException JavaDoc ce) {
1100            return false;
1101        } catch (LinkageError JavaDoc ce) {
1102            return false;
1103        }
1104    }
1105
1106    /**
1107     * Get the declaring class for a method.
1108     *
1109     * @param method A Member describing a method
1110     *
1111     * @return A String with the declaring class
1112     *
1113     * @see Member#getDeclaringClass
1114     */

1115    public String JavaDoc getDeclaringClass(Member method)
1116    {
1117        return method.getDeclaringClass().getName();
1118    }
1119
1120}
1121
1122
Popular Tags