1 28 29 package org.jibx.binding.classes; 30 31 import java.io.File ; 32 import java.io.FileInputStream ; 33 import java.io.FileOutputStream ; 34 import java.io.IOException ; 35 import java.io.InputStream ; 36 import java.io.OutputStream ; 37 import java.net.MalformedURLException ; 38 import java.net.URL ; 39 import java.net.URLClassLoader ; 40 import java.util.ArrayList ; 41 import java.util.Arrays ; 42 import java.util.HashMap ; 43 44 import org.apache.bcel.Constants; 45 import org.apache.bcel.classfile.ClassParser; 46 import org.apache.bcel.classfile.Code; 47 import org.apache.bcel.classfile.CodeException; 48 import org.apache.bcel.classfile.Constant; 49 import org.apache.bcel.classfile.ConstantDouble; 50 import org.apache.bcel.classfile.ConstantFloat; 51 import org.apache.bcel.classfile.ConstantInteger; 52 import org.apache.bcel.classfile.ConstantLong; 53 import org.apache.bcel.classfile.ConstantPool; 54 import org.apache.bcel.classfile.ConstantString; 55 import org.apache.bcel.classfile.ConstantUtf8; 56 import org.apache.bcel.classfile.ConstantValue; 57 import org.apache.bcel.classfile.ExceptionTable; 58 import org.apache.bcel.classfile.Field; 59 import org.apache.bcel.classfile.FieldOrMethod; 60 import org.apache.bcel.classfile.JavaClass; 61 import org.apache.bcel.classfile.Method; 62 import org.apache.bcel.classfile.Utility; 63 import org.apache.bcel.generic.ClassGen; 64 import org.apache.bcel.generic.ConstantPoolGen; 65 import org.apache.bcel.generic.FieldGen; 66 import org.apache.bcel.generic.Type; 67 import org.apache.bcel.util.ClassPath; 68 import org.jibx.runtime.JiBXException; 69 70 77 78 public class ClassFile 79 { 80 83 public static final int PRIVATE_ACCESS = 0; 84 public static final int PACKAGE_ACCESS = 1; 85 public static final int PROTECTED_ACCESS = 2; 86 public static final int PUBLIC_ACCESS = 3; 87 88 protected static final int PRIVATEFIELD_ACCESS = Constants.ACC_PRIVATE; 89 protected static final ExistingMethod[] EMPTY_METHOD_ARRAY = {}; 90 91 94 95 private static ClassPath s_loader; 96 97 98 private static ClassLoader s_directLoader; 99 100 103 104 private String m_name; 105 106 107 private String m_signature; 108 109 110 private Type m_type; 111 112 113 private File m_root; 114 115 116 private File m_file; 117 118 119 private boolean m_isSamePackage; 120 121 122 private boolean m_isWritable; 123 124 126 protected ClassFile m_superClass; 127 128 129 protected String [] m_interfaces; 130 131 133 private String [] m_instanceOfs; 134 135 136 private JavaClass m_curClass; 137 138 139 private ClassGen m_genClass; 140 141 143 private ConstantPoolGen m_genPool; 144 145 146 protected InstructionBuilder m_instBuilder; 147 148 150 private HashMap m_suffixMap; 151 152 153 private HashMap m_itemMap; 154 155 156 private boolean m_isModified; 157 158 159 private int m_useCount; 160 161 162 private boolean m_isHashCurrent; 163 164 165 private int m_hashCode; 166 167 168 private int m_inheritDepth; 169 170 171 private int m_uniqueIndex; 172 173 182 183 public ClassFile(String name, String path, InputStream ins) 184 throws JiBXException { 185 init(name, path, ins); 186 } 187 188 198 199 public ClassFile(String name, File root, File file) 200 throws IOException , JiBXException { 201 init(name, root.getPath(), new FileInputStream (file)); 202 m_root = root; 203 m_file = file; 204 m_isWritable = file.canWrite(); 205 } 206 207 215 216 public ClassFile(String name) throws IOException , JiBXException { 217 218 ClassPath.ClassFile cf = null; 220 try { 221 cf = s_loader.getClassFile(name); 222 } catch (IOException ex) { 223 try { 224 cf = ClassPath.SYSTEM_CLASS_PATH.getClassFile(name); 225 } catch (IOException ex1) { } 226 } 227 if (cf == null) { 228 throw new JiBXException("Class " + name + 229 " not found in any classpath"); 230 } else { 231 init(name, cf.getPath(), cf.getInputStream()); 232 } 233 } 234 235 242 243 public ClassFile(String name, String sig) { 244 m_name = name; 245 m_signature = sig; 246 m_type = Type.getType(sig); 247 m_interfaces = new String [0]; 248 m_itemMap = new HashMap (); 249 } 250 251 261 262 public ClassFile(String name, File root, ClassFile sclas, int access, 263 String [] impls) throws JiBXException { 264 String fname = name.replace('.', File.separatorChar)+".class"; 265 File file = new File (root, fname); 266 m_name = name; 267 m_signature = Utility.getSignature(name); 268 m_type = ClassItem.typeFromName(name); 269 m_root = root; 270 m_superClass = sclas; 271 m_interfaces = impls; 272 m_file = file; 273 m_isWritable = true; 274 m_genClass = new ClassGen(name, sclas.getName(), "", access, impls); 275 m_genPool = m_genClass.getConstantPool(); 276 m_instBuilder = new InstructionBuilder(m_genClass, m_genPool); 277 m_itemMap = new HashMap (); 278 ClassCache.addClassFile(this); 279 } 280 281 290 291 private void init(String name, String path, InputStream ins) 292 throws JiBXException { 293 m_name = name; 294 m_signature = Utility.getSignature(name); 295 m_type = ClassItem.typeFromName(name); 296 m_itemMap = new HashMap (); 297 if (path == null) { 298 m_interfaces = new String [0]; 299 } else { 300 String fname = name.replace('.', File.separatorChar) + ".class"; 301 ClassParser parser = new ClassParser(ins, fname); 302 try { 303 m_curClass = parser.parse(); 304 m_interfaces = m_curClass.getInterfaceNames(); 305 } catch (Exception ex) { 306 throw new JiBXException("Error reading path " + 307 path + " for class " + name); 308 } 309 } 310 } 311 312 318 319 public boolean isInterface() { 320 return m_curClass != null && m_curClass.isInterface(); 321 } 322 323 329 330 public boolean isAbstract() { 331 return m_curClass != null && m_curClass.isAbstract(); 332 } 333 334 340 341 public boolean isModifiable() { 342 return m_isWritable && !isInterface(); 343 } 344 345 350 351 public String getName() { 352 return m_name; 353 } 354 355 360 361 public String getSignature() { 362 return m_signature; 363 } 364 365 370 371 public Type getType() { 372 return m_type; 373 } 374 375 380 381 public String getPackage() { 382 int split = m_name.lastIndexOf('.'); 383 if (split >= 0) { 384 return m_name.substring(0, split); 385 } else { 386 return ""; 387 } 388 } 389 390 395 396 public File getRoot() { 397 return m_root; 398 } 399 400 405 406 public File getFile() { 407 return m_file; 408 } 409 410 415 416 public JavaClass getRawClass() { 417 if (m_curClass == null) { 418 throw new IllegalStateException 419 ("No loadable class information for " + m_name); 420 } else { 421 return m_curClass; 422 } 423 } 424 425 430 431 public String getSuperName() { 432 if (m_curClass == null) { 433 return null; 434 } else { 435 return m_curClass.getSuperclassName(); 436 } 437 } 438 439 444 445 public void setSuperFile(ClassFile sclas) { 446 m_superClass = sclas; 447 m_isSamePackage = getPackage().equals(sclas.getPackage()); 448 } 449 450 456 457 public ClassFile getSuperFile() { 458 return m_superClass; 459 } 460 461 466 467 public String [] getInterfaces() { 468 return m_interfaces; 469 } 470 471 479 480 public boolean addInterface(String intf) throws JiBXException { 481 ClassGen gen = getClassGen(); 482 String [] intfs = gen.getInterfaceNames(); 483 for (int i = 0; i < intfs.length; i++) { 484 if (intf.equals(intfs[i])) { 485 return false; 486 } 487 } 488 gen.addInterface(intf); 489 m_isModified = true; 490 m_instanceOfs = null; 491 return true; 492 } 493 494 502 503 protected void accumulateInterfaces(String [] intfs, HashMap map, 504 ArrayList accs) throws JiBXException { 505 for (int i = 0; i < intfs.length; i++) { 506 String name = intfs[i]; 507 if (map.get(name) == null) { 508 ClassFile cf = ClassCache.getClassFile(name); 509 String sig = cf.getSignature(); 510 map.put(name, sig); 511 accs.add(sig); 512 String [] inherits = cf.m_curClass.getInterfaceNames(); 513 accumulateInterfaces(inherits, map, accs); 514 } 515 } 516 } 517 518 525 526 public String [] getInstanceSigs() throws JiBXException { 527 if (m_instanceOfs == null) { 528 529 String name = getName(); 531 if (name.endsWith("[]")) { 532 533 String prefix = ""; 535 do { 536 name = name.substring(0, name.length()-2); 537 prefix = prefix + '['; 538 } while (name.endsWith("[]")); 539 540 String [] bsigs; 542 if (ClassItem.isPrimitive(name)) { 543 bsigs = new String [1]; 544 bsigs[0] = ClassItem.getPrimitiveSignature(name); 545 } else { 546 ClassFile bcf = ClassCache.getClassFile(name); 547 bsigs = bcf.getInstanceSigs(); 548 } 549 550 String [] asigs = new String [bsigs.length]; 552 for (int i = 0; i < bsigs.length; i++) { 553 asigs[i] = prefix + bsigs[i]; 554 } 555 m_instanceOfs = asigs; 556 557 } else { 558 559 HashMap map = new HashMap (); 561 ArrayList iofs = new ArrayList (); 562 ClassFile cur = this; 563 while (cur != null) { 564 String sig = cur.getSignature(); 565 map.put(name, sig); 566 iofs.add(sig); 567 accumulateInterfaces(cur.getInterfaces(), map, iofs); 568 cur = cur.getSuperFile(); 569 } 570 String [] sigs = new String [iofs.size()]; 571 m_instanceOfs = (String [])iofs.toArray(sigs); 572 573 } 574 } 575 return m_instanceOfs; 576 } 577 578 586 587 public boolean isImplements(String sig) throws JiBXException { 588 String [] sigs = getInstanceSigs(); 589 for (int i = 0; i < sigs.length; i++) { 590 if (sig.equals(sigs[i])) { 591 return true; 592 } 593 } 594 return false; 595 } 596 597 605 606 public boolean isSuperclass(String name) throws JiBXException { 607 ClassFile cur = this; 608 while (cur != null) { 609 if (cur.getName().equals(name)) { 610 return true; 611 } else { 612 cur = cur.getSuperFile(); 613 } 614 } 615 return false; 616 } 617 618 626 627 protected Field getDefinedField(String name) { 628 629 Field[] fields = m_curClass.getFields(); 631 for (int i = 0; i < fields.length; i++) { 632 if (fields[i].getName().equals(name)) { 633 return fields[i]; 634 } 635 } 636 return null; 637 } 638 639 647 648 protected Field getAccessibleField(String name) { 649 650 if (m_curClass == null) { 652 return null; 653 } else { 654 655 Field field = getDefinedField(name); 657 if (field == null) { 658 659 if (m_superClass != null) { 661 field = m_superClass.getAccessibleField(name); 662 if (field != null && (!m_isSamePackage || 663 field.isPrivate()) && !field.isPublic() && 664 !field.isProtected()) { 665 field = null; 666 } 667 } 668 669 } 670 return field; 671 } 672 } 673 674 682 683 public ClassItem getDirectField(String name) { 684 Field field = getAccessibleField(name); 685 if (field == null) { 686 return null; 687 } else { 688 ClassItem item = (ClassItem)m_itemMap.get(field); 689 if (item == null) { 690 item = new ClassItem(name, this, field); 691 m_itemMap.put(field, item); 692 } 693 return item; 694 } 695 } 696 697 706 707 public ClassItem getField(String name) throws JiBXException { 708 Field field = getAccessibleField(name); 709 if (field == null) { 710 throw new JiBXException("Field " + name + 711 " not found in class " + m_name); 712 } else { 713 ClassItem item = (ClassItem)m_itemMap.get(field); 714 if (item == null) { 715 item = new ClassItem(name, this, field); 716 m_itemMap.put(field, item); 717 } 718 return item; 719 } 720 } 721 722 734 735 protected Method getAccessibleMethod(String name, String sig) { 736 737 if (m_curClass != null) { 739 740 Method[] methods = m_curClass.getMethods(); 742 for (int i = 0; i < methods.length; i++) { 743 Method method = methods[i]; 744 if (method.getName().equals(name)) { 745 if (method.getSignature().startsWith(sig)) { 746 return method; 747 } 748 } 749 } 750 751 if (m_superClass != null) { 753 Method method = m_superClass.getAccessibleMethod(name, sig); 754 if (method != null && ((m_isSamePackage && 755 !method.isPrivate()) || method.isPublic() || 756 method.isProtected())) { 757 return method; 758 } 759 } 760 761 } 762 return null; 763 } 764 765 777 778 public ClassItem getMethod(String name, String sig) { 779 Method method = getAccessibleMethod(name, sig); 780 if (method == null) { 781 return null; 782 } else { 783 ClassItem item = (ClassItem)m_itemMap.get(method); 784 if (item == null) { 785 item = new ClassItem(name, this, method); 786 m_itemMap.put(method, item); 787 } 788 return item; 789 } 790 } 791 792 803 804 public ClassItem getMethod(String name, String [] sigs) { 805 Method method = null; 806 for (int i = 0; method == null && i < sigs.length; i++) { 807 method = getAccessibleMethod(name, sigs[i]); 808 } 809 if (method == null) { 810 return null; 811 } else { 812 ClassItem item = (ClassItem)m_itemMap.get(method); 813 if (item == null) { 814 item = new ClassItem(name, this, method); 815 m_itemMap.put(method, item); 816 } 817 return item; 818 } 819 } 820 821 831 832 private static boolean matchAccess(FieldOrMethod item, int access) { 833 if (item.isPublic()) { 834 return true; 835 } else if (item.isProtected()) { 836 return access <= PROTECTED_ACCESS; 837 } else if (item.isPrivate()) { 838 return access == PRIVATE_ACCESS; 839 } else { 840 return access <= PACKAGE_ACCESS; 841 } 842 } 843 844 852 private static boolean isAssignmentCompatible(Type have, Type need) { 853 if (have.equals(need)) { 854 return true; 855 } else { 856 try { 857 return ClassItem.isAssignable(have.toString(), need.toString()); 858 } catch (JiBXException e) { 859 throw new IllegalStateException 860 ("Internal error: Unable to access data for " + 861 have.toString() + " or " + need.toString() + ":\n" + 862 e.getMessage()); 863 } 864 } 865 } 866 867 882 883 private Method getBestAccessibleMethod(String name, int access, Type ret, 884 Type[] args) { 885 886 if (m_curClass == null) { 888 return null; 889 } 890 891 Method[] methods = m_curClass.getMethods(); 893 Method best = null; 894 int diff = Integer.MAX_VALUE; 895 for (int i = 0; i < methods.length; i++) { 896 Method method = methods[i]; 897 if (method.getName().equals(name) && matchAccess(method, access)) { 898 899 boolean match = true; 901 int ndiff = 0; 902 if (ret != null) { 903 Type type = method.getReturnType(); 904 match = isAssignmentCompatible(ret, type); 905 } 906 if (match) { 907 908 Type[] types = method.getArgumentTypes(); 910 if (args.length == types.length) { 911 for (int j = 0; j < args.length; j++) { 912 Type type = types[j]; 913 Type arg = args[j]; 914 if (!type.equals(arg)) { 915 ndiff++; 916 match = isAssignmentCompatible(arg, type); 917 if (!match) { 918 break; 919 } 920 } 921 } 922 } else { 923 match = false; 924 } 925 } 926 if (match && ndiff < diff) { 927 best = method; 928 } 929 } 930 } 931 if (best != null) { 932 return best; 933 } 934 935 if (m_superClass != null) { 937 if (access < PROTECTED_ACCESS) { 938 if (m_isSamePackage) { 939 access = PACKAGE_ACCESS; 940 } else { 941 access = PROTECTED_ACCESS; 942 } 943 } 944 return m_superClass.getBestAccessibleMethod(name, access, ret, args); 945 } else { 946 return null; 947 } 948 } 949 950 964 965 public ClassItem getBestMethod(String name, String ret, String [] args) { 966 Type rtype = null; 967 if (ret != null) { 968 rtype = ClassItem.typeFromName(ret); 969 } 970 Type[] atypes = new Type[args.length]; 971 for (int i = 0; i < args.length; i++) { 972 atypes[i] = ClassItem.typeFromName(args[i]); 973 } 974 Method method = 975 getBestAccessibleMethod(name, PRIVATE_ACCESS, rtype, atypes); 976 if (method == null) { 977 return null; 978 } 979 ClassItem item = (ClassItem)m_itemMap.get(method); 980 if (item == null) { 981 item = new ClassItem(name, this, method); 982 m_itemMap.put(method, item); 983 } 984 return item; 985 } 986 987 995 996 public ClassItem getInitializerMethod(String sig) { 997 998 if (m_curClass != null) { 1000 1001 Method[] methods = m_curClass.getMethods(); 1003 for (int i = 0; i < methods.length; i++) { 1004 Method method = methods[i]; 1005 if (method.getName().equals("<init>")) { 1006 String sign = method.getSignature(); 1007 if (method.getSignature().startsWith(sig)) { 1008 ClassItem item = (ClassItem)m_itemMap.get(method); 1009 if (item == null) { 1010 item = new ClassItem("<init>", this, method); 1011 m_itemMap.put(method, item); 1012 } 1013 return item; 1014 } 1015 } 1016 } 1017 1018 } 1019 return null; 1020 } 1021 1022 1031 1032 public ClassItem getStaticMethod(String name, String sig) { 1033 1034 if (m_curClass != null) { 1036 1037 Method[] methods = m_curClass.getMethods(); 1039 for (int i = 0; i < methods.length; i++) { 1040 Method method = methods[i]; 1041 if (method.getName().equals(name) && method.isStatic()) { 1042 if (method.getSignature().startsWith(sig)) { 1043 ClassItem item = (ClassItem)m_itemMap.get(method); 1044 if (item == null) { 1045 item = new ClassItem(name, this, method); 1046 m_itemMap.put(method, item); 1047 } 1048 return item; 1049 } 1050 } 1051 } 1052 1053 } 1054 return null; 1055 } 1056 1057 1069 1070 public ExistingMethod[] getBindingMethods(String prefix, String [] matches) { 1071 1072 if (m_curClass == null) { 1074 return EMPTY_METHOD_ARRAY; 1075 } 1076 1077 Method[] methods = m_curClass.getMethods(); 1079 int count = 0; 1080 for (int i = 0; i < methods.length; i++) { 1081 Method method = methods[i]; 1082 String name = method.getName(); 1083 if (name.startsWith(prefix)) { 1084 count++; 1085 } else { 1086 String sig = method.getSignature(); 1087 for (int j = 0; j < matches.length; j += 2) { 1088 if (name.equals(matches[j]) && sig.equals(matches[j+1])) { 1089 count++; 1090 break; 1091 } 1092 } 1093 } 1094 } 1095 1096 if (count == 0) { 1098 return EMPTY_METHOD_ARRAY; 1099 } else { 1100 ExistingMethod[] exists = new ExistingMethod[count]; 1101 int fill = 0; 1102 for (int i = 0; i < methods.length; i++) { 1103 Method method = methods[i]; 1104 String name = method.getName(); 1105 boolean match = name.startsWith(prefix); 1106 if (!match) { 1107 String sig = method.getSignature(); 1108 for (int j = 0; j < matches.length; j += 2) { 1109 if (name.equals(matches[j]) && 1110 sig.equals(matches[j+1])) { 1111 match = true; 1112 break; 1113 } 1114 } 1115 } 1116 if (match) { 1117 ClassItem item = (ClassItem)m_itemMap.get(method); 1118 if (item == null) { 1119 item = new ClassItem(name, this, method); 1120 m_itemMap.put(method, item); 1121 } 1122 exists[fill++] = new ExistingMethod(method, item, this); 1123 } 1124 } 1125 return exists; 1126 } 1127 } 1128 1129 1136 1137 public boolean isAccessible(ClassItem item) { 1138 if (item.getClassFile() == this) { 1139 return true; 1140 } else { 1141 int access = item.getAccessFlags(); 1142 if ((access & Constants.ACC_PUBLIC) != 0) { 1143 return true; 1144 } else if ((access & Constants.ACC_PRIVATE) != 0) { 1145 return false; 1146 } else if (getPackage().equals(item.getClassFile().getPackage())) { 1147 return true; 1148 } else if ((access & Constants.ACC_PROTECTED) != 0) { 1149 ClassFile target = item.getClassFile(); 1150 ClassFile ancestor = this; 1151 while ((ancestor = ancestor.getSuperFile()) != null) { 1152 if (ancestor == target) { 1153 return true; 1154 } 1155 } 1156 return false; 1157 } else { 1158 return false; 1159 } 1160 } 1161 } 1162 1163 1169 1170 private ClassGen getClassGen() throws JiBXException { 1171 if (m_genClass == null) { 1172 if (m_isWritable) { 1173 m_genClass = new ClassGen(m_curClass); 1174 m_genPool = m_genClass.getConstantPool(); 1175 m_instBuilder = new InstructionBuilder(m_genClass, m_genPool); 1176 m_isHashCurrent = false; 1177 } else { 1178 throw new JiBXException("Cannot modify class " + m_name); 1179 } 1180 } 1181 return m_genClass; 1182 } 1183 1184 1190 1191 public ConstantPoolGen getConstPoolGen() throws JiBXException { 1192 if (m_genPool == null) { 1193 getClassGen(); 1194 } 1195 return m_genPool; 1196 } 1197 1198 1204 1205 public InstructionBuilder getInstructionBuilder() throws JiBXException { 1206 if (m_instBuilder == null) { 1207 getClassGen(); 1208 } 1209 return m_instBuilder; 1210 } 1211 1212 1219 1220 public ClassItem addMethod(Method method) throws JiBXException { 1221 getClassGen().addMethod(method); 1222 setModified(); 1223 String mname = method.getName(); 1224 if (m_suffixMap != null && isSuffixName(mname)) { 1225 m_suffixMap.put(mname, method); 1226 } 1227 return new ClassItem(mname, this, method); 1228 } 1229 1230 1236 1237 public void removeMethod(Method method) throws JiBXException { 1238 getClassGen().removeMethod(method); 1239 setModified(); 1240 String mname = method.getName(); 1241 if (m_suffixMap != null && isSuffixName(mname)) { 1242 m_suffixMap.remove(mname); 1243 } 1244 } 1245 1246 1257 1258 public ClassItem addField(String type, String name, int access, String init) 1259 throws JiBXException { 1260 deleteField(name); 1261 FieldGen fgen = new FieldGen(access, 1262 Type.getType(Utility.getSignature(type)), name, getConstPoolGen()); 1263 fgen.setInitValue(init); 1264 Field field = fgen.getField(); 1265 getClassGen().addField(field); 1266 m_isModified = true; 1267 m_isHashCurrent = false; 1268 return new ClassItem(name, this, field); 1269 } 1270 1271 1283 1284 public ClassItem updateField(String type, String name, int access, 1285 String init) throws JiBXException { 1286 1287 Field[] fields = m_curClass.getFields(); 1289 for (int i = 0; i < fields.length; i++) { 1290 Field field = fields[i]; 1291 if (field.getName().equals(name) && 1292 field.getAccessFlags() == access) { 1293 String sig = field.getSignature(); 1294 if (type.equals(Utility.signatureToString(sig, false))) { 1295 ConstantValue cval = field.getConstantValue(); 1296 if (cval != null) { 1297 int index = cval.getConstantValueIndex(); 1298 ConstantPool cp = m_curClass.getConstantPool(); 1299 Constant cnst = cp.getConstant(index); 1300 if (cnst instanceof ConstantString) { 1301 Object value = ((ConstantString)cnst). 1302 getConstantValue(cp); 1303 if (init.equals(value)) { 1304 return new ClassItem(name,this, field); 1305 } 1306 } 1307 } 1308 } 1309 } 1310 } 1311 1312 deleteField(name); 1314 FieldGen fgen = new FieldGen(access, 1315 Type.getType(Utility.getSignature(type)), name, getConstPoolGen()); 1316 fgen.setInitValue(init); 1317 Field field = fgen.getField(); 1318 getClassGen().addField(field); 1319 m_isModified = true; 1320 m_isHashCurrent = false; 1321 return new ClassItem(name, this, field); 1322 } 1323 1324 1334 1335 public ClassItem addField(String type, String name, int access) 1336 throws JiBXException { 1337 deleteField(name); 1338 FieldGen fgen = new FieldGen(access, 1339 Type.getType(Utility.getSignature(type)), name, getConstPoolGen()); 1340 Field field = fgen.getField(); 1341 getClassGen().addField(field); 1342 m_isModified = true; 1343 m_isHashCurrent = false; 1344 return new ClassItem(name, this, field); 1345 } 1346 1347 1356 1357 public ClassItem addPrivateField(String type, String name) 1358 throws JiBXException { 1359 return addField(type, name, PRIVATEFIELD_ACCESS); 1360 } 1361 1362 1369 1370 public ClassItem addDefaultConstructor() throws JiBXException { 1371 1372 ExceptionMethodBuilder mb = new ExceptionMethodBuilder("<init>", 1374 Type.VOID, new Type[0], this, Constants.ACC_PUBLIC); 1375 1376 mb.appendLoadLocal(0); 1378 mb.appendCallInit(m_superClass.getName(), "()V"); 1379 1380 mb.appendReturn(); 1382 mb.codeComplete(false); 1383 return mb.addMethod(); 1384 } 1385 1386 1393 1394 private static boolean isSuffixName(String name) { 1395 int last = name.length() - 1; 1396 for (int i = last; i > 0; i--) { 1397 char chr = name.charAt(i); 1398 if (chr == '_') { 1399 return i < last; 1400 } else if (!Character.isDigit(chr)) { 1401 break; 1402 } 1403 } 1404 return false; 1405 } 1406 1407 1414 1415 public String makeUniqueMethodName(String name) { 1416 1417 if (m_suffixMap == null) { 1419 m_suffixMap = new HashMap (); 1420 if (m_curClass != null) { 1421 Method[] methods = m_curClass.getMethods(); 1422 for (int i = 0; i < methods.length; i++) { 1423 Method method = methods[i]; 1424 String mname = method.getName(); 1425 if (isSuffixName(mname)) { 1426 m_suffixMap.put(mname, method); 1427 } 1428 } 1429 } 1430 } 1431 1432 if (m_inheritDepth == 0) { 1434 ClassFile cf = this; 1435 while ((cf = cf.getSuperFile()) != null) { 1436 m_inheritDepth++; 1437 } 1438 } 1439 1440 while (true) { 1442 String uname = name + '_' + m_inheritDepth + '_' + m_uniqueIndex; 1443 if (m_suffixMap.get(uname) == null) { 1444 return uname; 1445 } else { 1446 m_uniqueIndex++; 1447 } 1448 } 1449 } 1450 1451 1458 1459 public boolean deleteField(String name) throws JiBXException { 1460 ClassGen cg = getClassGen(); 1461 Field field = cg.containsField(name); 1462 if (field == null) { 1463 return false; 1464 } else { 1465 cg.removeField(field); 1466 m_isModified = true; 1467 m_isHashCurrent = false; 1468 return true; 1469 } 1470 } 1471 1472 1477 1478 public int getUseCount() { 1479 return m_useCount; 1480 } 1481 1482 1487 1488 public int incrementUseCount() { 1489 return ++m_useCount; 1490 } 1491 1492 1497 1498 public boolean isModified() { 1499 return m_isModified; 1500 } 1501 1502 1505 1506 public void setModified() { 1507 m_isModified = true; 1508 } 1509 1510 1515 1516 public boolean isComplete() { 1517 return m_genClass == null; 1518 } 1519 1520 1532 1533 protected int computeHashCode() { 1534 1535 int hash = getPackage().hashCode(); 1537 ClassFile sfile = getSuperFile(); 1538 if (sfile != null) { 1539 hash += sfile.getName().hashCode(); 1540 } 1541 String [] intfs = getInterfaces(); 1542 for (int i = 0; i < intfs.length; i++) { 1543 hash += intfs[i].hashCode(); 1544 } 1545 hash += m_curClass.getAccessFlags(); 1546 1547 Field[] fields = m_curClass.getFields(); 1549 for (int i = 0; i < fields.length; i++) { 1550 hash = hash * 49 + fields[i].getName().hashCode(); 1551 } 1552 Method[] methods = m_curClass.getMethods(); 1553 for (int i = 0; i < methods.length; i++) { 1554 hash = hash * 49 + methods[i].getName().hashCode(); 1555 } 1556 1557 Constant[] cnsts = m_curClass.getConstantPool().getConstantPool(); 1559 for (int i = m_curClass.getClassNameIndex()+1; i < cnsts.length; i++) { 1560 Constant cnst = cnsts[i]; 1561 if (cnst != null) { 1562 int value = 0; 1563 switch (cnst.getTag()) { 1564 case Constants.CONSTANT_Double: 1565 value = (int)Double.doubleToRawLongBits 1566 (((ConstantDouble)cnst).getBytes()); 1567 break; 1568 case Constants.CONSTANT_Float: 1569 value = Float.floatToRawIntBits 1570 (((ConstantFloat)cnst).getBytes()); 1571 break; 1572 case Constants.CONSTANT_Integer: 1573 value = ((ConstantInteger)cnst).getBytes(); 1574 break; 1575 case Constants.CONSTANT_Long: 1576 value = (int)((ConstantLong)cnst).getBytes(); 1577 break; 1578 case Constants.CONSTANT_Utf8: 1579 String text = ((ConstantUtf8)cnst).getBytes(); 1580 if (!text.equals(m_signature)) { 1581 value = text.hashCode(); 1582 } 1583 break; 1584 default: 1585 break; 1586 } 1587 hash = hash * 49 + value; 1588 } 1589 } 1590 return hash; 1592 } 1593 1594 1600 1601 public void codeComplete() { 1602 if (m_genClass != null) { 1603 m_curClass = m_genClass.getJavaClass(); 1604 m_interfaces = m_curClass.getInterfaceNames(); 1605 m_genClass = null; 1606 } 1607 } 1608 1609 1616 1617 public int hashCode() { 1618 if (!m_isHashCurrent) { 1619 if (m_genClass != null) { 1620 throw new IllegalStateException 1621 ("Class still being constructed"); 1622 } 1623 m_hashCode = computeHashCode(); 1624 m_isHashCurrent = true; 1625 } 1626 return m_hashCode; 1627 } 1628 1629 1639 1640 public static boolean equalFieldOrMethods(FieldOrMethod a, 1641 FieldOrMethod b) { 1642 return a.getName().equals(b.getName()) && 1643 a.getSignature().equals(b.getSignature()); 1644 } 1645 1646 1654 1655 public static boolean equalMethods(Method a, Method b) { 1656 1657 ExceptionTable etaba = a.getExceptionTable(); 1659 ExceptionTable etabb = b.getExceptionTable(); 1660 if (etaba != null && etabb != null) { 1661 String [] aexcepts = etaba.getExceptionNames(); 1662 String [] bexcepts = etabb.getExceptionNames(); 1663 if (!Arrays.equals(aexcepts, bexcepts)) { 1664 return false; 1665 } 1666 } else if (etaba != null || etabb != null) { 1667 return false; 1668 } 1669 1670 Code acode = a.getCode(); 1672 Code bcode = b.getCode(); 1673 CodeException[] acexs = acode.getExceptionTable(); 1674 CodeException[] bcexs = bcode.getExceptionTable(); 1675 if (acexs.length == bcexs.length) { 1676 for (int i = 0; i < acexs.length; i++) { 1677 CodeException acex = acexs[i]; 1678 CodeException bcex = bcexs[i]; 1679 if (acex.getCatchType() != bcex.getCatchType() || 1680 acex.getStartPC() != bcex.getStartPC() || 1681 acex.getEndPC() != bcex.getEndPC() || 1682 acex.getHandlerPC() != bcex.getHandlerPC()) { 1683 return false; 1684 } 1685 } 1686 } 1687 1688 return Arrays.equals(acode.getCode(), bcode.getCode()); 1690 } 1691 1692 1700 1701 public boolean equals(Object obj) { 1702 if (obj instanceof ClassFile && obj.hashCode() == hashCode()) { 1703 1704 ClassFile comp = (ClassFile)obj; 1706 if (!org.jibx.runtime.Utility.isEqual(getPackage(), 1707 comp.getPackage()) || getSuperFile() != comp.getSuperFile() || 1708 !Arrays.equals(getInterfaces(), comp.getInterfaces())) { 1709 return false; 1710 } 1711 JavaClass tjc = m_curClass; 1712 JavaClass cjc = comp.m_curClass; 1713 if (tjc.getAccessFlags() != cjc.getAccessFlags()) { 1714 return false; 1715 } 1716 1717 Field[] tfields = tjc.getFields(); 1719 Field[] cfields = cjc.getFields(); 1720 if (tfields.length != cfields.length) { 1721 return false; 1722 } 1723 for (int i = 0; i < tfields.length; i++) { 1724 if (!equalFieldOrMethods(tfields[i], cfields[i])) { 1725 return false; 1726 } 1727 } 1728 1729 Method[] tmethods = tjc.getMethods(); 1731 Method[] cmethods = cjc.getMethods(); 1732 if (tmethods.length != cmethods.length) { 1733 return false; 1734 } 1735 for (int i = 0; i < tmethods.length; i++) { 1736 Method tmethod = tmethods[i]; 1737 Method cmethod = cmethods[i]; 1738 if (!equalFieldOrMethods(tmethod, cmethod) || 1739 !equalMethods(tmethod, cmethod)) { 1740 return false; 1741 } 1742 } 1743 1744 Constant[] tcnsts = tjc.getConstantPool().getConstantPool(); 1746 Constant[] ccnsts = cjc.getConstantPool().getConstantPool(); 1747 if (tcnsts.length != ccnsts.length) { 1748 return false; 1749 } 1750 for (int i = tjc.getClassNameIndex()+1; i < tcnsts.length; i++) { 1751 Constant tcnst = tcnsts[i]; 1752 Constant ccnst = ccnsts[i]; 1753 if (tcnst != null && ccnst != null) { 1754 int tag = tcnst.getTag(); 1755 if (tag != ccnst.getTag()) { 1756 return false; 1757 } 1758 boolean equal = true; 1759 switch (tag) { 1760 case Constants.CONSTANT_Double: 1761 equal = ((ConstantDouble)tcnst).getBytes() == 1762 ((ConstantDouble)ccnst).getBytes(); 1763 break; 1764 case Constants.CONSTANT_Float: 1765 equal = ((ConstantFloat)tcnst).getBytes() == 1766 ((ConstantFloat)ccnst).getBytes(); 1767 break; 1768 case Constants.CONSTANT_Integer: 1769 equal = ((ConstantInteger)tcnst).getBytes() == 1770 ((ConstantInteger)ccnst).getBytes(); 1771 break; 1772 case Constants.CONSTANT_Long: 1773 equal = ((ConstantLong)tcnst).getBytes() == 1774 ((ConstantLong)ccnst).getBytes(); 1775 break; 1776 case Constants.CONSTANT_Utf8: 1777 String ttext = ((ConstantUtf8)tcnst).getBytes(); 1778 String ctext = ((ConstantUtf8)ccnst).getBytes(); 1779 if (ttext.equals(m_signature)) { 1780 equal = ctext.equals(comp.m_signature); 1781 } else { 1782 equal = ttext.equals(ctext); 1783 } 1784 break; 1785 default: 1786 break; 1787 } 1788 if (!equal) { 1789 return false; 1790 } 1791 } else if (tcnst != null || ccnst != null) { 1792 return false; 1793 } 1794 } 1795 1796 return true; 1798 1799 } else { 1800 return false; 1801 } 1802 } 1803 1804 1811 1812 public void delete() throws IOException { 1813 if (m_file.exists()) { 1814 m_file.delete(); 1815 } 1816 } 1817 1818 1825 1826 public void writeFile(OutputStream os) throws IOException { 1827 codeComplete(); 1828 m_curClass.dump(os); 1829 os.close(); 1830 } 1831 1832 1839 1840 public void writeFile() throws IOException { 1841 if (m_isModified) { 1842 OutputStream os = new FileOutputStream (m_file); 1843 writeFile(os); 1844 } 1845 } 1846 1847 1856 1857 public String deriveClassName(String prefix, String suffix) { 1858 String pack = ""; 1859 String tname = m_name; 1860 int split = tname.lastIndexOf('.'); 1861 if (split >= 0) { 1862 pack = tname.substring(0, split+1); 1863 tname = tname.substring(split+1); 1864 } 1865 return pack + prefix + tname + suffix; 1866 } 1867 1868 1873 1874 public static void setPaths(String [] paths) { 1875 1876 StringBuffer full = new StringBuffer (); 1878 for (int i = 0; i < paths.length; i++) { 1879 if (i > 0) { 1880 full.append(File.pathSeparatorChar); 1881 } 1882 full.append(paths[i]); 1883 } 1884 s_loader = new ClassPath(full.toString()); 1885 1886 URL [] urls = new URL [paths.length]; 1888 try { 1889 1890 for (int i = 0; i < urls.length; i++) { 1892 1893 String path = paths[i]; 1895 int mark = path.lastIndexOf('/'); 1896 if (path.indexOf('.', mark) < 0) { 1897 path = path + '/'; 1898 } 1899 urls[i] = new URL ("file:" + path); 1900 } 1901 1902 s_directLoader = new URLClassLoader (urls); 1904 1905 } catch (MalformedURLException ex) { 1906 throw new IllegalArgumentException 1907 ("Error initializing classloading: " + ex.getMessage()); 1908 } 1909 } 1910 1911 1917 1918 public static Class loadClass(String name) { 1919 try { 1920 return s_directLoader.loadClass(name); 1921 } catch (ClassNotFoundException ex) { 1922 return null; 1923 } 1924 } 1925} | Popular Tags |