All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.bytecode.Descriptor Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package com.feilong.lib.javassist.bytecode;

import java.util.Map;

import com.feilong.lib.javassist.ClassPool;
import com.feilong.lib.javassist.CtClass;
import com.feilong.lib.javassist.CtPrimitiveType;
import com.feilong.lib.javassist.NotFoundException;

/**
 * A support class for dealing with descriptors.
 *
 * 

* See chapter 4.3 in "The Java Virtual Machine Specification (2nd ed.)" */ public class Descriptor{ /** * Converts a class name into the internal representation used in * the JVM. * *

* Note that toJvmName(toJvmName(s)) is equivalent * to toJvmName(s). */ public static String toJvmName(String classname){ return classname.replace('.', '/'); } /** * Converts a class name from the internal representation used in * the JVM to the normal one used in Java. * This method does not deal with an array type name such as * "[Ljava/lang/Object;" and "[I;". For such names, use * toClassName(). * * @see #toClassName(String) */ public static String toJavaName(String classname){ return classname.replace('/', '.'); } /** * Returns the internal representation of the class name in the * JVM. */ public static String toJvmName(CtClass clazz){ if (clazz.isArray()){ return of(clazz); } return toJvmName(clazz.getName()); } /** * Converts to a Java class name from a descriptor. * * @param descriptor * type descriptor. */ public static String toClassName(String descriptor){ int arrayDim = 0; int i = 0; char c = descriptor.charAt(0); while (c == '['){ ++arrayDim; c = descriptor.charAt(++i); } String name; if (c == 'L'){ int i2 = descriptor.indexOf(';', i++); name = descriptor.substring(i, i2).replace('/', '.'); i = i2; }else if (c == 'V'){ name = "void"; }else if (c == 'I'){ name = "int"; }else if (c == 'B'){ name = "byte"; }else if (c == 'J'){ name = "long"; }else if (c == 'D'){ name = "double"; }else if (c == 'F'){ name = "float"; }else if (c == 'C'){ name = "char"; }else if (c == 'S'){ name = "short"; }else if (c == 'Z'){ name = "boolean"; }else{ throw new RuntimeException("bad descriptor: " + descriptor); } if (i + 1 != descriptor.length()){ throw new RuntimeException("multiple descriptors?: " + descriptor); } if (arrayDim == 0){ return name; } StringBuffer sbuf = new StringBuffer(name); do{ sbuf.append("[]"); }while (--arrayDim > 0); return sbuf.toString(); } /** * Converts to a descriptor from a Java class name */ public static String of(String classname){ if (classname.equals("void")){ return "V"; }else if (classname.equals("int")){ return "I"; }else if (classname.equals("byte")){ return "B"; }else if (classname.equals("long")){ return "J"; }else if (classname.equals("double")){ return "D"; }else if (classname.equals("float")){ return "F"; }else if (classname.equals("char")){ return "C"; }else if (classname.equals("short")){ return "S"; }else if (classname.equals("boolean")){ return "Z"; }else{ return "L" + toJvmName(classname) + ";"; } } /** * Substitutes a class name * in the given descriptor string. * * @param desc * descriptor string * @param oldname * replaced JVM class name * @param newname * substituted JVM class name * * @see Descriptor#toJvmName(String) */ public static String rename(String desc,String oldname,String newname){ if (desc.indexOf(oldname) < 0){ return desc; } StringBuffer newdesc = new StringBuffer(); int head = 0; int i = 0; for (;;){ int j = desc.indexOf('L', i); if (j < 0){ break; }else if (desc.startsWith(oldname, j + 1) && desc.charAt(j + oldname.length() + 1) == ';'){ newdesc.append(desc.substring(head, j)); newdesc.append('L'); newdesc.append(newname); newdesc.append(';'); head = i = j + oldname.length() + 2; }else{ i = desc.indexOf(';', j) + 1; if (i < 1){ break; // ';' was not found. } } } if (head == 0){ return desc; } int len = desc.length(); if (head < len){ newdesc.append(desc.substring(head, len)); } return newdesc.toString(); } /** * Substitutes class names in the given descriptor string * according to the given map. * * @param map * a map between replaced and substituted * JVM class names. * @see Descriptor#toJvmName(String) */ public static String rename(String desc,Map map){ if (map == null){ return desc; } StringBuffer newdesc = new StringBuffer(); int head = 0; int i = 0; for (;;){ int j = desc.indexOf('L', i); if (j < 0){ break; } int k = desc.indexOf(';', j); if (k < 0){ break; } i = k + 1; String name = desc.substring(j + 1, k); String name2 = map.get(name); if (name2 != null){ newdesc.append(desc.substring(head, j)); newdesc.append('L'); newdesc.append(name2); newdesc.append(';'); head = i; } } if (head == 0){ return desc; } int len = desc.length(); if (head < len){ newdesc.append(desc.substring(head, len)); } return newdesc.toString(); } /** * Returns the descriptor representing the given type. */ public static String of(CtClass type){ StringBuffer sbuf = new StringBuffer(); toDescriptor(sbuf, type); return sbuf.toString(); } private static void toDescriptor(StringBuffer desc,CtClass type){ if (type.isArray()){ desc.append('['); try{ toDescriptor(desc, type.getComponentType()); }catch (NotFoundException e){ desc.append('L'); String name = type.getName(); desc.append(toJvmName(name.substring(0, name.length() - 2))); desc.append(';'); } }else if (type.isPrimitive()){ CtPrimitiveType pt = (CtPrimitiveType) type; desc.append(pt.getDescriptor()); }else{ // class type desc.append('L'); desc.append(type.getName().replace('.', '/')); desc.append(';'); } } /** * Returns the descriptor representing a constructor receiving * the given parameter types. * * @param paramTypes * parameter types */ public static String ofConstructor(CtClass[] paramTypes){ return ofMethod(CtClass.voidType, paramTypes); } /** * Returns the descriptor representing a method that receives * the given parameter types and returns the given type. * * @param returnType * return type * @param paramTypes * parameter types */ public static String ofMethod(CtClass returnType,CtClass[] paramTypes){ StringBuffer desc = new StringBuffer(); desc.append('('); if (paramTypes != null){ int n = paramTypes.length; for (int i = 0; i < n; ++i){ toDescriptor(desc, paramTypes[i]); } } desc.append(')'); if (returnType != null){ toDescriptor(desc, returnType); } return desc.toString(); } /** * Returns the descriptor representing a list of parameter types. * For example, if the given parameter types are two int, * then this method returns "(II)". * * @param paramTypes * parameter types */ public static String ofParameters(CtClass[] paramTypes){ return ofMethod(null, paramTypes); } /** * Appends a parameter type to the parameter list represented * by the given descriptor. * *

* classname must not be an array type. * * @param classname * parameter type (not primitive type) * @param desc * descriptor */ public static String appendParameter(String classname,String desc){ int i = desc.indexOf(')'); if (i < 0){ return desc; } StringBuffer newdesc = new StringBuffer(); newdesc.append(desc.substring(0, i)); newdesc.append('L'); newdesc.append(classname.replace('.', '/')); newdesc.append(';'); newdesc.append(desc.substring(i)); return newdesc.toString(); } /** * Inserts a parameter type at the beginning of the parameter * list represented * by the given descriptor. * *

* classname must not be an array type. * * @param classname * parameter type (not primitive type) * @param desc * descriptor */ public static String insertParameter(String classname,String desc){ if (desc.charAt(0) != '('){ return desc; } return "(L" + classname.replace('.', '/') + ';' + desc.substring(1); } /** * Appends a parameter type to the parameter list represented * by the given descriptor. The appended parameter becomes * the last parameter. * * @param type * the type of the appended parameter. * @param descriptor * the original descriptor. */ public static String appendParameter(CtClass type,String descriptor){ int i = descriptor.indexOf(')'); if (i < 0){ return descriptor; } StringBuffer newdesc = new StringBuffer(); newdesc.append(descriptor.substring(0, i)); toDescriptor(newdesc, type); newdesc.append(descriptor.substring(i)); return newdesc.toString(); } /** * Inserts a parameter type at the beginning of the parameter * list represented * by the given descriptor. * * @param type * the type of the inserted parameter. * @param descriptor * the descriptor of the method. */ public static String insertParameter(CtClass type,String descriptor){ if (descriptor.charAt(0) != '('){ return descriptor; } return "(" + of(type) + descriptor.substring(1); } /** * Changes the return type included in the given descriptor. * *

* classname must not be an array type. * * @param classname * return type * @param desc * descriptor */ public static String changeReturnType(String classname,String desc){ int i = desc.indexOf(')'); if (i < 0){ return desc; } StringBuffer newdesc = new StringBuffer(); newdesc.append(desc.substring(0, i + 1)); newdesc.append('L'); newdesc.append(classname.replace('.', '/')); newdesc.append(';'); return newdesc.toString(); } /** * Returns the CtClass objects representing the parameter * types specified by the given descriptor. * * @param desc * descriptor * @param cp * the class pool used for obtaining * a CtClass object. */ public static CtClass[] getParameterTypes(String desc,ClassPool cp) throws NotFoundException{ if (desc.charAt(0) != '('){ return null; } int num = numOfParameters(desc); CtClass[] args = new CtClass[num]; int n = 0; int i = 1; do{ i = toCtClass(cp, desc, i, args, n++); }while (i > 0); return args; } /** * Returns true if the list of the parameter types of desc1 is equal to * that of desc2. * For example, "(II)V" and "(II)I" are equal. */ public static boolean eqParamTypes(String desc1,String desc2){ if (desc1.charAt(0) != '('){ return false; } for (int i = 0; true; ++i){ char c = desc1.charAt(i); if (c != desc2.charAt(i)){ return false; } if (c == ')'){ return true; } } } /** * Returns the signature of the given descriptor. The signature does * not include the return type. For example, the signature of "(I)V" * is "(I)". */ public static String getParamDescriptor(String decl){ return decl.substring(0, decl.indexOf(')') + 1); } /** * Returns the CtClass object representing the return * type specified by the given descriptor. * * @param desc * descriptor * @param cp * the class pool used for obtaining * a CtClass object. */ public static CtClass getReturnType(String desc,ClassPool cp) throws NotFoundException{ int i = desc.indexOf(')'); if (i < 0){ return null; } CtClass[] type = new CtClass[1]; toCtClass(cp, desc, i + 1, type, 0); return type[0]; } /** * Returns the number of the prameters included in the given * descriptor. * * @param desc * descriptor */ public static int numOfParameters(String desc){ int n = 0; int i = 1; for (;;){ char c = desc.charAt(i); if (c == ')'){ break; } while (c == '['){ c = desc.charAt(++i); } if (c == 'L'){ i = desc.indexOf(';', i) + 1; if (i <= 0){ throw new IndexOutOfBoundsException("bad descriptor"); } }else{ ++i; } ++n; } return n; } /** * Returns a CtClass object representing the type * specified by the given descriptor. * *

* This method works even if the package-class separator is * not / but . (period). For example, * it accepts Ljava.lang.Object; * as well as Ljava/lang/Object;. * * @param desc * descriptor. * @param cp * the class pool used for obtaining * a CtClass object. */ public static CtClass toCtClass(String desc,ClassPool cp) throws NotFoundException{ CtClass[] clazz = new CtClass[1]; int res = toCtClass(cp, desc, 0, clazz, 0); if (res >= 0){ return clazz[0]; } // maybe, you forgot to surround the class name with // L and ;. It violates the protocol, but I'm tolerant... return cp.get(desc.replace('/', '.')); } private static int toCtClass(ClassPool cp,String desc,int i,CtClass[] args,int n) throws NotFoundException{ int i2; String name; int arrayDim = 0; char c = desc.charAt(i); while (c == '['){ ++arrayDim; c = desc.charAt(++i); } if (c == 'L'){ i2 = desc.indexOf(';', ++i); name = desc.substring(i, i2++).replace('/', '.'); }else{ CtClass type = toPrimitiveClass(c); if (type == null){ return -1; // error } i2 = i + 1; if (arrayDim == 0){ args[n] = type; return i2; // neither an array type or a class type } name = type.getName(); } if (arrayDim > 0){ StringBuffer sbuf = new StringBuffer(name); while (arrayDim-- > 0){ sbuf.append("[]"); } name = sbuf.toString(); } args[n] = cp.get(name); return i2; } static CtClass toPrimitiveClass(char c){ CtClass type = null; switch (c) { case 'Z': type = CtClass.booleanType; break; case 'C': type = CtClass.charType; break; case 'B': type = CtClass.byteType; break; case 'S': type = CtClass.shortType; break; case 'I': type = CtClass.intType; break; case 'J': type = CtClass.longType; break; case 'F': type = CtClass.floatType; break; case 'D': type = CtClass.doubleType; break; case 'V': type = CtClass.voidType; break; } return type; } /** * Computes the dimension of the array represented by the given * descriptor. For example, if the descriptor is "[[I", * then this method returns 2. * * @param desc * the descriptor. * @return 0 if the descriptor does not represent an array type. */ public static int arrayDimension(String desc){ int dim = 0; while (desc.charAt(dim) == '['){ ++dim; } return dim; } /** * Returns the descriptor of the type of the array component. * For example, if the given descriptor is * "[[Ljava/lang/String;" and the given dimension is 2, * then this method returns "Ljava/lang/String;". * * @param desc * the descriptor. * @param dim * the array dimension. */ public static String toArrayComponent(String desc,int dim){ return desc.substring(dim); } /** * Computes the data size specified by the given descriptor. * For example, if the descriptor is "D", this method returns 2. * *

* If the descriptor represents a method type, this method returns * (the size of the returned value) - (the sum of the data sizes * of all the parameters). For example, if the descriptor is * "(I)D", then this method returns 1 (= 2 - 1). * * @param desc * descriptor */ public static int dataSize(String desc){ return dataSize(desc, true); } /** * Computes the data size of parameters. * If one of the parameters is double type, the size of that parameter * is 2 words. For example, if the given descriptor is * "(IJ)D", then this method returns 3. The size of the * return type is not computed. * * @param desc * a method descriptor. */ public static int paramSize(String desc){ return -dataSize(desc, false); } private static int dataSize(String desc,boolean withRet){ int n = 0; char c = desc.charAt(0); if (c == '('){ int i = 1; for (;;){ c = desc.charAt(i); if (c == ')'){ c = desc.charAt(i + 1); break; } boolean array = false; while (c == '['){ array = true; c = desc.charAt(++i); } if (c == 'L'){ i = desc.indexOf(';', i) + 1; if (i <= 0){ throw new IndexOutOfBoundsException("bad descriptor"); } }else{ ++i; } if (!array && (c == 'J' || c == 'D')){ n -= 2; }else{ --n; } } } if (withRet){ if (c == 'J' || c == 'D'){ n += 2; }else if (c != 'V'){ ++n; } } return n; } /** * Returns a human-readable representation of the * given descriptor. For example, Ljava/lang/Object; * is converted into java.lang.Object. * (I[I)V is converted into (int, int[]) * (the return type is ignored). */ public static String toString(String desc){ return PrettyPrinter.toString(desc); } static class PrettyPrinter{ static String toString(String desc){ StringBuffer sbuf = new StringBuffer(); if (desc.charAt(0) == '('){ int pos = 1; sbuf.append('('); while (desc.charAt(pos) != ')'){ if (pos > 1){ sbuf.append(','); } pos = readType(sbuf, pos, desc); } sbuf.append(')'); }else{ readType(sbuf, 0, desc); } return sbuf.toString(); } static int readType(StringBuffer sbuf,int pos,String desc){ char c = desc.charAt(pos); int arrayDim = 0; while (c == '['){ arrayDim++; c = desc.charAt(++pos); } if (c == 'L'){ while (true){ c = desc.charAt(++pos); if (c == ';'){ break; } if (c == '/'){ c = '.'; } sbuf.append(c); } }else{ CtClass t = toPrimitiveClass(c); sbuf.append(t.getName()); } while (arrayDim-- > 0){ sbuf.append("[]"); } return pos + 1; } } /** * An Iterator over a descriptor. */ public static class Iterator{ private String desc; private int index, curPos; private boolean param; /** * Constructs an iterator. * * @param s * descriptor. */ public Iterator(String s){ desc = s; index = curPos = 0; param = false; } /** * Returns true if the iteration has more elements. */ public boolean hasNext(){ return index < desc.length(); } /** * Returns true if the current element is a parameter type. */ public boolean isParameter(){ return param; } /** * Returns the first character of the current element. */ public char currentChar(){ return desc.charAt(curPos); } /** * Returns true if the current element is double or long type. */ public boolean is2byte(){ char c = currentChar(); return c == 'D' || c == 'J'; } /** * Returns the position of the next type character. * That type character becomes a new current element. */ public int next(){ int nextPos = index; char c = desc.charAt(nextPos); if (c == '('){ ++index; c = desc.charAt(++nextPos); param = true; } if (c == ')'){ ++index; c = desc.charAt(++nextPos); param = false; } while (c == '['){ c = desc.charAt(++nextPos); } if (c == 'L'){ nextPos = desc.indexOf(';', nextPos) + 1; if (nextPos <= 0){ throw new IndexOutOfBoundsException("bad descriptor"); } }else{ ++nextPos; } curPos = index; index = nextPos; return curPos; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy