/*******************************************************************************
* Copyright © 2000, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.ide.core.model;
import org.eclipse.edt.compiler.internal.core.utils.CharOperation;
;
// TODO Get all types done
/**
* Provides methods for encoding and decoding type and method signature strings.
* <p>
* The syntax for a type signature is:
* <pre>
* typeSignature ::=
* "A" // bigint
* | "B" // bin
* | "C" // byte
* | "D" // char
* | "E" // date
* | "F" // dbchar
* | "G" // decimal
* | "H" // decimalfloat
* | "I" // float
* | "J" // int
* | "K" // interval
* | "L" // integerdate
* | "M" // mbchar
* | "N" // num
* | "O" // smallint
* | "P" // time
* | "Q" // timestamp
* | "R" // unicode
* | "S" // varchar
* | "T" // vardbchar
* | "U" // varmbchar
* | "V" // varunicode
* | "W" // void
* | "X" // boolean
* | "Y" + sourceTypeName + ";" // unresolved named type (in source code)
* | "[" + typeSignature // array of type denoted by typeSignature
* </pre>
* </p>
* <p>
* Examples:
* <ul>
* <li><code>"[[I"</code> denotes <code>int[][]</code></li>
* <li><code>"QRecordX"</code> denotes <code>RecordX</code> in source code</li>
* <li><code>"Qmy.pkg.RecordX"</code> denotes <code>my.pkg.RecordX</code> in source code</li>
* <li><code>"[QString"</code> denotes <code>String[]</code> in source code</li>
* </ul>
* </p>
* <p>
* The syntax for a method signature is:
* <pre>
* methodSignature ::= "(" + paramTypeSignature* + ")" + returnTypeSignature
* paramTypeSignature ::= typeSignature
* returnTypeSignature ::= typeSignature
* </pre>
* <p>
* Examples:
* <ul>
* <li><code>"()I"</code> denotes <code>int foo()</code></li>
* <li><code>"([Ljava.lang.String;)V"</code> denotes <code>void foo(java.lang.String[])</code> in compiled code</li>
* <li><code>"(QString;)QObject;"</code> denotes <code>Object foo(String)</code> in source code</li>
* </ul>
* </p>
* <p>
* This class provides static methods and constants only; it is not intended to be
* instantiated or subclassed by clients.
* </p>
*/
public final class Signature {
public static final char C_ARRAY = '[';
public static final char C_BIGINT = 'A';
public static final char C_BIN = 'B';
public static final char C_BYTE = 'C';
public static final char C_CHAR = 'D';
public static final char C_DATE = 'E';
public static final char C_DBCHAR = 'F';
public static final char C_DECIMAL = 'G';
public static final char C_DECIMALFLOAT = 'H';
public static final char C_FLOAT = 'I';
public static final char C_INT = 'J';
public static final char C_INTERVAL = 'K';
public static final char C_INTEGERDATE = 'L';
public static final char C_MBCHAR = 'M';
public static final char C_NUM = 'N';
public static final char C_NUMBER = 'O';
public static final char C_SMALLINT = 'P';
public static final char C_TIME = 'Q';
public static final char C_TIMESTAMP = 'R';
public static final char C_UNICODE = 'S';
public static final char C_VARCHAR = 'T';
public static final char C_VARDBCHAR = 'U';
public static final char C_VARMBCHAR = 'V';
public static final char C_VARUNICODE = 'W';
public static final char C_VOID = 'X';
public static final char C_RESOLVED = 'Y';
public static final char C_UNRESOLVED = 'Z';
public static final char C_DOT = '.';
public static final char C_SEMICOLON = ';';
public static final char C_DOLLAR = '$';
public static final char C_NAME_END = ';';
public static final char C_PARAM_START = '(';
public static final char C_PARAM_END = ')';
public static final String SIG_ARRAY = "["; //$NON-NLS-1$
public static final String SIG_BIGINT = "A"; //$NON-NLS-1$
public static final String SIG_BIN = "B"; //$NON-NLS-1$
public static final String SIG_BYTE = "C"; //$NON-NLS-1$
public static final String SIG_CHAR = "D"; //$NON-NLS-1$
public static final String SIG_DATE = "E"; //$NON-NLS-1$
public static final String SIG_DBCHAR = "F"; //$NON-NLS-1$
public static final String SIG_DECIMAL = "G"; //$NON-NLS-1$
public static final String SIG_DECIMALFLOAT = "H"; //$NON-NLS-1$
public static final String SIG_FLOAT = "I"; //$NON-NLS-1$
public static final String SIG_INT = "J"; //$NON-NLS-1$
public static final String SIG_INTERVAL = "K"; //$NON-NLS-1$
public static final String SIG_INTEGERDATE = "L"; //$NON-NLS-1$
public static final String SIG_MBCHAR = "M"; //$NON-NLS-1$
public static final String SIG_NUM = "N"; //$NON-NLS-1$
public static final String SIG_NUMBER = "O"; //$NON-NLS-1$
public static final String SIG_SMALLINT = "P"; //$NON-NLS-1$
public static final String SIG_TIME = "Q"; //$NON-NLS-1$
public static final String SIG_TIMESTAMP = "R"; //$NON-NLS-1$
public static final String SIG_UNICODE = "S"; //$NON-NLS-1$
public static final String SIG_VARCHAR = "T"; //$NON-NLS-1$
public static final String SIG_VARDBCHAR = "U"; //$NON-NLS-1$
public static final String SIG_VARMBCHAR = "V"; //$NON-NLS-1$
public static final String SIG_VARUNICODE = "W"; //$NON-NLS-1$
public static final String SIG_VOID = "X"; //$NON-NLS-1$
public static final String SIG_RESOLVED = "Y"; //$NON-NLS-1$
public static final String SIG_UNRESOLVED = "Z"; //$NON-NLS-1$
public static final String SIG_DOT = "."; //$NON-NLS-1$
public static final String SIG_SEMICOLON = ";"; //$NON-NLS-1$
public static final String SIG_DOLLAR = "$"; //$NON-NLS-1$
public static final String SIG_NAME_END = ";"; //$NON-NLS-1$
public static final String SIG_PARAM_START = "("; //$NON-NLS-1$
public static final String SIG_PARAM_END = ")"; //$NON-NLS-1$
private static final String EMPTY = new String(CharOperation.NO_CHAR);
private static final char[] BIGINT = { 'b', 'i', 'g', 'i', 'n', 't' };
private static final char[] BIN = { 'b', 'i', 'n' };
private static final char[] BYTE = { 'b', 'y', 't', 'e' };
private static final char[] CHAR = { 'c', 'h', 'a', 'r' };
private static final char[] DATE = { 'd', 'a', 't', 'e' };
private static final char[] DBCHAR = { 'd', 'b', 'c', 'h', 'a', 'r' };
private static final char[] DECIMAL = { 'd', 'e', 'c', 'i', 'm', 'a', 'l' };
private static final char[] DECIMALFLOAT =
{ 'd', 'e', 'c', 'i', 'm', 'a', 'l', 'f', 'l', 'o', 'a', 't' };
private static final char[] FLOAT = { 'f', 'l', 'o', 'a', 't' };
private static final char[] INT = { 'i', 'n', 't' };
private static final char[] INTERVAL =
{ 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l' };
private static final char[] INTEGERDATE =
{ 'i', 'n', 't', 'e', 'g', 'e', 'r', 'd', 'a', 't', 'e' };
private static final char[] MBCHAR = { 'm', 'b', 'c', 'h', 'a', 'r' };
private static final char[] NUM = { 'n', 'u', 'm' };
private static final char[] NUMBER = { 'n', 'u', 'm','b','e','r' };
private static final char[] SMALLINT =
{ 's', 'm', 'a', 'l', 'l', 'i', 'n', 't' };
private static final char[] TIME = { 't', 'i', 'm', 'e' };
private static final char[] TIMESTAMP =
{ 't', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p' };
private static final char[] UNICODE = { 'u', 'n', 'i', 'c', 'o', 'd', 'e' };
private static final char[] VARCHAR = { 'v', 'a', 'r', 'c', 'h', 'a', 'r' };
private static final char[] VARDBCHAR =
{ 'v', 'a', 'r', 'd', 'b', 'c', 'h', 'a', 'r' };
private static final char[] VARMBCHAR =
{ 'v', 'a', 'r', 'm', 'b', 'c', 'h', 'a', 'r' };
private static final char[] VARUNICODE =
{ 'u', 'n', 'i', 'c', 'o', 'd', 'e' };
/**
* Not instantiable.
*/
private Signature() {
}
private static long copyType(
char[] signature,
int sigPos,
char[] dest,
int index,
boolean fullyQualifyTypeNames) {
int arrayCount = 0;
loop : while (true) {
switch (signature[sigPos++]) {
case C_ARRAY :
arrayCount++;
break;
case C_BIGINT :
case C_BIN :
int length = BIN.length;
System.arraycopy(BIN, 0, dest, index, length);
index += length;
break loop;
case C_BYTE :
length = BYTE.length;
System.arraycopy(BYTE, 0, dest, index, length);
index += length;
break loop;
case C_CHAR :
length = CHAR.length;
System.arraycopy(CHAR, 0, dest, index, length);
index += length;
break loop;
case C_DATE :
length = DATE.length;
System.arraycopy(DATE, 0, dest, index, length);
index += length;
break loop;
case C_DBCHAR :
length = DBCHAR.length;
System.arraycopy(DBCHAR, 0, dest, index, length);
index += length;
break loop;
case C_DECIMAL :
length = DECIMAL.length;
System.arraycopy(DECIMAL, 0, dest, index, length);
index += length;
break loop;
case C_DECIMALFLOAT :
length = DECIMALFLOAT.length;
System.arraycopy(DECIMALFLOAT, 0, dest, index, length);
index += length;
break loop;
case C_FLOAT :
length = FLOAT.length;
System.arraycopy(FLOAT, 0, dest, index, length);
index += length;
break loop;
case C_INT :
length = INT.length;
System.arraycopy(INT, 0, dest, index, length);
index += length;
break loop;
case C_INTERVAL :
length = INTERVAL.length;
System.arraycopy(INTERVAL, 0, dest, index, length);
index += length;
break loop;
case C_INTEGERDATE :
length = INT.length;
System.arraycopy(INTEGERDATE, 0, dest, index, length);
index += length;
break loop;
case C_MBCHAR :
length = MBCHAR.length;
System.arraycopy(MBCHAR, 0, dest, index, length);
index += length;
break loop;
case C_NUM :
length = NUM.length;
System.arraycopy(NUM, 0, dest, index, length);
index += length;
break loop;
case C_NUMBER :
length = NUMBER.length;
System.arraycopy(NUMBER, 0, dest, index, length);
index += length;
break loop;
case C_SMALLINT :
length = SMALLINT.length;
System.arraycopy(SMALLINT, 0, dest, index, length);
index += length;
break loop;
case C_TIME :
length = TIME.length;
System.arraycopy(TIME, 0, dest, index, length);
index += length;
break loop;
case C_TIMESTAMP :
length = TIMESTAMP.length;
System.arraycopy(TIMESTAMP, 0, dest, index, length);
index += length;
break loop;
case C_UNICODE :
length = UNICODE.length;
System.arraycopy(UNICODE, 0, dest, index, length);
index += length;
break loop;
case C_VARCHAR :
length = VARCHAR.length;
System.arraycopy(VARCHAR, 0, dest, index, length);
index += length;
break loop;
case C_VARDBCHAR :
length = VARDBCHAR.length;
System.arraycopy(VARDBCHAR, 0, dest, index, length);
index += length;
break loop;
case C_VARMBCHAR :
length = VARMBCHAR.length;
System.arraycopy(VARMBCHAR, 0, dest, index, length);
index += length;
break loop;
case C_VARUNICODE :
length = VARUNICODE.length;
System.arraycopy(VARUNICODE, 0, dest, index, length);
index += length;
break loop;
case C_RESOLVED :
case C_UNRESOLVED :
int end =
CharOperation.indexOf(C_SEMICOLON, signature, sigPos);
if (end == -1)
throw new IllegalArgumentException();
int start;
if (fullyQualifyTypeNames) {
start = sigPos;
} else {
start =
CharOperation.lastIndexOf(
C_DOT,
signature,
sigPos,
end)
+ 1;
if (start == 0)
start = sigPos;
}
length = end - start;
System.arraycopy(signature, start, dest, index, length);
sigPos = end + 1;
index += length;
break loop;
}
}
while (arrayCount-- > 0) {
dest[index++] = '[';
dest[index++] = ']';
}
return (((long) index) << 32) + sigPos;
}
/**
* Creates a new type signature with the given amount of array nesting added
* to the given type signature.
*
* @param typeSignature the type signature
* @param arrayCount the desired number of levels of array nesting
* @return the encoded array type signature
*
* @since 2.0
*/
public static char[] createArraySignature(
char[] typeSignature,
int arrayCount) {
if (arrayCount == 0)
return typeSignature;
int sigLength = typeSignature.length;
char[] result = new char[arrayCount + sigLength];
for (int i = 0; i < arrayCount; i++) {
result[i] = C_ARRAY;
}
System.arraycopy(typeSignature, 0, result, arrayCount, sigLength);
return result;
}
/**
* Creates a new type signature with the given amount of array nesting added
* to the given type signature.
*
* @param typeSignature the type signature
* @param arrayCount the desired number of levels of array nesting
* @return the encoded array type signature
*/
public static String createArraySignature(
String typeSignature,
int arrayCount) {
return new String(
createArraySignature(typeSignature.toCharArray(), arrayCount));
}
/**
* Creates a method signature from the given parameter and return type
* signatures. The encoded method signature is dot-based.
*
* @param parameterTypes the list of parameter type signatures
* @param returnType the return type signature
* @return the encoded method signature
*
* @since 2.0
*/
public static char[] createFunctionSignature(
char[][] parameterTypes,
char[] returnType) {
int parameterTypesLength = parameterTypes.length;
int parameterLength = 0;
for (int i = 0; i < parameterTypesLength; i++) {
parameterLength += parameterTypes[i].length;
}
int returnTypeLength = returnType.length;
char[] result = new char[1 + parameterLength + 1 + returnTypeLength];
result[0] = C_PARAM_START;
int index = 1;
for (int i = 0; i < parameterTypesLength; i++) {
char[] parameterType = parameterTypes[i];
int length = parameterType.length;
System.arraycopy(parameterType, 0, result, index, length);
index += length;
}
result[index] = C_PARAM_END;
System.arraycopy(returnType, 0, result, index + 1, returnTypeLength);
return result;
}
/**
* Creates a method signature from the given parameter and return type
* signatures. The encoded method signature is dot-based.
*
* @param parameterTypes the list of parameter type signatures
* @param returnType the return type signature
* @return the encoded method signature
*/
public static String createFunctionSignature(
String[] parameterTypes,
String returnType) {
int parameterTypesLenth = parameterTypes.length;
char[][] parameters = new char[parameterTypesLenth][];
for (int i = 0; i < parameterTypesLenth; i++) {
parameters[i] = parameterTypes[i].toCharArray();
}
return new String(
createFunctionSignature(parameters, returnType.toCharArray()));
}
/**
* Creates a new type signature from the given type name encoded as a character
* array. This method is equivalent to
* <code>createTypeSignature(new String(typeName),isResolved)</code>, although
* more efficient for callers with character arrays rather than strings. If the
* type name is qualified, then it is expected to be dot-based.
*
* @param typeName the possibly qualified type name
* @param isResolved <code>true</code> if the type name is to be considered
* resolved (for example, a type name from a binary class file), and
* <code>false</code> if the type name is to be considered unresolved
* (for example, a type name found in source code)
* @return the encoded type signature
* @see #createTypeSignature(java.lang.String,boolean)
*/
public static String createTypeSignature(
char[] typeName,
boolean isResolved) {
return typeName.length == 0 ? "" : new String(createCharArrayTypeSignature(typeName, isResolved));
}
/**
* Creates a new type signature from the given type name encoded as a character
* array. This method is equivalent to
* <code>createTypeSignature(new String(typeName),isResolved).toCharArray()</code>, although
* more efficient for callers with character arrays rather than strings. If the
* type name is qualified, then it is expected to be dot-based.
*
* @param typeName the possibly qualified type name
* @param isResolved <code>true</code> if the type name is to be considered
* resolved (for example, a type name from a binary class file), and
* <code>false</code> if the type name is to be considered unresolved
* (for example, a type name found in source code)
* @return the encoded type signature
* @see #createTypeSignature(java.lang.String,boolean)
*
* @since 2.0
*/
public static char[] createCharArrayTypeSignature(
char[] typeName,
boolean isResolved) {
if (typeName == null)
throw new IllegalArgumentException("null"); //$NON-NLS-1$
int length = typeName.length;
if (length == 0)
throw new IllegalArgumentException(new String(typeName));
int arrayCount = CharOperation.occurencesOf('[', typeName);
char[] sig;
switch (typeName[0]) {
// primitive type?
case 'b' :
if (CharOperation.fragmentEquals(BIGINT, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_BIGINT;
break;
} else if (
CharOperation.fragmentEquals(BYTE, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_BYTE;
break;
} else if (
CharOperation.fragmentEquals(BIN, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_BIN;
break;
}
case 'c' :
if (CharOperation.fragmentEquals(CHAR, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_CHAR;
break;
}
case 'd' :
if (CharOperation
.fragmentEquals(DECIMALFLOAT, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_DECIMALFLOAT;
break;
} else if (
CharOperation.fragmentEquals(
DECIMAL,
typeName,
0,
false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_DECIMAL;
break;
} else if (
CharOperation.fragmentEquals(DATE, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_DATE;
break;
} else if (
CharOperation.fragmentEquals(DBCHAR, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_DBCHAR;
break;
}
case 'f' :
if (CharOperation.fragmentEquals(FLOAT, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_FLOAT;
break;
}
case 'i' :
if (CharOperation.fragmentEquals(
INTEGERDATE,
typeName,
0,
false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_INTEGERDATE;
break;
}else if (CharOperation.fragmentEquals(
INTERVAL,
typeName,
0,
false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_INTERVAL;
break;
} else if (CharOperation.fragmentEquals(INT, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_INT;
break;
}
case 'm' :
if (CharOperation.fragmentEquals(MBCHAR, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_MBCHAR;
break;
}
case 'n' :
if (CharOperation.fragmentEquals(NUM, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_NUM;
break;
} else if (CharOperation.fragmentEquals(NUMBER, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_NUMBER;
break;
}
case 's' :
if (CharOperation
.fragmentEquals(SMALLINT, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_SMALLINT;
break;
}
case 't' :
if (CharOperation.fragmentEquals(TIME, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_TIME;
break;
} else if (
CharOperation.fragmentEquals(
TIMESTAMP,
typeName,
0,
false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_TIMESTAMP;
break;
}
case 'u' :
if (CharOperation
.fragmentEquals(UNICODE, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_UNICODE;
break;
}
case 'v' :
if (CharOperation
.fragmentEquals(VARCHAR, typeName, 0, false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_VARCHAR;
break;
} else if (
CharOperation.fragmentEquals(
VARDBCHAR,
typeName,
0,
false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_VARDBCHAR;
break;
} else if (
CharOperation.fragmentEquals(
VARUNICODE,
typeName,
0,
false)) {
sig = new char[arrayCount + 1];
sig[arrayCount] = C_VARUNICODE;
break;
}
default :
// non primitive type
int sigLength = arrayCount + 1 + length + 1;
// for example '[[[Ljava.lang.String;'
sig = new char[sigLength];
int sigIndex = arrayCount + 1; // index in sig
int startID = 0; // start of current ID in typeName
int index = 0; // index in typeName
while (index < length) {
char currentChar = typeName[index];
switch (currentChar) {
case '.' :
if (startID == -1)
throw new IllegalArgumentException(
new String(typeName));
if (startID < index) {
sig =
CharOperation.append(
sig,
sigIndex,
typeName,
startID,
index);
sigIndex += index - startID;
}
sig[sigIndex++] = C_DOT;
index++;
startID = index;
break;
case '[' :
if (startID != -1) {
if (startID < index) {
sig =
CharOperation.append(
sig,
sigIndex,
typeName,
startID,
index);
sigIndex += index - startID;
}
startID = -1; // no more id after []
}
index++;
break;
default :
if (startID != -1
&& CharOperation.isWhitespace(currentChar)) {
if (startID < index) {
sig =
CharOperation.append(
sig,
sigIndex,
typeName,
startID,
index);
sigIndex += index - startID;
}
startID = index + 1;
}
index++;
break;
}
}
// last id
if (startID != -1 && startID < index) {
sig =
CharOperation.append(
sig,
sigIndex,
typeName,
startID,
index);
sigIndex += index - startID;
}
// add L (or Q) at the beigininig and ; at the end
sig[arrayCount] = isResolved ? C_RESOLVED : C_UNRESOLVED;
sig[sigIndex++] = C_NAME_END;
// resize if needed
if (sigLength > sigIndex) {
System.arraycopy(
sig,
0,
sig = new char[sigIndex],
0,
sigIndex);
}
}
// add array info
for (int i = 0; i < arrayCount; i++) {
sig[i] = C_ARRAY;
}
return sig;
}
/**
* Creates a new type signature from the given type name. If the type name is qualified,
* then it is expected to be dot-based.
* <p>
* For example:
* <pre>
* <code>
* createTypeSignature("int", hucairz) -> "I"
* createTypeSignature("my.company.Record1", true) -> "Ymy.company.Record1;"
* createTypeSignature("Record1", false) -> "ZRecord1;"
* createTypeSignature("my.company.Record1", false) -> "Zjava.lang.String;"
* createTypeSignature("int []", false) -> "[I"
* </code>
* </pre>
* </p>
*
* @param typeName the possibly qualified type name
* @param isResolved <code>true</code> if the type name is to be considered
* resolved (for example, a type name from a binary class file), and
* <code>false</code> if the type name is to be considered unresolved
* (for example, a type name found in source code)
* @return the encoded type signature
*/
public static String createTypeSignature(
String typeName,
boolean isResolved) {
return createTypeSignature(
typeName == null ? null : typeName.toCharArray(),
isResolved);
}
/**
* Returns the array count (array nesting depth) of the given type signature.
*
* @param typeSignature the type signature
* @return the array nesting depth, or 0 if not an array
* @exception IllegalArgumentException if the signature is not syntactically
* correct
*
* @since 2.0
*/
public static int getArrayCount(char[] typeSignature)
throws IllegalArgumentException {
try {
int count = 0;
while (typeSignature[count] == C_ARRAY) {
++count;
}
return count;
} catch (ArrayIndexOutOfBoundsException e) { // signature is syntactically incorrect if last character is C_ARRAY
throw new IllegalArgumentException();
}
}
/**
* Returns the array count (array nesting depth) of the given type signature.
*
* @param typeSignature the type signature
* @return the array nesting depth, or 0 if not an array
* @exception IllegalArgumentException if the signature is not syntactically
* correct
*/
public static int getArrayCount(String typeSignature)
throws IllegalArgumentException {
return getArrayCount(typeSignature.toCharArray());
}
/**
* Returns the type signature without any array nesting.
* <p>
* For example:
* <pre>
* <code>
* getElementType({'[', '[', 'I'}) --> {'I'}.
* </code>
* </pre>
* </p>
*
* @param typeSignature the type signature
* @return the type signature without arrays
* @exception IllegalArgumentException if the signature is not syntactically
* correct
*
* @since 2.0
*/
public static char[] getElementType(char[] typeSignature)
throws IllegalArgumentException {
int count = getArrayCount(typeSignature);
if (count == 0)
return typeSignature;
int length = typeSignature.length;
char[] result = new char[length - count];
System.arraycopy(typeSignature, count, result, 0, length - count);
return result;
}
/**
* Returns the type signature without any array nesting.
* <p>
* For example:
* <pre>
* <code>
* getElementType("[[I") --> "I".
* </code>
* </pre>
* </p>
*
* @param typeSignature the type signature
* @return the type signature without arrays
* @exception IllegalArgumentException if the signature is not syntactically
* correct
*/
public static String getElementType(String typeSignature)
throws IllegalArgumentException {
return new String(getElementType(typeSignature.toCharArray()));
}
/**
* Returns the number of parameter types in the given method signature.
*
* @param methodSignature the method signature
* @return the number of parameters
* @exception IllegalArgumentException if the signature is not syntactically
* correct
* @since 2.0
*/
public static int getParameterCount(char[] methodSignature)
throws IllegalArgumentException {
try {
int count = 0;
int i = CharOperation.indexOf(C_PARAM_START, methodSignature) + 1;
if (i == 0)
throw new IllegalArgumentException();
for (;;) {
char c = methodSignature[i++];
switch (c) {
case C_ARRAY :
break;
case C_BIGINT :
case C_BIN :
case C_BYTE :
case C_CHAR :
case C_DATE :
case C_DBCHAR :
case C_DECIMAL :
case C_DECIMALFLOAT :
case C_FLOAT :
case C_INT :
case C_INTERVAL :
case C_INTEGERDATE :
case C_MBCHAR :
case C_NUM :
case C_NUMBER :
case C_SMALLINT :
case C_TIME :
case C_TIMESTAMP :
case C_UNICODE :
case C_VARCHAR :
case C_VARDBCHAR :
case C_VARMBCHAR :
case C_VARUNICODE :
++count;
break;
case C_RESOLVED :
case C_UNRESOLVED :
i =
CharOperation.indexOf(
C_SEMICOLON,
methodSignature,
i)
+ 1;
if (i == 0)
throw new IllegalArgumentException();
++count;
break;
case C_PARAM_END :
return count;
default :
throw new IllegalArgumentException();
}
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException();
}
}
/**
* Returns the number of parameter types in the given method signature.
*
* @param methodSignature the method signature
* @return the number of parameters
* @exception IllegalArgumentException if the signature is not syntactically
* correct
*/
public static int getParameterCount(String methodSignature)
throws IllegalArgumentException {
return getParameterCount(methodSignature.toCharArray());
}
/**
* Extracts the parameter type signatures from the given method signature.
* The method signature is expected to be dot-based.
*
* @param methodSignature the method signature
* @return the list of parameter type signatures
* @exception IllegalArgumentException if the signature is syntactically
* incorrect
*
* @since 2.0
*/
public static char[][] getParameterTypes(char[] methodSignature)
throws IllegalArgumentException {
try {
int count = getParameterCount(methodSignature);
char[][] result = new char[count][];
if (count == 0)
return result;
int i = CharOperation.indexOf(C_PARAM_START, methodSignature) + 1;
count = 0;
int start = i;
for (;;) {
char c = methodSignature[i++];
switch (c) {
case C_ARRAY :
// array depth is i - start;
break;
case C_BIGINT :
case C_BIN :
case C_BYTE :
case C_CHAR :
case C_DATE :
case C_DBCHAR :
case C_DECIMAL :
case C_DECIMALFLOAT :
case C_FLOAT :
case C_INT :
case C_INTERVAL :
case C_INTEGERDATE :
case C_MBCHAR :
case C_NUM :
case C_NUMBER :
case C_SMALLINT :
case C_TIME :
case C_TIMESTAMP :
case C_UNICODE :
case C_VARCHAR :
case C_VARDBCHAR :
case C_VARMBCHAR :
case C_VARUNICODE :
// common case of base types
if (i - start == 1) {
switch (c) {
case C_BIGINT :
result[count++] = new char[] { C_BIGINT };
break;
case C_BIN :
result[count++] = new char[] { C_BIN };
break;
case C_BYTE :
result[count++] = new char[] { C_BYTE };
break;
case C_CHAR :
result[count++] = new char[] { C_CHAR };
break;
case C_DATE :
result[count++] = new char[] { C_DATE };
break;
case C_DBCHAR :
result[count++] = new char[] { C_DBCHAR };
break;
case C_DECIMAL :
result[count++] = new char[] { C_DECIMAL };
break;
case C_DECIMALFLOAT :
result[count++] =
new char[] { C_DECIMALFLOAT };
break;
case C_FLOAT :
result[count++] = new char[] { C_FLOAT };
break;
case C_INT :
result[count++] = new char[] { C_INT };
break;
case C_INTERVAL :
result[count++] = new char[] { C_INTERVAL };
break;
case C_INTEGERDATE :
result[count++] =
new char[] { C_INTEGERDATE };
break;
case C_MBCHAR :
result[count++] = new char[] { C_MBCHAR };
break;
case C_NUM :
result[count++] = new char[] { C_NUM };
break;
case C_NUMBER :
result[count++] = new char[] { C_NUMBER };
break;
case C_SMALLINT :
result[count++] = new char[] { C_SMALLINT };
break;
case C_TIME :
result[count++] = new char[] { C_TIME };
break;
case C_TIMESTAMP :
result[count++] =
new char[] { C_TIMESTAMP };
break;
case C_UNICODE :
result[count++] = new char[] { C_UNICODE };
break;
case C_VARCHAR :
result[count++] = new char[] { C_VARCHAR };
break;
case C_VARDBCHAR :
result[count++] =
new char[] { C_VARDBCHAR };
break;
case C_VARMBCHAR :
result[count++] =
new char[] { C_VARMBCHAR };
break;
case C_VARUNICODE :
result[count++] =
new char[] { C_VARUNICODE };
break;
}
} else {
result[count++] =
CharOperation.subarray(
methodSignature,
start,
i);
}
start = i;
break;
case C_RESOLVED :
case C_UNRESOLVED :
i =
CharOperation.indexOf(
C_SEMICOLON,
methodSignature,
i)
+ 1;
if (i == 0)
throw new IllegalArgumentException();
result[count++] =
CharOperation.subarray(methodSignature, start, i);
start = i;
break;
case C_PARAM_END :
return result;
default :
throw new IllegalArgumentException();
}
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException();
}
}
/**
* Extracts the parameter type signatures from the given method signature.
* The method signature is expected to be dot-based.
*
* @param methodSignature the method signature
* @return the list of parameter type signatures
* @exception IllegalArgumentException if the signature is syntactically
* incorrect
*/
public static String[] getParameterTypes(String methodSignature)
throws IllegalArgumentException {
char[][] parameterTypes =
getParameterTypes(methodSignature.toCharArray());
int length = parameterTypes.length;
String[] result = new String[length];
for (int i = 0; i < length; i++) {
result[i] = new String(parameterTypes[i]);
}
return result;
}
/**
* Returns a char array containing all but the last segment of the given
* dot-separated qualified name. Returns the empty char array if it is not qualified.
* <p>
* For example:
* <pre>
* <code>
* getQualifier({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g'}
* getQualifier({'O', 'u', 't', 'e', 'r', '.', 'I', 'n', 'n', 'e', 'r'}) -> {'O', 'u', 't', 'e', 'r'}
* </code>
* </pre>
* </p>
*
* @param name the name
* @return the qualifier prefix, or the empty char array if the name contains no
* dots
* @exception NullPointerException if name is null
* @since 2.0
*/
public static char[] getQualifier(char[] name) {
int lastDot = CharOperation.lastIndexOf(C_DOT, name);
if (lastDot == -1) {
return CharOperation.NO_CHAR;
}
return CharOperation.subarray(name, 0, lastDot);
}
/**
* Returns a string containing all but the last segment of the given
* dot-separated qualified name. Returns the empty string if it is not qualified.
* <p>
* For example:
* <pre>
* <code>
* getQualifier("java.lang.Object") -> "java.lang"
* getQualifier("Outer.Inner") -> "Outer"
* </code>
* </pre>
* </p>
*
* @param name the name
* @return the qualifier prefix, or the empty string if the name contains no
* dots
* @exception NullPointerException if name is null
*/
public static String getQualifier(String name) {
int lastDot = name.lastIndexOf(C_DOT);
if (lastDot == -1) {
return EMPTY;
}
return name.substring(0, lastDot);
}
/**
* Extracts the return type from the given method signature. The method signature is
* expected to be dot-based.
*
* @param methodSignature the method signature
* @return the type signature of the return type
* @exception IllegalArgumentException if the signature is syntactically
* incorrect
*
* @since 2.0
*/
public static char[] getReturnType(char[] methodSignature)
throws IllegalArgumentException {
int i = CharOperation.lastIndexOf(C_PARAM_END, methodSignature);
if (i == -1) {
throw new IllegalArgumentException();
}
return CharOperation.subarray(
methodSignature,
i + 1,
methodSignature.length);
}
/**
* Extracts the return type from the given method signature. The method signature is
* expected to be dot-based.
*
* @param methodSignature the method signature
* @return the type signature of the return type
* @exception IllegalArgumentException if the signature is syntactically
* incorrect
*/
public static String getReturnType(String methodSignature)
throws IllegalArgumentException {
return new String(getReturnType(methodSignature.toCharArray()));
}
/**
* Returns the last segment of the given dot-separated qualified name.
* Returns the given name if it is not qualified.
* <p>
* For example:
* <pre>
* <code>
* getSimpleName({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'O', 'b', 'j', 'e', 'c', 't'}
* </code>
* </pre>
* </p>
*
* @param name the name
* @return the last segment of the qualified name
* @exception NullPointerException if name is null
* @since 2.0
*/
public static char[] getSimpleName(char[] name) {
int lastDot = CharOperation.lastIndexOf(C_DOT, name);
if (lastDot == -1) {
return name;
}
return CharOperation.subarray(name, lastDot + 1, name.length);
}
/**
* Returns the last segment of the given dot-separated qualified name.
* Returns the given name if it is not qualified.
* <p>
* For example:
* <pre>
* <code>
* getSimpleName("java.lang.Object") -> "Object"
* </code>
* </pre>
* </p>
*
* @param name the name
* @return the last segment of the qualified name
* @exception NullPointerException if name is null
*/
public static String getSimpleName(String name) {
int lastDot = name.lastIndexOf(C_DOT);
if (lastDot == -1) {
return name;
}
return name.substring(lastDot + 1, name.length());
}
/**
* Returns all segments of the given dot-separated qualified name.
* Returns an array with only the given name if it is not qualified.
* Returns an empty array if the name is empty.
* <p>
* For example:
* <pre>
* <code>
* getSimpleNames({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}
* getSimpleNames({'O', 'b', 'j', 'e', 'c', 't'}) -> {{'O', 'b', 'j', 'e', 'c', 't'}}
* getSimpleNames("") -> {}
* </code>
* </pre>
*
* @param name the name
* @return the list of simple names, possibly empty
* @exception NullPointerException if name is null
* @since 2.0
*/
public static char[][] getSimpleNames(char[] name) {
if (name.length == 0) {
return CharOperation.NO_CHAR_CHAR;
}
int dot = CharOperation.indexOf(C_DOT, name);
if (dot == -1) {
return new char[][] { name };
}
int n = 1;
while ((dot = CharOperation.indexOf(C_DOT, name, dot + 1)) != -1) {
++n;
}
char[][] result = new char[n + 1][];
int segStart = 0;
for (int i = 0; i < n; ++i) {
dot = CharOperation.indexOf(C_DOT, name, segStart);
result[i] = CharOperation.subarray(name, segStart, dot);
segStart = dot + 1;
}
result[n] = CharOperation.subarray(name, segStart, name.length);
return result;
}
/**
* Returns all segments of the given dot-separated qualified name.
* Returns an array with only the given name if it is not qualified.
* Returns an empty array if the name is empty.
* <p>
* For example:
* <pre>
* <code>
* getSimpleNames("java.lang.Object") -> {"java", "lang", "Object"}
* getSimpleNames("Object") -> {"Object"}
* getSimpleNames("") -> {}
* </code>
* </pre>
*
* @param name the name
* @return the list of simple names, possibly empty
* @exception NullPointerException if name is null
*/
public static String[] getSimpleNames(String name) {
char[][] simpleNames = getSimpleNames(name.toCharArray());
int length = simpleNames.length;
String[] result = new String[length];
for (int i = 0; i < length; i++) {
result[i] = new String(simpleNames[i]);
}
return result;
}
/**
* Converts the given method signature to a readable form. The method signature is expected to
* be dot-based.
* <p>
* For example:
* <pre>
* <code>
* toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
* </code>
* </pre>
* </p>
*
* @param methodSignature the method signature to convert
* @param methodName the name of the method to insert in the result, or
* <code>null</code> if no method name is to be included
* @param parameterNames the parameter names to insert in the result, or
* <code>null</code> if no parameter names are to be included; if supplied,
* the number of parameter names must match that of the method signature
* @param fullyQualifyTypeNames <code>true</code> if type names should be fully
* qualified, and <code>false</code> to use only simple names
* @param includeReturnType <code>true</code> if the return type is to be
* included
* @return the char array representation of the method signature
*
* @since 2.0
*/
public static char[] toCharArray(
char[] methodSignature,
char[] methodName,
char[][] parameterNames,
boolean fullyQualifyTypeNames,
boolean includeReturnType) {
try {
int firstParen =
CharOperation.indexOf(C_PARAM_START, methodSignature);
if (firstParen == -1)
throw new IllegalArgumentException();
int sigLength = methodSignature.length;
// compute result length
// method signature
int paramCount = 0;
int lastParen = -1;
int resultLength = 0;
signature : for (int i = firstParen; i < sigLength; i++) {
switch (methodSignature[i]) {
case C_ARRAY :
resultLength += 2; // []
continue signature;
case C_BIGINT :
resultLength += BIGINT.length;
break;
case C_BIN :
resultLength += BIN.length;
break;
case C_BYTE :
resultLength += BYTE.length;
break;
case C_CHAR :
resultLength += CHAR.length;
break;
case C_DATE :
resultLength += DATE.length;
break;
case C_DBCHAR :
resultLength += DBCHAR.length;
break;
case C_DECIMAL :
resultLength += DECIMAL.length;
break;
case C_DECIMALFLOAT :
resultLength += DECIMALFLOAT.length;
break;
case C_FLOAT :
resultLength += FLOAT.length;
break;
case C_INT :
resultLength += INT.length;
break;
case C_INTERVAL :
resultLength += INTERVAL.length;
break;
case C_INTEGERDATE :
resultLength += INTEGERDATE.length;
break;
case C_MBCHAR :
resultLength += MBCHAR.length;
break;
case C_NUM :
resultLength += NUM.length;
break;
case C_NUMBER :
resultLength += NUMBER.length;
break;
case C_SMALLINT :
resultLength += SMALLINT.length;
break;
case C_TIME :
resultLength += TIME.length;
break;
case C_TIMESTAMP :
resultLength += TIMESTAMP.length;
break;
case C_UNICODE :
resultLength += UNICODE.length;
break;
case C_VARCHAR :
resultLength += VARCHAR.length;
break;
case C_VARDBCHAR :
resultLength += VARDBCHAR.length;
break;
case C_VARMBCHAR :
resultLength += VARMBCHAR.length;
break;
case C_VARUNICODE :
resultLength += VARUNICODE.length;
break;
case C_RESOLVED :
case C_UNRESOLVED :
int end =
CharOperation.indexOf(
C_SEMICOLON,
methodSignature,
i);
if (end == -1)
throw new IllegalArgumentException();
int start;
if (fullyQualifyTypeNames) {
start = i + 1;
} else {
start =
CharOperation.lastIndexOf(
C_DOT,
methodSignature,
i,
end)
+ 1;
if (start == 0)
start = i + 1;
}
resultLength += end - start;
i = end;
break;
case C_PARAM_START :
// add space for "("
resultLength++;
continue signature;
case C_PARAM_END :
lastParen = i;
if (includeReturnType) {
if (paramCount > 0) {
// remove space for ", " that was added with last parameter and remove space that is going to be added for ", " after return type
// and add space for ") "
resultLength -= 2;
} //else
// remove space that is going to be added for ", " after return type
// and add space for ") "
// -> noop
// decrement param count because it is going to be added for return type
paramCount--;
continue signature;
} else {
if (paramCount > 0) {
// remove space for ", " that was added with last parameter and add space for ")"
resultLength--;
} else {
// add space for ")"
resultLength++;
}
break signature;
}
default :
throw new IllegalArgumentException();
}
resultLength += 2; // add space for ", "
paramCount++;
}
// parameter names
int parameterNamesLength =
parameterNames == null ? 0 : parameterNames.length;
for (int i = 0; i < parameterNamesLength; i++) {
resultLength += parameterNames[i].length + 1;
// parameter name + space
}
// selector
int selectorLength = methodName == null ? 0 : methodName.length;
resultLength += selectorLength;
// create resulting char array
char[] result = new char[resultLength];
// returned type
int index = 0;
if (includeReturnType) {
long pos =
copyType(
methodSignature,
lastParen + 1,
result,
index,
fullyQualifyTypeNames);
index = (int) (pos >>> 32);
result[index++] = ' ';
}
// selector
if (methodName != null) {
System.arraycopy(methodName, 0, result, index, selectorLength);
index += selectorLength;
}
// parameters
result[index++] = C_PARAM_START;
int sigPos = firstParen + 1;
for (int i = 0; i < paramCount; i++) {
long pos =
copyType(
methodSignature,
sigPos,
result,
index,
fullyQualifyTypeNames);
index = (int) (pos >>> 32);
sigPos = (int) pos;
if (parameterNames != null) {
result[index++] = ' ';
char[] parameterName = parameterNames[i];
int paramLength = parameterName.length;
System.arraycopy(
parameterName,
0,
result,
index,
paramLength);
index += paramLength;
}
if (i != paramCount - 1) {
result[index++] = ',';
result[index++] = ' ';
}
}
if (sigPos >= sigLength) {
throw new IllegalArgumentException();
// should be on last paren
}
result[index++] = C_PARAM_END;
return result;
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException();
}
}
/**
* Converts the given type signature to a readable string. The signature is expected to
* be dot-based.
*
* <p>
* For example:
* <pre>
* <code>
* toString({'[', 'L', 'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', ';'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', '[', ']'}
* toString({'I'}) -> {'i', 'n', 't'}
* </code>
* </pre>
* </p>
* <p>
* Note: This method assumes that a type signature containing a <code>'$'</code>
* is an inner type signature. While this is correct in most cases, someone could
* define a non-inner type name containing a <code>'$'</code>. Handling this
* correctly in all cases would have required resolving the signature, which
* generally not feasible.
* </p>
*
* @param signature the type signature
* @return the string representation of the type
* @exception IllegalArgumentException if the signature is not syntactically
* correct
*
* @since 2.0
*/
public static char[] toCharArray(char[] signature)
throws IllegalArgumentException {
try {
int sigLength = signature.length;
if (sigLength == 0 || signature[0] == C_PARAM_START) {
try {
return toCharArray(
signature,
CharOperation.NO_CHAR,
null,
true,
true);
}
catch(IllegalArgumentException e) {
return new char[0];
}
}
// compute result length
int resultLength = 0;
int index = -1;
while (signature[++index] == C_ARRAY) {
resultLength += 2; // []
}
switch (signature[index]) {
case C_BIGINT :
resultLength += BIGINT.length;
break;
case C_BIN :
resultLength += BIN.length;
break;
case C_BYTE :
resultLength += BYTE.length;
break;
case C_CHAR :
resultLength += CHAR.length;
break;
case C_DATE :
resultLength += DATE.length;
break;
case C_DBCHAR :
resultLength += DBCHAR.length;
break;
case C_DECIMAL :
resultLength += DECIMAL.length;
break;
case C_DECIMALFLOAT :
resultLength += DECIMALFLOAT.length;
break;
case C_FLOAT :
resultLength += FLOAT.length;
break;
case C_INT :
resultLength += INT.length;
break;
case C_INTERVAL :
resultLength += INTERVAL.length;
break;
case C_INTEGERDATE :
resultLength += INTEGERDATE.length;
break;
case C_MBCHAR :
resultLength += MBCHAR.length;
break;
case C_NUM :
resultLength += NUM.length;
break;
case C_NUMBER :
resultLength += NUMBER.length;
break;
case C_SMALLINT :
resultLength += SMALLINT.length;
break;
case C_TIME :
resultLength += TIME.length;
break;
case C_TIMESTAMP :
resultLength += TIMESTAMP.length;
break;
case C_UNICODE :
resultLength += UNICODE.length;
break;
case C_VARCHAR :
resultLength += VARCHAR.length;
break;
case C_VARDBCHAR :
resultLength += VARDBCHAR.length;
break;
case C_VARMBCHAR :
resultLength += VARMBCHAR.length;
break;
case C_VARUNICODE :
resultLength += VARUNICODE.length;
break;
case C_RESOLVED :
case C_UNRESOLVED :
int end =
CharOperation.indexOf(C_SEMICOLON, signature, index);
if (end == -1)
throw new IllegalArgumentException();
int start = index + 1;
resultLength += end - start;
break;
default :
throw new IllegalArgumentException();
}
char[] result = new char[resultLength];
copyType(signature, 0, result, 0, true);
return result;
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException();
}
}
/**
* Converts the given array of qualified name segments to a qualified name.
* <p>
* For example:
* <pre>
* <code>
* toQualifiedName({{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}
* toQualifiedName({{'O', 'b', 'j', 'e', 'c', 't'}}) -> {'O', 'b', 'j', 'e', 'c', 't'}
* toQualifiedName({{}}) -> {}
* </code>
* </pre>
* </p>
*
* @param segments the list of name segments, possibly empty
* @return the dot-separated qualified name, or the empty string
*
* @since 2.0
*/
public static char[] toQualifiedName(char[][] segments) {
int length = segments.length;
if (length == 0)
return CharOperation.NO_CHAR;
if (length == 1)
return segments[0];
int resultLength = 0;
for (int i = 0; i < length; i++) {
resultLength += segments[i].length + 1;
}
resultLength--;
char[] result = new char[resultLength];
int index = 0;
for (int i = 0; i < length; i++) {
char[] segment = segments[i];
int segmentLength = segment.length;
System.arraycopy(segment, 0, result, index, segmentLength);
index += segmentLength;
if (i != length - 1) {
result[index++] = C_DOT;
}
}
return result;
}
/**
* Converts the given array of qualified name segments to a qualified name.
* <p>
* For example:
* <pre>
* <code>
* toQualifiedName(new String[] {"java", "lang", "Object"}) -> "java.lang.Object"
* toQualifiedName(new String[] {"Object"}) -> "Object"
* toQualifiedName(new String[0]) -> ""
* </code>
* </pre>
* </p>
*
* @param segments the list of name segments, possibly empty
* @return the dot-separated qualified name, or the empty string
*/
public static String toQualifiedName(String[] segments) {
int length = segments.length;
char[][] charArrays = new char[length][];
for (int i = 0; i < length; i++) {
charArrays[i] = segments[i].toCharArray();
}
return new String(toQualifiedName(charArrays));
}
/**
* Converts the given type signature to a readable string. The signature is expected to
* be dot-based.
*
* <p>
* For example:
* <pre>
* <code>
* toString("[Ljava.lang.String;") -> "java.lang.String[]"
* toString("I") -> "int"
* </code>
* </pre>
* </p>
* <p>
* Note: This method assumes that a type signature containing a <code>'$'</code>
* is an inner type signature. While this is correct in most cases, someone could
* define a non-inner type name containing a <code>'$'</code>. Handling this
* correctly in all cases would have required resolving the signature, which
* generally not feasible.
* </p>
*
* @param signature the type signature
* @return the string representation of the type
* @exception IllegalArgumentException if the signature is not syntactically
* correct
*/
public static String toString(String signature)
throws IllegalArgumentException {
return new String(toCharArray(signature.toCharArray()));
}
/**
* Converts the given method signature to a readable string. The method signature is expected to
* be dot-based.
* <p>
* For example:
* <pre>
* <code>
* toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
* </code>
* </pre>
* </p>
*
* @param methodSignature the method signature to convert
* @param methodName the name of the method to insert in the result, or
* <code>null</code> if no method name is to be included
* @param parameterNames the parameter names to insert in the result, or
* <code>null</code> if no parameter names are to be included; if supplied,
* the number of parameter names must match that of the method signature
* @param fullyQualifyTypeNames <code>true</code> if type names should be fully
* qualified, and <code>false</code> to use only simple names
* @param includeReturnType <code>true</code> if the return type is to be
* included
* @return the string representation of the method signature
*/
public static String toString(
String methodSignature,
String methodName,
String[] parameterNames,
boolean fullyQualifyTypeNames,
boolean includeReturnType) {
char[][] params;
if (parameterNames == null) {
params = null;
} else {
int paramLength = parameterNames.length;
params = new char[paramLength][];
for (int i = 0; i < paramLength; i++) {
params[i] = parameterNames[i].toCharArray();
}
}
return new String(
toCharArray(
methodSignature.toCharArray(),
methodName == null ? null : methodName.toCharArray(),
params,
fullyQualifyTypeNames,
includeReturnType));
}
}