1 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 ; 32 import java.util.List ; 33 import java.util.ArrayList ; 34 import java.util.NoSuchElementException ; 35 import java.util.Collections ; 36 37 43 public final class ClassInspector 44 { 45 private static final String [] primTypeNames = 46 {"boolean", "byte", "char", "short", "int", "long", "float", "double"}; 47 48 51 private static final String [] 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 61 public ClassInspector(ClassFactory cf) { 62 this.cf = cf; 63 } 64 65 74 public boolean instanceOf(String className, Object obj) 75 throws ClassNotFoundException 76 { 77 Class clazz = getClass(className); 78 if (clazz == null) 80 return false; 81 82 return clazz.isInstance(obj); 83 } 84 85 94 public boolean assignableTo(String fromClassName, String toClassName) 95 { 96 try 97 { 98 Class toClass = getClass(toClassName); 99 if (toClass == null) { 101 return false; 102 } 103 104 Class fromClass = getClass(fromClassName); 105 106 if (fromClass == null) 108 return !toClass.isPrimitive() || (toClass == Void.TYPE); 109 110 111 return toClass.isAssignableFrom(fromClass); 112 } 113 catch (ClassNotFoundException cnfe) 114 { 115 116 return false; 117 } 118 } 119 120 127 public boolean accessible(String className) 128 throws ClassNotFoundException 129 { 130 Class theClass = getClass(className); 131 if (theClass == null) 132 return false; 133 134 135 if (! Modifier.isPublic(theClass.getModifiers())) 136 return false; 137 138 return true; 139 } 140 141 142 152 public String getType(Member member) 153 { 154 Class 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 219 public Member findPublicMethod(String receiverType, 220 String methodName, 221 String [] parmTypes, 222 String [] primParmTypes, 223 boolean[] isParam, 224 boolean staticMethod, 225 boolean repeatLastParameter) 226 throws ClassNotFoundException , StandardException 227 { 228 Class receiverClass = getClass(receiverType); 229 if (receiverClass == null) 230 return null; 231 232 if (receiverClass.isPrimitive()) { 236 return null; 237 } 238 239 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 return methods[index]; 255 } 256 } 257 return null; 259 } 260 261 Class [] paramClasses = new Class [parmTypes.length]; 263 Class [] primParamClasses = null; 264 if (primParmTypes != null) 265 primParamClasses = new Class [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])) primParamClasses[i] = null; 273 else 274 primParamClasses[i] = getClass(primParmTypes[i]); 275 } 276 277 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 nsme2) { 292 293 294 if (!receiverClass.isInterface()) 296 return null; 297 } 298 } 299 300 Member[] methodList = receiverClass.getMethods(); 302 if (receiverClass.isInterface()) { 304 305 Member[] objectMethods = java.lang.Object .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 338 public Member findPublicField(String receiverType, 339 String fieldName, 340 boolean staticField) 341 throws StandardException 342 { 343 344 Exception e = null; 345 try { 346 347 Class receiverClass = getClass(receiverType); 348 if (receiverClass == null) 349 return null; 350 if (receiverClass.isArray() || receiverClass.isPrimitive()) { 351 return null; 353 } 354 355 int modifier = staticField ? (Modifier.PUBLIC | Modifier.STATIC) : Modifier.PUBLIC; 356 357 Field publicField = receiverClass.getField(fieldName); 359 360 if ((publicField.getModifiers() & modifier) == modifier) 361 { 362 367 if (receiverClass.isInterface() || (publicField.getDeclaringClass().equals(receiverClass))) 368 return publicField; 369 370 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 nsfe) { 385 386 return publicField; 388 } 389 } 390 391 } catch (ClassNotFoundException cnfe) { 392 e = cnfe; 393 } catch (NoSuchFieldException nsfep) { 394 e = nsfep; 395 } catch (SecurityException 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 430 public Member findPublicConstructor(String receiverType, 431 String [] parmTypes, 432 String [] primParmTypes, 433 boolean[] isParam) 434 throws ClassNotFoundException , StandardException 435 { 436 Class receiverClass = getClass(receiverType); 437 if (receiverClass == null) 438 return null; 439 440 if (receiverClass.isArray() || receiverClass.isPrimitive() || receiverClass.isInterface()) { 442 return null; 443 } 444 445 Class [] paramClasses = new Class [parmTypes.length]; 447 Class [] primParamClasses = null; 448 if (primParmTypes != null) 449 primParamClasses = new Class [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])) primParamClasses[i] = null; 459 else 460 primParamClasses[i] = getClass(primParmTypes[i]); 461 } 462 463 try { 464 465 if (!unknownParameters && (primParmTypes == null)) { 466 Member method = receiverClass.getConstructor(paramClasses); 468 469 return method; 470 } 471 472 } catch (NoSuchMethodException nsme) { 473 474 if (paramClasses.length == 0) 476 return null; 477 478 } 480 481 return resolveMethod(receiverClass, "<init>", paramClasses, 483 primParamClasses, isParam, false, false, 484 receiverClass.getConstructors()); 485 } 486 487 494 public String [] getParameterTypes(Member method) 495 { 496 497 Class [] parameterClasses; 498 if (method instanceof Method) { 499 parameterClasses = ((Method) method).getParameterTypes(); 500 } else { 501 parameterClasses = ((Constructor) method).getParameterTypes(); 502 } 503 504 String [] parameterTypes = new String [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 520 public static boolean primitiveType(String 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 549 private Member resolveMethod( 550 Class receiverClass, 551 String methodName, 552 Class [] paramClasses, 553 Class [] 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 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 if ((currentMethod == null) || 595 (i == candidateIndex)) 596 { 597 continue; 598 } 599 600 Class [] currentMethodParameters = currentMethod instanceof Method ? 602 ((Method) currentMethod).getParameterTypes(): 603 ((Constructor) currentMethod).getParameterTypes(); 604 605 if (firstTimeAround) { 607 608 if (repeatLastParameter) { 609 if (currentMethodParameters.length < paramClasses.length) { 612 methods[i] = null; continue; 614 } 615 616 617 } else { 618 619 if (currentMethodParameters.length != paramClasses.length) { 621 methods[i] = null; continue; 623 } 624 } 625 626 627 if (staticMethod && !Modifier.isStatic(currentMethod.getModifiers())) { 628 methods[i] = null; continue; 630 } 631 632 633 if (!methodName.startsWith("<")) { 634 if ( ! methodName.equals(currentMethod.getName())) { 635 methods[i] = null; continue; 637 } 638 } 639 640 641 if (repeatLastParameter) { 642 for (int pr = paramClasses.length - 1; pr < currentMethodParameters.length; pr++) { 645 if (!currentMethodParameters[pr].equals(paramClasses[paramClasses.length - 1])) { 646 methods[i] = null; 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 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; 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 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 700 701 Member candidateMethod = methods[candidateIndex]; 702 703 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; continue; 720 } 721 722 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; candidateIndex = i; 735 somethingChanged = true; 736 continue; 737 } 738 739 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 762 if (ambiguous) 763 { 764 765 String 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 801 public Class getClass(String className) throws ClassNotFoundException { 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 return Class.forName(className); 823 } 824 825 if (arrayDepth != 0) 826 className = className.substring(0, classNameLength); 827 828 Class 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 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 880 private boolean isMethodMoreSpecificOrEqual(Member T, Member U, boolean[] isParam) { 881 882 Class [] TC; 883 Class [] 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 911 private boolean signatureConvertableFromTo(Class [] fromTypes, Class [] primFromTypes, 912 Class [] toTypes, boolean[] isParam, 913 boolean mixTypes) { 914 915 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 fromClass = fromTypes[i]; 926 Class toClass = toTypes[i]; 927 928 if (fromClass == null) { 933 934 if (toClass.isPrimitive()) 937 { 938 if ((primFromTypes == null) || (isParam != null && ! isParam[i])) 940 { 941 return false; 942 } 943 } 944 continue; 945 } 946 947 948 if ((!classConvertableFromTo(fromClass, toClass, mixTypes)) && 949 ((primFromTypes == null) || (primFromTypes[i] == null) || 951 (!classConvertableFromTo(primFromTypes[i], toClass, mixTypes)) 952 )) 953 return false; 954 } 955 956 return true; 957 } 958 959 969 protected boolean classConvertableFromTo(Class fromClass, Class toClass, boolean mixTypes) { 970 971 if (toClass.isAssignableFrom(fromClass)) { 972 return true; 973 } 974 975 if ((!(toClass.isPrimitive() && fromClass.isPrimitive())) && (!mixTypes)) 986 return false; 987 988 995 String 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 (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 1065 public static String readableClassName(Class 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 sb = new StringBuffer (clazz.getName()); 1077 1078 for (int i = 0; i < arrayDepth; i++) { 1079 sb.append("[]"); 1080 } 1081 1082 return sb.toString(); 1083 } 1084 1085 1092 public static boolean classIsLoadable(String className) 1093 { 1094 try { 1095 1096 Class.forName(className); 1097 return true; 1098 1099 } catch (ClassNotFoundException ce) { 1100 return false; 1101 } catch (LinkageError ce) { 1102 return false; 1103 } 1104 } 1105 1106 1115 public String getDeclaringClass(Member method) 1116 { 1117 return method.getDeclaringClass().getName(); 1118 } 1119 1120} 1121 1122 | Popular Tags |