@@ -1,402 +0,0 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2005 Contributors. | |||
* 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://eclipse.org/legal/epl-v10.html | |||
* | |||
* Contributors: | |||
* Adrian Colyer Initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.aspectj.apache.bcel.classfile.Signature.ArrayTypeSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.ClassTypeSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.FieldTypeSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.FormalTypeParameter; | |||
import org.aspectj.apache.bcel.classfile.Signature.MethodTypeSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.SimpleClassTypeSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.TypeArgument; | |||
import org.aspectj.apache.bcel.classfile.Signature.TypeSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.TypeVariableSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.BaseTypeSignature; | |||
/** | |||
* Parses the generic signature attribute as defined in the JVM spec. | |||
*/ | |||
public class GenericSignatureParser { | |||
private String inputString; | |||
private String[] tokenStream; // for parse in flight | |||
private int tokenIndex = 0; | |||
/** | |||
* AMC. | |||
* Parse the signature string interpreting it as a ClassSignature according to | |||
* the grammar defined in Section 4.4.4 of the JVM specification. | |||
*/ | |||
public Signature.ClassSignature parseAsClassSignature(String sig) { | |||
this.inputString = sig; | |||
tokenStream = tokenize(sig); | |||
tokenIndex = 0; | |||
Signature.ClassSignature classSig = new Signature.ClassSignature(); | |||
// FormalTypeParameters-opt | |||
if (maybeEat("<")) { | |||
List formalTypeParametersList = new ArrayList(); | |||
do { | |||
formalTypeParametersList.add(parseFormalTypeParameter()); | |||
} while (!maybeEat(">")); | |||
classSig.formalTypeParameters = new FormalTypeParameter[formalTypeParametersList.size()]; | |||
formalTypeParametersList.toArray(classSig.formalTypeParameters); | |||
} | |||
classSig.superclassSignature = parseClassTypeSignature(); | |||
List superIntSigs = new ArrayList(); | |||
while (tokenIndex < tokenStream.length) { | |||
superIntSigs.add(parseClassTypeSignature()); | |||
} | |||
classSig.superInterfaceSignatures = new ClassTypeSignature[superIntSigs.size()]; | |||
superIntSigs.toArray(classSig.superInterfaceSignatures); | |||
return classSig; | |||
} | |||
/** | |||
* AMC. | |||
* Parse the signature string interpreting it as a MethodTypeSignature according to | |||
* the grammar defined in Section 4.4.4 of the JVM specification. | |||
*/ | |||
public MethodTypeSignature parseAsMethodSignature(String sig) { | |||
this.inputString = sig; | |||
tokenStream = tokenize(sig); | |||
tokenIndex = 0; | |||
FormalTypeParameter[] formals = new FormalTypeParameter[0]; | |||
TypeSignature returnType = null; | |||
// FormalTypeParameters-opt | |||
if (maybeEat("<")) { | |||
List formalTypeParametersList = new ArrayList(); | |||
do { | |||
formalTypeParametersList.add(parseFormalTypeParameter()); | |||
} while (!maybeEat(">")); | |||
formals = new FormalTypeParameter[formalTypeParametersList.size()]; | |||
formalTypeParametersList.toArray(formals); | |||
} | |||
// Parameters | |||
eat("("); | |||
List paramList = new ArrayList(); | |||
while(!maybeEat(")")) { | |||
FieldTypeSignature fsig = parseFieldTypeSignature(true); | |||
if (fsig != null) { | |||
paramList.add(fsig); | |||
} else { | |||
paramList.add(new Signature.BaseTypeSignature(eatIdentifier())); | |||
} | |||
} | |||
TypeSignature[] params = new TypeSignature[paramList.size()]; | |||
paramList.toArray(params); | |||
// return type | |||
returnType = parseFieldTypeSignature(true); | |||
if (returnType == null) returnType = new Signature.BaseTypeSignature(eatIdentifier()); | |||
// throws | |||
List throwsList = new ArrayList(); | |||
while (maybeEat("^")) { | |||
FieldTypeSignature fsig = parseFieldTypeSignature(false); | |||
throwsList.add(fsig); | |||
} | |||
FieldTypeSignature[] throwsSigs = new FieldTypeSignature[throwsList.size()]; | |||
throwsList.toArray(throwsSigs); | |||
return new Signature.MethodTypeSignature(formals,params,returnType,throwsSigs); | |||
} | |||
/** | |||
* AMC. | |||
* Parse the signature string interpreting it as a FieldTypeSignature according to | |||
* the grammar defined in Section 4.4.4 of the JVM specification. | |||
*/ | |||
public FieldTypeSignature parseAsFieldSignature(String sig) { | |||
this.inputString = sig; | |||
tokenStream = tokenize(sig); | |||
tokenIndex = 0; | |||
return parseFieldTypeSignature(false); | |||
} | |||
private FormalTypeParameter parseFormalTypeParameter() { | |||
FormalTypeParameter ftp = new FormalTypeParameter(); | |||
// Identifier | |||
ftp.identifier = eatIdentifier(); | |||
// ClassBound | |||
eat(":"); | |||
ftp.classBound = parseFieldTypeSignature(true); | |||
if (ftp.classBound == null) { | |||
ftp.classBound = new ClassTypeSignature("Ljava/lang/Object;","Ljava/lang/Object"); | |||
} | |||
// Optional InterfaceBounds | |||
List optionalBounds = new ArrayList(); | |||
while (maybeEat(":")) { | |||
optionalBounds.add(parseFieldTypeSignature(false)); | |||
} | |||
ftp.interfaceBounds = new FieldTypeSignature[optionalBounds.size()]; | |||
optionalBounds.toArray(ftp.interfaceBounds); | |||
return ftp; | |||
} | |||
private FieldTypeSignature parseFieldTypeSignature(boolean isOptional) { | |||
if (isOptional) { | |||
// anything other than 'L', 'T' or '[' and we're out of here | |||
if (!tokenStream[tokenIndex].startsWith("L") && | |||
!tokenStream[tokenIndex].startsWith("T") && | |||
!tokenStream[tokenIndex].startsWith("[")) { | |||
return null; | |||
} | |||
} | |||
if (maybeEat("[")) { | |||
return parseArrayTypeSignature(); | |||
} else if (tokenStream[tokenIndex].startsWith("L")) { | |||
return parseClassTypeSignature(); | |||
} else if (tokenStream[tokenIndex].startsWith("T")) { | |||
return parseTypeVariableSignature(); | |||
} else { | |||
throw new IllegalStateException("Expecting [,L, or T, but found " + | |||
tokenStream[tokenIndex] + " while unpacking " + inputString); | |||
} | |||
} | |||
private ArrayTypeSignature parseArrayTypeSignature() { | |||
// opening [ already eaten | |||
FieldTypeSignature fieldType = parseFieldTypeSignature(true); | |||
if (fieldType != null) { | |||
return new ArrayTypeSignature(fieldType); | |||
} else { | |||
// must be BaseType array | |||
return new ArrayTypeSignature(new BaseTypeSignature(eatIdentifier())); | |||
} | |||
} | |||
// L PackageSpecifier* SimpleClassTypeSignature ClassTypeSignature* ; | |||
private ClassTypeSignature parseClassTypeSignature() { | |||
SimpleClassTypeSignature outerType = null; | |||
SimpleClassTypeSignature[] nestedTypes = new SimpleClassTypeSignature[0]; | |||
StringBuffer ret = new StringBuffer(); | |||
String identifier = eatIdentifier(); | |||
ret.append(identifier); | |||
while (maybeEat("/")) { | |||
ret.append("/"); // dont forget this... | |||
ret.append(eatIdentifier()); | |||
} | |||
identifier = ret.toString(); | |||
// now we have either a "." indicating the start of a nested type, | |||
// or a "<" indication type arguments, or ";" and we are done. | |||
while (!maybeEat(";")) { | |||
if (maybeEat(".")) { | |||
// outer type completed | |||
outerType = new SimpleClassTypeSignature(identifier); | |||
List nestedTypeList = new ArrayList(); | |||
do { | |||
ret.append("."); | |||
SimpleClassTypeSignature sig = parseSimpleClassTypeSignature(); | |||
ret.append(sig.toString()); | |||
nestedTypeList.add(sig); | |||
} while(maybeEat(".")); | |||
nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()]; | |||
nestedTypeList.toArray(nestedTypes); | |||
} else if (tokenStream[tokenIndex].equals("<")) { | |||
ret.append("<"); | |||
TypeArgument[] tArgs = maybeParseTypeArguments(); | |||
for (int i=0; i < tArgs.length; i++) { | |||
ret.append(tArgs[i].toString()); | |||
} | |||
ret.append(">"); | |||
outerType = new SimpleClassTypeSignature(identifier,tArgs); | |||
// now parse possible nesteds... | |||
List nestedTypeList = new ArrayList(); | |||
while (maybeEat(".")) { | |||
ret.append("."); | |||
SimpleClassTypeSignature sig = parseSimpleClassTypeSignature(); | |||
ret.append(sig.toString()); | |||
nestedTypeList.add(sig); | |||
} | |||
nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()]; | |||
nestedTypeList.toArray(nestedTypes); | |||
} else { | |||
throw new IllegalStateException("Expecting .,<, or ;, but found " + tokenStream[tokenIndex] + " while unpacking " + inputString); | |||
} | |||
} | |||
ret.append(";"); | |||
if (outerType == null) outerType = new SimpleClassTypeSignature(ret.toString()); | |||
return new ClassTypeSignature(ret.toString(),outerType,nestedTypes); | |||
} | |||
private SimpleClassTypeSignature parseSimpleClassTypeSignature() { | |||
String identifier = eatIdentifier(); | |||
TypeArgument[] tArgs = maybeParseTypeArguments(); | |||
if (tArgs != null) { | |||
return new SimpleClassTypeSignature(identifier,tArgs); | |||
} else { | |||
return new SimpleClassTypeSignature(identifier); | |||
} | |||
} | |||
private TypeArgument parseTypeArgument() { | |||
boolean isPlus = false; | |||
boolean isMinus = false; | |||
if (maybeEat("*")) { | |||
return new TypeArgument(); | |||
} else if (maybeEat("+")) { | |||
isPlus = true; | |||
} else if (maybeEat("-")) { | |||
isMinus = true; | |||
} | |||
FieldTypeSignature sig = parseFieldTypeSignature(false); | |||
return new TypeArgument(isPlus,isMinus,sig); | |||
} | |||
private TypeArgument[] maybeParseTypeArguments() { | |||
if (maybeEat("<")) { | |||
List typeArgs = new ArrayList(); | |||
do { | |||
TypeArgument arg = parseTypeArgument(); | |||
typeArgs.add(arg); | |||
} while(!maybeEat(">")); | |||
TypeArgument[] tArgs = new TypeArgument[typeArgs.size()]; | |||
typeArgs.toArray(tArgs); | |||
return tArgs; | |||
} else { | |||
return null; | |||
} | |||
} | |||
private TypeVariableSignature parseTypeVariableSignature() { | |||
TypeVariableSignature tv = new TypeVariableSignature(eatIdentifier()); | |||
eat(";"); | |||
return tv; | |||
} | |||
private boolean maybeEat(String token) { | |||
if (tokenStream.length <= tokenIndex) return false; | |||
if (tokenStream[tokenIndex].equals(token)) { | |||
tokenIndex++; | |||
return true; | |||
} | |||
return false; | |||
} | |||
private void eat(String token) { | |||
if (!tokenStream[tokenIndex].equals(token)) { | |||
throw new IllegalStateException("Expecting " + token + " but found " + tokenStream[tokenIndex] + " while unpacking " + inputString); | |||
} | |||
tokenIndex++; | |||
} | |||
private String eatIdentifier() { | |||
return tokenStream[tokenIndex++]; | |||
} | |||
/** | |||
* non-private for test visibility | |||
* Splits a string containing a generic signature into tokens for consumption | |||
* by the parser. | |||
*/ | |||
public String[] tokenize(String signatureString) { | |||
char[] chars = signatureString.toCharArray(); | |||
int index = 0; | |||
List tokens = new ArrayList(); | |||
StringBuffer identifier = new StringBuffer(); | |||
boolean inParens = false; | |||
boolean inArray = false; | |||
boolean couldSeePrimitive = false; | |||
do { | |||
switch (chars[index]) { | |||
case '<' : | |||
if (identifier.length() > 0) tokens.add(identifier.toString()); | |||
identifier = new StringBuffer(); | |||
tokens.add("<"); | |||
break; | |||
case '>' : | |||
if (identifier.length() > 0) tokens.add(identifier.toString()); | |||
identifier = new StringBuffer(); | |||
tokens.add(">"); | |||
break; | |||
case ':' : | |||
if (identifier.length() > 0) tokens.add(identifier.toString()); | |||
identifier = new StringBuffer(); | |||
tokens.add(":"); | |||
break; | |||
case '/' : | |||
if (identifier.length() > 0) tokens.add(identifier.toString()); | |||
identifier = new StringBuffer(); | |||
tokens.add("/"); | |||
couldSeePrimitive = false; | |||
break; | |||
case ';' : | |||
if (identifier.length() > 0) tokens.add(identifier.toString()); | |||
identifier = new StringBuffer(); | |||
tokens.add(";"); | |||
couldSeePrimitive = true; | |||
inArray = false; | |||
break; | |||
case '^': | |||
if (identifier.length() > 0) tokens.add(identifier.toString()); | |||
identifier = new StringBuffer(); | |||
tokens.add("^"); | |||
break; | |||
case '+': | |||
tokens.add("+"); | |||
break; | |||
case '-': | |||
tokens.add("-"); | |||
break; | |||
case '*': | |||
tokens.add("*"); | |||
break; | |||
case '.' : | |||
if (identifier.length() > 0) tokens.add(identifier.toString()); | |||
identifier = new StringBuffer(); | |||
couldSeePrimitive = false; | |||
tokens.add("."); | |||
break; | |||
case '(' : | |||
tokens.add("("); | |||
inParens = true; | |||
couldSeePrimitive = true; | |||
break; | |||
case ')' : | |||
tokens.add(")"); | |||
inParens = false; | |||
break; | |||
case '[' : | |||
tokens.add("["); | |||
couldSeePrimitive = true; | |||
inArray = true; | |||
break; | |||
case 'B' : | |||
case 'C' : | |||
case 'D' : | |||
case 'F' : | |||
case 'I' : | |||
case 'J' : | |||
case 'S' : | |||
case 'V' : | |||
case 'Z' : | |||
if ((inParens || inArray) && couldSeePrimitive && identifier.length() == 0) { | |||
tokens.add(new String("" + chars[index])); | |||
} else { | |||
identifier.append(chars[index]); | |||
} | |||
inArray = false; | |||
break; | |||
case 'L' : | |||
couldSeePrimitive = false; | |||
// deliberate fall-through | |||
default : | |||
identifier.append(chars[index]); | |||
} | |||
} while((++index) < chars.length); | |||
if (identifier.length() > 0) tokens.add(identifier.toString()); | |||
String [] tokenArray = new String[tokens.size()]; | |||
tokens.toArray(tokenArray); | |||
return tokenArray; | |||
} | |||
} |
@@ -79,7 +79,7 @@ import org.aspectj.apache.bcel.util.SyntheticRepository; | |||
* The intent of this class is to represent a parsed or otherwise existing class file. Those interested in programatically | |||
* generating classes should see the <a href="../generic/ClassGen.html">ClassGen</a> class. | |||
* | |||
* @version $Id: JavaClass.java,v 1.13 2008/08/28 15:36:59 aclement Exp $ | |||
* @version $Id: JavaClass.java,v 1.14 2008/10/20 18:31:01 aclement Exp $ | |||
* @see org.aspectj.apache.bcel.generic.ClassGen | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
@@ -939,15 +939,9 @@ public class JavaClass extends Modifiers implements Cloneable, Node { | |||
} | |||
} | |||
/** | |||
* the parsed version of the above | |||
*/ | |||
public final Signature.ClassSignature getGenericClassTypeSignature() { | |||
public final Signature getSignatureAttribute() { | |||
loadGenericSignatureInfoIfNecessary(); | |||
if (signatureAttribute != null) { | |||
return signatureAttribute.asClassSignature(); | |||
} | |||
return null; | |||
return signatureAttribute; | |||
} | |||
} |
@@ -57,7 +57,6 @@ package org.aspectj.apache.bcel.classfile; | |||
* attribute | |||
*/ | |||
import java.io.ByteArrayInputStream; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
@@ -66,465 +65,242 @@ import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
/** | |||
* This class is derived from <em>Attribute</em> and represents a reference | |||
* to a <href="http://wwwipd.ira.uka.de/~pizza/gj/">GJ</a> attribute. | |||
* | |||
* @version $Id: Signature.java,v 1.8 2008/08/26 15:01:23 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Attribute | |||
* This class is derived from <em>Attribute</em> and represents a reference to a <href="http://wwwipd.ira.uka.de/~pizza/gj/">GJ</a> | |||
* attribute. | |||
* | |||
* @version $Id: Signature.java,v 1.9 2008/10/20 18:31:01 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Attribute | |||
*/ | |||
public final class Signature extends Attribute { | |||
private int signature_index; | |||
/** | |||
* Initialize from another object. Note that both objects use the same | |||
* references (shallow copy). Use clone() for a physical copy. | |||
*/ | |||
public Signature(Signature c) { | |||
this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool()); | |||
} | |||
/** | |||
* Construct object from file stream. | |||
* @param name_index Index in constant pool to CONSTANT_Utf8 | |||
* @param length Content length in bytes | |||
* @param file Input stream | |||
* @param constant_pool Array of constants | |||
* @throws IOException | |||
*/ | |||
Signature(int name_index, int length, DataInputStream file, | |||
ConstantPool constant_pool) throws IOException | |||
{ | |||
this(name_index, length, file.readUnsignedShort(), constant_pool); | |||
} | |||
/** | |||
* @param name_index Index in constant pool to CONSTANT_Utf8 | |||
* @param length Content length in bytes | |||
* @param constant_pool Array of constants | |||
* @param Signature_index Index in constant pool to CONSTANT_Utf8 | |||
*/ | |||
public Signature(int name_index, int length, int signature_index, | |||
ConstantPool constant_pool) | |||
{ | |||
super(Constants.ATTR_SIGNATURE, name_index, length, constant_pool); | |||
this.signature_index = signature_index; | |||
} | |||
/** | |||
* Called by objects that are traversing the nodes of the tree implicitely | |||
* defined by the contents of a Java class. I.e., the hierarchy of methods, | |||
* fields, attributes, etc. spawns a tree of objects. | |||
* | |||
* @param v Visitor object | |||
*/ | |||
public void accept(ClassVisitor v) { | |||
System.err.println("Visiting non-standard Signature object"); | |||
v.visitSignature(this); | |||
} | |||
/** | |||
* Dump source file attribute to file stream in binary format. | |||
* | |||
* @param file Output file stream | |||
* @throws IOException | |||
*/ | |||
public final void dump(DataOutputStream file) throws IOException | |||
{ | |||
super.dump(file); | |||
file.writeShort(signature_index); | |||
} | |||
/** | |||
* @return Index in constant pool of source file name. | |||
*/ | |||
public final int getSignatureIndex() { return signature_index; } | |||
/** | |||
* @param Signature_index. | |||
*/ | |||
public final void setSignatureIndex(int signature_index) { | |||
this.signature_index = signature_index; | |||
} | |||
/** | |||
* @return GJ signature. | |||
*/ | |||
public final String getSignature() { | |||
ConstantUtf8 c = (ConstantUtf8)constantPool.getConstant(signature_index, | |||
Constants.CONSTANT_Utf8); | |||
return c.getBytes(); | |||
} | |||
/** | |||
* Extends ByteArrayInputStream to make 'unreading' chars possible. | |||
*/ | |||
private static final class MyByteArrayInputStream extends ByteArrayInputStream { | |||
MyByteArrayInputStream(String data) { super(data.getBytes()); } | |||
final int mark() { return pos; } | |||
final String getData() { return new String(buf); } | |||
final void reset(int p) { pos = p; } | |||
final void unread() { if(pos > 0) pos--; } | |||
} | |||
private static boolean identStart(int ch) { | |||
return ch == 'T' || ch == 'L'; | |||
} | |||
private static final void matchIdent(MyByteArrayInputStream in, StringBuffer buf) { | |||
int ch; | |||
if((ch = in.read()) == -1) | |||
throw new RuntimeException("Illegal signature: " + in.getData() + | |||
" no ident, reaching EOF"); | |||
//System.out.println("return from ident:" + (char)ch); | |||
if(!identStart(ch)) { | |||
StringBuffer buf2 = new StringBuffer(); | |||
int count = 1; | |||
while(Character.isJavaIdentifierPart((char)ch)) { | |||
buf2.append((char)ch); | |||
count++; | |||
ch = in.read(); | |||
} | |||
if(ch == ':') { // Ok, formal parameter | |||
in.skip("Ljava/lang/Object".length()); | |||
buf.append(buf2); | |||
ch = in.read(); | |||
in.unread(); | |||
//System.out.println("so far:" + buf2 + ":next:" +(char)ch); | |||
} else { | |||
for(int i=0; i < count; i++) | |||
in.unread(); | |||
} | |||
return; | |||
} | |||
StringBuffer buf2 = new StringBuffer(); | |||
ch = in.read(); | |||
do { | |||
buf2.append((char)ch); | |||
ch = in.read(); | |||
//System.out.println("within ident:"+ (char)ch); | |||
} while((ch != -1) && (Character.isJavaIdentifierPart((char)ch) || (ch == '/'))); | |||
buf.append(buf2.toString().replace('/', '.')); | |||
//System.out.println("regular return ident:"+ (char)ch + ":" + buf2); | |||
if(ch != -1) | |||
in.unread(); | |||
} | |||
private static final void matchGJIdent(MyByteArrayInputStream in, | |||
StringBuffer buf) | |||
{ | |||
int ch; | |||
matchIdent(in, buf); | |||
ch = in.read(); | |||
if((ch == '<') || ch == '(') { // Parameterized or method | |||
//System.out.println("Enter <"); | |||
buf.append((char)ch); | |||
matchGJIdent(in, buf); | |||
while(((ch = in.read()) != '>') && (ch != ')')) { // List of parameters | |||
if(ch == -1) | |||
throw new RuntimeException("Illegal signature: " + in.getData() + | |||
" reaching EOF"); | |||
//System.out.println("Still no >"); | |||
buf.append(", "); | |||
in.unread(); | |||
matchGJIdent(in, buf); // Recursive call | |||
} | |||
//System.out.println("Exit >"); | |||
buf.append((char)ch); | |||
} else | |||
in.unread(); | |||
ch = in.read(); | |||
if(identStart(ch)) { | |||
in.unread(); | |||
matchGJIdent(in, buf); | |||
} else if(ch == ')') { | |||
in.unread(); | |||
return; | |||
} else if(ch != ';') | |||
throw new RuntimeException("Illegal signature: " + in.getData() + " read " + | |||
(char)ch); | |||
} | |||
public static String translate(String s) { | |||
//System.out.println("Sig:" + s); | |||
StringBuffer buf = new StringBuffer(); | |||
matchGJIdent(new MyByteArrayInputStream(s), buf); | |||
return buf.toString(); | |||
} | |||
public static final boolean isFormalParameterList(String s) { | |||
return s.startsWith("<") && (s.indexOf(':') > 0); | |||
} | |||
public static final boolean isActualParameterList(String s) { | |||
return s.startsWith("L") && s.endsWith(">;"); | |||
} | |||
/** | |||
* @return String representation | |||
*/ | |||
public final String toString() { | |||
String s = getSignature(); | |||
return "Signature(" + s + ")"; | |||
} | |||
/** | |||
* @return deep copy of this attribute | |||
*/ | |||
public Attribute copy(ConstantPool constant_pool) { | |||
return (Signature)clone(); | |||
} | |||
// ============================================= | |||
// AMC extensions | |||
private ClassSignature classSig; | |||
private MethodTypeSignature methodSig; | |||
private FieldTypeSignature fieldSig; | |||
public ClassSignature asClassSignature() { | |||
if (classSig == null) { | |||
GenericSignatureParser parser = new GenericSignatureParser(); | |||
classSig = parser.parseAsClassSignature(getSignature()); | |||
} | |||
return classSig; | |||
} | |||
public MethodTypeSignature asMethodTypeSignature() { | |||
if (methodSig == null) { | |||
GenericSignatureParser parser = new GenericSignatureParser(); | |||
methodSig = parser.parseAsMethodSignature(getSignature()); | |||
} | |||
return methodSig; | |||
} | |||
public FieldTypeSignature asFieldTypeSignature() { | |||
if (fieldSig == null) { | |||
GenericSignatureParser parser = new GenericSignatureParser(); | |||
fieldSig = parser.parseAsFieldSignature(getSignature()); | |||
} | |||
return fieldSig; | |||
} | |||
/** | |||
* structure holding a parsed class signature | |||
*/ | |||
public static class ClassSignature { | |||
public FormalTypeParameter[] formalTypeParameters = new FormalTypeParameter[0]; | |||
public ClassTypeSignature superclassSignature; | |||
public ClassTypeSignature[] superInterfaceSignatures = new ClassTypeSignature[0]; | |||
public String toString() { | |||
StringBuffer ret = new StringBuffer(); | |||
ret.append(formalTypeParameters.toString()); | |||
ret.append(superclassSignature.toString()); | |||
for (int i = 0; i < superInterfaceSignatures.length; i++) { | |||
ret.append(superInterfaceSignatures[i].toString()); | |||
} | |||
return ret.toString(); | |||
} | |||
} | |||
public static class MethodTypeSignature { | |||
public FormalTypeParameter[] formalTypeParameters = new FormalTypeParameter[0]; | |||
public TypeSignature[] parameters = new TypeSignature[0]; | |||
public TypeSignature returnType; | |||
public FieldTypeSignature[] throwsSignatures = new FieldTypeSignature[0]; | |||
public MethodTypeSignature( | |||
FormalTypeParameter[] aFormalParameterList, | |||
TypeSignature[] aParameterList, | |||
TypeSignature aReturnType, | |||
FieldTypeSignature[] aThrowsSignatureList | |||
) { | |||
this.formalTypeParameters = aFormalParameterList; | |||
this.parameters = aParameterList; | |||
this.returnType = aReturnType; | |||
this.throwsSignatures = aThrowsSignatureList; | |||
} | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(); | |||
if (formalTypeParameters.length > 0) { | |||
sb.append("<"); | |||
for (int i = 0; i < formalTypeParameters.length; i++) { | |||
sb.append(formalTypeParameters[i].toString()); | |||
} | |||
sb.append(">"); | |||
} | |||
sb.append("("); | |||
for (int i = 0; i < parameters.length; i++) { | |||
sb.append(parameters[i].toString()); | |||
} | |||
sb.append(")"); | |||
sb.append(returnType.toString()); | |||
for (int i = 0; i < throwsSignatures.length; i++) { | |||
sb.append("^"); | |||
sb.append(throwsSignatures[i].toString()); | |||
} | |||
return sb.toString(); | |||
} | |||
} | |||
/** | |||
* structure capturing a FormalTypeParameter from the Signature grammar | |||
*/ | |||
public static class FormalTypeParameter { | |||
public String identifier; | |||
public FieldTypeSignature classBound; | |||
public FieldTypeSignature[] interfaceBounds; | |||
public String toString() { | |||
StringBuffer ret = new StringBuffer(); | |||
ret.append("T"); | |||
ret.append(identifier); | |||
ret.append(":"); | |||
ret.append(classBound.toString()); | |||
for (int i = 0; i < interfaceBounds.length; i++) { | |||
ret.append(":"); | |||
ret.append(interfaceBounds[i].toString()); | |||
} | |||
return ret.toString(); | |||
} | |||
} | |||
public static abstract class TypeSignature { | |||
public boolean isBaseType() { return false; } | |||
} | |||
public static class BaseTypeSignature extends TypeSignature { | |||
private String sig; | |||
public BaseTypeSignature(String aPrimitiveType) { | |||
sig = aPrimitiveType; | |||
} | |||
public boolean isBaseType() { return true; } | |||
public String toString() { | |||
return sig; | |||
} | |||
} | |||
public static abstract class FieldTypeSignature extends TypeSignature { | |||
public boolean isClassTypeSignature() { return false; } | |||
public boolean isTypeVariableSignature() { return false; } | |||
public boolean isArrayTypeSignature() { return false; } | |||
} | |||
public static class ClassTypeSignature extends FieldTypeSignature { | |||
public String classSignature; | |||
public SimpleClassTypeSignature outerType; | |||
public SimpleClassTypeSignature[] nestedTypes; | |||
public ClassTypeSignature(String sig,String identifier) { | |||
this.classSignature = sig; | |||
this.outerType = new SimpleClassTypeSignature(identifier); | |||
this.nestedTypes = new SimpleClassTypeSignature[0]; | |||
} | |||
public ClassTypeSignature(String sig, SimpleClassTypeSignature outer, SimpleClassTypeSignature[] inners) { | |||
this.classSignature = sig; | |||
this.outerType = outer; | |||
this.nestedTypes = inners; | |||
} | |||
public boolean isClassTypeSignature() { return true; } | |||
public String toString() { | |||
return classSignature; | |||
} | |||
} | |||
public static class TypeVariableSignature extends FieldTypeSignature { | |||
public String typeVariableName; | |||
public TypeVariableSignature(String typeVarToken) { | |||
this.typeVariableName = typeVarToken.substring(1); | |||
} | |||
public boolean isTypeVariableSignature() { return true; } | |||
public String toString() { | |||
return "T" + typeVariableName + ";"; | |||
} | |||
} | |||
public static class ArrayTypeSignature extends FieldTypeSignature { | |||
public TypeSignature typeSig; | |||
public ArrayTypeSignature(TypeSignature aTypeSig) { | |||
this.typeSig = aTypeSig; | |||
} | |||
public boolean isArrayTypeSignature() { return true; } | |||
public String toString() { | |||
return "[" + typeSig.toString(); | |||
} | |||
} | |||
public static class SimpleClassTypeSignature { | |||
public String identifier; | |||
public TypeArgument[] typeArguments; | |||
public SimpleClassTypeSignature(String identifier) { | |||
this.identifier = identifier; | |||
this.typeArguments = new TypeArgument[0]; | |||
} | |||
public SimpleClassTypeSignature(String identifier, TypeArgument[] args) { | |||
this.identifier = identifier; | |||
this.typeArguments = args; | |||
} | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(identifier); | |||
if (typeArguments.length > 0) { | |||
sb.append("<"); | |||
for (int i = 0; i < typeArguments.length; i++) { | |||
sb.append(typeArguments[i].toString()); | |||
} | |||
sb.append(">"); | |||
} | |||
return sb.toString(); | |||
} | |||
} | |||
public static class TypeArgument { | |||
public boolean isWildcard = false; | |||
public boolean isPlus = false; | |||
public boolean isMinus = false; | |||
public FieldTypeSignature signature; // null if isWildcard | |||
public TypeArgument() { | |||
isWildcard = true; | |||
} | |||
public TypeArgument(boolean plus, boolean minus, FieldTypeSignature aSig) { | |||
this.isPlus = plus; | |||
this.isMinus = minus; | |||
this.signature = aSig; | |||
} | |||
public String toString() { | |||
if (isWildcard) return "*"; | |||
StringBuffer sb = new StringBuffer(); | |||
if (isPlus) sb.append("+"); | |||
if (isMinus) sb.append("-"); | |||
sb.append(signature.toString()); | |||
return sb.toString(); | |||
} | |||
} | |||
private int signature_index; | |||
/** | |||
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a physical | |||
* copy. | |||
*/ | |||
public Signature(Signature c) { | |||
this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool()); | |||
} | |||
/** | |||
* Construct object from file stream. | |||
* | |||
* @param name_index Index in constant pool to CONSTANT_Utf8 | |||
* @param length Content length in bytes | |||
* @param file Input stream | |||
* @param constant_pool Array of constants | |||
* @throws IOException | |||
*/ | |||
Signature(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { | |||
this(name_index, length, file.readUnsignedShort(), constant_pool); | |||
} | |||
/** | |||
* @param name_index Index in constant pool to CONSTANT_Utf8 | |||
* @param length Content length in bytes | |||
* @param constant_pool Array of constants | |||
* @param Signature_index Index in constant pool to CONSTANT_Utf8 | |||
*/ | |||
public Signature(int name_index, int length, int signature_index, ConstantPool constant_pool) { | |||
super(Constants.ATTR_SIGNATURE, name_index, length, constant_pool); | |||
this.signature_index = signature_index; | |||
} | |||
/** | |||
* Called by objects that are traversing the nodes of the tree implicitely defined by the contents of a Java class. I.e., the | |||
* hierarchy of methods, fields, attributes, etc. spawns a tree of objects. | |||
* | |||
* @param v Visitor object | |||
*/ | |||
public void accept(ClassVisitor v) { | |||
System.err.println("Visiting non-standard Signature object"); | |||
v.visitSignature(this); | |||
} | |||
/** | |||
* Dump source file attribute to file stream in binary format. | |||
* | |||
* @param file Output file stream | |||
* @throws IOException | |||
*/ | |||
public final void dump(DataOutputStream file) throws IOException { | |||
super.dump(file); | |||
file.writeShort(signature_index); | |||
} | |||
/** | |||
* @return Index in constant pool of source file name. | |||
*/ | |||
public final int getSignatureIndex() { | |||
return signature_index; | |||
} | |||
/** | |||
* @param Signature_index. | |||
*/ | |||
public final void setSignatureIndex(int signature_index) { | |||
this.signature_index = signature_index; | |||
} | |||
/** | |||
* @return GJ signature. | |||
*/ | |||
public final String getSignature() { | |||
ConstantUtf8 c = (ConstantUtf8) constantPool.getConstant(signature_index, Constants.CONSTANT_Utf8); | |||
return c.getBytes(); | |||
} | |||
/** | |||
* Extends ByteArrayInputStream to make 'unreading' chars possible. | |||
*/ | |||
private static final class MyByteArrayInputStream extends ByteArrayInputStream { | |||
MyByteArrayInputStream(String data) { | |||
super(data.getBytes()); | |||
} | |||
final int mark() { | |||
return pos; | |||
} | |||
final String getData() { | |||
return new String(buf); | |||
} | |||
final void reset(int p) { | |||
pos = p; | |||
} | |||
final void unread() { | |||
if (pos > 0) | |||
pos--; | |||
} | |||
} | |||
private static boolean identStart(int ch) { | |||
return ch == 'T' || ch == 'L'; | |||
} | |||
private static final void matchIdent(MyByteArrayInputStream in, StringBuffer buf) { | |||
int ch; | |||
if ((ch = in.read()) == -1) | |||
throw new RuntimeException("Illegal signature: " + in.getData() + " no ident, reaching EOF"); | |||
// System.out.println("return from ident:" + (char)ch); | |||
if (!identStart(ch)) { | |||
StringBuffer buf2 = new StringBuffer(); | |||
int count = 1; | |||
while (Character.isJavaIdentifierPart((char) ch)) { | |||
buf2.append((char) ch); | |||
count++; | |||
ch = in.read(); | |||
} | |||
if (ch == ':') { // Ok, formal parameter | |||
in.skip("Ljava/lang/Object".length()); | |||
buf.append(buf2); | |||
ch = in.read(); | |||
in.unread(); | |||
// System.out.println("so far:" + buf2 + ":next:" +(char)ch); | |||
} else { | |||
for (int i = 0; i < count; i++) | |||
in.unread(); | |||
} | |||
return; | |||
} | |||
StringBuffer buf2 = new StringBuffer(); | |||
ch = in.read(); | |||
do { | |||
buf2.append((char) ch); | |||
ch = in.read(); | |||
// System.out.println("within ident:"+ (char)ch); | |||
} while ((ch != -1) && (Character.isJavaIdentifierPart((char) ch) || (ch == '/'))); | |||
buf.append(buf2.toString().replace('/', '.')); | |||
// System.out.println("regular return ident:"+ (char)ch + ":" + buf2); | |||
if (ch != -1) | |||
in.unread(); | |||
} | |||
private static final void matchGJIdent(MyByteArrayInputStream in, StringBuffer buf) { | |||
int ch; | |||
matchIdent(in, buf); | |||
ch = in.read(); | |||
if ((ch == '<') || ch == '(') { // Parameterized or method | |||
// System.out.println("Enter <"); | |||
buf.append((char) ch); | |||
matchGJIdent(in, buf); | |||
while (((ch = in.read()) != '>') && (ch != ')')) { // List of parameters | |||
if (ch == -1) | |||
throw new RuntimeException("Illegal signature: " + in.getData() + " reaching EOF"); | |||
// System.out.println("Still no >"); | |||
buf.append(", "); | |||
in.unread(); | |||
matchGJIdent(in, buf); // Recursive call | |||
} | |||
// System.out.println("Exit >"); | |||
buf.append((char) ch); | |||
} else | |||
in.unread(); | |||
ch = in.read(); | |||
if (identStart(ch)) { | |||
in.unread(); | |||
matchGJIdent(in, buf); | |||
} else if (ch == ')') { | |||
in.unread(); | |||
return; | |||
} else if (ch != ';') | |||
throw new RuntimeException("Illegal signature: " + in.getData() + " read " + (char) ch); | |||
} | |||
public static String translate(String s) { | |||
// System.out.println("Sig:" + s); | |||
StringBuffer buf = new StringBuffer(); | |||
matchGJIdent(new MyByteArrayInputStream(s), buf); | |||
return buf.toString(); | |||
} | |||
public static final boolean isFormalParameterList(String s) { | |||
return s.startsWith("<") && (s.indexOf(':') > 0); | |||
} | |||
public static final boolean isActualParameterList(String s) { | |||
return s.startsWith("L") && s.endsWith(">;"); | |||
} | |||
/** | |||
* @return String representation | |||
*/ | |||
public final String toString() { | |||
String s = getSignature(); | |||
return "Signature(" + s + ")"; | |||
} | |||
/** | |||
* @return deep copy of this attribute | |||
*/ | |||
public Attribute copy(ConstantPool constant_pool) { | |||
return (Signature) clone(); | |||
} | |||
} |
@@ -1,277 +0,0 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2005 Contributors | |||
* 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: | |||
* Adrian Colyer initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.apache.bcel.classfile.tests; | |||
import org.aspectj.apache.bcel.classfile.GenericSignatureParser; | |||
import org.aspectj.apache.bcel.classfile.JavaClass; | |||
import org.aspectj.apache.bcel.classfile.Method; | |||
import org.aspectj.apache.bcel.classfile.Signature; | |||
import org.aspectj.apache.bcel.classfile.Signature.ClassSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.ClassTypeSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.FieldTypeSignature; | |||
import org.aspectj.apache.bcel.classfile.Signature.SimpleClassTypeSignature; | |||
import org.aspectj.apache.bcel.util.SyntheticRepository; | |||
import junit.framework.TestCase; | |||
public class GenericSignatureParserTest extends TestCase { | |||
GenericSignatureParser parser; | |||
public void testSimpleTokenize() { | |||
String [] tokens = parser.tokenize("Ljava/lang/String;"); | |||
assertEquals(new String[] {"Ljava","/","lang","/","String",";"},tokens); | |||
} | |||
public void testTokenizeWithWildTypeArguments() { | |||
String[] tokens = parser.tokenize("Ljava/lang/String<*>;"); | |||
assertEquals(new String[] {"Ljava","/","lang","/","String","<","*",">",";"},tokens); | |||
} | |||
public void testTokenizeWithExtendsTypeArguments() { | |||
String[] tokens = parser.tokenize("Ljava/util/List<+TE>;"); | |||
assertEquals(new String[] {"Ljava","/","util","/","List","<","+","TE",">",";"},tokens); | |||
} | |||
public void testTokenizeWithSuperTypeArguments() { | |||
String[] tokens = parser.tokenize("Ljava/util/List<-TE>;"); | |||
assertEquals(new String[] {"Ljava","/","util","/","List","<","-","TE",">",";"},tokens); | |||
} | |||
public void testTokenizeArrayType() { | |||
String [] tokens = parser.tokenize("[Ljava/lang/String;"); | |||
assertEquals(new String[] {"[","Ljava","/","lang","/","String",";"},tokens); | |||
} | |||
public void testTokenizeFormalTypeParameters() { | |||
String[] tokens = parser.tokenize("<T:Ljava/lang/String;:Ljava/util/Comparable;>"); | |||
assertEquals(new String[] {"<","T",":","Ljava","/","lang","/","String",";",":","Ljava","/","util","/","Comparable",";",">"},tokens); | |||
} | |||
public void testParseClassSignatureSimple() { | |||
ClassSignature sig = parser.parseAsClassSignature("Ljava/lang/String;"); | |||
assertEquals("No type parameters",0,sig.formalTypeParameters.length); | |||
assertEquals("No superinterfaces",0,sig.superInterfaceSignatures.length); | |||
assertEquals("Ljava/lang/String;",sig.superclassSignature.classSignature); | |||
SimpleClassTypeSignature outerType = sig.superclassSignature.outerType; | |||
assertEquals("Ljava/lang/String;",outerType.identifier); | |||
assertEquals("No type args",0,outerType.typeArguments.length); | |||
} | |||
public void testParseClassSignatureTypeArgs() { | |||
ClassSignature sig = parser.parseAsClassSignature("Ljava/util/List<+Ljava/lang/String;>;"); | |||
assertEquals("No type parameters",0,sig.formalTypeParameters.length); | |||
assertEquals("No superinterfaces",0,sig.superInterfaceSignatures.length); | |||
assertEquals("Ljava/util/List<+Ljava/lang/String;>;",sig.superclassSignature.classSignature); | |||
SimpleClassTypeSignature outerType = sig.superclassSignature.outerType; | |||
assertEquals("Ljava/util/List",outerType.identifier); | |||
assertEquals("One type arg",1,outerType.typeArguments.length); | |||
assertTrue(outerType.typeArguments[0].isPlus); | |||
assertEquals("+Ljava/lang/String;",outerType.typeArguments[0].toString()); | |||
} | |||
public void testParseClassSignatureTheFullMonty() { | |||
ClassSignature sig = parser.parseAsClassSignature("<E:Ljava/lang/String;:Ljava/lang/Number<TE;>;>Ljava/util/List<TE;>;Ljava/util/Comparable<-TE;>;"); | |||
assertEquals("1 formal parameter",1,sig.formalTypeParameters.length); | |||
assertEquals("E",sig.formalTypeParameters[0].identifier); | |||
ClassTypeSignature fsig = (ClassTypeSignature) sig.formalTypeParameters[0].classBound; | |||
assertEquals("Ljava/lang/String;",fsig.classSignature); | |||
assertEquals("1 interface bound",1,sig.formalTypeParameters[0].interfaceBounds.length); | |||
ClassTypeSignature isig = (ClassTypeSignature) sig.formalTypeParameters[0].interfaceBounds[0]; | |||
assertEquals("Ljava/lang/Number<TE;>;",isig.classSignature); | |||
assertEquals("Ljava/util/List<TE;>;",sig.superclassSignature.classSignature); | |||
assertEquals("1 type argument",1,sig.superclassSignature.outerType.typeArguments.length); | |||
assertEquals("TE;",sig.superclassSignature.outerType.typeArguments[0].toString()); | |||
assertEquals("1 super interface",1,sig.superInterfaceSignatures.length); | |||
assertEquals("Ljava/util/Comparable<-TE;>;",sig.superInterfaceSignatures[0].toString()); | |||
} | |||
public void testClassSignatureParsingInJDK() throws Exception { | |||
SyntheticRepository repository = SyntheticRepository.getInstance(); | |||
String[] testClasses = new String[] { | |||
"java.lang.Comparable", | |||
"java.lang.Iterable", | |||
"java.lang.Class", | |||
"java.lang.Enum", | |||
"java.lang.InheritableThreadLocal", | |||
"java.lang.ThreadLocal", | |||
"java.util.Collection", | |||
"java.util.Comparator", | |||
"java.util.Enumeration", | |||
"java.util.Iterator", | |||
"java.util.List", | |||
"java.util.ListIterator", | |||
"java.util.Map", | |||
"java.util.Map$Entry", | |||
"java.util.Queue", | |||
"java.util.Set", | |||
"java.util.SortedMap", | |||
"java.util.SortedSet" | |||
}; | |||
for (int i = 0; i < testClasses.length; i++) { | |||
JavaClass jc = repository.loadClass(testClasses[i]); | |||
String sig = jc.getGenericSignature(); | |||
parser.parseAsClassSignature(sig); | |||
} | |||
} | |||
public void testFieldSignatureParsingClassType() { | |||
FieldTypeSignature fsig = parser.parseAsFieldSignature("Ljava/lang/String;"); | |||
assertTrue("ClassTypeSignature", fsig instanceof ClassTypeSignature); | |||
assertEquals("Ljava/lang/String;",fsig.toString()); | |||
} | |||
public void testFieldSignatureParsingArrayType() { | |||
FieldTypeSignature fsig = parser.parseAsFieldSignature("[Ljava/lang/String;"); | |||
assertTrue("ArrayTypeSignature", fsig instanceof Signature.ArrayTypeSignature); | |||
assertEquals("[Ljava/lang/String;",fsig.toString()); | |||
} | |||
public void testFieldSignatureParsingTypeVariable() { | |||
FieldTypeSignature fsig = parser.parseAsFieldSignature("TT;"); | |||
assertTrue("TypeVariableSignature",fsig instanceof Signature.TypeVariableSignature); | |||
assertEquals("TT;",fsig.toString()); | |||
} | |||
public void testSimpleMethodSignatureParsing() { | |||
Signature.MethodTypeSignature mSig = parser.parseAsMethodSignature("()V"); | |||
assertEquals("No type parameters",0,mSig.formalTypeParameters.length); | |||
assertEquals("No parameters",0,mSig.parameters.length); | |||
assertEquals("Void return type","V",mSig.returnType.toString()); | |||
assertEquals("No throws",0,mSig.throwsSignatures.length); | |||
} | |||
public void testMethodSignatureTypeParams() { | |||
Signature.MethodTypeSignature mSig = parser.parseAsMethodSignature("<T:>(TT;)V"); | |||
assertEquals("One type parameter",1,mSig.formalTypeParameters.length); | |||
assertEquals("T",mSig.formalTypeParameters[0].identifier); | |||
assertEquals("Ljava/lang/Object;",mSig.formalTypeParameters[0].classBound.toString()); | |||
assertEquals("One parameter",1,mSig.parameters.length); | |||
assertEquals("TT;",mSig.parameters[0].toString()); | |||
assertEquals("Void return type","V",mSig.returnType.toString()); | |||
assertEquals("No throws",0,mSig.throwsSignatures.length); | |||
} | |||
public void testMethodSignatureGenericReturn() { | |||
Signature.MethodTypeSignature mSig = parser.parseAsMethodSignature("<T:>()TT;"); | |||
assertEquals("One type parameter",1,mSig.formalTypeParameters.length); | |||
assertEquals("T",mSig.formalTypeParameters[0].identifier); | |||
assertEquals("Ljava/lang/Object;",mSig.formalTypeParameters[0].classBound.toString()); | |||
assertEquals("No parameters",0,mSig.parameters.length); | |||
assertEquals("'T' return type","TT;",mSig.returnType.toString()); | |||
assertEquals("No throws",0,mSig.throwsSignatures.length); | |||
} | |||
public void testMethodSignatureThrows() { | |||
Signature.MethodTypeSignature mSig = parser.parseAsMethodSignature("<T:>(TT;)V^Ljava/lang/Exception;^Ljava/lang/RuntimeException;"); | |||
assertEquals("One type parameter",1,mSig.formalTypeParameters.length); | |||
assertEquals("T",mSig.formalTypeParameters[0].identifier); | |||
assertEquals("Ljava/lang/Object;",mSig.formalTypeParameters[0].classBound.toString()); | |||
assertEquals("One parameter",1,mSig.parameters.length); | |||
assertEquals("TT;",mSig.parameters[0].toString()); | |||
assertEquals("Void return type","V",mSig.returnType.toString()); | |||
assertEquals("2 throws",2,mSig.throwsSignatures.length); | |||
assertEquals("Ljava/lang/Exception;",mSig.throwsSignatures[0].toString()); | |||
assertEquals("Ljava/lang/RuntimeException;",mSig.throwsSignatures[1].toString()); | |||
} | |||
public void testMethodSignaturePrimitiveParams() { | |||
Signature.MethodTypeSignature mSig = parser.parseAsMethodSignature("(ILjava/lang/Object;)V"); | |||
assertEquals("2 parameters",2,mSig.parameters.length); | |||
assertEquals("I",mSig.parameters[0].toString()); | |||
assertEquals("Ljava/lang/Object;",mSig.parameters[1].toString()); | |||
} | |||
public void testMethodSignatureParsingInJDK() throws Exception{ | |||
SyntheticRepository repository = SyntheticRepository.getInstance(); | |||
String[] testClasses = new String[] { | |||
"java.lang.Comparable", | |||
"java.lang.Iterable", | |||
"java.lang.Class", | |||
"java.lang.Enum", | |||
"java.lang.InheritableThreadLocal", | |||
"java.lang.ThreadLocal", | |||
"java.util.Collection", | |||
"java.util.Comparator", | |||
"java.util.Enumeration", | |||
"java.util.Iterator", | |||
"java.util.List", | |||
"java.util.ListIterator", | |||
"java.util.Map", | |||
"java.util.Map$Entry", | |||
"java.util.Queue", | |||
"java.util.Set", | |||
"java.util.SortedMap", | |||
"java.util.SortedSet" | |||
}; | |||
for (int i = 0; i < testClasses.length; i++) { | |||
JavaClass jc = repository.loadClass(testClasses[i]); | |||
Method[] methods = jc.getMethods(); | |||
for (int j = 0; j < methods.length; j++) { | |||
String sig = methods[j].getGenericSignature(); | |||
if (sig != null) parser.parseAsMethodSignature(sig); | |||
} | |||
} | |||
} | |||
public void testFullyQualifiedSuperclassAfterTypeParams() { | |||
try { | |||
Signature.FieldTypeSignature cSig = parser.parseAsFieldSignature("Ljava/util/List</;"); | |||
fail("Expected IllegalStateException"); | |||
} catch (IllegalStateException ex) { | |||
assertTrue(ex.getMessage().indexOf("Ljava/util/List</;") != -1); | |||
} | |||
} | |||
public void testPr107784() { | |||
parser.parseAsMethodSignature( | |||
"(Lcom/cibc/responders/mapping/CommonDataBeanScenario;Ljava/lang/Object;)Lcom/cibc/responders/response/Formatter<[BLjava/lang/Object;>;"); | |||
parser.parseAsClassSignature("<Parent:Ljava/lang/Object;Child:Ljava/lang/Object;>Ljava/lang/Object;"); | |||
} | |||
private void assertEquals(String[] expected, String[] actual) { | |||
if (actual.length != expected.length) { | |||
int shorter = Math.min(expected.length,actual.length); | |||
for (int i = 0; i < shorter; i++) { | |||
if (!actual[i].equals(expected[i])) { | |||
fail("Expected " + expected[i] + " at position " + i + " but found " + | |||
actual[i]); | |||
} | |||
} | |||
fail("Expected " + expected.length + " tokens but got " + actual.length + | |||
tokensToString(actual)); | |||
} | |||
for (int i = 0; i < actual.length; i++) { | |||
if (!actual[i].equals(expected[i])) { | |||
fail("Expected " + expected[i] + " at position " + i + " but found " + | |||
actual[i]); | |||
} | |||
} | |||
} | |||
private String tokensToString(String[] tokens) { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(tokens[0]); | |||
for (int i = 1; i < tokens.length; i++) { | |||
sb.append(","); | |||
sb.append(tokens[i]); | |||
} | |||
return sb.toString(); | |||
} | |||
protected void setUp() throws Exception { | |||
super.setUp(); | |||
parser = new GenericSignatureParser(); | |||
} | |||
} |