package bluej.utility;
import bluej.debugger.gentype.GenTypeClass;
import bluej.debugger.gentype.GenTypeDeclTpar;
import bluej.debugger.gentype.GenTypeParameter;
import bluej.debugger.gentype.GenTypeSolid;
import bluej.debugger.gentype.JavaPrimitiveType;
import bluej.debugger.gentype.JavaType;
import bluej.debugger.gentype.Reflective;
import threadchecker.OnThread;
import threadchecker.Tag;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
| Utilities for dealing with reflection, which must behave differently for
| Java 1.4 / 1.5. Use the factory method "getJavaUtils" to retrieve an object
|* to use.
*
* @author Davin McCall
*/
@OnThread(Tag.Any)
public abstract class JavaUtils{
private static JavaUtils jutils;
/**
* Factory method. Returns a JavaUtils object.
| @return an object supporting the appropriate feature set
|
public static JavaUtils getJavaUtils()
{
if ( jutils != null ) {
return jutils;
}
jutils = new JavaUtils15();
return jutils;
}
| Get a "signature" description of a method.
|* Looks like: void method(int, int, int)
* (ie. excludes parameter names)
* @param method The method to get the signature for
* @return the signature string
public static String getSignature(Method method)
{
String name = getFQTypeName(method.getReturnType()).replace('$', '.') + " " + method.getName();
Class<?>[] params = method.getParameterTypes();
return makeSignature(name, params);
}
| Get a fully-qualified type name. For array types return the base type
| name plus the appropriate number of "[]" qualifiers.
|*/
static public String getFQTypeName(Class<?> type)
{
// Early exit for common case:
if (!type.isArray())
return type.getName();
Class<?> primtype = type;
|
|int dimensions = 0;
|
|while (primtype.isArray()){
|
|dimensions++;
|
|primtype = primtype.getComponentType();
|
|}
|
|StringBuffer sb = new StringBuffer();
|
|sb.append(primtype.getName());
|
|for (int i = 0; i < dimensions; i++)
|
|sb.append("[]");
return sb.toString();
}
/**
* Build the signature string. Format: name(type,type,type)
*/
private static String makeSignature(String name, Class<?>[] params)
{
|
|StringBuffer sb = new StringBuffer();
|
|sb.append(name);
|
|sb.append("(");
for (int j = 0; j < params.length; j++) {
String typeName = getFQTypeName(params[j]).replace('$', '.');
sb.append(typeName);
if (j < (params.length - 1))
sb.append(", ");
}
sb.append(")");
return sb.toString();
}
/**
* Get a "signature" description of a constructor.
* Looks like: ClassName(int, int, int)
* (ie. excludes parameter names)
* @param cons the Constructor to get the signature for
* @return the signature string
public static String getSignature(Constructor<?> cons)
{
String name = JavaNames.getBase(cons.getName());
Class<?>[] params = cons.getParameterTypes();
return makeSignature(name, params);
}
| Translate escape characters into their source representation.
| The result is suitable for inserting into Java source (between quotes).
|
public static String escapeString(String s)
{
StringBuffer outBuf = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\b') {
outBuf.append("\\b");
}
else if (c == '\t') {
outBuf.append("\\t");
}
else if (c == '\n') {
outBuf.append("\\n");
}
else if (c == '\f') {
outBuf.append("\\f");
}
else if (c == '\r') {
outBuf.append("\\r");
}
else if (c == '\\') {
outBuf.append("\\\\");
}
else if (c == '\"') {
outBuf.append("\\\"");
}
else if (c < 32) {
String uescape = Integer.toHexString(c);
uescape = "0000".substring(uescape.length()) + uescape;
outBuf.append("\\u" + uescape);
}
else {
outBuf.append(c);
}
}
return outBuf.toString();
}
| Get a "short description" of a method. This is like the signature,
|* but substitutes the parameter names for their types.
*
* @param method The method to get the description of
* @param paramnames The parameter names of the method
| @return The description.
|
abstract public String getShortDesc(Method method, String [] paramnames)
throws ClassNotFoundException;
| Get a "short description" of a method, and map class type parameters to
|* the given types. A short description is like the signature, but
* substitutes the parameter names for their types. Generic method type
* parameters are left unmapped.
|
| @param method The method to get the description of
| @param paramnames The parameter names of the method
| @param tparams The map (String -> GenType) for class type parameters
| @return The description.
|
abstract public String getShortDesc(Method method, String [] paramnames,
Map<String,GenTypeParameter> tparams) throws ClassNotFoundException;
| Get a long String describing the method. A long description is
| similar to the short description, but it has type names and parameters
| included.
|
abstract public String getLongDesc(Method method, String [] paramnames)
throws ClassNotFoundException;
| Get a long String describing the method, with class type parameters
| mapped to their instantiation types. A long description is similar to a
| short description, but it has type names of parameters included.
|
| @param method The method to get the description of
| @param paramnames The parameters names of the method
| @param tparams The map (String -> GenType) for class type parameters
| @return The long description string.
|
abstract public String getLongDesc(Method method, String [] paramnames,
Map<String,GenTypeParameter> tparams) throws ClassNotFoundException;
| Get a "short description" of a constructor. This is like the signature,
|* but substitutes the parameter names for their types.
*
* @param constructor The constructor to get the description of
* @return The description.
*/
|
|abstract public String getShortDesc(Constructor<?> constructor, String [] paramnames)
|
|throws ClassNotFoundException;
|
|/**
| Get a long String describing the constructor. A long description is
| similar to the short description, but it has type names and parameters
| included.
|
abstract public String getLongDesc(Constructor<?> constructor, String [] paramnames)
throws ClassNotFoundException;
abstract public boolean isVarArgs(Constructor<?> cons);
abstract public boolean isVarArgs(Method method);
abstract public boolean isSynthetic(Method method);
abstract public boolean isEnum(Class<?> cl);
| Get the return type of a method.
|
abstract public JavaType getReturnType(Method method) throws ClassNotFoundException;
abstract public JavaType getRawReturnType(Method method);
| Get the declared type of a field.
|
abstract public JavaType getFieldType(Field field) throws ClassNotFoundException;
abstract public JavaType getRawFieldType(Field field);
| Get a list of the type parameters for a generic method.
| (return an empty list if the method is not generic).
|
| @param method The method fro which to find the type parameters
| @return A list of GenTypeDeclTpar
|
abstract public List getTypeParams(Method method);
| Get a list of the type parameters for a generic constructor.
| (return an empty list if the method is not generic).
|
| @param cons The constructors for which to find the type parameters
| @return A list of GenTypeDeclTpar
|
abstract public List getTypeParams(Constructor<?> cons);
| Get a list of the type parameters for a class. Return an empty list if
| the class is not generic.
|
| @param cl the class
| @return A List of GenTypeDeclTpar
|
abstract public List getTypeParams(Class<?> cl);
| Get the declared supertype of a class.
|
abstract public GenTypeClass getSuperclass(Class<?> cl) throws ClassNotFoundException;
| Get a list of the interfaces directly implemented by the given class.
| @param cl The class for which to find the interfaces
| @return An array of interfaces
|
abstract public GenTypeClass [] getInterfaces(Class<?> cl) throws ClassNotFoundException;
| Gets an array of nicely formatted strings with the types of the parameters.
| Include the ellipsis (...) for a varargs method.
|
| @param method The method to get the parameters for.
|
abstract public String[] getParameterTypes(Method method) throws ClassNotFoundException;
| Get an array containing the argument types of the method.
|
| In the case of a varargs method, the last argument will be an array
| type.
|
| @param method the method whose argument types to get
| @param raw whether to return the raw versions of argument types
| @return the argument types
|
abstract public JavaType[] getParamGenTypes(Method method, boolean raw) throws ClassNotFoundException;
| Gets an array of nicely formatted strings with the types of the parameters.
| Include the ellipsis (...) for a varargs constructor.
|
| @param constructor The constructor to get the parameters for.
|
abstract public String[] getParameterTypes(Constructor<?> constructor) throws ClassNotFoundException;
| Get an array containing the argument types of the method.
|
| In the case of a varargs method, the last argument will be an array
| type.
|
| @param constructor the constructor whose argument types to get
| @return the argument types
|
abstract public JavaType[] getParamGenTypes(Constructor<?> constructor) throws ClassNotFoundException;
| Change a list of type parameters (with bounds) into a map, which maps
| the name of the parameter to its bounding type.
|
| @param tparams A list of GenTypeDeclTpar
| @return A map (String -> GenTypeSolid)
|
public static Map TParamsToMap(List<GenTypeDeclTpar> tparams)
{
Map<String,GenTypeSolid> rmap = new HashMap<String,GenTypeSolid>();
for ( Iterator<GenTypeDeclTpar> i = tparams.iterator(); i.hasNext(); ) {
GenTypeDeclTpar n = i.next();
rmap.put(n.getTparName(), n.getBound().mapTparsToTypes(rmap).getUpperBound().asSolid());
}
return rmap;
}
| Check whether a member of some container type can be accessed from another type
| according to its modifiers.
|
| @param container The type containing the member to which access is being checked
| @param targetType The type of the expression from which the member is accessed
| @param accessor The type trying to access the member
| @param modifiers The modifiers of the member
| @param isStatic True if the access is a in static context; false if not
|
| @return true if the access is allowed, false otherwise
|
public static boolean checkMemberAccess(Reflective container, GenTypeSolid targetType,
Reflective accessor, int modifiers, boolean isStatic)
{
if (isStatic && !Modifier.isStatic(modifiers))
return false;
if (Modifier.isPublic(modifiers)) {
return true;
}
if (accessor == null) {
return false;
}
String accessorName = accessor.getName();
if (! Modifier.isPrivate(modifiers)) {
String cpackage = JavaNames.getPrefix(container.getName());
if (accessorName.startsWith(cpackage)
&& accessorName.indexOf('.', cpackage.length() + 1) == -1) {
return true;
}
}
if (accessorName.equals(container.getName())) {
return true;
}
Reflective outer = accessor.getOuterClass();
if (outer != null) {
isStatic |= accessor.isStatic();
if (checkMemberAccess(container, targetType, outer, modifiers, isStatic)) {
return true;
}
}
Set<Reflective> targetSupers = new HashSet<Reflective>();
targetType.erasedSuperTypes(targetSupers);
boolean allowProtected = false;
for (Reflective ref : targetSupers) {
if (accessor.isAssignableFrom(ref)) {
allowProtected = true;
break;
}
}
List<Reflective> supers = accessor.getSuperTypesR();
Set<String> done = new HashSet<String>();
while (! supers.isEmpty()){
Reflective r = supers.remove(0);
if (done.add(r.getName())) {
if (r.getName().equals(container.getName())) {
if (Modifier.isProtected(modifiers)) {
return allowProtected;
}
}
else {
for (Reflective rParent : r.getSuperTypesR()) {
supers.add(rParent);
}
}
}
}
return false;
}
| Make a descriptive signature. This includes the method/constructor name (which may
| be preceded by type parameters), and parameter types or names or types and names.
| (The type is always substituted if the name is missing).
|
| @param name The method/constructor name (including preceding
| type parameters if any)
| @param paramTypes The parameter types
| @param paramNames The parameter names (may be null)
| @param includeTypeNames True if the parameter type should always be included
| @param isVarArgs True if the method is varargs (requires ellipsis insertion)
|
protected static String makeDescription(String name, String[] paramTypes, String[] paramNames, boolean includeTypeNames, boolean isVarArgs)
{
StringBuffer sb = new StringBuffer();
sb.append(name);
sb.append("(");
for (int j = 0; j < paramTypes.length; j++) {
boolean typePrinted = false;
if (isVarArgs && j == paramTypes.length - 1) {
if (includeTypeNames || paramNames == null || paramNames[j] == null) {
sb.append(paramTypes[j].substring(0, paramTypes[j].length() - 2));
sb.append(" ");
}
sb.append("...");
typePrinted = true;
}
else if (includeTypeNames || paramNames == null || paramNames[j] == null) {
sb.append(paramTypes[j]);
typePrinted = true;
}
if (paramNames != null && paramNames[j] != null) {
if (typePrinted)
sb.append(" ");
sb.append(paramNames[j]);
}
if (j < (paramTypes.length - 1))
sb.append(", ");
}
sb.append(")");
return sb.toString();
}
| Convert a javadoc comment to a string with just the comment body, i.e. strip the
| leading asterisks.
|
public static String javadocToString(String javadoc)
{
String eol = System.getProperty("line.separator");
if (javadoc == null || javadoc.length() < 5) {
return null;
}
StringBuffer outbuf = new StringBuffer();
String str = javadoc;
if (javadoc.charAt(0) == '/') {
if (javadoc.charAt(1) == '*') {
if (javadoc.charAt(2) == '*') {
str = javadoc.substring(3, javadoc.length() - 2);
}
else {
str = javadoc.substring(2, javadoc.length() - 2);
}
}
}
int nl = str.indexOf('\n');
int cr = str.indexOf('\r');
int pos = 0;
while (nl != -1 || cr != -1){
int lineEnd = Math.min(nl, cr);
lineEnd = (nl == -1) ? cr : lineEnd;
lineEnd = (cr == -1) ? nl : lineEnd;
String line = str.substring(pos, lineEnd);
line = stripLeadingStars(line);
outbuf.append(line);
outbuf.append(eol);
pos = lineEnd + 1;
if (pos == nl) {
pos++;
}
nl = str.indexOf('\n', pos);
cr = str.indexOf('\r', pos);
}
String line = stripLeadingStars(str.substring(pos)).trim();
if (line.length() > 0) {
outbuf.append(line);
}
return outbuf.toString();
}
public static class Javadoc
{
private final String intro;
private final List<String> blocks;
public Javadoc(String intro, List<String> blocks)
{
this.intro = intro;
this.blocks = blocks;
}
public String getHeader()
{
return intro;
}
public List getBlocks()
{
return blocks;
}
}
public static Javadoc parseJavadoc(String javadocString)
{
if (javadocString == null)
return null;
int i;
for (i = 0; i < javadocString.length(); i++) {
while (i < javadocString.length() && Character.isWhitespace(javadocString.charAt(i))){
i++;
}
if (i >= javadocString.length() || javadocString.charAt(i) == '@') {
break;
}
while (i < javadocString.length()
&& javadocString.charAt(i) != '\n'
&& javadocString.charAt(i) != '\r'){
i++;
}
}
if (i >= javadocString.length()) {
return new Javadoc(javadocString, Collections.emptyList());
}
String header = javadocString.substring(0, i);
String blocksText = javadocString.substring(i);
String[] lines = Utility.splitLines(blocksText);
List<String> blocks = getBlockTags(lines);
return new Javadoc(header, blocks);
}
| Strip leading asterisk characters (and any preceding whitespace) from a single
| line of text.
|
private static String stripLeadingStars(String s)
{
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '*') {
do {
i++;
} while (i < s.length() && s.charAt(i) == '*'){;
s = s.substring(i);
}
break;
}
if (! Character.isWhitespace(s.charAt(i))) {
break;
}
}
return s;
}
| Get a GenType corresponding to the (raw) class c
|
public static JavaType genTypeFromClass(Class<?> c)
{
if (c.isPrimitive()) {
if (c == boolean.class)
return JavaPrimitiveType.getBoolean();
if (c == char.class)
return JavaPrimitiveType.getChar();
if (c == byte.class)
return JavaPrimitiveType.getByte();
if (c == short.class)
return JavaPrimitiveType.getShort();
if (c == int.class)
return JavaPrimitiveType.getInt();
if (c == long.class)
return JavaPrimitiveType.getLong();
if (c == float.class)
return JavaPrimitiveType.getFloat();
if (c == double.class)
return JavaPrimitiveType.getDouble();
if (c == void.class)
return JavaPrimitiveType.getVoid();
Debug.message("getReturnType: Unknown primitive type");
}
if (c.isArray()) {
JavaType componentT = genTypeFromClass(c.getComponentType());
return componentT.getArray();
}
return new GenTypeClass(new JavaReflective(c));
}
private static final Pattern paramNamePattern = Pattern.compile("param\\s+\\w");
private static final Pattern paramDescPattern = Pattern.compile("\\s+\\w");
| Convert javadoc comment body (as extracted by javadocToString for instance)
| to HTML suitable for display by HTMLEditorKit.
|
public static String javadocToHtml(String javadocString)
{
String javadocStringCodeTagged = convertCodeTokens(javadocString);
Javadoc j = parseJavadoc(javadocStringCodeTagged);
StringBuilder rest = new StringBuilder();
StringBuilder params = new StringBuilder();
params.append("<h3>Parameters</h3>").append("<table border=0>");
boolean hasParamDoc = false;
for (String block : j.getBlocks()) {
Matcher matcher = paramNamePattern.matcher(block);
String paramName = "";
String paramDesc = "";
if (matcher.find()) {
int p = matcher.end() - 1;
matcher = paramDescPattern.matcher(block.substring(p));
if (matcher.find()) {
int k = p + matcher.end() - 1;
paramName = block.substring(p, k);
paramDesc = block.substring(k);
}
params.append("<tr><td valign=\"top\"> ");
params.append(makeCommentColour(paramName));
params.append("</td><td>");
params.append(makeCommentColour(" - " + paramDesc));
params.append("</td></tr>");
hasParamDoc = true;
}
else {
String blockTag = convertBlockTag(block);
if (!blockTag.isEmpty())
rest.append(blockTag).append("<br>");
}
}
params.append("</table><p>");
String result = makeCommentColour(j.getHeader()) + (hasParamDoc ? params.toString() : "<p>") + rest.toString();
return result;
}
private static String convertCodeTokens(String rawString)
{
String result = rawString;
int startIndex;
while ((startIndex = result.indexOf("{@code")) != -1){
int insideOpeningBrackets = 0;
int endIndex = -1;
for (int i = startIndex + 6; i < result.length(); i++) {
if (result.charAt(i) == '{') {
insideOpeningBrackets++;
}
else if (result.charAt(i) == '}') {
if (insideOpeningBrackets != 0) {
insideOpeningBrackets--;
}
else {
endIndex = i;
break;
}
}
}
result = result.substring(0, startIndex) + "<code>" + result.substring(startIndex + 6, endIndex) + " </code>" + result.substring(endIndex + 1);
}
return result;
}
private static String makeCommentColour(String text)
{
return "<font color='#994400'>" + text + "</font>";
}
| For a set of text lines representing block tags in a a javadoc comment,
| with some block tags potentially flowing over more than one line, return
| a list of Strings corresponding to each block tag with its complete text.
|
private static List getBlockTags(String[] lines)
{
LinkedList<String> blocks = new LinkedList<>();
StringBuilder cur = new StringBuilder();
for (String line : lines) {
line = line.trim();
if (line.startsWith("@")) {
if (cur.length() > 0) {
blocks.addLast(cur.toString());
}
cur = new StringBuilder(line.substring(1));
}
else {
cur.append(" ").append(line);
}
}
blocks.addLast(cur.toString());
return blocks;
}
private static String convertBlockTag(String block)
{
int spaceIndex = block.indexOf(' ');
if (spaceIndex < 0) {
return "";
}
return "<b>" + block.substring(0, spaceIndex) + "</b> - " + makeCommentColour(block.substring(spaceIndex));
}
public static String escapeAngleBrackets(String sig)
{
return sig.replace("<", "<").replace(">", ">");
}
}
. getJavaUtils
. getSignature
. getSignature
. escapeString
. getShortDesc
. getShortDesc
. getLongDesc
. getLongDesc
. getLongDesc
. isVarArgs
. isVarArgs
. isSynthetic
. isEnum
. getReturnType
. getRawReturnType
. getFieldType
. getRawFieldType
. getTypeParams
. getTypeParams
. getTypeParams
. getSuperclass
. getInterfaces
. getParameterTypes
. getParamGenTypes
. getParameterTypes
. getParamGenTypes
. TParamsToMap
. checkMemberAccess
. makeDescription
. javadocToString
top,
use,
map,
class Javadoc
. Javadoc
. getHeader
. getBlocks
. parseJavadoc
. stripLeadingStars
. genTypeFromClass
. javadocToHtml
. convertCodeTokens
. makeCommentColour
. getBlockTags
. convertBlockTag
. escapeAngleBrackets
758 neLoCode
+ 110 LoComm