michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.annotationProcessors.utils; michael@0: michael@0: import java.lang.annotation.Annotation; michael@0: import java.lang.reflect.Constructor; michael@0: import java.lang.reflect.Field; michael@0: import java.lang.reflect.Member; michael@0: import java.lang.reflect.Method; michael@0: import java.lang.reflect.Modifier; michael@0: import java.util.HashMap; michael@0: michael@0: /** michael@0: * A collection of utility methods used by CodeGenerator. Largely used for translating types. michael@0: */ michael@0: public class Utils { michael@0: michael@0: // A collection of lookup tables to simplify the functions to follow... michael@0: private static final HashMap sBasicCTypes = new HashMap(); michael@0: michael@0: static { michael@0: sBasicCTypes.put("void", "void"); michael@0: sBasicCTypes.put("int", "int32_t"); michael@0: sBasicCTypes.put("boolean", "bool"); michael@0: sBasicCTypes.put("long", "int64_t"); michael@0: sBasicCTypes.put("double", "jdouble"); michael@0: sBasicCTypes.put("float", "jfloat"); michael@0: sBasicCTypes.put("char", "uint16_t"); michael@0: sBasicCTypes.put("byte", "int8_t"); michael@0: sBasicCTypes.put("short", "int16_t"); michael@0: } michael@0: michael@0: private static final HashMap sArrayCTypes = new HashMap(); michael@0: michael@0: static { michael@0: sArrayCTypes.put("int", "jintArray"); michael@0: sArrayCTypes.put("boolean", "jbooleanArray"); michael@0: sArrayCTypes.put("long", "jlongArray"); michael@0: sArrayCTypes.put("double", "jdoubleArray"); michael@0: sArrayCTypes.put("float", "jfloatArray"); michael@0: sArrayCTypes.put("char", "jcharArray"); michael@0: sArrayCTypes.put("byte", "jbyteArray"); michael@0: sArrayCTypes.put("short", "jshortArray"); michael@0: } michael@0: michael@0: private static final HashMap sStaticCallTypes = new HashMap(); michael@0: michael@0: static { michael@0: sStaticCallTypes.put("void", "CallStaticVoidMethod"); michael@0: sStaticCallTypes.put("int", "CallStaticIntMethod"); michael@0: sStaticCallTypes.put("boolean", "CallStaticBooleanMethod"); michael@0: sStaticCallTypes.put("long", "CallStaticLongMethod"); michael@0: sStaticCallTypes.put("double", "CallStaticDoubleMethod"); michael@0: sStaticCallTypes.put("float", "CallStaticFloatMethod"); michael@0: sStaticCallTypes.put("char", "CallStaticCharMethod"); michael@0: sStaticCallTypes.put("byte", "CallStaticByteMethod"); michael@0: sStaticCallTypes.put("short", "CallStaticShortMethod"); michael@0: } michael@0: michael@0: private static final HashMap sInstanceCallTypes = new HashMap(); michael@0: michael@0: static { michael@0: sInstanceCallTypes.put("void", "CallVoidMethod"); michael@0: sInstanceCallTypes.put("int", "CallIntMethod"); michael@0: sInstanceCallTypes.put("boolean", "CallBooleanMethod"); michael@0: sInstanceCallTypes.put("long", "CallLongMethod"); michael@0: sInstanceCallTypes.put("double", "CallDoubleMethod"); michael@0: sInstanceCallTypes.put("float", "CallFloatMethod"); michael@0: sInstanceCallTypes.put("char", "CallCharMethod"); michael@0: sInstanceCallTypes.put("byte", "CallByteMethod"); michael@0: sInstanceCallTypes.put("short", "CallShortMethod"); michael@0: } michael@0: michael@0: private static final HashMap sFieldTypes = new HashMap(); michael@0: michael@0: static { michael@0: sFieldTypes.put("int", "Int"); michael@0: sFieldTypes.put("boolean", "Boolean"); michael@0: sFieldTypes.put("long", "Long"); michael@0: sFieldTypes.put("double", "Double"); michael@0: sFieldTypes.put("float", "Float"); michael@0: sFieldTypes.put("char", "Char"); michael@0: sFieldTypes.put("byte", "Byte"); michael@0: sFieldTypes.put("short", "Short"); michael@0: } michael@0: michael@0: private static final HashMap sFailureReturns = new HashMap(); michael@0: michael@0: static { michael@0: sFailureReturns.put("java.lang.Void", ""); michael@0: sFailureReturns.put("void", ""); michael@0: sFailureReturns.put("int", " 0"); michael@0: sFailureReturns.put("boolean", " false"); michael@0: sFailureReturns.put("long", " 0"); michael@0: sFailureReturns.put("double", " 0.0"); michael@0: sFailureReturns.put("float", " 0.0"); michael@0: sFailureReturns.put("char", " 0"); michael@0: sFailureReturns.put("byte", " 0"); michael@0: sFailureReturns.put("short", " 0"); michael@0: } michael@0: michael@0: private static final HashMap sCanonicalSignatureParts = new HashMap(); michael@0: michael@0: static { michael@0: sCanonicalSignatureParts.put("java/lang/Void", "V"); michael@0: sCanonicalSignatureParts.put("void", "V"); michael@0: sCanonicalSignatureParts.put("int", "I"); michael@0: sCanonicalSignatureParts.put("boolean", "Z"); michael@0: sCanonicalSignatureParts.put("long", "J"); michael@0: sCanonicalSignatureParts.put("double", "D"); michael@0: sCanonicalSignatureParts.put("float", "F"); michael@0: sCanonicalSignatureParts.put("char", "C"); michael@0: sCanonicalSignatureParts.put("byte", "B"); michael@0: sCanonicalSignatureParts.put("short", "S"); michael@0: } michael@0: michael@0: michael@0: private static final HashMap sDefaultParameterValues = new HashMap(); michael@0: michael@0: static { michael@0: sDefaultParameterValues.put("int", "0"); michael@0: sDefaultParameterValues.put("boolean", "false"); michael@0: sDefaultParameterValues.put("long", "0"); michael@0: sDefaultParameterValues.put("double", "0"); michael@0: sDefaultParameterValues.put("float", "0.0"); michael@0: sDefaultParameterValues.put("char", "0"); michael@0: sDefaultParameterValues.put("byte", "0"); michael@0: sDefaultParameterValues.put("short", "0"); michael@0: } michael@0: michael@0: /** michael@0: * Get the C type corresponding to the provided type parameter. Used for generating argument michael@0: * types for the wrapper method. michael@0: * michael@0: * @param type Class to determine the corresponding JNI type for. michael@0: * @return true if the type an object type, false otherwise. michael@0: */ michael@0: public static String getCParameterType(Class type) { michael@0: String name = type.getCanonicalName(); michael@0: if (sBasicCTypes.containsKey(name)) { michael@0: return sBasicCTypes.get(name); michael@0: } michael@0: // Are we dealing with an array type? michael@0: int len = name.length(); michael@0: if (name.endsWith("[]")) { michael@0: // Determine if it is a 2D array - these map to jobjectArrays michael@0: name = name.substring(0, len - 2); michael@0: if (name.endsWith("[]")) { michael@0: return "jobjectArray"; michael@0: } else { michael@0: // Which flavour of Array is it? michael@0: if (sArrayCTypes.containsKey(name)) { michael@0: return sArrayCTypes.get(name); michael@0: } michael@0: return "jobjectArray"; michael@0: } michael@0: } michael@0: // Not an array type, check the remaining possibilities before we fall back to jobject michael@0: michael@0: // Check for CharSequences (Strings and things that are string-like) michael@0: if (isCharSequence(type)) { michael@0: return "const nsAString&"; michael@0: } michael@0: michael@0: if (name.equals("java.lang.Class")) { michael@0: // You're doing reflection on Java objects from inside C, returning Class objects michael@0: // to C, generating the corresponding code using this Java program. Really?! michael@0: return "jclass"; michael@0: } michael@0: if (name.equals("java.lang.Throwable")) { michael@0: return "jthrowable"; michael@0: } michael@0: return "jobject"; michael@0: } michael@0: michael@0: /** michael@0: * For a given Java type, get the corresponding C++ type if we're returning it from a function. michael@0: * michael@0: * @param type The Java return type. michael@0: * @return A string representation of the C++ return type. michael@0: */ michael@0: public static String getCReturnType(Class type) { michael@0: if (type.getCanonicalName().equals("java.lang.Void")) { michael@0: return "void"; michael@0: } michael@0: String cParameterType = getCParameterType(type); michael@0: if (cParameterType.equals("const nsAString&")) { michael@0: return "jstring"; michael@0: } else { michael@0: return cParameterType; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Gets the type-specific part of the JNI function to use to get or set a field of a given type. michael@0: * michael@0: * @param aFieldType The Java type of the field. michael@0: * @return A string representation of the JNI call function substring to use. michael@0: */ michael@0: public static String getFieldType(Class aFieldType) { michael@0: String name = aFieldType.getCanonicalName(); michael@0: michael@0: if (sFieldTypes.containsKey(name)) { michael@0: return sFieldTypes.get(name); michael@0: } michael@0: return "Object"; michael@0: } michael@0: michael@0: /** michael@0: * Gets the appropriate JNI call function to use to invoke a Java method with the given return michael@0: * type. This, plus a call postfix (Such as "A") forms a complete JNI call function name. michael@0: * michael@0: * @param aReturnType The Java return type of the method being generated. michael@0: * @param isStatic Boolean indicating if the underlying Java method is declared static. michael@0: * @return A string representation of the JNI call function prefix to use. michael@0: */ michael@0: public static String getCallPrefix(Class aReturnType, boolean isStatic) { michael@0: String name = aReturnType.getCanonicalName(); michael@0: if (isStatic) { michael@0: if (sStaticCallTypes.containsKey(name)) { michael@0: return sStaticCallTypes.get(name); michael@0: } michael@0: return "CallStaticObjectMethod"; michael@0: } else { michael@0: if (sInstanceCallTypes.containsKey(name)) { michael@0: return sInstanceCallTypes.get(name); michael@0: } michael@0: return "CallObjectMethod"; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * On failure, the generated method returns a null-esque value. This helper method gets the michael@0: * appropriate failure return value for a given Java return type, plus a leading space. michael@0: * michael@0: * @param type Java return type of method being generated michael@0: * @return String representation of the failure return value to be used in the generated code. michael@0: */ michael@0: public static String getFailureReturnForType(Class type) { michael@0: String name = type.getCanonicalName(); michael@0: if (sFailureReturns.containsKey(name)) { michael@0: return sFailureReturns.get(name); michael@0: } michael@0: return " nullptr"; michael@0: } michael@0: michael@0: /** michael@0: * Helper method to get the type signature for methods, given argument and return type. michael@0: * Allows for the near-identical logic needed for constructors and methods to be shared. michael@0: * (Alas, constructor does not extend method) michael@0: * michael@0: * @param arguments Argument types of the underlying method. michael@0: * @param returnType Return type of the underlying method. michael@0: * @return The canonical Java type string for the method. eg. (IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform; michael@0: */ michael@0: private static String getTypeSignatureInternal(Class[] arguments, Class returnType) { michael@0: StringBuilder sb = new StringBuilder(); michael@0: sb.append('('); michael@0: michael@0: // For each argument, write its signature component to the buffer.. michael@0: for (int i = 0; i < arguments.length; i++) { michael@0: writeTypeSignature(sb, arguments[i]); michael@0: } michael@0: sb.append(')'); michael@0: michael@0: // Write the return value's signature.. michael@0: writeTypeSignature(sb, returnType); michael@0: return sb.toString(); michael@0: } michael@0: michael@0: /** michael@0: * Get the canonical JNI type signature for a Field. michael@0: * michael@0: * @param aField The field to generate a signature for. michael@0: * @return The canonical JNI type signature for this method. michael@0: */ michael@0: protected static String getTypeSignatureStringForField(Field aField) { michael@0: StringBuilder sb = new StringBuilder(); michael@0: writeTypeSignature(sb, aField.getType()); michael@0: return sb.toString(); michael@0: } michael@0: michael@0: /** michael@0: * Get the canonical JNI type signature for a method. michael@0: * michael@0: * @param aMethod The method to generate a signature for. michael@0: * @return The canonical JNI type signature for this method. michael@0: */ michael@0: protected static String getTypeSignatureStringForMethod(Method aMethod) { michael@0: Class[] arguments = aMethod.getParameterTypes(); michael@0: Class returnType = aMethod.getReturnType(); michael@0: return getTypeSignatureInternal(arguments, returnType); michael@0: } michael@0: michael@0: /** michael@0: * Get the canonical JNI type signature for a Constructor. michael@0: * michael@0: * @param aConstructor The Constructor to generate a signature for. michael@0: * @return The canonical JNI type signature for this method. michael@0: */ michael@0: protected static String getTypeSignatureStringForConstructor(Constructor aConstructor) { michael@0: Class[] arguments = aConstructor.getParameterTypes(); michael@0: return getTypeSignatureInternal(arguments, Void.class); michael@0: } michael@0: michael@0: public static String getTypeSignatureStringForMember(Member aMember) { michael@0: if (aMember instanceof Method) { michael@0: return getTypeSignatureStringForMethod((Method) aMember); michael@0: } else if (aMember instanceof Field) { michael@0: return getTypeSignatureStringForField((Field) aMember); michael@0: } else { michael@0: return getTypeSignatureStringForConstructor((Constructor) aMember); michael@0: } michael@0: } michael@0: michael@0: public static String getTypeSignatureString(Constructor aConstructor) { michael@0: Class[] arguments = aConstructor.getParameterTypes(); michael@0: StringBuilder sb = new StringBuilder(); michael@0: sb.append('('); michael@0: michael@0: // For each argument, write its signature component to the buffer.. michael@0: for (int i = 0; i < arguments.length; i++) { michael@0: writeTypeSignature(sb, arguments[i]); michael@0: } michael@0: michael@0: // Constructors always return Void. michael@0: sb.append(")V"); michael@0: return sb.toString(); michael@0: } michael@0: michael@0: /** michael@0: * Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature michael@0: * of a given type into the buffer. michael@0: * michael@0: * @param sb The buffer to write into. michael@0: * @param c The type of the element to write the subsignature of. michael@0: */ michael@0: private static void writeTypeSignature(StringBuilder sb, Class c) { michael@0: String name = c.getCanonicalName().replaceAll("\\.", "/"); michael@0: michael@0: // Determine if this is an array type and, if so, peel away the array operators.. michael@0: int len = name.length(); michael@0: while (name.endsWith("[]")) { michael@0: sb.append('['); michael@0: name = name.substring(0, len - 2); michael@0: len = len - 2; michael@0: } michael@0: michael@0: if (c.isArray()) { michael@0: c = c.getComponentType(); michael@0: } michael@0: michael@0: Class containerClass = c.getDeclaringClass(); michael@0: if (containerClass != null) { michael@0: // Is an inner class. Add the $ symbol. michael@0: final int lastSlash = name.lastIndexOf('/'); michael@0: name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1); michael@0: } michael@0: michael@0: // Look in the hashmap for the remainder... michael@0: if (sCanonicalSignatureParts.containsKey(name)) { michael@0: // It was a primitive type, so lookup was a success. michael@0: sb.append(sCanonicalSignatureParts.get(name)); michael@0: } else { michael@0: // It was a reference type - generate. michael@0: sb.append('L'); michael@0: sb.append(name); michael@0: sb.append(';'); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both michael@0: * generating header files and method bodies. michael@0: * michael@0: * @param aArgumentTypes Argument types of the Java method being wrapped. michael@0: * @param aReturnType Return type of the Java method being wrapped. michael@0: * @param aCMethodName Name of the method to generate in the C++ class. michael@0: * @param aCClassName Name of the C++ class into which the method is declared. michael@0: * @return The C++ method implementation signature for the method described. michael@0: */ michael@0: public static String getCImplementationMethodSignature(Class[] aArgumentTypes, Class aReturnType, String aCMethodName, String aCClassName) { michael@0: StringBuilder retBuffer = new StringBuilder(); michael@0: michael@0: retBuffer.append(getCReturnType(aReturnType)); michael@0: retBuffer.append(' '); michael@0: retBuffer.append(aCClassName); michael@0: retBuffer.append("::"); michael@0: retBuffer.append(aCMethodName); michael@0: retBuffer.append('('); michael@0: michael@0: // Write argument types... michael@0: for (int aT = 0; aT < aArgumentTypes.length; aT++) { michael@0: retBuffer.append(getCParameterType(aArgumentTypes[aT])); michael@0: retBuffer.append(" a"); michael@0: // We, imaginatively, call our arguments a1, a2, a3... michael@0: // The only way to preserve the names from Java would be to parse the michael@0: // Java source, which would be computationally hard. michael@0: retBuffer.append(aT); michael@0: if (aT != aArgumentTypes.length - 1) { michael@0: retBuffer.append(", "); michael@0: } michael@0: } michael@0: retBuffer.append(')'); michael@0: return retBuffer.toString(); michael@0: } michael@0: michael@0: /** michael@0: * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both michael@0: * generating header files and method bodies. michael@0: * michael@0: * @param aArgumentTypes Argument types of the Java method being wrapped. michael@0: * @param aArgumentAnnotations The annotations on the Java method arguments. Used to specify michael@0: * default values etc. michael@0: * @param aReturnType Return type of the Java method being wrapped. michael@0: * @param aCMethodName Name of the method to generate in the C++ class. michael@0: * @param aCClassName Name of the C++ class into which the method is declared.e michael@0: * @param aIsStaticStub true if the generated C++ method should be static, false otherwise. michael@0: * @return The generated C++ header method signature for the method described. michael@0: */ michael@0: public static String getCHeaderMethodSignature(Class[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub) { michael@0: StringBuilder retBuffer = new StringBuilder(); michael@0: michael@0: // Add the static keyword, if applicable. michael@0: if (aIsStaticStub) { michael@0: retBuffer.append("static "); michael@0: } michael@0: michael@0: // Write return type.. michael@0: retBuffer.append(getCReturnType(aReturnType)); michael@0: retBuffer.append(' '); michael@0: retBuffer.append(aCMethodName); michael@0: retBuffer.append('('); michael@0: michael@0: // Write argument types... michael@0: for (int aT = 0; aT < aArgumentTypes.length; aT++) { michael@0: retBuffer.append(getCParameterType(aArgumentTypes[aT])); michael@0: retBuffer.append(" a"); michael@0: // We, imaginatively, call our arguments a1, a2, a3... michael@0: // The only way to preserve the names from Java would be to parse the michael@0: // Java source, which would be computationally hard. michael@0: retBuffer.append(aT); michael@0: michael@0: // Append the default value, if there is one.. michael@0: retBuffer.append(getDefaultValueString(aArgumentTypes[aT], aArgumentAnnotations[aT])); michael@0: michael@0: if (aT != aArgumentTypes.length - 1) { michael@0: retBuffer.append(", "); michael@0: } michael@0: } michael@0: retBuffer.append(')'); michael@0: return retBuffer.toString(); michael@0: } michael@0: michael@0: /** michael@0: * If the given Annotation[] contains an OptionalGeneratedParameter annotation then return a michael@0: * string assigning an argument of type aArgumentType to the default value for that type. michael@0: * Otherwise, return the empty string. michael@0: * michael@0: * @param aArgumentType The type of the argument to consider. michael@0: * @param aArgumentAnnotations The annotations on the argument to consider. michael@0: * @return An appropriate string to append to the signature of this argument assigning it to a michael@0: * default value (Or not, as applicable). michael@0: */ michael@0: public static String getDefaultValueString(Class aArgumentType, Annotation[] aArgumentAnnotations) { michael@0: for (int i = 0; i < aArgumentAnnotations.length; i++) { michael@0: Class annotationType = aArgumentAnnotations[i].annotationType(); michael@0: final String annotationTypeName = annotationType.getName(); michael@0: if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter")) { michael@0: return " = " + getDefaultParameterValueForType(aArgumentType); michael@0: } michael@0: } michael@0: return ""; michael@0: } michael@0: michael@0: /** michael@0: * Helper method to return an appropriate default parameter value for an argument of a given type. michael@0: * The lookup table contains values for primitive types and strings. All other object types default michael@0: * to null pointers. michael@0: * michael@0: * @param aArgumentType The parameter type for which a default value is desired. michael@0: * @return An appropriate string representation of the default value selected, for use in generated michael@0: * C++ code. michael@0: */ michael@0: private static String getDefaultParameterValueForType(Class aArgumentType) { michael@0: String typeName = aArgumentType.getCanonicalName(); michael@0: if (sDefaultParameterValues.containsKey(typeName)) { michael@0: return sDefaultParameterValues.get(typeName); michael@0: } else if (isCharSequence(aArgumentType)) { michael@0: return "EmptyString()"; michael@0: } else { michael@0: return "nullptr"; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Helper method that returns the number of reference types in the arguments of m. michael@0: * michael@0: * @param aArgs The method arguments to consider. michael@0: * @return How many of the arguments of m are nonprimitive. michael@0: */ michael@0: public static int enumerateReferenceArguments(Class[] aArgs) { michael@0: int ret = 0; michael@0: for (int i = 0; i < aArgs.length; i++) { michael@0: String name = aArgs[i].getCanonicalName(); michael@0: if (!sBasicCTypes.containsKey(name)) { michael@0: ret++; michael@0: } michael@0: } michael@0: return ret; michael@0: } michael@0: michael@0: /** michael@0: * Helper method that returns true iff the given method has a string argument. michael@0: * michael@0: * @param m The method to consider. michael@0: * @return True if the given method has a string argument, false otherwise. michael@0: */ michael@0: public static boolean hasStringArgument(Method m) { michael@0: Class[] args = m.getParameterTypes(); michael@0: for (int i = 0; i < args.length; i++) { michael@0: if (isCharSequence(args[i])) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: /** michael@0: * Write the argument array assignment line for the given argument type. Does not support array michael@0: * types. michael@0: * michael@0: * @param type Type of this argument according to the target Java method's signature. michael@0: * @param argName Wrapper function argument name corresponding to this argument. michael@0: */ michael@0: public static String getArrayArgumentMashallingLine(Class type, String argName) { michael@0: StringBuilder sb = new StringBuilder(); michael@0: michael@0: String name = type.getCanonicalName(); michael@0: if (sCanonicalSignatureParts.containsKey(name)) { michael@0: sb.append(sCanonicalSignatureParts.get(name).toLowerCase()); michael@0: sb.append(" = ").append(argName).append(";\n"); michael@0: } else { michael@0: if (isCharSequence(type)) { michael@0: sb.append("l = AndroidBridge::NewJavaString(env, ").append(argName).append(");\n"); michael@0: } else { michael@0: sb.append("l = ").append(argName).append(";\n"); michael@0: } michael@0: } michael@0: michael@0: return sb.toString(); michael@0: } michael@0: michael@0: /** michael@0: * Returns true if the type provided is an object type. Returns false otherwise michael@0: * michael@0: * @param aType The type to consider. michael@0: * @return true if the method provided is an object type, false otherwise. michael@0: */ michael@0: public static boolean isObjectType(Class aType) { michael@0: return !sBasicCTypes.containsKey(aType.getCanonicalName()); michael@0: } michael@0: michael@0: /** michael@0: * For a given Java class, get the name of the value in C++ which holds a reference to it. michael@0: * michael@0: * @param aClass Target Java class. michael@0: * @return The name of the C++ jclass entity referencing the given class. michael@0: */ michael@0: public static String getClassReferenceName(Class aClass) { michael@0: String className = aClass.getSimpleName(); michael@0: return 'm' + className + "Class"; michael@0: } michael@0: michael@0: /** michael@0: * Generate a line to get a global reference to the Java class given. michael@0: * michael@0: * @param aClass The target Java class. michael@0: * @return The generated code to populate the reference to the class. michael@0: */ michael@0: public static String getStartupLineForClass(Class aClass) { michael@0: StringBuilder sb = new StringBuilder(); michael@0: sb.append(" "); michael@0: sb.append(getClassReferenceName(aClass)); michael@0: sb.append(" = getClassGlobalRef(\""); michael@0: michael@0: String name = aClass.getCanonicalName().replaceAll("\\.", "/"); michael@0: Class containerClass = aClass.getDeclaringClass(); michael@0: if (containerClass != null) { michael@0: // Is an inner class. Add the $ symbol. michael@0: final int lastSlash = name.lastIndexOf('/'); michael@0: name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1); michael@0: } michael@0: michael@0: sb.append(name); michael@0: sb.append("\");\n"); michael@0: return sb.toString(); michael@0: } michael@0: michael@0: /** michael@0: * Helper method to determine if this object implements CharSequence michael@0: * @param aClass Class to check for CharSequence-esqueness michael@0: * @return True if the given class implements CharSequence, false otherwise. michael@0: */ michael@0: public static boolean isCharSequence(Class aClass) { michael@0: if (aClass.getCanonicalName().equals("java.lang.CharSequence")) { michael@0: return true; michael@0: } michael@0: Class[] interfaces = aClass.getInterfaces(); michael@0: for (Class c : interfaces) { michael@0: if (c.getCanonicalName().equals("java.lang.CharSequence")) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: /** michael@0: * Helper method to read the modifier bits of the given method to determine if it is static. michael@0: * @param aMember The Member to check. michael@0: * @return true of the method is declared static, false otherwise. michael@0: */ michael@0: public static boolean isMemberStatic(Member aMember) { michael@0: int aMethodModifiers = aMember.getModifiers(); michael@0: return Modifier.isStatic(aMethodModifiers); michael@0: } michael@0: michael@0: /** michael@0: * Helper method to read the modifier bits of the given method to determine if it is static. michael@0: * @param aMember The Member to check. michael@0: * @return true of the method is declared static, false otherwise. michael@0: */ michael@0: public static boolean isMemberFinal(Member aMember) { michael@0: int aMethodModifiers = aMember.getModifiers(); michael@0: return Modifier.isFinal(aMethodModifiers); michael@0: } michael@0: }