Source Code Cross Referenced for ClassInspector.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » iapi » services » loader » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.iapi.services.loader 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.iapi.services.loader.ClassInspector
0004:
0005:           Licensed to the Apache Software Foundation (ASF) under one or more
0006:           contributor license agreements.  See the NOTICE file distributed with
0007:           this work for additional information regarding copyright ownership.
0008:           The ASF licenses this file to you under the Apache License, Version 2.0
0009:           (the "License"); you may not use this file except in compliance with
0010:           the License.  You may obtain a copy of the License at
0011:
0012:              http://www.apache.org/licenses/LICENSE-2.0
0013:
0014:           Unless required by applicable law or agreed to in writing, software
0015:           distributed under the License is distributed on an "AS IS" BASIS,
0016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017:           See the License for the specific language governing permissions and
0018:           limitations under the License.
0019:
0020:         */
0021:
0022:        package org.apache.derby.iapi.services.loader;
0023:
0024:        import org.apache.derby.iapi.services.sanity.SanityManager;
0025:
0026:        import org.apache.derby.iapi.error.StandardException;
0027:
0028:        import org.apache.derby.iapi.reference.SQLState;
0029:
0030:        import java.lang.reflect.*;
0031:        import java.util.StringTokenizer;
0032:        import java.util.List;
0033:        import java.util.ArrayList;
0034:        import java.util.NoSuchElementException;
0035:        import java.util.Collections;
0036:
0037:        /**
0038:         Methods to find out relationships between classes and methods within a class.
0039:         All class names within this interface are treated as java language class names,
0040:         e.g. int, COM.foo.Myclass, int[], java.lang.Object[]. That is java internal
0041:         class names as defined in the class file format are not understood.
0042:         */
0043:        public final class ClassInspector {
0044:            private static final String[] primTypeNames = { "boolean", "byte",
0045:                    "char", "short", "int", "long", "float", "double" };
0046:
0047:            // collect these as static, instead of each time allocates these new
0048:            // Strings for every method resolution
0049:
0050:            private static final String[] nonPrimTypeNames = {
0051:                    "java.lang.Boolean", "java.lang.Byte",
0052:                    "java.lang.Character", "java.lang.Short",
0053:                    "java.lang.Integer", "java.lang.Long", "java.lang.Float",
0054:                    "java.lang.Double" };
0055:
0056:            private final ClassFactory cf;
0057:
0058:            /**
0059:            	DO NOT USE! use the method in ClassFactory.
0060:             */
0061:            public ClassInspector(ClassFactory cf) {
0062:                this .cf = cf;
0063:            }
0064:
0065:            /**
0066:             * Is the given object an instance of the named class?
0067:             *
0068:             * @param className	The name of the class
0069:             * @param obj		The object to test to see if it's an instance
0070:             *			of the named class
0071:             *
0072:             * @return	true if obj is an instanceof className, false if not
0073:             */
0074:            public boolean instanceOf(String className, Object obj)
0075:                    throws ClassNotFoundException {
0076:                Class clazz = getClass(className);
0077:                // is className an untyped null
0078:                if (clazz == null)
0079:                    return false;
0080:
0081:                return clazz.isInstance(obj);
0082:            }
0083:
0084:            /**
0085:             * Is one named class assignable to another named class or interface?
0086:             *
0087:             * @param fromClassName	The name of the class to be assigned
0088:             * @param toClassName	The name of the class to be assigned to
0089:             *
0090:             * @return	true if an object of type fromClass can be assigned to an
0091:             *			object of type toClass, false if not.
0092:             */
0093:            public boolean assignableTo(String fromClassName, String toClassName) {
0094:                try {
0095:                    Class toClass = getClass(toClassName);
0096:                    // is toClass an untyped null
0097:                    if (toClass == null) {
0098:                        return false;
0099:                    }
0100:
0101:                    Class fromClass = getClass(fromClassName);
0102:
0103:                    // is fromClass an untyped null
0104:                    if (fromClass == null)
0105:                        return !toClass.isPrimitive() || (toClass == Void.TYPE);
0106:
0107:                    return toClass.isAssignableFrom(fromClass);
0108:                } catch (ClassNotFoundException cnfe) {
0109:                    /* If either class can't be found, they can't be assigned */
0110:                    return false;
0111:                }
0112:            }
0113:
0114:            /**
0115:             * Does the named class exist, and is it accessible?
0116:             *
0117:             * @param className	The name of the class to test for existence
0118:             *
0119:             * @return	true if the class exists and is accessible, false if not
0120:             */
0121:            public boolean accessible(String className)
0122:                    throws ClassNotFoundException {
0123:                Class theClass = getClass(className);
0124:                if (theClass == null)
0125:                    return false;
0126:
0127:                /* Classes must be public to be accessible */
0128:                if (!Modifier.isPublic(theClass.getModifiers()))
0129:                    return false;
0130:
0131:                return true;
0132:            }
0133:
0134:            /**
0135:             * Get the Java name of the return type from a Member representing
0136:             * a method or the type of a Member representing a field.
0137:             *
0138:             * @param member		A Member representing the method for
0139:             *						which we want the return type.
0140:             *
0141:             * @return	A Java-language-style string describing the return type of
0142:             *			the method (for example, it returns "int" instead of "I".
0143:             */
0144:            public String getType(Member member) {
0145:                Class type;
0146:
0147:                if (member instanceof  Method)
0148:                    type = ((Method) member).getReturnType();
0149:                else if (member instanceof  Field)
0150:                    type = ((Field) member).getType();
0151:                else if (member instanceof  Constructor)
0152:                    type = ((Constructor) member).getDeclaringClass();
0153:                else
0154:                    type = Void.TYPE;
0155:
0156:                return ClassInspector.readableClassName(type);
0157:            }
0158:
0159:            /**
0160:             * Find a public method that implements a given signature.
0161:             * The signature is given using the full Java class names of the types.
0162:             <BR>
0163:             * A untyped null paramter is indicated by passing in an empty string ("")
0164:             * as its class name.
0165:             <BR>
0166:             If receiverType respresents an interface then the methods of java.lang.Object
0167:             arer included in the candidate list.
0168:             <BR>
0169:             If the caller is simply checking to see that a public method with the
0170:             specified name exists, regardless of the signature, exists, then the
0171:             caller should pass in a null for parmTypes.  (This is useful for checking
0172:             the validity of a method alias when creating one.)
0173:             <BR>
0174:             We use a two-pass algorithm to resolve methods.  In the first pass, we
0175:             use all "object" types to try to match a method.  If this fails, in the
0176:             second pass, an array of "primitive" types (if the parameter has one,
0177:             otherwise the same object type is used) is passed in, as well as the
0178:             "object" type array.  For each parameter of a method, we try to match it
0179:             against either the "object" type, or the "primitive" type.  Of all the
0180:             qualified candidate methods found, we choose the closest one to the input
0181:             parameter types.  This involves comparing methods whose parameters are
0182:             mixed "object" and "primitive" types in the second pass.  This is
0183:             eventually handled in classConvertableFromTo.
0184:             *
0185:             * @param receiverType	The class name of the receiver
0186:             * @param methodName	The name of the method
0187:             * @param parmTypes		An array of class names representing the
0188:             *						parameter types.  Pass a zero-element array if
0189:             *						there are no parameters.  Pass a null if it is
0190:             *						okay to match any signature.
0191:             * @param primParmTypes This is used in the second pass of the two-pass
0192:             *						method resolution algorithm.  Use primitive type
0193:             *						if it has one, otherwise use same object type
0194:             * @param isParam		Array of booleans telling whether parameter is a ?.
0195:             * @param staticMethod	Find a static method.
0196:               @param repeatLastParameter If true the last parameter may be repeated any number of times (total count must be greater than one).
0197:               If false the laste parameter is matched as usual. This also requires an exact match on the last parameter type.
0198:             *
0199:             * @return	A Member representing the matching method.  Returns null
0200:             *			if no such method.
0201:             *
0202:             * @exception ClassNotFoundException	One or more of the classes does
0203:             *										not exist.
0204:             * @exception StandardException			Thrown on ambiguous method invocation.
0205:             *
0206:             * @see	Member
0207:             * @see Modifier
0208:             */
0209:            public Member findPublicMethod(String receiverType,
0210:                    String methodName, String[] parmTypes,
0211:                    String[] primParmTypes, boolean[] isParam,
0212:                    boolean staticMethod, boolean repeatLastParameter)
0213:                    throws ClassNotFoundException, StandardException {
0214:                Class receiverClass = getClass(receiverType);
0215:                if (receiverClass == null)
0216:                    return null;
0217:
0218:                // primitives don't have methods
0219:                // note that arrays do since they are objects they have
0220:                // all the methods of java.lang.Object
0221:                if (receiverClass.isPrimitive()) {
0222:                    return null;
0223:                }
0224:
0225:                // if parmTypes is null, then the caller is simply 
0226:                // looking to see if any public method with the
0227:                // specified name exists, regardless of its signature
0228:                if (parmTypes == null) {
0229:                    Method[] methods = receiverClass.getMethods();
0230:
0231:                    for (int index = 0; index < methods.length; index++) {
0232:                        if (staticMethod) {
0233:                            if (!Modifier.isStatic(methods[index]
0234:                                    .getModifiers())) {
0235:                                continue;
0236:                            }
0237:                        }
0238:
0239:                        if (methodName.equals(methods[index].getName())) {
0240:                            // We found a match
0241:                            return methods[index];
0242:                        }
0243:                    }
0244:                    // No match
0245:                    return null;
0246:                }
0247:
0248:                // convert the parameter types to classes
0249:                Class[] paramClasses = new Class[parmTypes.length];
0250:                Class[] primParamClasses = null;
0251:                if (primParmTypes != null)
0252:                    primParamClasses = new Class[primParmTypes.length];
0253:                for (int i = 0; i < paramClasses.length; i++) {
0254:                    paramClasses[i] = getClass(parmTypes[i]);
0255:                    if (primParmTypes == null)
0256:                        continue;
0257:                    if (primParmTypes[i].equals(parmTypes[i])) // no separate primitive
0258:                        primParamClasses[i] = null;
0259:                    else
0260:                        primParamClasses[i] = getClass(primParmTypes[i]);
0261:                }
0262:
0263:                // no overloading possible if there are no arguments, so perform
0264:                // an exact match lookup.
0265:                if (paramClasses.length == 0) {
0266:
0267:                    try {
0268:                        Method method = receiverClass.getMethod(methodName,
0269:                                paramClasses);
0270:
0271:                        if (staticMethod) {
0272:                            if (!Modifier.isStatic(method.getModifiers()))
0273:                                return null;
0274:                        }
0275:
0276:                        return method;
0277:
0278:                    } catch (NoSuchMethodException nsme2) {
0279:
0280:                        // if we are an interface then the method could be defined on Object
0281:                        if (!receiverClass.isInterface())
0282:                            return null;
0283:                    }
0284:                }
0285:
0286:                // now the tricky method resolution
0287:                Member[] methodList = receiverClass.getMethods();
0288:                // if we have an interface we need to add the methods of Object into the mix
0289:                if (receiverClass.isInterface()) {
0290:
0291:                    Member[] objectMethods = java.lang.Object.class
0292:                            .getMethods();
0293:                    if (methodList.length == 0) {
0294:                        methodList = objectMethods;
0295:                    } else {
0296:                        Member[] set = new Member[methodList.length
0297:                                + objectMethods.length];
0298:                        System.arraycopy(methodList, 0, set, 0,
0299:                                methodList.length);
0300:                        System.arraycopy(objectMethods, 0, set,
0301:                                methodList.length, objectMethods.length);
0302:                        methodList = set;
0303:                    }
0304:                }
0305:
0306:                return resolveMethod(receiverClass, methodName, paramClasses,
0307:                        primParamClasses, isParam, staticMethod,
0308:                        repeatLastParameter, methodList);
0309:            }
0310:
0311:            /**
0312:             * Find a public field  for a class.
0313:               This follows the sematics of the java compiler for locating a field.
0314:               This means if a field fieldName exists in the class with package, private or
0315:               protected then an error is raised. Even if the field hides a field fieldName
0316:               in a super-class/super--interface. See the JVM spec on fields.
0317:             *
0318:             * @param receiverType	The class name of the receiver
0319:             * @param fieldName		The name of the field
0320:             * @param staticField	Find a static field
0321:             *
0322:             * @return	A Member representing the matching field.  
0323:             * @exception StandardException	Class or field does not exist or is not public or a security exception.
0324:             *
0325:             * @see	Member
0326:             * @see Modifier
0327:             */
0328:            public Member findPublicField(String receiverType,
0329:                    String fieldName, boolean staticField)
0330:                    throws StandardException {
0331:
0332:                Exception e = null;
0333:                try {
0334:
0335:                    Class receiverClass = getClass(receiverType);
0336:                    if (receiverClass == null)
0337:                        return null;
0338:                    if (receiverClass.isArray() || receiverClass.isPrimitive()) {
0339:                        // arrays don't have fields (the fake field 'length' is not returned here)
0340:                        return null;
0341:                    }
0342:
0343:                    int modifier = staticField ? (Modifier.PUBLIC | Modifier.STATIC)
0344:                            : Modifier.PUBLIC;
0345:
0346:                    // Look for a public field first
0347:                    Field publicField = receiverClass.getField(fieldName);
0348:
0349:                    if ((publicField.getModifiers() & modifier) == modifier) {
0350:                        /*
0351:                        	If the class is an interface then we avoid looking for a declared field
0352:                        	that can hide a super-class's public field and not be accessable. This is because
0353:                        	a interface's fields are always public. This avoids a security check.
0354:                         */
0355:                        if (receiverClass.isInterface()
0356:                                || (publicField.getDeclaringClass()
0357:                                        .equals(receiverClass)))
0358:                            return publicField;
0359:
0360:                        /*
0361:                        	Now check to see if there is a declared field that hides the public field.
0362:                         */
0363:
0364:                        try {
0365:
0366:                            Field declaredField = receiverClass
0367:                                    .getDeclaredField(fieldName);
0368:
0369:                            if (SanityManager.DEBUG) {
0370:
0371:                                if ((declaredField.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC)
0372:                                    SanityManager
0373:                                            .THROWASSERT("declared field not expected to be public here "
0374:                                                    + declaredField);
0375:                            }
0376:
0377:                        } catch (NoSuchFieldException nsfe) {
0378:
0379:                            // no field hides the public field in the super class
0380:                            return publicField;
0381:                        }
0382:                    }
0383:
0384:                } catch (ClassNotFoundException cnfe) {
0385:                    e = cnfe;
0386:                } catch (NoSuchFieldException nsfep) {
0387:                    e = nsfep;
0388:                } catch (SecurityException se) {
0389:                    e = se;
0390:                }
0391:
0392:                throw StandardException.newException(
0393:                        staticField ? SQLState.LANG_NO_STATIC_FIELD_FOUND
0394:                                : SQLState.LANG_NO_FIELD_FOUND, e, fieldName,
0395:                        receiverType);
0396:            }
0397:
0398:            /**
0399:             * Find a public constructor that implements a given signature.
0400:             * The signature is given using the full Java class names of the types.
0401:             <BR>
0402:             * A untyped null paramter is indicated by passing in an empty string ("")
0403:             * as its class name. 
0404:             *
0405:             * @param receiverType	The class name of the receiver
0406:             * @param parmTypes		An array of class names representing the
0407:             *						parameter types.  Pass a zero-element array if
0408:             *						there are no parameters.
0409:             * @param primParmTypes This is used in the second pass of the two-pass
0410:             *						method resolution algorithm.  Use primitive type
0411:             *						if it has one, otherwise use same object type
0412:             * @param isParam		Array of booleans telling whether parameter is a ?.
0413:             *
0414:             * @return	A Member representing the matching constructor.  Returns null
0415:             *			if no such constructor.
0416:             *
0417:             * @exception ClassNotFoundException	One or more of the classes does
0418:             *										not exist.
0419:             * @exception StandardException			Thrown on ambiguous constructor invocation.
0420:             *
0421:             * @see	Member
0422:             * @see Modifier
0423:             */
0424:            public Member findPublicConstructor(String receiverType,
0425:                    String[] parmTypes, String[] primParmTypes,
0426:                    boolean[] isParam) throws ClassNotFoundException,
0427:                    StandardException {
0428:                Class receiverClass = getClass(receiverType);
0429:                if (receiverClass == null)
0430:                    return null;
0431:
0432:                // arrays, primitives, and interfaces do not have constructors
0433:                if (receiverClass.isArray() || receiverClass.isPrimitive()
0434:                        || receiverClass.isInterface()) {
0435:                    return null;
0436:                }
0437:
0438:                // convert the parameter types to classes
0439:                Class[] paramClasses = new Class[parmTypes.length];
0440:                Class[] primParamClasses = null;
0441:                if (primParmTypes != null)
0442:                    primParamClasses = new Class[primParmTypes.length];
0443:                boolean unknownParameters = false;
0444:                for (int i = 0; i < paramClasses.length; i++) {
0445:                    paramClasses[i] = getClass(parmTypes[i]);
0446:                    if (paramClasses[i] == null)
0447:                        unknownParameters = true;
0448:                    if (primParmTypes == null)
0449:                        continue;
0450:                    if (primParmTypes[i].equals(parmTypes[i])) // no separate primitive
0451:                        primParamClasses[i] = null;
0452:                    else
0453:                        primParamClasses[i] = getClass(primParmTypes[i]);
0454:                }
0455:
0456:                try {
0457:
0458:                    if (!unknownParameters && (primParmTypes == null)) {
0459:                        // look for an exact match for first pass
0460:                        Member method = receiverClass
0461:                                .getConstructor(paramClasses);
0462:
0463:                        return method;
0464:                    }
0465:
0466:                } catch (NoSuchMethodException nsme) {
0467:
0468:                    // no overloading possible if there are no arguments
0469:                    if (paramClasses.length == 0)
0470:                        return null;
0471:
0472:                    // now the tricky method resolution
0473:                }
0474:
0475:                // name is only used for debugging
0476:                return resolveMethod(receiverClass, "<init>", paramClasses,
0477:                        primParamClasses, isParam, false, false, receiverClass
0478:                                .getConstructors());
0479:            }
0480:
0481:            /**
0482:             * Get the parameter types for a method described by a Member as a String[].
0483:             *
0484:             * @param method	A Member describing a method
0485:             *
0486:             * @return	A String[] describing the parameters of the method
0487:             */
0488:            public String[] getParameterTypes(Member method) {
0489:
0490:                Class[] parameterClasses;
0491:                if (method instanceof  Method) {
0492:                    parameterClasses = ((Method) method).getParameterTypes();
0493:                } else {
0494:                    parameterClasses = ((Constructor) method)
0495:                            .getParameterTypes();
0496:                }
0497:
0498:                String[] parameterTypes = new String[parameterClasses.length];
0499:
0500:                for (int i = 0; i < parameterTypes.length; i++) {
0501:                    parameterTypes[i] = ClassInspector
0502:                            .readableClassName(parameterClasses[i]);
0503:                }
0504:
0505:                return parameterTypes;
0506:            }
0507:
0508:            /**
0509:             * Determine whether a type is a Java primitive, like int or boolean
0510:             *
0511:             * @param typeName	The name of the Java type
0512:             *
0513:             * @return	true if it's a primitive type
0514:             */
0515:            public static boolean primitiveType(String typeName) {
0516:                for (int i = 0; i < primTypeNames.length; i++) {
0517:                    if (typeName.equals(primTypeNames[i]))
0518:                        return true;
0519:                }
0520:
0521:                return false;
0522:            }
0523:
0524:            /**
0525:             *  Tricky function to resolve a method.  If primParamClasses is null
0526:             *  we know it's first pass.  First pass try to match as all "object"
0527:             *  types, second pass try to match any combination of "object" and
0528:             *  "primitive" types.  Find the closest match among all the qualified
0529:             *  candidates.  If there's a tie, it's ambiguous.
0530:             *
0531:             *  @param receiverClass 	the class who holds the methods
0532:             *  @param methodName		the name of method
0533:             *	@param paramClasses		object type classes of input parameters
0534:             *  @param primParamClasses	primitive type classes or null
0535:             *  @param isParam			isParam (for ?) array
0536:             *  @param staticMethod		static method or not
0537:             *  @param methods			method stack
0538:             *  @return	the matched method
0539:             *
0540:             **/
0541:            private Member resolveMethod(Class receiverClass,
0542:                    String methodName, Class[] paramClasses,
0543:                    Class[] primParamClasses, boolean[] isParam,
0544:                    boolean staticMethod, boolean repeatLastParameter,
0545:                    Member[] methods) throws StandardException {
0546:
0547:                if (SanityManager.DEBUG) {
0548:                    if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
0549:                        SanityManager.DEBUG("MethodResolutionInfo",
0550:                                "MRI - Begin method resolution trace for "
0551:                                        + methodName + "() with "
0552:                                        + paramClasses.length
0553:                                        + (repeatLastParameter ? "+" : "")
0554:                                        + " parameters");
0555:
0556:                        for (int parmCtr = 0; parmCtr < paramClasses.length; parmCtr++) {
0557:                            SanityManager
0558:                                    .DEBUG(
0559:                                            "MethodResolutionInfo",
0560:                                            "MRI - Parameter #"
0561:                                                    + parmCtr
0562:                                                    + " is of type "
0563:                                                    + (paramClasses[parmCtr] == null ? "null"
0564:                                                            : paramClasses[parmCtr]
0565:                                                                    .getName()));
0566:                        }
0567:                    }
0568:                }
0569:
0570:                /* Step through all the methods available in this class */
0571:                int candidateIndex = -1;
0572:
0573:                boolean firstTimeAround = true;
0574:                boolean ambiguous;
0575:                boolean somethingChanged;
0576:                do {
0577:
0578:                    ambiguous = false;
0579:                    somethingChanged = false;
0580:
0581:                    nextMethod: for (int i = 0; i < methods.length; i++) {
0582:
0583:                        Member currentMethod = methods[i];
0584:
0585:                        // on second and later times around there will be null entries
0586:                        // also, don't compare ourself to ourself
0587:                        if ((currentMethod == null) || (i == candidateIndex)) {
0588:                            continue;
0589:                        }
0590:
0591:                        // must have the same number of parameters
0592:                        Class[] currentMethodParameters = currentMethod instanceof  Method ? ((Method) currentMethod)
0593:                                .getParameterTypes()
0594:                                : ((Constructor) currentMethod)
0595:                                        .getParameterTypes();
0596:
0597:                        // only check the basic stuff once
0598:                        if (firstTimeAround) {
0599:
0600:                            if (repeatLastParameter) {
0601:                                // match any number of parameters greater or equal to
0602:                                // the passed in number, but repeating the last type.
0603:                                if (currentMethodParameters.length < paramClasses.length) {
0604:                                    methods[i] = null; // remove non-applicable methods
0605:                                    continue;
0606:                                }
0607:
0608:                            } else {
0609:
0610:                                // regular match on parameter count
0611:                                if (currentMethodParameters.length != paramClasses.length) {
0612:                                    methods[i] = null; // remove non-applicable methods
0613:                                    continue;
0614:                                }
0615:                            }
0616:
0617:                            /* Look only at methods that match the modifiers */
0618:                            if (staticMethod
0619:                                    && !Modifier.isStatic(currentMethod
0620:                                            .getModifiers())) {
0621:                                methods[i] = null; // remove non-applicable methods
0622:                                continue;
0623:                            }
0624:
0625:                            /* Look only at methods with the right name */
0626:                            if (!methodName.startsWith("<")) {
0627:                                if (!methodName.equals(currentMethod.getName())) {
0628:                                    methods[i] = null; // remove non-applicable methods
0629:                                    continue;
0630:                                }
0631:                            }
0632:
0633:                            if (repeatLastParameter) {
0634:                                // With N parameters requested check all parameters from N-1 to end are equal
0635:                                // to the requested parameter.
0636:                                for (int pr = paramClasses.length - 1; pr < currentMethodParameters.length; pr++) {
0637:                                    if (!currentMethodParameters[pr]
0638:                                            .equals(paramClasses[paramClasses.length - 1])) {
0639:                                        methods[i] = null; // remove non-applicable methods
0640:                                        continue nextMethod;
0641:                                    }
0642:                                }
0643:                            }
0644:                        }
0645:
0646:                        if (SanityManager.DEBUG) {
0647:                            if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
0648:                                SanityManager.DEBUG("MethodResolutionInfo",
0649:                                        "MRI - Considering :"
0650:                                                + currentMethod.toString());
0651:                            }
0652:                        }
0653:
0654:                        // can the required signature be converted to those of this method
0655:                        if (!signatureConvertableFromTo(paramClasses,
0656:                                primParamClasses, currentMethodParameters,
0657:                                isParam, false)) {
0658:
0659:                            if (SanityManager.DEBUG) {
0660:                                if (SanityManager
0661:                                        .DEBUG_ON("MethodResolutionInfo")) {
0662:                                    SanityManager.DEBUG("MethodResolutionInfo",
0663:                                            "MRI - Skipping :"
0664:                                                    + currentMethod.toString());
0665:                                }
0666:                            }
0667:
0668:                            methods[i] = null; // remove non-applicable methods
0669:                            continue;
0670:                        }
0671:
0672:                        if (SanityManager.DEBUG) {
0673:                            if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
0674:                                SanityManager.DEBUG("MethodResolutionInfo",
0675:                                        "MRI - Match found ");
0676:                            }
0677:                        }
0678:
0679:                        /* Is this the first match? */
0680:                        if (candidateIndex == -1) {
0681:                            candidateIndex = i;
0682:                            if (SanityManager.DEBUG) {
0683:                                if (SanityManager
0684:                                        .DEBUG_ON("MethodResolutionInfo")) {
0685:                                    SanityManager
0686:                                            .DEBUG("MethodResolutionInfo",
0687:                                                    "MRI - Current method is now candidate");
0688:                                }
0689:                            }
0690:                            continue;
0691:                        }
0692:
0693:                        /* Not the first match, so find out which one, if either one,
0694:                         * has the best match on the parameters.  (No narrowing
0695:                         * conversions.)  15.11 of Java Language Specification.
0696:                         */
0697:
0698:                        Member candidateMethod = methods[candidateIndex];
0699:
0700:                        // If the candidate method is more specific than the current
0701:                        // method then the candidate method is still the maximally specific method
0702:                        // Note at this point we could still have a ambiguous situation.
0703:
0704:                        boolean candidateMoreOrEqual = isMethodMoreSpecificOrEqual(
0705:                                candidateMethod, currentMethod, isParam);
0706:                        boolean currentMoreOrEqual = isMethodMoreSpecificOrEqual(
0707:                                currentMethod, candidateMethod, isParam);
0708:                        if (candidateMoreOrEqual && !currentMoreOrEqual) {
0709:                            if (SanityManager.DEBUG) {
0710:                                if (SanityManager
0711:                                        .DEBUG_ON("MethodResolutionInfo")) {
0712:                                    SanityManager
0713:                                            .DEBUG("MethodResolutionInfo",
0714:                                                    "MRI - Candidate is still maximally specific");
0715:                                }
0716:                            }
0717:                            methods[i] = null; // remove non-applicable methods
0718:                            continue;
0719:                        }
0720:
0721:                        // if the current method is more specific than the candidiate
0722:                        // method then it becomes the new maximally specific method
0723:                        // Note at this point we could still have a ambiguous situation.
0724:
0725:                        if (currentMoreOrEqual && !candidateMoreOrEqual) {
0726:                            if (SanityManager.DEBUG) {
0727:                                if (SanityManager
0728:                                        .DEBUG_ON("MethodResolutionInfo")) {
0729:                                    SanityManager
0730:                                            .DEBUG("MethodResolutionInfo",
0731:                                                    "MRI - Current method is now candidate, replaced previous candidate");
0732:                                }
0733:                            }
0734:                            methods[candidateIndex] = null; // remove non-applicable methods
0735:                            candidateIndex = i;
0736:                            somethingChanged = true;
0737:                            continue;
0738:                        }
0739:
0740:                        /* We have seen an ambiguous situation; one of the cases may
0741:                         * tie on each parameter.
0742:                         */
0743:                        ambiguous = true;
0744:
0745:                        if (SanityManager.DEBUG) {
0746:                            if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
0747:                                SanityManager.DEBUG("MethodResolutionInfo",
0748:                                        "MRI - Ambiguous match");
0749:                            }
0750:                        }
0751:                    }
0752:                    firstTimeAround = false;
0753:                } while (ambiguous && somethingChanged);
0754:
0755:                if (SanityManager.DEBUG) {
0756:                    if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
0757:                        SanityManager.DEBUG("MethodResolutionInfo",
0758:                                "MRI - End method resolution trace for "
0759:                                        + methodName + "()" + "\nMRI - ");
0760:                    }
0761:                }
0762:
0763:                /* Throw an exception here if the method invocation ambiguous */
0764:                if (ambiguous) {
0765:                    /* Put the parameter type names into a single string */
0766:                    String parmTypesString = "";
0767:                    for (int i = 0; i < paramClasses.length; i++) {
0768:                        if (i != 0)
0769:                            parmTypesString += ", ";
0770:                        parmTypesString += (paramClasses[i] == null ? "null"
0771:                                : paramClasses[i].getName());
0772:                        if (primParamClasses != null
0773:                                && primParamClasses[i] != null)
0774:                            parmTypesString += "("
0775:                                    + primParamClasses[i].getName() + ")";
0776:                    }
0777:
0778:                    throw StandardException.newException(
0779:                            SQLState.LANG_AMBIGUOUS_METHOD_INVOCATION,
0780:                            receiverClass.getName(), methodName,
0781:                            parmTypesString);
0782:                }
0783:
0784:                if (candidateIndex == -1)
0785:                    return null;
0786:
0787:                if (SanityManager.DEBUG) {
0788:                    if (methods[candidateIndex] == null)
0789:                        SanityManager.THROWASSERT("methods is null at index "
0790:                                + candidateIndex);
0791:                }
0792:                return methods[candidateIndex];
0793:            }
0794:
0795:            /**
0796:            	Get (load) the class for the given class name.
0797:            	This method converts any java language class name
0798:            	into a Class object. This includes cases like String[]
0799:            	and primitive types.
0800:            	This will attempt to load the class from the application set.
0801:
0802:            	@exception ClassNotFoundException Class cannot be found, or
0803:            	a SecurityException or LinkageException was thrown loading the class.
0804:             */
0805:            public Class getClass(String className)
0806:                    throws ClassNotFoundException {
0807:
0808:                if ((className == null) || (className.length() == 0)) {
0809:                    return null;
0810:                }
0811:
0812:                int arrayDepth = 0;
0813:                int classNameLength = className.length();
0814:
0815:                int position = classNameLength - 2;
0816:
0817:                while ((position >= 0)
0818:                        && className.substring(position, position + 2).equals(
0819:                                "[]")) {
0820:                    arrayDepth++;
0821:                    position -= 2;
0822:                    classNameLength -= 2;
0823:                }
0824:
0825:                if (classNameLength <= 0) {
0826:                    // a bogus class name, let Class.forName deal with the error.
0827:                    return Class.forName(className);
0828:                }
0829:
0830:                if (arrayDepth != 0)
0831:                    className = className.substring(0, classNameLength);
0832:
0833:                Class baseClass = null;
0834:
0835:                if (classNameLength >= 3 && classNameLength <= 7) {
0836:                    if ("int".equals(className))
0837:                        baseClass = Integer.TYPE;
0838:                    else if ("short".equals(className))
0839:                        baseClass = Short.TYPE;
0840:                    else if ("boolean".equals(className))
0841:                        baseClass = Boolean.TYPE;
0842:                    else if ("byte".equals(className))
0843:                        baseClass = Byte.TYPE;
0844:                    else if ("float".equals(className))
0845:                        baseClass = Float.TYPE;
0846:                    else if ("double".equals(className))
0847:                        baseClass = Double.TYPE;
0848:                    else if ("long".equals(className))
0849:                        baseClass = Long.TYPE;
0850:                    else if ("char".equals(className))
0851:                        baseClass = Character.TYPE;
0852:                    else if ("void".equals(className))
0853:                        baseClass = Void.TYPE;
0854:                }
0855:
0856:                if (baseClass == null) {
0857:                    baseClass = cf.loadApplicationClass(className);
0858:                }
0859:
0860:                if (arrayDepth == 0)
0861:                    return baseClass;
0862:
0863:                // need to create an actual instance of the array type
0864:                // and get its class from that. There is no other documented
0865:                // way to do this. While a getName() on an array class
0866:                // returns [[[Lclassname; format it's not consistent
0867:                // with primitive types, e.g.
0868:                //
0869:                // Integer.TYPE.getName()   returns "int"
0870:                // Class.forName(new int[0] returns "[I"
0871:                // 
0872:
0873:                if (arrayDepth == 1)
0874:                    return Array.newInstance(baseClass, 0).getClass();
0875:
0876:                return Array.newInstance(baseClass, new int[arrayDepth])
0877:                        .getClass();
0878:            }
0879:
0880:            /**
0881:            	Is method/constructor T more or equally specific than method U.
0882:
0883:            	See the Java Language Specification section 15.11.2.2.
0884:             */
0885:            private boolean isMethodMoreSpecificOrEqual(Member T, Member U,
0886:                    boolean[] isParam) {
0887:
0888:                Class[] TC;
0889:                Class[] UC;
0890:
0891:                if (T instanceof  Method) {
0892:                    if (!classConvertableFromTo(T.getDeclaringClass(), U
0893:                            .getDeclaringClass(), true))
0894:                        return false;
0895:
0896:                    TC = ((Method) T).getParameterTypes();
0897:                    UC = ((Method) U).getParameterTypes();
0898:                } else {
0899:                    TC = ((Constructor) T).getParameterTypes();
0900:                    UC = ((Constructor) U).getParameterTypes();
0901:                }
0902:
0903:                return signatureConvertableFromTo(TC, null, UC, isParam, true);
0904:            }
0905:
0906:            /**
0907:             *  Can we convert a signature from fromTypes(primFromTypes) to toTypes.
0908:             *  "mixTypes" is a flag to show if object/primitive type conversion is
0909:             *  possible; this is used for comparing two candidate methods in the
0910:             *  second pass of the two pass method resolution.
0911:             *
0912:             *  @param fromTypes	from types' classes
0913:             *	@param primFromTypes primitive from types or null
0914:             *	@param toTypes		to types' classes
0915:             *	@param isParam		is parameter (?) or not
0916:             *	@param mixTypes		mixing object/primitive types for comparison
0917:             **/
0918:            private boolean signatureConvertableFromTo(Class[] fromTypes,
0919:                    Class[] primFromTypes, Class[] toTypes, boolean[] isParam,
0920:                    boolean mixTypes) {
0921:
0922:                // In the case repeatLastParameter was true, then the two methods may have
0923:                // different numbers of parameters. We need to compare only the non-repeated
0924:                // parameters, which is the number of input parameters.
0925:
0926:                int checkCount = fromTypes.length;
0927:                if (toTypes.length < checkCount)
0928:                    checkCount = toTypes.length;
0929:
0930:                for (int i = 0; i < checkCount; i++) {
0931:
0932:                    Class fromClass = fromTypes[i];
0933:                    Class toClass = toTypes[i];
0934:
0935:                    // this means an untyped null was passed in. Can only ever be in the
0936:                    // from side as the null can only be in the signature passed in by
0937:                    // the caller of findPublicMethod. Any signatures of existing methods
0938:                    // are always typed.
0939:                    if (fromClass == null) {
0940:
0941:                        // primitive types are only considered on
0942:                        // the 2nd pass
0943:                        if (toClass.isPrimitive()) {
0944:                            if ((primFromTypes == null) // first pass
0945:                                    || (isParam != null && !isParam[i])) {
0946:                                return false;
0947:                            }
0948:                        }
0949:                        continue;
0950:                    }
0951:
0952:                    if ((!classConvertableFromTo(fromClass, toClass, mixTypes))
0953:                            &&
0954:                            // primitive type, if any, also doesn't work
0955:                            ((primFromTypes == null)
0956:                                    || (primFromTypes[i] == null) || (!classConvertableFromTo(
0957:                                    primFromTypes[i], toClass, mixTypes))))
0958:                        return false;
0959:                }
0960:
0961:                return true;
0962:            }
0963:
0964:            /**
0965:             *  Can we convert a fromClass to toClass.
0966:             *  "mixTypes" is a flag to show if object/primitive type conversion is
0967:             *  possible; this is used for comparing two candidate methods in the
0968:             *  second pass of the two pass method resolution.
0969:             *
0970:             *  @param fromClass	from class
0971:             *	@param toClass		to class
0972:             *	@param mixTypes		mixing object/primitive types for comparison
0973:             **/
0974:            protected boolean classConvertableFromTo(Class fromClass,
0975:                    Class toClass, boolean mixTypes) {
0976:
0977:                if (toClass.isAssignableFrom(fromClass)) {
0978:                    return true;
0979:                }
0980:
0981:                // When comparing two candidate methods to see which one is closer,
0982:                // we want to mix object type and primitive type, because they could
0983:                // both be chosen in the second pass.  But when deciding if a method
0984:                // is qualified (to be a candidate), we do not want to mix types at
0985:                // any time, the reason is that we can NOT do more than one step
0986:                // conversion: for example, input parameter is BigDecimal, we convert
0987:                // it to double for method resolution, we can NOT convert it again to
0988:                // Double to match a method. "(paramTypes, primParamTypes)" already
0989:                // includes all the one-step conversions.  But at any time we do want
0990:                // to see if two primitives are convertable.
0991:                if ((!(toClass.isPrimitive() && fromClass.isPrimitive()))
0992:                        && (!mixTypes))
0993:                    return false;
0994:
0995:                // There are nine predefined Class objects to represent the eight 
0996:                // primitive Java types and void.  We also handle prim vs. non-prim
0997:                // conversion of the same type.  boolean and double are only convertable
0998:                // to themseleves.  void should never be seen here.  In the second pass
0999:                // we treat primitive type and the corrsponding non-primitive type
1000:                // uniformly
1001:
1002:                String fromName = fromClass.getName(), toName = toClass
1003:                        .getName();
1004:                if ((fromClass == Boolean.TYPE)
1005:                        || fromName.equals(nonPrimTypeNames[0])) {
1006:                    if ((toClass == Boolean.TYPE)
1007:                            || toName.equals(nonPrimTypeNames[0]))
1008:                        return true;
1009:                } else if ((fromClass == Byte.TYPE)
1010:                        || fromName.equals(nonPrimTypeNames[1])) {
1011:                    if ((toClass == Byte.TYPE)
1012:                            || toName.equals(nonPrimTypeNames[1])
1013:                            ||
1014:                            // we never need to see if toClass is of wider "object" type,
1015:                            // because a wider "object" type and a narrower "primitive"
1016:                            // type can never both be candidate, eg, "int" and "Long" can
1017:                            // never both accomodate the same parameter; while "long" and
1018:                            // "Integer" can.
1019:                            (toClass == Short.TYPE)
1020:                            || (toClass == Integer.TYPE)
1021:                            || (toClass == Long.TYPE)
1022:                            || (toClass == Float.TYPE)
1023:                            || (toClass == Double.TYPE))
1024:                        return true;
1025:                } else if ((fromClass == Character.TYPE)
1026:                        || fromName.equals(nonPrimTypeNames[2])) {
1027:                    if ((toClass == Character.TYPE)
1028:                            || toName.equals(nonPrimTypeNames[2])
1029:                            || (toClass == Integer.TYPE)
1030:                            || (toClass == Long.TYPE)
1031:                            || (toClass == Float.TYPE)
1032:                            || (toClass == Double.TYPE))
1033:                        return true;
1034:                } else if ((fromClass == Short.TYPE)
1035:                        || fromName.equals(nonPrimTypeNames[3])) {
1036:                    if ((toClass == Short.TYPE)
1037:                            || toName.equals(nonPrimTypeNames[3])
1038:                            || (toClass == Integer.TYPE)
1039:                            || (toClass == Long.TYPE)
1040:                            || (toClass == Float.TYPE)
1041:                            || (toClass == Double.TYPE))
1042:                        return true;
1043:                } else if ((fromClass == Integer.TYPE)
1044:                        || fromName.equals(nonPrimTypeNames[4])) {
1045:                    if ((toClass == Integer.TYPE)
1046:                            || toName.equals(nonPrimTypeNames[4])
1047:                            || (toClass == Long.TYPE)
1048:                            || (toClass == Float.TYPE)
1049:                            || (toClass == Double.TYPE))
1050:                        return true;
1051:                } else if ((fromClass == Long.TYPE)
1052:                        || fromName.equals(nonPrimTypeNames[5])) {
1053:                    if ((toClass == Long.TYPE)
1054:                            || toName.equals(nonPrimTypeNames[5])
1055:                            || (toClass == Float.TYPE)
1056:                            || (toClass == Double.TYPE))
1057:                        return true;
1058:                } else if ((fromClass == Float.TYPE)
1059:                        || fromName.equals(nonPrimTypeNames[6])) {
1060:                    if ((toClass == Float.TYPE)
1061:                            || toName.equals(nonPrimTypeNames[6])
1062:                            || (toClass == Double.TYPE))
1063:                        return true;
1064:                } else if ((fromClass == Double.TYPE)
1065:                        || fromName.equals(nonPrimTypeNames[7])) {
1066:                    if ((toClass == Double.TYPE)
1067:                            || toName.equals(nonPrimTypeNames[7]))
1068:                        return true;
1069:                }
1070:
1071:                return false;
1072:            }
1073:
1074:            /**
1075:             * Translate a JVM-style type descriptor to a Java-language-style type
1076:             * name.
1077:             *
1078:             * @param clazz		The String that contains the JVM type name
1079:             *
1080:             * @return	The Java-language-style type name
1081:             */
1082:            public static String readableClassName(Class clazz) {
1083:                if (!clazz.isArray())
1084:                    return clazz.getName();
1085:
1086:                int arrayDepth = 0;
1087:                do {
1088:                    arrayDepth++;
1089:                    clazz = clazz.getComponentType();
1090:                } while (clazz.isArray());
1091:
1092:                StringBuffer sb = new StringBuffer(clazz.getName());
1093:
1094:                for (int i = 0; i < arrayDepth; i++) {
1095:                    sb.append("[]");
1096:                }
1097:
1098:                return sb.toString();
1099:            }
1100:
1101:            /**
1102:             * Determine whether or not the received class can be
1103:             * loaded.
1104:             *
1105:             * @param className The name of the class in question
1106:             * @return True if className can be loaded, false otherwise
1107:             */
1108:            public static boolean classIsLoadable(String className) {
1109:                try {
1110:
1111:                    Class.forName(className);
1112:                    return true;
1113:
1114:                } catch (ClassNotFoundException ce) {
1115:                    return false;
1116:                } catch (LinkageError ce) {
1117:                    return false;
1118:                }
1119:            }
1120:
1121:            /**
1122:             * Get the declaring class for a method.
1123:             *
1124:             * @param method	A Member describing a method
1125:             *
1126:             * @return	A String with the declaring class
1127:             *
1128:             * @see Member#getDeclaringClass
1129:             */
1130:            public String getDeclaringClass(Member method) {
1131:                return method.getDeclaringClass().getName();
1132:            }
1133:
1134:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.