/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. * * This program and the accompanying materials are made available under * the terms of the Common Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/cpl-v10.html * * $Id: Types.java,v 1.1.1.1 2004/05/09 16:57:50 vlad_r Exp $ */ package com.vladium.jcd.lib; import java.io.IOException; import java.lang.reflect.*; import com.vladium.jcd.cls.IAccessFlags; // ---------------------------------------------------------------------------- /** * Utility methods for manipulating type signatures and descriptors. * * TODO: fix usage of chars in parsers * * @author (C) 2001, Vlad Roubtsov */ public abstract class Types { // public: ................................................................ /** * Returns 'c''s package name [does not include trailing '.'] or "" * if 'c' is in the default package. */ public static String getClassPackageName (final Class c) { // TODO: handle array and other types final String className = c.getName (); final int lastDot = className.lastIndexOf ('.'); return lastDot >= 0 ? className.substring (0, lastDot) : ""; } public static String accessFlagsToString (final int flags, final boolean isClass) { final StringBuffer result = new StringBuffer (); boolean first = true; if (isClass) { for (int f = 0; f < IAccessFlags.ALL_ACC.length; ++ f) { final int bit = IAccessFlags.ALL_ACC [f]; if ((flags & bit) != 0) { if (first) first = false; else result.append (" "); if (bit == IAccessFlags.ACC_SUPER) result.append ("super"); else result.append (IAccessFlags.ALL_ACC_NAMES [f]); } } } else { for (int f = 0; f < IAccessFlags.ALL_ACC.length; ++ f) { final int bit = IAccessFlags.ALL_ACC [f]; if ((flags & bit) != 0) { if (first) first = false; else result.append (" "); result.append (IAccessFlags.ALL_ACC_NAMES [f]); } } } return result.toString (); } /** * Converts Java-styled package/class name to how it would be * represented in the VM.
*
* Example:
* javaNameToVMName("java.lang.Object") = "java/lang/Object"
*
* @see #vmNameToJavaName
*/
public static String javaNameToVMName (final String javaName)
{
if (javaName == null) return null;
return javaName.replace ('.', '/');
}
/**
* Converts a VM-styled package/class name to how it would be
* represented in Java.
*
* Example:
* vmNameToJavaName("java/lang/Object") = "java.lang.Object"
*
* @see #javaNameToVMName
*/
public static String vmNameToJavaName (final String vmName)
{
if (vmName == null) return null;
return vmName.replace ('/', '.');
}
/**
* Converts a method signature to its VM descriptor representation.
* See $4.3 of the VM spec 1.0 for the descriptor grammar.
*
* Example:
* signatureToDescriptor(new Object().getClass().getMethod("equals" ,new Class[0])) = "(Ljava/lang/Object;)Z"
*
*
* Equivalent to
* signatureToDescriptor(method.getParameterTypes (), method.getReturnType ())
.
*/
public static String signatureToDescriptor (Method method)
{
if (method == null) throw new IllegalArgumentException ("null input: method");
return signatureToDescriptor (method.getParameterTypes (), method.getReturnType ());
}
/**
* Converts a method signature (parameter types + return type) to its VM descriptor
* representation. See $4.3 of the VM spec 1.0 for the descriptor grammar.
*/ public static String signatureToDescriptor (Class [] parameterTypes, Class returnType) { return new signatureCompiler ().signatureDescriptor (parameterTypes, returnType); } /** * Converts a type (a Class) to its VM descriptor representation.
*
* Example:
* typeToDescriptor(Object.class) = "Ljava/lang/Object;"
* typeToDescriptor(boolean.class) = "Z"
*
* Note the invariant typeToDescriptor(descriptorToType(desc)) == desc. * * @see #descriptorToType */ public static String typeToDescriptor (Class type) { return new signatureCompiler ().typeDescriptor (type); } /** * Converts a VM descriptor to the corresponding type.
*
* Example:
* descriptorToType("[[I") = int[][].class
* descriptorToType("B") = byte.class
*
* Note the invariant descriptorToType(typeToDescriptor(c)) == c.
*
* @see #descriptorToType
*/
public static Class descriptorToType (String typedescriptor) throws ClassNotFoundException
{
return new typeDescriptorCompiler ().descriptorToClass (typedescriptor);
}
public static String descriptorToReturnType (String methoddescriptor)
{
final int i1 = methoddescriptor.indexOf ('(');
final int i2 = methoddescriptor.lastIndexOf (')');
if ((i1 < 0) || (i2 <= 0) || (i1 >= i2) || (i2 >= methoddescriptor.length () - 1))
throw new IllegalArgumentException ("malformed method descriptor: [" + methoddescriptor + "]");
return methoddescriptor.substring (i2 + 1);
}
public static String [] descriptorToParameterTypes (String methoddescriptor)
{
//System.out.println ("METHOD DESCRIPTOR: [" + methoddescriptor + "]");
try
{
final methodDescriptorCompiler compiler = new methodDescriptorCompiler (methoddescriptor);
compiler.methodDescriptor ();
return compiler.getResult ();
}
catch (IOException e)
{
throw new IllegalArgumentException ("error parsing [" + methoddescriptor + "]: " + e.toString ());
}
/*
final java.util.Vector _result = new java.util.Vector ();
final StringBuffer token = new StringBuffer ();
char c = '*';
int scan = 0;
for (int state = 0; state != 4; )
{
try
{
switch (state)
{
case 0:
c = methoddescriptor.charAt (scan++);
if (c == '(')
state = 1;
else
throw new IllegalArgumentException ("malformed method descriptor: [" + methoddescriptor + "]");
break;
case 1:
c = methoddescriptor.charAt (scan);
switch (c)
{
case 'B':
case 'C':
case 'D':
case 'F':
case 'I':
case 'J':
case 'S':
case 'Z':
token.append (c);
_result.addElement (token.toString ());
token.setLength (0);
scan++;
break;
case 'L':
state = 2;
token.append (c);
scan++;
break;
case '[':
state = 3;
token.append (c);
scan++;
break;
case ')':
if (token.length () > 0)
{
_result.addElement (token.toString ());
token.setLength (0);
}
state = 4;
break;
default:
throw new IllegalArgumentException ("[state = " + state + ", c = " + c + "] malformed method descriptor: [" + methoddescriptor + "]");
} // end of nested switch
break;
case 2:
c = methoddescriptor.charAt (scan++);
token.append (c);
if (c == ';')
{
_result.addElement (token.toString ());
token.setLength (0);
state = 1;
}
break;
case 3:
c = methoddescriptor.charAt (scan++);
token.append (c);
if (c != '[')
{
state = 1;
}
break;
} // end of switch
//System.out.println ("[state = " + state + ", c = " + c + "]");
}
catch (StringIndexOutOfBoundsException e)
{
throw new IllegalArgumentException ("malformed method descriptor: [" + methoddescriptor + "]");
}
}
String [] result = new String [_result.size ()];
_result.copyInto (result);
return result;
*/
}
public static String signatureToMethodDescriptor (final String [] parameterTypeDescriptors, final String returnTypeDescriptor)
{
final StringBuffer result = new StringBuffer ("(");
for (int p = 0; p < parameterTypeDescriptors.length; p++)
{
result.append (parameterTypeDescriptors [p]);
}
result.append (')');
result.append (returnTypeDescriptor);
return result.toString ();
}
public static String typeDescriptorToUserName (final String typedescriptor)
{
return new typeDescriptorCompiler2 ().descriptorToClass (typedescriptor);
}
public static String methodDescriptorToUserName (final String methoddescriptor)
{
final String [] parameterTypes = descriptorToParameterTypes (methoddescriptor);
final StringBuffer result = new StringBuffer ("(");
for (int p = 0; p < parameterTypes.length; p++)
{
//System.out.println ("DESCRIPTOR: [" + parameterTypes [p] + "]");
if (p > 0) result.append (", ");
final String typeUserName = typeDescriptorToUserName (parameterTypes [p]);
int lastDot = typeUserName.lastIndexOf ('.');
if ((lastDot < 0) || ! "java.lang.".equals (typeUserName.substring (0, lastDot + 1)))
result.append (typeUserName);
else
result.append (typeUserName.substring (lastDot + 1));
}
result.append (')');
return result.toString ();
}
public static String fullMethodDescriptorToUserName (final String classJavaName, String methodName, final String methoddescriptor)
{
if ("