in src/main/java/org/apache/bcel/classfile/Utility.java [1376:1535]
public static String typeSignatureToString(final String signature, final boolean chopit) throws ClassFormatException {
// corrected concurrent private static field acess
wrap(CONSUMER_CHARS, 1); // This is the default, read just one char like 'B'
try {
switch (signature.charAt(0)) {
case 'B':
return "byte";
case 'C':
return "char";
case 'D':
return "double";
case 'F':
return "float";
case 'I':
return "int";
case 'J':
return "long";
case 'T': { // TypeVariableSignature
final int index = signature.indexOf(';'); // Look for closing ';'
if (index < 0) {
throw new ClassFormatException("Invalid type variable signature: " + signature);
}
// corrected concurrent private static field acess
wrap(CONSUMER_CHARS, index + 1); // "Tblabla;" 'T' and ';' are removed
return compactClassName(signature.substring(1, index), chopit);
}
case 'L': { // Full class name
// should this be a while loop? can there be more than
// one generic clause? (markro)
int fromIndex = signature.indexOf('<'); // generic type?
if (fromIndex < 0) {
fromIndex = 0;
} else {
fromIndex = signature.indexOf('>', fromIndex);
if (fromIndex < 0) {
throw new ClassFormatException("Invalid signature: " + signature);
}
}
final int index = signature.indexOf(';', fromIndex); // Look for closing ';'
if (index < 0) {
throw new ClassFormatException("Invalid signature: " + signature);
}
// check to see if there are any TypeArguments
final int bracketIndex = signature.substring(0, index).indexOf('<');
if (bracketIndex < 0) {
// just a class identifier
wrap(CONSUMER_CHARS, index + 1); // "Lblabla;" 'L' and ';' are removed
return compactClassName(signature.substring(1, index), chopit);
}
// but make sure we are not looking past the end of the current item
fromIndex = signature.indexOf(';');
if (fromIndex < 0) {
throw new ClassFormatException("Invalid signature: " + signature);
}
if (fromIndex < bracketIndex) {
// just a class identifier
wrap(CONSUMER_CHARS, fromIndex + 1); // "Lblabla;" 'L' and ';' are removed
return compactClassName(signature.substring(1, fromIndex), chopit);
}
// we have TypeArguments; build up partial result
// as we recurse for each TypeArgument
final StringBuilder type = new StringBuilder(compactClassName(signature.substring(1, bracketIndex), chopit)).append("<");
int consumedChars = bracketIndex + 1; // Shadows global var
// check for wildcards
if (signature.charAt(consumedChars) == '+') {
type.append("? extends ");
consumedChars++;
} else if (signature.charAt(consumedChars) == '-') {
type.append("? super ");
consumedChars++;
}
// get the first TypeArgument
if (signature.charAt(consumedChars) == '*') {
type.append("?");
consumedChars++;
} else {
type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
// update our consumed count by the number of characters the for type argument
consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
wrap(CONSUMER_CHARS, consumedChars);
}
// are there more TypeArguments?
while (signature.charAt(consumedChars) != '>') {
type.append(", ");
// check for wildcards
if (signature.charAt(consumedChars) == '+') {
type.append("? extends ");
consumedChars++;
} else if (signature.charAt(consumedChars) == '-') {
type.append("? super ");
consumedChars++;
}
if (signature.charAt(consumedChars) == '*') {
type.append("?");
consumedChars++;
} else {
type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
// update our consumed count by the number of characters the for type argument
consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
wrap(CONSUMER_CHARS, consumedChars);
}
}
// process the closing ">"
consumedChars++;
type.append(">");
if (signature.charAt(consumedChars) == '.') {
// we have a ClassTypeSignatureSuffix
type.append(".");
// convert SimpleClassTypeSignature to fake ClassTypeSignature
// and then recurse to parse it
type.append(typeSignatureToString("L" + signature.substring(consumedChars + 1), chopit));
// update our consumed count by the number of characters the for type argument
// note that this count includes the "L" we added, but that is ok
// as it accounts for the "." we didn't consume
consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
wrap(CONSUMER_CHARS, consumedChars);
return type.toString();
}
if (signature.charAt(consumedChars) != ';') {
throw new ClassFormatException("Invalid signature: " + signature);
}
wrap(CONSUMER_CHARS, consumedChars + 1); // remove final ";"
return type.toString();
}
case 'S':
return "short";
case 'Z':
return "boolean";
case '[': { // Array declaration
int n;
final StringBuilder brackets = new StringBuilder(); // Accumulate []'s
// Count opening brackets and look for optional size argument
for (n = 0; signature.charAt(n) == '['; n++) {
brackets.append("[]");
}
final int consumedChars = n; // Remember value
// The rest of the string denotes a '<field_type>'
final String type = typeSignatureToString(signature.substring(n), chopit);
// corrected concurrent private static field acess
// consumed_chars += consumed_chars; is replaced by:
final int temp = unwrap(CONSUMER_CHARS) + consumedChars;
wrap(CONSUMER_CHARS, temp);
return type + brackets.toString();
}
case 'V':
return "void";
default:
throw new ClassFormatException("Invalid signature: '" + signature + "'");
}
} catch (final StringIndexOutOfBoundsException e) { // Should never occur
throw new ClassFormatException("Invalid signature: " + signature, e);
}
}