Browse Source

supported generic type signatures.


git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@347 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba 17 years ago
parent
commit
0552a7af39

+ 27
- 5
src/main/javassist/bytecode/ClassFileWriter.java View File

@@ -68,7 +68,7 @@ public class ClassFileWriter {
out.println(Modifier.toString(AccessFlag.toModifier(acc))
+ " " + finfo.getName() + "\t"
+ finfo.getDescriptor());
printAttributes(finfo.getAttributes(), out);
printAttributes(finfo.getAttributes(), out, false);
}

out.println();
@@ -80,15 +80,15 @@ public class ClassFileWriter {
out.println(Modifier.toString(AccessFlag.toModifier(acc))
+ " " + minfo.getName() + "\t"
+ minfo.getDescriptor());
printAttributes(minfo.getAttributes(), out);
printAttributes(minfo.getAttributes(), out, false);
out.println();
}

out.println();
printAttributes(cf.getAttributes(), out);
printAttributes(cf.getAttributes(), out, true);
}

static void printAttributes(List list, PrintWriter out) {
static void printAttributes(List list, PrintWriter out, boolean forClass) {
if (list == null)
return;

@@ -104,9 +104,31 @@ public class ClassFileWriter {
+ ", " + ca.getExceptionTable().size()
+ " catch blocks");
out.println("<code attribute begin>");
printAttributes(ca.getAttributes(), out);
printAttributes(ca.getAttributes(), out, forClass);
out.println("<code attribute end>");
}
else if (ai instanceof StackMapTable) {
out.println("<stack map table begin>");
StackMapTable.Writer.print((StackMapTable)ai, out);
out.println("<stack map table end>");
}
else if (ai instanceof SignatureAttribute) {
SignatureAttribute sa = (SignatureAttribute)ai;
String sig = sa.getSignature();
out.println("signature: " + sig);
try {
String s;
if (forClass)
s = SignatureAttribute.toClassSignature(sig).toString();
else
s = SignatureAttribute.toMethodSignature(sig).toString();

out.println(" " + s);
}
catch (BadBytecode e) {
out.println(" syntax error");
}
}
else
out.println("attribute: " + ai.getName()
+ " (" + ai.get().length + " byte): "

+ 1
- 1
src/main/javassist/bytecode/Descriptor.java View File

@@ -550,7 +550,7 @@ public class Descriptor {
return i2;
}

private static CtClass toPrimitiveClass(char c) {
static CtClass toPrimitiveClass(char c) {
CtClass type = null;
switch (c) {
case 'Z' :

+ 647
- 0
src/main/javassist/bytecode/SignatureAttribute.java View File

@@ -18,6 +18,8 @@ package javassist.bytecode;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Map;
import java.util.ArrayList;
import javassist.CtClass;

/**
* <code>Signature_attribute</code>.
@@ -51,6 +53,9 @@ public class SignatureAttribute extends AttributeInfo {

/**
* Returns the signature indicated by <code>signature_index</code>.
*
* @see #toClassSignature(String)
* @see #toMethodSignature(String)
*/
public String getSignature() {
return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0));
@@ -67,4 +72,646 @@ public class SignatureAttribute extends AttributeInfo {
public AttributeInfo copy(ConstPool newCp, Map classnames) {
return new SignatureAttribute(newCp, getSignature());
}

static private class Cursor {
int position = 0;

int indexOf(String s, int ch) throws BadBytecode {
int i = s.indexOf(ch, position);
if (i < 0)
throw error(s);
else {
position = i + 1;
return i;
}
}
}

/**
* Class signature.
*/
public static class ClassSignature {
TypeParameter[] params;
ClassType superClass;
ClassType[] interfaces;
ClassSignature(TypeParameter[] p, ClassType s, ClassType[] i) {
params = p;
superClass = s;
interfaces = i;
}

/**
* Returns the type parameters.
*
* @return a zero-length array if the type parameters are not specified.
*/
public TypeParameter[] getParameters() {
return params;
}

/**
* Returns the super class.
*/
public ClassType getSuperClass() { return superClass; }

/**
* Returns the super interfaces.
*
* @return a zero-length array if the super interfaces are not specified.
*/
public ClassType[] getInterfaces() { return interfaces; }

/**
* Returns the string representation.
*/
public String toString() {
StringBuffer sbuf = new StringBuffer();

TypeParameter.toString(sbuf, params);
sbuf.append(" extends ").append(superClass);
if (interfaces.length > 0) {
sbuf.append(" implements ");
Type.toString(sbuf, interfaces);
}

return sbuf.toString();
}
}

/**
* Method type signature.
*/
public static class MethodSignature {
TypeParameter[] typeParams;
Type[] params;
Type retType;
ObjectType[] exceptions;

MethodSignature(TypeParameter[] tp, Type[] p, Type ret, ObjectType[] ex) {
typeParams = tp;
params = p;
retType = ret;
exceptions = ex;
}

/**
* Returns the formal type parameters.
*
* @return a zero-length array if the type parameters are not specified.
*/
public TypeParameter[] getTypeParameters() { return typeParams; }

/**
* Returns the types of the formal parameters.
*
* @return a zero-length array if no formal parameter is taken.
*/
public Type[] getParameterTypes() { return params; }

/**
* Returns the type of the returned value.
*/
public Type getReturnType() { return retType; }

/**
* Returns the types of the exceptions that may be thrown.
*
* @return a zero-length array if exceptions are never thrown or
* the exception types are not parameterized types or type variables.
*/
public ObjectType[] getExceptionTypes() { return exceptions; }

/**
* Returns the string representation.
*/
public String toString() {
StringBuffer sbuf = new StringBuffer();

TypeParameter.toString(sbuf, typeParams);
sbuf.append(" (");
Type.toString(sbuf, params);
sbuf.append(") ");
sbuf.append(retType);
if (exceptions.length > 0) {
sbuf.append(" throws ");
Type.toString(sbuf, exceptions);
}

return sbuf.toString();
}
}

/**
* Formal type parameters.
*/
public static class TypeParameter {
String name;
ObjectType superClass;
ObjectType[] superInterfaces;

TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si) {
name = sig.substring(nb, ne);
superClass = sc;
superInterfaces = si;
}

/**
* Returns the name of the type parameter.
*/
public String getName() {
return name;
}

/**
* Returns the class bound of this parameter.
*
* @return null if the class bound is not specified.
*/
public ObjectType getClassBound() { return superClass; }

/**
* Returns the interface bound of this parameter.
*
* @return a zero-length array if the interface bound is not specified.
*/
public ObjectType[] getInterfaceBound() { return superInterfaces; }

/**
* Returns the string representation.
*/
public String toString() {
StringBuffer sbuf = new StringBuffer(getName());
if (superClass != null)
sbuf.append(" extends ").append(superClass.toString());

int len = superInterfaces.length;
if (len > 0) {
for (int i = 0; i < len; i++) {
if (i > 0 || superClass != null)
sbuf.append(" & ");
else
sbuf.append(" extends ");

sbuf.append(superInterfaces[i].toString());
}
}

return sbuf.toString();
}

static void toString(StringBuffer sbuf, TypeParameter[] tp) {
sbuf.append('<');
for (int i = 0; i < tp.length; i++) {
if (i > 0)
sbuf.append(", ");

sbuf.append(tp[i]);
}

sbuf.append('>');
}
}

/**
* Type argument.
*/
public static class TypeArgument {
ObjectType arg;
char wildcard;

TypeArgument(ObjectType a, char w) {
arg = a;
wildcard = w;
}

/**
* Returns the kind of this type argument.
*
* @return ' ' (not-wildcard), '*' (wildcard), '+' (wildcard with
* upper bound), or '-' (wildcard with lower bound).
*/
public char getKind() { return wildcard; }

/**
* Returns true if this type argument is a wildcard type such as
* ?, ? extends String, or ? super Integer.
*/
public boolean isWildcard() { return wildcard != ' '; }

/**
* Returns the type represented by this argument
* if the argument is not a wildcard type. Otherwise, this method
* returns the upper bound (if the kind is '+'),
* the lower bound (if the kind is '-'), or null (if the upper or lower
* bound is not specified).
*/
public ObjectType getType() { return arg; }

/**
* Returns the string representation.
*/
public String toString() {
if (wildcard == '*')
return "?";

String type = arg.toString();
if (wildcard == ' ')
return type;
else if (wildcard == '+')
return "? extends " + type;
else
return "? super " + type;
}
}

/**
* Primitive types and object types.
*/
public static abstract class Type {
static void toString(StringBuffer sbuf, Type[] ts) {
for (int i = 0; i < ts.length; i++) {
if (i > 0)
sbuf.append(", ");

sbuf.append(ts[i]);
}
}
}

/**
* Primitive types.
*/
public static class BaseType extends Type {
char descriptor;
BaseType(char c) { descriptor = c; }

/**
* Returns the descriptor representing this primitive type.
*
* @see javassist.bytecode.Descriptor
*/
public char getDescriptor() { return descriptor; }

/**
* Returns the <code>CtClass</code> representing this
* primitive type.
*/
public CtClass getCtlass() {
return Descriptor.toPrimitiveClass(descriptor);
}

/**
* Returns the string representation.
*/
public String toString() {
return Descriptor.toClassName(Character.toString(descriptor));
}
}

/**
* Class types, array types, and type variables.
*/
public static abstract class ObjectType extends Type {}

/**
* Class types.
*/
public static class ClassType extends ObjectType {
String name;
TypeArgument[] arguments;

static ClassType make(String s, int b, int e,
TypeArgument[] targs, ClassType parent) {
if (parent == null)
return new ClassType(s, b, e, targs);
else
return new NestedClassType(s, b, e, targs, parent);
}

ClassType(String signature, int begin, int end, TypeArgument[] targs) {
name = signature.substring(begin, end).replace('/', '.');
arguments = targs;
}

/**
* Returns the class name.
*/
public String getName() {
return name;
}

/**
* Returns the type arguments.
*
* @return null if no type arguments are given to this class.
*/
public TypeArgument[] getTypeArguments() { return arguments; }

/**
* If this class is a member of another class, returns the
* class in which this class is declared.
*
* @return null if this class is not a member of another class.
*/
public ClassType getDeclaringClass() { return null; }

/**
* Returns the string representation.
*/
public String toString() {
StringBuffer sbuf = new StringBuffer();
ClassType parent = getDeclaringClass();
if (parent != null)
sbuf.append(parent.toString()).append('.');

sbuf.append(name);
if (arguments != null) {
sbuf.append('<');
int n = arguments.length;
for (int i = 0; i < n; i++) {
if (i > 0)
sbuf.append(", ");

sbuf.append(arguments[i].toString());
}

sbuf.append('>');
}

return sbuf.toString();
}
}

static class NestedClassType extends ClassType {
ClassType parent;
NestedClassType(String s, int b, int e,
TypeArgument[] targs, ClassType p) {
super(s, b, e, targs);
parent = p;
}

public ClassType getDeclaringClass() { return parent; }
}

/**
* Array types.
*/
public static class ArrayType extends ObjectType {
int dim;
Type componentType;

public ArrayType(int d, Type comp) {
dim = d;
componentType = comp;
}

/**
* Returns the dimension of the array.
*/
public int getDimension() { return dim; }

/**
* Returns the component type.
*/
public Type getComponentType() {
return componentType;
}

/**
* Returns the string representation.
*/
public String toString() {
StringBuffer sbuf = new StringBuffer(componentType.toString());
for (int i = 0; i < dim; i++)
sbuf.append("[]");

return sbuf.toString();
}
}

public static class TypeVariable extends ObjectType {
String name;

TypeVariable(String sig, int begin, int end) {
name = sig.substring(begin, end);
}

/**
* Returns the variable name.
*/
public String getName() {
return name;
}

/**
* Returns the string representation.
*/
public String toString() {
return name;
}
}

/**
* Parses the given signature string as a class signature.
*
* @param sig the signature.
* @throws BadBytecode thrown when a syntactical error is found.
*/
public static ClassSignature toClassSignature(String sig) throws BadBytecode {
try {
return parseSig(sig);
}
catch (IndexOutOfBoundsException e) {
throw error(sig);
}
}

/**
* Parses the given signature string as a method type signature.
*
* @param sig the signature.
* @throws BadBytecode thrown when a syntactical error is found.
*/
public static MethodSignature toMethodSignature(String sig) throws BadBytecode {
try {
return parseMethodSig(sig);
}
catch (IndexOutOfBoundsException e) {
throw error(sig);
}
}

private static ClassSignature parseSig(String sig)
throws BadBytecode, IndexOutOfBoundsException
{
Cursor cur = new Cursor();
TypeParameter[] tp = parseTypeParams(sig, cur);
ClassType superClass = parseClassType(sig, cur);
int sigLen = sig.length();
ArrayList ifArray = new ArrayList();
while (cur.position < sigLen && sig.charAt(cur.position) == 'L')
ifArray.add(parseClassType(sig, cur));

ClassType[] ifs
= (ClassType[])ifArray.toArray(new ClassType[ifArray.size()]);
return new ClassSignature(tp, superClass, ifs);
}

private static MethodSignature parseMethodSig(String sig)
throws BadBytecode
{
Cursor cur = new Cursor();
TypeParameter[] tp = parseTypeParams(sig, cur);
if (sig.charAt(cur.position++) != '(')
throw error(sig);

ArrayList params = new ArrayList();
while (sig.charAt(cur.position) != ')') {
Type t = parseType(sig, cur);
params.add(t);
}

cur.position++;
Type ret = parseType(sig, cur);
int sigLen = sig.length();
ArrayList exceptions = new ArrayList();
while (cur.position < sigLen && sig.charAt(cur.position) == '^') {
cur.position++;
ObjectType t = parseObjectType(sig, cur, false);
if (t instanceof ArrayType)
throw error(sig);

exceptions.add(t);
}

Type[] p = (Type[])params.toArray(new Type[params.size()]);
ObjectType[] ex = (ObjectType[])exceptions.toArray(new ObjectType[exceptions.size()]);
return new MethodSignature(tp, p, ret, ex);
}

private static TypeParameter[] parseTypeParams(String sig, Cursor cur)
throws BadBytecode
{
ArrayList typeParam = new ArrayList();
if (sig.charAt(cur.position) == '<') {
cur.position++;
while (sig.charAt(cur.position) != '>') {
int nameBegin = cur.position;
int nameEnd = cur.indexOf(sig, ':');
ObjectType classBound = parseObjectType(sig, cur, true);
ArrayList ifBound = new ArrayList();
while (sig.charAt(cur.position) == ':') {
cur.position++;
ObjectType t = parseObjectType(sig, cur, false);
ifBound.add(t);
}

TypeParameter p = new TypeParameter(sig, nameBegin, nameEnd,
classBound, (ObjectType[])ifBound.toArray(new ObjectType[ifBound.size()]));
typeParam.add(p);
}

cur.position++;
}

return (TypeParameter[])typeParam.toArray(new TypeParameter[typeParam.size()]);
}

private static ObjectType parseObjectType(String sig, Cursor c, boolean dontThrow)
throws BadBytecode
{
int i;
int begin = c.position;
switch (sig.charAt(begin)) {
case 'L' :
return parseClassType2(sig, c, null);
case 'T' :
i = c.indexOf(sig, ';');
return new TypeVariable(sig, begin + 1, i);
case '[' :
return parseArray(sig, c);
default :
if (dontThrow)
return null;
else
throw error(sig);
}
}

private static ClassType parseClassType(String sig, Cursor c)
throws BadBytecode
{
if (sig.charAt(c.position) == 'L')
return parseClassType2(sig, c, null);
else
throw error(sig);
}

private static ClassType parseClassType2(String sig, Cursor c, ClassType parent)
throws BadBytecode
{
int start = ++c.position;
char t;
do {
t = sig.charAt(c.position++);
} while (t != '$' && t != '<' && t != ';');
int end = c.position - 1;
TypeArgument[] targs;
if (t == '<') {
targs = parseTypeArgs(sig, c);
t = sig.charAt(c.position++);
}
else
targs = null;

ClassType thisClass = ClassType.make(sig, start, end, targs, parent);
if (t == '$') {
c.position--;
return parseClassType2(sig, c, thisClass);
}
else
return thisClass;
}

private static TypeArgument[] parseTypeArgs(String sig, Cursor c) throws BadBytecode {
ArrayList args = new ArrayList();
char t;
while ((t = sig.charAt(c.position++)) != '>') {
TypeArgument ta;
if (t == '*' )
ta = new TypeArgument(null, '*');
else {
if (t != '+' && t != '-') {
t = ' ';
c.position--;
}

ta = new TypeArgument(parseObjectType(sig, c, false), t);
}

args.add(ta);
}

return (TypeArgument[])args.toArray(new TypeArgument[args.size()]);
}

private static ObjectType parseArray(String sig, Cursor c) throws BadBytecode {
int dim = 1;
while (sig.charAt(++c.position) == '[')
dim++;

return new ArrayType(dim, parseType(sig, c));
}

private static Type parseType(String sig, Cursor c) throws BadBytecode {
Type t = parseObjectType(sig, c, true);
if (t == null)
t = new BaseType(sig.charAt(c.position++));

return t;
}

private static BadBytecode error(String sig) {
return new BadBytecode("bad signature: " + sig);
}
}

Loading…
Cancel
Save