1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/build/annotationProcessors/utils/Utils.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,639 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.annotationProcessors.utils; 1.9 + 1.10 +import java.lang.annotation.Annotation; 1.11 +import java.lang.reflect.Constructor; 1.12 +import java.lang.reflect.Field; 1.13 +import java.lang.reflect.Member; 1.14 +import java.lang.reflect.Method; 1.15 +import java.lang.reflect.Modifier; 1.16 +import java.util.HashMap; 1.17 + 1.18 +/** 1.19 + * A collection of utility methods used by CodeGenerator. Largely used for translating types. 1.20 + */ 1.21 +public class Utils { 1.22 + 1.23 + // A collection of lookup tables to simplify the functions to follow... 1.24 + private static final HashMap<String, String> sBasicCTypes = new HashMap<String, String>(); 1.25 + 1.26 + static { 1.27 + sBasicCTypes.put("void", "void"); 1.28 + sBasicCTypes.put("int", "int32_t"); 1.29 + sBasicCTypes.put("boolean", "bool"); 1.30 + sBasicCTypes.put("long", "int64_t"); 1.31 + sBasicCTypes.put("double", "jdouble"); 1.32 + sBasicCTypes.put("float", "jfloat"); 1.33 + sBasicCTypes.put("char", "uint16_t"); 1.34 + sBasicCTypes.put("byte", "int8_t"); 1.35 + sBasicCTypes.put("short", "int16_t"); 1.36 + } 1.37 + 1.38 + private static final HashMap<String, String> sArrayCTypes = new HashMap<String, String>(); 1.39 + 1.40 + static { 1.41 + sArrayCTypes.put("int", "jintArray"); 1.42 + sArrayCTypes.put("boolean", "jbooleanArray"); 1.43 + sArrayCTypes.put("long", "jlongArray"); 1.44 + sArrayCTypes.put("double", "jdoubleArray"); 1.45 + sArrayCTypes.put("float", "jfloatArray"); 1.46 + sArrayCTypes.put("char", "jcharArray"); 1.47 + sArrayCTypes.put("byte", "jbyteArray"); 1.48 + sArrayCTypes.put("short", "jshortArray"); 1.49 + } 1.50 + 1.51 + private static final HashMap<String, String> sStaticCallTypes = new HashMap<String, String>(); 1.52 + 1.53 + static { 1.54 + sStaticCallTypes.put("void", "CallStaticVoidMethod"); 1.55 + sStaticCallTypes.put("int", "CallStaticIntMethod"); 1.56 + sStaticCallTypes.put("boolean", "CallStaticBooleanMethod"); 1.57 + sStaticCallTypes.put("long", "CallStaticLongMethod"); 1.58 + sStaticCallTypes.put("double", "CallStaticDoubleMethod"); 1.59 + sStaticCallTypes.put("float", "CallStaticFloatMethod"); 1.60 + sStaticCallTypes.put("char", "CallStaticCharMethod"); 1.61 + sStaticCallTypes.put("byte", "CallStaticByteMethod"); 1.62 + sStaticCallTypes.put("short", "CallStaticShortMethod"); 1.63 + } 1.64 + 1.65 + private static final HashMap<String, String> sInstanceCallTypes = new HashMap<String, String>(); 1.66 + 1.67 + static { 1.68 + sInstanceCallTypes.put("void", "CallVoidMethod"); 1.69 + sInstanceCallTypes.put("int", "CallIntMethod"); 1.70 + sInstanceCallTypes.put("boolean", "CallBooleanMethod"); 1.71 + sInstanceCallTypes.put("long", "CallLongMethod"); 1.72 + sInstanceCallTypes.put("double", "CallDoubleMethod"); 1.73 + sInstanceCallTypes.put("float", "CallFloatMethod"); 1.74 + sInstanceCallTypes.put("char", "CallCharMethod"); 1.75 + sInstanceCallTypes.put("byte", "CallByteMethod"); 1.76 + sInstanceCallTypes.put("short", "CallShortMethod"); 1.77 + } 1.78 + 1.79 + private static final HashMap<String, String> sFieldTypes = new HashMap<String, String>(); 1.80 + 1.81 + static { 1.82 + sFieldTypes.put("int", "Int"); 1.83 + sFieldTypes.put("boolean", "Boolean"); 1.84 + sFieldTypes.put("long", "Long"); 1.85 + sFieldTypes.put("double", "Double"); 1.86 + sFieldTypes.put("float", "Float"); 1.87 + sFieldTypes.put("char", "Char"); 1.88 + sFieldTypes.put("byte", "Byte"); 1.89 + sFieldTypes.put("short", "Short"); 1.90 + } 1.91 + 1.92 + private static final HashMap<String, String> sFailureReturns = new HashMap<String, String>(); 1.93 + 1.94 + static { 1.95 + sFailureReturns.put("java.lang.Void", ""); 1.96 + sFailureReturns.put("void", ""); 1.97 + sFailureReturns.put("int", " 0"); 1.98 + sFailureReturns.put("boolean", " false"); 1.99 + sFailureReturns.put("long", " 0"); 1.100 + sFailureReturns.put("double", " 0.0"); 1.101 + sFailureReturns.put("float", " 0.0"); 1.102 + sFailureReturns.put("char", " 0"); 1.103 + sFailureReturns.put("byte", " 0"); 1.104 + sFailureReturns.put("short", " 0"); 1.105 + } 1.106 + 1.107 + private static final HashMap<String, String> sCanonicalSignatureParts = new HashMap<String, String>(); 1.108 + 1.109 + static { 1.110 + sCanonicalSignatureParts.put("java/lang/Void", "V"); 1.111 + sCanonicalSignatureParts.put("void", "V"); 1.112 + sCanonicalSignatureParts.put("int", "I"); 1.113 + sCanonicalSignatureParts.put("boolean", "Z"); 1.114 + sCanonicalSignatureParts.put("long", "J"); 1.115 + sCanonicalSignatureParts.put("double", "D"); 1.116 + sCanonicalSignatureParts.put("float", "F"); 1.117 + sCanonicalSignatureParts.put("char", "C"); 1.118 + sCanonicalSignatureParts.put("byte", "B"); 1.119 + sCanonicalSignatureParts.put("short", "S"); 1.120 + } 1.121 + 1.122 + 1.123 + private static final HashMap<String, String> sDefaultParameterValues = new HashMap<String, String>(); 1.124 + 1.125 + static { 1.126 + sDefaultParameterValues.put("int", "0"); 1.127 + sDefaultParameterValues.put("boolean", "false"); 1.128 + sDefaultParameterValues.put("long", "0"); 1.129 + sDefaultParameterValues.put("double", "0"); 1.130 + sDefaultParameterValues.put("float", "0.0"); 1.131 + sDefaultParameterValues.put("char", "0"); 1.132 + sDefaultParameterValues.put("byte", "0"); 1.133 + sDefaultParameterValues.put("short", "0"); 1.134 + } 1.135 + 1.136 + /** 1.137 + * Get the C type corresponding to the provided type parameter. Used for generating argument 1.138 + * types for the wrapper method. 1.139 + * 1.140 + * @param type Class to determine the corresponding JNI type for. 1.141 + * @return true if the type an object type, false otherwise. 1.142 + */ 1.143 + public static String getCParameterType(Class<?> type) { 1.144 + String name = type.getCanonicalName(); 1.145 + if (sBasicCTypes.containsKey(name)) { 1.146 + return sBasicCTypes.get(name); 1.147 + } 1.148 + // Are we dealing with an array type? 1.149 + int len = name.length(); 1.150 + if (name.endsWith("[]")) { 1.151 + // Determine if it is a 2D array - these map to jobjectArrays 1.152 + name = name.substring(0, len - 2); 1.153 + if (name.endsWith("[]")) { 1.154 + return "jobjectArray"; 1.155 + } else { 1.156 + // Which flavour of Array is it? 1.157 + if (sArrayCTypes.containsKey(name)) { 1.158 + return sArrayCTypes.get(name); 1.159 + } 1.160 + return "jobjectArray"; 1.161 + } 1.162 + } 1.163 + // Not an array type, check the remaining possibilities before we fall back to jobject 1.164 + 1.165 + // Check for CharSequences (Strings and things that are string-like) 1.166 + if (isCharSequence(type)) { 1.167 + return "const nsAString&"; 1.168 + } 1.169 + 1.170 + if (name.equals("java.lang.Class")) { 1.171 + // You're doing reflection on Java objects from inside C, returning Class objects 1.172 + // to C, generating the corresponding code using this Java program. Really?! 1.173 + return "jclass"; 1.174 + } 1.175 + if (name.equals("java.lang.Throwable")) { 1.176 + return "jthrowable"; 1.177 + } 1.178 + return "jobject"; 1.179 + } 1.180 + 1.181 + /** 1.182 + * For a given Java type, get the corresponding C++ type if we're returning it from a function. 1.183 + * 1.184 + * @param type The Java return type. 1.185 + * @return A string representation of the C++ return type. 1.186 + */ 1.187 + public static String getCReturnType(Class<?> type) { 1.188 + if (type.getCanonicalName().equals("java.lang.Void")) { 1.189 + return "void"; 1.190 + } 1.191 + String cParameterType = getCParameterType(type); 1.192 + if (cParameterType.equals("const nsAString&")) { 1.193 + return "jstring"; 1.194 + } else { 1.195 + return cParameterType; 1.196 + } 1.197 + } 1.198 + 1.199 + /** 1.200 + * Gets the type-specific part of the JNI function to use to get or set a field of a given type. 1.201 + * 1.202 + * @param aFieldType The Java type of the field. 1.203 + * @return A string representation of the JNI call function substring to use. 1.204 + */ 1.205 + public static String getFieldType(Class<?> aFieldType) { 1.206 + String name = aFieldType.getCanonicalName(); 1.207 + 1.208 + if (sFieldTypes.containsKey(name)) { 1.209 + return sFieldTypes.get(name); 1.210 + } 1.211 + return "Object"; 1.212 + } 1.213 + 1.214 + /** 1.215 + * Gets the appropriate JNI call function to use to invoke a Java method with the given return 1.216 + * type. This, plus a call postfix (Such as "A") forms a complete JNI call function name. 1.217 + * 1.218 + * @param aReturnType The Java return type of the method being generated. 1.219 + * @param isStatic Boolean indicating if the underlying Java method is declared static. 1.220 + * @return A string representation of the JNI call function prefix to use. 1.221 + */ 1.222 + public static String getCallPrefix(Class<?> aReturnType, boolean isStatic) { 1.223 + String name = aReturnType.getCanonicalName(); 1.224 + if (isStatic) { 1.225 + if (sStaticCallTypes.containsKey(name)) { 1.226 + return sStaticCallTypes.get(name); 1.227 + } 1.228 + return "CallStaticObjectMethod"; 1.229 + } else { 1.230 + if (sInstanceCallTypes.containsKey(name)) { 1.231 + return sInstanceCallTypes.get(name); 1.232 + } 1.233 + return "CallObjectMethod"; 1.234 + } 1.235 + } 1.236 + 1.237 + /** 1.238 + * On failure, the generated method returns a null-esque value. This helper method gets the 1.239 + * appropriate failure return value for a given Java return type, plus a leading space. 1.240 + * 1.241 + * @param type Java return type of method being generated 1.242 + * @return String representation of the failure return value to be used in the generated code. 1.243 + */ 1.244 + public static String getFailureReturnForType(Class<?> type) { 1.245 + String name = type.getCanonicalName(); 1.246 + if (sFailureReturns.containsKey(name)) { 1.247 + return sFailureReturns.get(name); 1.248 + } 1.249 + return " nullptr"; 1.250 + } 1.251 + 1.252 + /** 1.253 + * Helper method to get the type signature for methods, given argument and return type. 1.254 + * Allows for the near-identical logic needed for constructors and methods to be shared. 1.255 + * (Alas, constructor does not extend method) 1.256 + * 1.257 + * @param arguments Argument types of the underlying method. 1.258 + * @param returnType Return type of the underlying method. 1.259 + * @return The canonical Java type string for the method. eg. (IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform; 1.260 + */ 1.261 + private static String getTypeSignatureInternal(Class<?>[] arguments, Class<?> returnType) { 1.262 + StringBuilder sb = new StringBuilder(); 1.263 + sb.append('('); 1.264 + 1.265 + // For each argument, write its signature component to the buffer.. 1.266 + for (int i = 0; i < arguments.length; i++) { 1.267 + writeTypeSignature(sb, arguments[i]); 1.268 + } 1.269 + sb.append(')'); 1.270 + 1.271 + // Write the return value's signature.. 1.272 + writeTypeSignature(sb, returnType); 1.273 + return sb.toString(); 1.274 + } 1.275 + 1.276 + /** 1.277 + * Get the canonical JNI type signature for a Field. 1.278 + * 1.279 + * @param aField The field to generate a signature for. 1.280 + * @return The canonical JNI type signature for this method. 1.281 + */ 1.282 + protected static String getTypeSignatureStringForField(Field aField) { 1.283 + StringBuilder sb = new StringBuilder(); 1.284 + writeTypeSignature(sb, aField.getType()); 1.285 + return sb.toString(); 1.286 + } 1.287 + 1.288 + /** 1.289 + * Get the canonical JNI type signature for a method. 1.290 + * 1.291 + * @param aMethod The method to generate a signature for. 1.292 + * @return The canonical JNI type signature for this method. 1.293 + */ 1.294 + protected static String getTypeSignatureStringForMethod(Method aMethod) { 1.295 + Class<?>[] arguments = aMethod.getParameterTypes(); 1.296 + Class<?> returnType = aMethod.getReturnType(); 1.297 + return getTypeSignatureInternal(arguments, returnType); 1.298 + } 1.299 + 1.300 + /** 1.301 + * Get the canonical JNI type signature for a Constructor. 1.302 + * 1.303 + * @param aConstructor The Constructor to generate a signature for. 1.304 + * @return The canonical JNI type signature for this method. 1.305 + */ 1.306 + protected static String getTypeSignatureStringForConstructor(Constructor aConstructor) { 1.307 + Class<?>[] arguments = aConstructor.getParameterTypes(); 1.308 + return getTypeSignatureInternal(arguments, Void.class); 1.309 + } 1.310 + 1.311 + public static String getTypeSignatureStringForMember(Member aMember) { 1.312 + if (aMember instanceof Method) { 1.313 + return getTypeSignatureStringForMethod((Method) aMember); 1.314 + } else if (aMember instanceof Field) { 1.315 + return getTypeSignatureStringForField((Field) aMember); 1.316 + } else { 1.317 + return getTypeSignatureStringForConstructor((Constructor) aMember); 1.318 + } 1.319 + } 1.320 + 1.321 + public static String getTypeSignatureString(Constructor aConstructor) { 1.322 + Class<?>[] arguments = aConstructor.getParameterTypes(); 1.323 + StringBuilder sb = new StringBuilder(); 1.324 + sb.append('('); 1.325 + 1.326 + // For each argument, write its signature component to the buffer.. 1.327 + for (int i = 0; i < arguments.length; i++) { 1.328 + writeTypeSignature(sb, arguments[i]); 1.329 + } 1.330 + 1.331 + // Constructors always return Void. 1.332 + sb.append(")V"); 1.333 + return sb.toString(); 1.334 + } 1.335 + 1.336 + /** 1.337 + * Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature 1.338 + * of a given type into the buffer. 1.339 + * 1.340 + * @param sb The buffer to write into. 1.341 + * @param c The type of the element to write the subsignature of. 1.342 + */ 1.343 + private static void writeTypeSignature(StringBuilder sb, Class<?> c) { 1.344 + String name = c.getCanonicalName().replaceAll("\\.", "/"); 1.345 + 1.346 + // Determine if this is an array type and, if so, peel away the array operators.. 1.347 + int len = name.length(); 1.348 + while (name.endsWith("[]")) { 1.349 + sb.append('['); 1.350 + name = name.substring(0, len - 2); 1.351 + len = len - 2; 1.352 + } 1.353 + 1.354 + if (c.isArray()) { 1.355 + c = c.getComponentType(); 1.356 + } 1.357 + 1.358 + Class<?> containerClass = c.getDeclaringClass(); 1.359 + if (containerClass != null) { 1.360 + // Is an inner class. Add the $ symbol. 1.361 + final int lastSlash = name.lastIndexOf('/'); 1.362 + name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1); 1.363 + } 1.364 + 1.365 + // Look in the hashmap for the remainder... 1.366 + if (sCanonicalSignatureParts.containsKey(name)) { 1.367 + // It was a primitive type, so lookup was a success. 1.368 + sb.append(sCanonicalSignatureParts.get(name)); 1.369 + } else { 1.370 + // It was a reference type - generate. 1.371 + sb.append('L'); 1.372 + sb.append(name); 1.373 + sb.append(';'); 1.374 + } 1.375 + } 1.376 + 1.377 + /** 1.378 + * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both 1.379 + * generating header files and method bodies. 1.380 + * 1.381 + * @param aArgumentTypes Argument types of the Java method being wrapped. 1.382 + * @param aReturnType Return type of the Java method being wrapped. 1.383 + * @param aCMethodName Name of the method to generate in the C++ class. 1.384 + * @param aCClassName Name of the C++ class into which the method is declared. 1.385 + * @return The C++ method implementation signature for the method described. 1.386 + */ 1.387 + public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName) { 1.388 + StringBuilder retBuffer = new StringBuilder(); 1.389 + 1.390 + retBuffer.append(getCReturnType(aReturnType)); 1.391 + retBuffer.append(' '); 1.392 + retBuffer.append(aCClassName); 1.393 + retBuffer.append("::"); 1.394 + retBuffer.append(aCMethodName); 1.395 + retBuffer.append('('); 1.396 + 1.397 + // Write argument types... 1.398 + for (int aT = 0; aT < aArgumentTypes.length; aT++) { 1.399 + retBuffer.append(getCParameterType(aArgumentTypes[aT])); 1.400 + retBuffer.append(" a"); 1.401 + // We, imaginatively, call our arguments a1, a2, a3... 1.402 + // The only way to preserve the names from Java would be to parse the 1.403 + // Java source, which would be computationally hard. 1.404 + retBuffer.append(aT); 1.405 + if (aT != aArgumentTypes.length - 1) { 1.406 + retBuffer.append(", "); 1.407 + } 1.408 + } 1.409 + retBuffer.append(')'); 1.410 + return retBuffer.toString(); 1.411 + } 1.412 + 1.413 + /** 1.414 + * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both 1.415 + * generating header files and method bodies. 1.416 + * 1.417 + * @param aArgumentTypes Argument types of the Java method being wrapped. 1.418 + * @param aArgumentAnnotations The annotations on the Java method arguments. Used to specify 1.419 + * default values etc. 1.420 + * @param aReturnType Return type of the Java method being wrapped. 1.421 + * @param aCMethodName Name of the method to generate in the C++ class. 1.422 + * @param aCClassName Name of the C++ class into which the method is declared.e 1.423 + * @param aIsStaticStub true if the generated C++ method should be static, false otherwise. 1.424 + * @return The generated C++ header method signature for the method described. 1.425 + */ 1.426 + public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub) { 1.427 + StringBuilder retBuffer = new StringBuilder(); 1.428 + 1.429 + // Add the static keyword, if applicable. 1.430 + if (aIsStaticStub) { 1.431 + retBuffer.append("static "); 1.432 + } 1.433 + 1.434 + // Write return type.. 1.435 + retBuffer.append(getCReturnType(aReturnType)); 1.436 + retBuffer.append(' '); 1.437 + retBuffer.append(aCMethodName); 1.438 + retBuffer.append('('); 1.439 + 1.440 + // Write argument types... 1.441 + for (int aT = 0; aT < aArgumentTypes.length; aT++) { 1.442 + retBuffer.append(getCParameterType(aArgumentTypes[aT])); 1.443 + retBuffer.append(" a"); 1.444 + // We, imaginatively, call our arguments a1, a2, a3... 1.445 + // The only way to preserve the names from Java would be to parse the 1.446 + // Java source, which would be computationally hard. 1.447 + retBuffer.append(aT); 1.448 + 1.449 + // Append the default value, if there is one.. 1.450 + retBuffer.append(getDefaultValueString(aArgumentTypes[aT], aArgumentAnnotations[aT])); 1.451 + 1.452 + if (aT != aArgumentTypes.length - 1) { 1.453 + retBuffer.append(", "); 1.454 + } 1.455 + } 1.456 + retBuffer.append(')'); 1.457 + return retBuffer.toString(); 1.458 + } 1.459 + 1.460 + /** 1.461 + * If the given Annotation[] contains an OptionalGeneratedParameter annotation then return a 1.462 + * string assigning an argument of type aArgumentType to the default value for that type. 1.463 + * Otherwise, return the empty string. 1.464 + * 1.465 + * @param aArgumentType The type of the argument to consider. 1.466 + * @param aArgumentAnnotations The annotations on the argument to consider. 1.467 + * @return An appropriate string to append to the signature of this argument assigning it to a 1.468 + * default value (Or not, as applicable). 1.469 + */ 1.470 + public static String getDefaultValueString(Class<?> aArgumentType, Annotation[] aArgumentAnnotations) { 1.471 + for (int i = 0; i < aArgumentAnnotations.length; i++) { 1.472 + Class<? extends Annotation> annotationType = aArgumentAnnotations[i].annotationType(); 1.473 + final String annotationTypeName = annotationType.getName(); 1.474 + if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter")) { 1.475 + return " = " + getDefaultParameterValueForType(aArgumentType); 1.476 + } 1.477 + } 1.478 + return ""; 1.479 + } 1.480 + 1.481 + /** 1.482 + * Helper method to return an appropriate default parameter value for an argument of a given type. 1.483 + * The lookup table contains values for primitive types and strings. All other object types default 1.484 + * to null pointers. 1.485 + * 1.486 + * @param aArgumentType The parameter type for which a default value is desired. 1.487 + * @return An appropriate string representation of the default value selected, for use in generated 1.488 + * C++ code. 1.489 + */ 1.490 + private static String getDefaultParameterValueForType(Class<?> aArgumentType) { 1.491 + String typeName = aArgumentType.getCanonicalName(); 1.492 + if (sDefaultParameterValues.containsKey(typeName)) { 1.493 + return sDefaultParameterValues.get(typeName); 1.494 + } else if (isCharSequence(aArgumentType)) { 1.495 + return "EmptyString()"; 1.496 + } else { 1.497 + return "nullptr"; 1.498 + } 1.499 + } 1.500 + 1.501 + /** 1.502 + * Helper method that returns the number of reference types in the arguments of m. 1.503 + * 1.504 + * @param aArgs The method arguments to consider. 1.505 + * @return How many of the arguments of m are nonprimitive. 1.506 + */ 1.507 + public static int enumerateReferenceArguments(Class<?>[] aArgs) { 1.508 + int ret = 0; 1.509 + for (int i = 0; i < aArgs.length; i++) { 1.510 + String name = aArgs[i].getCanonicalName(); 1.511 + if (!sBasicCTypes.containsKey(name)) { 1.512 + ret++; 1.513 + } 1.514 + } 1.515 + return ret; 1.516 + } 1.517 + 1.518 + /** 1.519 + * Helper method that returns true iff the given method has a string argument. 1.520 + * 1.521 + * @param m The method to consider. 1.522 + * @return True if the given method has a string argument, false otherwise. 1.523 + */ 1.524 + public static boolean hasStringArgument(Method m) { 1.525 + Class<?>[] args = m.getParameterTypes(); 1.526 + for (int i = 0; i < args.length; i++) { 1.527 + if (isCharSequence(args[i])) { 1.528 + return true; 1.529 + } 1.530 + } 1.531 + return false; 1.532 + } 1.533 + 1.534 + /** 1.535 + * Write the argument array assignment line for the given argument type. Does not support array 1.536 + * types. 1.537 + * 1.538 + * @param type Type of this argument according to the target Java method's signature. 1.539 + * @param argName Wrapper function argument name corresponding to this argument. 1.540 + */ 1.541 + public static String getArrayArgumentMashallingLine(Class<?> type, String argName) { 1.542 + StringBuilder sb = new StringBuilder(); 1.543 + 1.544 + String name = type.getCanonicalName(); 1.545 + if (sCanonicalSignatureParts.containsKey(name)) { 1.546 + sb.append(sCanonicalSignatureParts.get(name).toLowerCase()); 1.547 + sb.append(" = ").append(argName).append(";\n"); 1.548 + } else { 1.549 + if (isCharSequence(type)) { 1.550 + sb.append("l = AndroidBridge::NewJavaString(env, ").append(argName).append(");\n"); 1.551 + } else { 1.552 + sb.append("l = ").append(argName).append(";\n"); 1.553 + } 1.554 + } 1.555 + 1.556 + return sb.toString(); 1.557 + } 1.558 + 1.559 + /** 1.560 + * Returns true if the type provided is an object type. Returns false otherwise 1.561 + * 1.562 + * @param aType The type to consider. 1.563 + * @return true if the method provided is an object type, false otherwise. 1.564 + */ 1.565 + public static boolean isObjectType(Class<?> aType) { 1.566 + return !sBasicCTypes.containsKey(aType.getCanonicalName()); 1.567 + } 1.568 + 1.569 + /** 1.570 + * For a given Java class, get the name of the value in C++ which holds a reference to it. 1.571 + * 1.572 + * @param aClass Target Java class. 1.573 + * @return The name of the C++ jclass entity referencing the given class. 1.574 + */ 1.575 + public static String getClassReferenceName(Class<?> aClass) { 1.576 + String className = aClass.getSimpleName(); 1.577 + return 'm' + className + "Class"; 1.578 + } 1.579 + 1.580 + /** 1.581 + * Generate a line to get a global reference to the Java class given. 1.582 + * 1.583 + * @param aClass The target Java class. 1.584 + * @return The generated code to populate the reference to the class. 1.585 + */ 1.586 + public static String getStartupLineForClass(Class<?> aClass) { 1.587 + StringBuilder sb = new StringBuilder(); 1.588 + sb.append(" "); 1.589 + sb.append(getClassReferenceName(aClass)); 1.590 + sb.append(" = getClassGlobalRef(\""); 1.591 + 1.592 + String name = aClass.getCanonicalName().replaceAll("\\.", "/"); 1.593 + Class<?> containerClass = aClass.getDeclaringClass(); 1.594 + if (containerClass != null) { 1.595 + // Is an inner class. Add the $ symbol. 1.596 + final int lastSlash = name.lastIndexOf('/'); 1.597 + name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1); 1.598 + } 1.599 + 1.600 + sb.append(name); 1.601 + sb.append("\");\n"); 1.602 + return sb.toString(); 1.603 + } 1.604 + 1.605 + /** 1.606 + * Helper method to determine if this object implements CharSequence 1.607 + * @param aClass Class to check for CharSequence-esqueness 1.608 + * @return True if the given class implements CharSequence, false otherwise. 1.609 + */ 1.610 + public static boolean isCharSequence(Class<?> aClass) { 1.611 + if (aClass.getCanonicalName().equals("java.lang.CharSequence")) { 1.612 + return true; 1.613 + } 1.614 + Class<?>[] interfaces = aClass.getInterfaces(); 1.615 + for (Class<?> c : interfaces) { 1.616 + if (c.getCanonicalName().equals("java.lang.CharSequence")) { 1.617 + return true; 1.618 + } 1.619 + } 1.620 + return false; 1.621 + } 1.622 + 1.623 + /** 1.624 + * Helper method to read the modifier bits of the given method to determine if it is static. 1.625 + * @param aMember The Member to check. 1.626 + * @return true of the method is declared static, false otherwise. 1.627 + */ 1.628 + public static boolean isMemberStatic(Member aMember) { 1.629 + int aMethodModifiers = aMember.getModifiers(); 1.630 + return Modifier.isStatic(aMethodModifiers); 1.631 + } 1.632 + 1.633 + /** 1.634 + * Helper method to read the modifier bits of the given method to determine if it is static. 1.635 + * @param aMember The Member to check. 1.636 + * @return true of the method is declared static, false otherwise. 1.637 + */ 1.638 + public static boolean isMemberFinal(Member aMember) { 1.639 + int aMethodModifiers = aMember.getModifiers(); 1.640 + return Modifier.isFinal(aMethodModifiers); 1.641 + } 1.642 +}