📄 classfile.java
字号:
} /** * Check if a method name matches the pattern for a generated unique suffix. * * @param name method name to be checked * @return <code>true</code> if name matches suffix pattern, * <code>false</code> if not */ private static boolean isSuffixName(String name) { int last = name.length() - 1; for (int i = last; i > 0; i--) { char chr = name.charAt(i); if (chr == '_') { return i < last; } else if (!Character.isDigit(chr)) { break; } } return false; } /** * Make method name unique with generated suffix. The suffixed method name * is tracked so that it will not be used again. * * @param name base name before suffix is appended * @return name with unique suffix appended */ public String makeUniqueMethodName(String name) { // check if map creation is needed if (m_suffixMap == null) { m_suffixMap = new HashMap(); if (m_curClass != null) { Method[] methods = getMethods(); for (int i = 0; i < methods.length; i++) { Method method = methods[i]; String mname = method.getName(); if (isSuffixName(mname)) { m_suffixMap.put(mname, method); } } } } // check if inheritance depth is needed if (m_inheritDepth == 0) { ClassFile cf = this; while ((cf = cf.getSuperFile()) != null) { m_inheritDepth++; } } // generate suffix to make name unique, trying low values first while (true) { String uname = name + '_' + m_inheritDepth + '_' + m_uniqueIndex; if (m_suffixMap.get(uname) == null) { return uname; } else { m_uniqueIndex++; } } } /** * Delete field from class. * * @param name field name * @return <code>true</code> if field was present, <code>false</code> if not * @throws JiBXException if unable to delete field */ public boolean deleteField(String name) throws JiBXException { ClassGen cg = getClassGen(); Field field = cg.containsField(name); if (field == null) { return false; } else { cg.removeField(field); m_isModified = true; m_isHashCurrent = false; return true; } } /** * Get use count for class. * * @return use count for this class */ public int getUseCount() { return m_useCount; } /** * Increment use count for class. * * @return use count (after increment) */ public int incrementUseCount() { return ++m_useCount; } /** * Check if class has been modified. * * @return <code>true</code> if class is modified, <code>false</code> if not */ public boolean isModified() { return m_isModified; } /** * Set class modified flag. */ public void setModified() { m_isModified = true; MungedClass.addModifiedClass(this); } /** * Check if class is in complete state. * * @return <code>true</code> if class is complete, <code>false</code> if not */ public boolean isComplete() { return m_genClass == null; } /** * Computes a hash code based on characteristics of the class. The * characteristics used in computing the hash code include the base class, * implemented interfaces, method names, field names, and package, but not * the actual class name or signature. The current static version of the * class is used for this computation, so if the class is being modified * {@link #codeComplete} should be called before this method. Note that this * is designed for use with the classes generated by JiBX, and is not * necessarily a good model for general usage. * * @return computed hash code value */ protected int computeHashCode() { // start with basic characteristics of class int hash = getPackage().hashCode(); ClassFile sfile = getSuperFile(); if (sfile != null) { hash += sfile.getName().hashCode(); } String[] intfs = getInterfaces(); for (int i = 0; i < intfs.length; i++) { hash += intfs[i].hashCode(); } hash += m_curClass.getAccessFlags(); // include field and method names Field[] fields = m_curClass.getFields(); for (int i = 0; i < fields.length; i++) { hash = hash * 49 + fields[i].getName().hashCode(); } Method[] methods = m_curClass.getMethods(); for (int i = 0; i < methods.length; i++) { hash = hash * 49 + methods[i].getName().hashCode(); } // finish with constant table simple values (except name and signature) Constant[] cnsts = m_curClass.getConstantPool().getConstantPool(); for (int i = m_curClass.getClassNameIndex()+1; i < cnsts.length; i++) { Constant cnst = cnsts[i]; if (cnst != null) { int value = 0; switch (cnst.getTag()) { case Constants.CONSTANT_Double: value = (int)Double.doubleToRawLongBits (((ConstantDouble)cnst).getBytes()); break; case Constants.CONSTANT_Float: value = Float.floatToRawIntBits (((ConstantFloat)cnst).getBytes()); break; case Constants.CONSTANT_Integer: value = ((ConstantInteger)cnst).getBytes(); break; case Constants.CONSTANT_Long: value = (int)((ConstantLong)cnst).getBytes(); break; case Constants.CONSTANT_Utf8: String text = ((ConstantUtf8)cnst).getBytes(); if (!text.equals(m_signature)) { value = text.hashCode(); } break; default: break; } hash = hash * 49 + value; } }// System.out.println("Hashed " + m_name + " to value " + hash); return hash; } /** * Finalize current modified state of class. This converts the modified * class state into a static form, then computes a hash code based on * characteristics of the class. If the class has not been modified it * just computes the hash code. Note that this won't initialize the array * of superinterfaces if used with an interface, but that shouldn't be a * problem since we don't create any interfaces. */ public void codeComplete() { if (m_genClass != null) { m_curClass = m_genClass.getJavaClass(); m_interfaceNames = m_curClass.getInterfaceNames(); m_superInterfaces = new ClassFile[0]; m_genClass = null; } } /** * Get hash code. This is based on most characteristics of the class, * including the actual methods, but excluding the class name. It is only * valid after the {@link #codeComplete} method is called. * * @return hash code based on code sequence */ public int hashCode() { if (!m_isHashCurrent) { if (m_genClass != null) { throw new IllegalStateException ("Class still being constructed"); } m_hashCode = computeHashCode(); m_isHashCurrent = true; } return m_hashCode; } /** * Compare two field or method items to see if they're equal. This handles * only the comparisons that apply to both fields and methods. It does not * include comparing access flags, since these may be different due to * access requirements. * * @param a first field or method item * @param b second field or method item * @return <code>true</code> if the equal, <code>false</code> if not */ public static boolean equalFieldOrMethods(FieldOrMethod a, FieldOrMethod b) { return a.getName().equals(b.getName()) && a.getSignature().equals(b.getSignature()); } /** * Compare two methods to see if they're equal. This checks only the details * of the exception handling and actual code, not the name or signature. * * @param a first method * @param b second method * @return <code>true</code> if the equal, <code>false</code> if not */ public static boolean equalMethods(Method a, Method b) { // check the exceptions thrown by the method ExceptionTable etaba = a.getExceptionTable(); ExceptionTable etabb = b.getExceptionTable(); if (etaba != null && etabb != null) { String[] aexcepts = etaba.getExceptionNames(); String[] bexcepts = etabb.getExceptionNames(); if (!Arrays.equals(aexcepts, bexcepts)) { return false; } } else if (etaba != null || etabb != null) { return false; } // compare the exception handling details Code acode = a.getCode(); Code bcode = b.getCode(); CodeException[] acexs = acode.getExceptionTable(); CodeException[] bcexs = bcode.getExceptionTable(); if (acexs.length == bcexs.length) { for (int i = 0; i < acexs.length; i++) { CodeException acex = acexs[i]; CodeException bcex = bcexs[i]; if (acex.getCatchType() != bcex.getCatchType() || acex.getStartPC() != bcex.getStartPC() || acex.getEndPC() != bcex.getEndPC() || acex.getHandlerPC() != bcex.getHandlerPC()) { return false; } } } // finally compare the actual byte codes return Arrays.equals(acode.getCode(), bcode.getCode()); } /** * Check if objects are equal. Compares first based on hash code, then on * the actual contents of the class, including package, implemented * interfaces, superclass, methods, and fields (but not the actual class * name). It is only valid after the {@link #codeComplete} method is called. * * @return <code>true</code> if equal objects, <code>false</code> if not */ public boolean equals(Object obj) { if (obj instanceof ClassFile && obj.hashCode() == hashCode()) { // check basic details of the classes ClassFile comp = (ClassFile)obj; if (!org.jibx.runtime.Utility.isEqual(getPackage(), comp.getPackage()) || getSuperFile() != comp.getSuperFile() || !Arrays.equals(getInterfaces(), comp.getInterfaces())) { return false; } JavaClass tjc = m_curClass; JavaClass cjc = comp.m_curClass; if (tjc.getAccessFlags() != cjc.getAccessFlags()) { return false; } // compare the defined fields Field[] tfields = tjc.getFields(); Field[] cfields = cjc.getFields(); if (tfields.length != cfields.length) { return false; } for (int i = 0; i < tfields.length; i++) { if (!equalFieldOrMethods(tfields[i], cfields[i])) { return false; } } // compare the defined methods Method[] tmethods = tjc.getMethods(); Method[] cmethods = cjc.getMethods(); if (tmethods.length != cmethods.length) { return false; } for (int i = 0; i < tmethods.length; i++) { Method tmethod = tmethods[i]; Method cmethod = cmethods[i]; if (!equalFieldOrMethods(tmethod, cmethod) || !equalMethods(tmethod, cmethod)) { return false; } } // finish with constant table values (correcting name and signature) Constant[] tcnsts = tjc.getConstantPool().getConstantPool(); Constant[] ccnsts = cjc.getConstantPool().getConstantPool(); if (tcnsts.length != ccnsts.length) { return false; } for (int i = tjc.getClassNameIndex()+1; i < tcnsts.length; i++) { Constant tcnst = tcnsts[i]; Constant ccnst = ccnsts[i]; if (tcnst != null && ccnst != null) { int tag = tcnst.getTag(); if (tag != ccnst.getTag()) { return false; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -