build/annotationProcessors/CodeGenerator.java

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 package org.mozilla.gecko.annotationProcessors;
     7 import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
     8 import org.mozilla.gecko.annotationProcessors.utils.Utils;
    10 import java.lang.annotation.Annotation;
    11 import java.lang.reflect.Constructor;
    12 import java.lang.reflect.Field;
    13 import java.lang.reflect.Member;
    14 import java.lang.reflect.Method;
    15 import java.lang.reflect.Modifier;
    16 import java.util.HashMap;
    17 import java.util.HashSet;
    19 public class CodeGenerator {
    20     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
    21     private static final Annotation[][] GETTER_ARGUMENT_ANNOTATIONS = new Annotation[0][0];
    22     private static final Annotation[][] SETTER_ARGUMENT_ANNOTATIONS = new Annotation[1][0];
    24     // Buffers holding the strings to ultimately be written to the output files.
    25     private final StringBuilder zeroingCode = new StringBuilder();
    26     private final StringBuilder wrapperStartupCode = new StringBuilder();
    27     private final StringBuilder wrapperMethodBodies = new StringBuilder();
    28     private final StringBuilder headerPublic = new StringBuilder();
    29     private final StringBuilder headerProtected = new StringBuilder();
    31     private final HashSet<String> seenClasses = new HashSet<String>();
    33     private final String mCClassName;
    35     private final Class<?> mClassToWrap;
    37     private boolean mHasEncounteredDefaultConstructor;
    39     // Used for creating unique names for method ID fields in the face of
    40     private final HashMap<Member, String> mMembersToIds = new HashMap<Member, String>();
    41     private final HashSet<String> mTakenMemberNames = new HashSet<String>();
    42     private int mNameMunger;
    44     public CodeGenerator(Class<?> aClass, String aGeneratedName) {
    45         mClassToWrap = aClass;
    46         mCClassName = aGeneratedName;
    48         // Write the file header things. Includes and so forth.
    49         // GeneratedJNIWrappers.cpp is generated as the concatenation of wrapperStartupCode with
    50         // wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerPublic
    51         // with headerProtected.
    52         wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *jEnv) {\n" +
    53                                   "    initInit();\n");
    55         // Now we write the various GetStaticMethodID calls here...
    56         headerPublic.append("class ").append(mCClassName).append(" : public AutoGlobalWrappedJavaObject {\n" +
    57                             "public:\n" +
    58                             "    static void InitStubs(JNIEnv *jEnv);\n");
    59         headerProtected.append("protected:");
    61         generateWrapperMethod();
    62     }
    64     /**
    65      * Emit a static method which takes an instance of the class being wrapped and returns an instance
    66      * of the C++ wrapper class backed by that object.
    67      */
    68     private void generateWrapperMethod() {
    69         headerPublic.append("    static ").append(mCClassName).append("* Wrap(jobject obj);\n" +
    70                 "    ").append(mCClassName).append("(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};\n");
    72         wrapperMethodBodies.append("\n").append(mCClassName).append("* ").append(mCClassName).append("::Wrap(jobject obj) {\n" +
    73                 "    JNIEnv *env = GetJNIForThread();\n" +
    74                 "    ").append(mCClassName).append("* ret = new ").append(mCClassName).append("(obj, env);\n" +
    75                 "    env->DeleteLocalRef(obj);\n" +
    76                 "    return ret;\n" +
    77                 "}\n");
    78     }
    80     private void generateMemberCommon(Member theMethod, String aCMethodName, Class<?> aClass) {
    81         ensureClassHeaderAndStartup(aClass);
    82         writeMemberIdField(theMethod, aCMethodName);
    83         writeStartupCode(theMethod);
    84     }
    86     /**
    87      * Append the appropriate generated code to the buffers for the method provided.
    88      *
    89      * @param aMethodTuple The Java method, plus annotation data.
    90      */
    91     public void generateMethod(AnnotatableEntity aMethodTuple) {
    92         // Unpack the tuple and extract some useful fields from the Method..
    93         Method theMethod = aMethodTuple.getMethod();
    95         String CMethodName = aMethodTuple.mAnnotationInfo.wrapperName;
    97         generateMemberCommon(theMethod, CMethodName, mClassToWrap);
    99         boolean isFieldStatic = Utils.isMemberStatic(theMethod);
   100         boolean shallGenerateStatic = isFieldStatic || aMethodTuple.mAnnotationInfo.isStatic;
   102         Class<?>[] parameterTypes = theMethod.getParameterTypes();
   103         Class<?> returnType = theMethod.getReturnType();
   105         // Get the C++ method signature for this method.
   106         String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName);
   107         String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, shallGenerateStatic);
   109         // Add the header signature to the header file.
   110         writeSignatureToHeader(headerSignature);
   112         // Use the implementation signature to generate the method body...
   113         writeMethodBody(implementationSignature, CMethodName, theMethod, mClassToWrap,
   114             aMethodTuple.mAnnotationInfo.isStatic,
   115             aMethodTuple.mAnnotationInfo.isMultithreaded,
   116             aMethodTuple.mAnnotationInfo.noThrow);
   117     }
   119     private void generateGetterOrSetterBody(Class<?> aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter) {
   120         StringBuilder argumentContent = null;
   122         if (isSetter) {
   123             Class<?>[] setterArguments = new Class<?>[]{aFieldType};
   124             // Marshall the argument..
   125             argumentContent = getArgumentMarshalling(setterArguments);
   126         }
   128         boolean isObjectReturningMethod = Utils.isObjectType(aFieldType);
   129         wrapperMethodBodies.append("    ");
   130         if (isSetter) {
   131             wrapperMethodBodies.append("env->Set");
   132         } else {
   133             wrapperMethodBodies.append("return ");
   135             if (isObjectReturningMethod) {
   136                 wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType)).append(">(");
   137             }
   139             wrapperMethodBodies.append("env->Get");
   140         }
   142         if (aIsFieldStatic) {
   143             wrapperMethodBodies.append("Static");
   144         }
   145         wrapperMethodBodies.append(Utils.getFieldType(aFieldType))
   146                            .append("Field(");
   148         // Static will require the class and the field id. Nonstatic, the object and the field id.
   149         if (aIsFieldStatic) {
   150             wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap));
   151         } else {
   152             wrapperMethodBodies.append("wrapped_obj");
   153         }
   154         wrapperMethodBodies.append(", j")
   155                            .append(aFieldName);
   156         if (isSetter) {
   157             wrapperMethodBodies.append(argumentContent);
   158         }
   160         if (!isSetter && isObjectReturningMethod) {
   161             wrapperMethodBodies.append(')');
   162         }
   163         wrapperMethodBodies.append(");\n" +
   164                                "}\n");
   165     }
   167     public void generateField(AnnotatableEntity aFieldTuple) {
   168         Field theField = aFieldTuple.getField();
   170         // Handles a peculiar case when dealing with enum types. We don't care about this field.
   171         // It just gets in the way and stops our code from compiling.
   172         if (theField.getName().equals("$VALUES")) {
   173             return;
   174         }
   176         String CFieldName = aFieldTuple.mAnnotationInfo.wrapperName;
   178         Class<?> fieldType = theField.getType();
   180         generateMemberCommon(theField, CFieldName, mClassToWrap);
   182         boolean isFieldStatic = Utils.isMemberStatic(theField);
   183         boolean isFieldFinal = Utils.isMemberFinal(theField);
   184         boolean shallGenerateStatic = isFieldStatic || aFieldTuple.mAnnotationInfo.isStatic;
   186         String getterName = "get" + CFieldName;
   187         String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName);
   188         String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, shallGenerateStatic);
   190         writeSignatureToHeader(getterHeaderSignature);
   192         writeFunctionStartupBoilerPlate(getterSignature, fieldType, isFieldStatic, true);
   194         generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false);
   196         // If field not final, also generate a setter function.
   197         if (!isFieldFinal) {
   198             String setterName = "set" + CFieldName;
   200             Class<?>[] setterArguments = new Class<?>[]{fieldType};
   202             String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName);
   203             String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, shallGenerateStatic);
   205             writeSignatureToHeader(setterHeaderSignature);
   207             writeFunctionStartupBoilerPlate(setterSignature, Void.class, isFieldStatic, true);
   209             generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true);
   210         }
   211     }
   213     public void generateConstructor(AnnotatableEntity aCtorTuple) {
   214         // Unpack the tuple and extract some useful fields from the Method..
   215         Constructor theCtor = aCtorTuple.getConstructor();
   216         String CMethodName = mCClassName;
   218         generateMemberCommon(theCtor, mCClassName, mClassToWrap);
   220         String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName);
   221         String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false);
   223         // Slice off the "void " from the start of the constructor declaration.
   224         headerSignature = headerSignature.substring(5);
   225         implementationSignature = implementationSignature.substring(5);
   227         // Add the header signatures to the header file.
   228         writeSignatureToHeader(headerSignature);
   230         // Use the implementation signature to generate the method body...
   231         writeCtorBody(implementationSignature, theCtor,
   232             aCtorTuple.mAnnotationInfo.isMultithreaded,
   233             aCtorTuple.mAnnotationInfo.noThrow);
   235         if (theCtor.getParameterTypes().length == 0) {
   236             mHasEncounteredDefaultConstructor = true;
   237         }
   238     }
   240     /**
   241      * Writes the appropriate header and startup code to ensure the existence of a reference to the
   242      * class specified. If this is already done, does nothing.
   243      *
   244      * @param aClass The target class.
   245      */
   246     private void ensureClassHeaderAndStartup(Class<?> aClass) {
   247         String className = aClass.getCanonicalName();
   248         if (seenClasses.contains(className)) {
   249             return;
   250         }
   252         zeroingCode.append("jclass ")
   253                    .append(mCClassName)
   254                    .append("::")
   255                    .append(Utils.getClassReferenceName(aClass))
   256                    .append(" = 0;\n");
   258         // Add a field to hold the reference...
   259         headerProtected.append("\n    static jclass ")
   260                        .append(Utils.getClassReferenceName(aClass))
   261                        .append(";\n");
   263         // Add startup code to populate it..
   264         wrapperStartupCode.append('\n')
   265                           .append(Utils.getStartupLineForClass(aClass));
   267         seenClasses.add(className);
   268     }
   270     /**
   271      * Write out the function startup boilerplate for the method described. Check for environment
   272      * existence,
   273      * @param methodSignature
   274      * @param returnType
   275      * @param aIsStatic
   276      * @param aIsThreaded
   277      */
   278     private void writeFunctionStartupBoilerPlate(String methodSignature, Class<?> returnType, boolean aIsStatic, boolean aIsThreaded) {
   279         // The start-of-function boilerplate. Does the bridge exist? Does the env exist? etc.
   280         wrapperMethodBodies.append('\n')
   281                            .append(methodSignature)
   282                            .append(" {\n");
   284         wrapperMethodBodies.append("    JNIEnv *env = ");
   285         if (!aIsThreaded) {
   286             wrapperMethodBodies.append("AndroidBridge::GetJNIEnv();\n");
   287         } else {
   288             wrapperMethodBodies.append("GetJNIForThread();\n");
   289         }
   290     }
   292     /**
   293      * Write out the appropriate JNI frame pushing boilerplate for a call to the member provided (
   294      * which must be a constructor or method).
   295      *
   296      * @param aMethod A constructor/method being wrapped.
   297      * @param aIsObjectReturningMethod Does the method being wrapped return an object?
   298      */
   299     private void writeFramePushBoilerplate(Member aMethod,
   300             boolean aIsObjectReturningMethod, boolean aNoThrow) {
   301         if (aMethod instanceof Field) {
   302             throw new IllegalArgumentException("Tried to push frame for a FIELD?!");
   303         }
   305         Method m;
   306         Constructor c;
   308         Class<?> returnType;
   310         int localReferencesNeeded;
   311         if (aMethod instanceof Method) {
   312             m = (Method) aMethod;
   313             returnType = m.getReturnType();
   314             localReferencesNeeded = Utils.enumerateReferenceArguments(m.getParameterTypes());
   315         } else {
   316             c = (Constructor) aMethod;
   317             returnType = Void.class;
   318             localReferencesNeeded = Utils.enumerateReferenceArguments(c.getParameterTypes());
   319         }
   321         // Determine the number of local refs required for our local frame..
   322         // AutoLocalJNIFrame is not applicable here due to it's inability to handle return values.
   323         if (aIsObjectReturningMethod) {
   324             localReferencesNeeded++;
   325         }
   326         wrapperMethodBodies.append(
   327                 "    if (env->PushLocalFrame(").append(localReferencesNeeded).append(") != 0) {\n");
   328         if (!aNoThrow) {
   329             wrapperMethodBodies.append(
   330                 "        AndroidBridge::HandleUncaughtException(env);\n" +
   331                 "        MOZ_ASSUME_UNREACHABLE(\"Exception should have caused crash.\");\n");
   332         } else {
   333             wrapperMethodBodies.append(
   334                 "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n");
   335         }
   336         wrapperMethodBodies.append(
   337                 "    }\n\n");
   338     }
   340     private StringBuilder getArgumentMarshalling(Class<?>[] argumentTypes) {
   341         StringBuilder argumentContent = new StringBuilder();
   343         // If we have >2 arguments, use the jvalue[] calling approach.
   344         argumentContent.append(", ");
   345         if (argumentTypes.length > 2) {
   346             wrapperMethodBodies.append("    jvalue args[").append(argumentTypes.length).append("];\n");
   347             for (int aT = 0; aT < argumentTypes.length; aT++) {
   348                 wrapperMethodBodies.append("    args[").append(aT).append("].")
   349                                    .append(Utils.getArrayArgumentMashallingLine(argumentTypes[aT], "a" + aT));
   350             }
   352             // The only argument is the array of arguments.
   353             argumentContent.append("args");
   354             wrapperMethodBodies.append('\n');
   355         } else {
   356             // Otherwise, use the vanilla calling approach.
   357             boolean needsNewline = false;
   358             for (int aT = 0; aT < argumentTypes.length; aT++) {
   359                 // If the argument is a string-esque type, create a jstring from it, otherwise
   360                 // it can be passed directly.
   361                 if (Utils.isCharSequence(argumentTypes[aT])) {
   362                     wrapperMethodBodies.append("    jstring j").append(aT).append(" = AndroidBridge::NewJavaString(env, a").append(aT).append(");\n");
   363                     needsNewline = true;
   364                     // Ensure we refer to the newly constructed Java string - not to the original
   365                     // parameter to the wrapper function.
   366                     argumentContent.append('j').append(aT);
   367                 } else {
   368                     argumentContent.append('a').append(aT);
   369                 }
   370                 if (aT != argumentTypes.length - 1) {
   371                     argumentContent.append(", ");
   372                 }
   373             }
   374             if (needsNewline) {
   375                 wrapperMethodBodies.append('\n');
   376             }
   377         }
   379         return argumentContent;
   380     }
   382     private void writeCtorBody(String implementationSignature, Constructor theCtor,
   383             boolean aIsThreaded, boolean aNoThrow) {
   384         Class<?>[] argumentTypes = theCtor.getParameterTypes();
   386         writeFunctionStartupBoilerPlate(implementationSignature, Void.class, false, aIsThreaded);
   388         writeFramePushBoilerplate(theCtor, false, aNoThrow);
   390         // Marshall arguments for this constructor, if any...
   391         boolean hasArguments = argumentTypes.length != 0;
   393         StringBuilder argumentContent = new StringBuilder();
   394         if (hasArguments) {
   395             argumentContent = getArgumentMarshalling(argumentTypes);
   396         }
   398         // The call into Java
   399         wrapperMethodBodies.append("    Init(env->NewObject");
   400         if (argumentTypes.length > 2) {
   401             wrapperMethodBodies.append('A');
   402         }
   404         wrapperMethodBodies.append('(');
   407         // Call takes class id, method id of constructor method, then arguments.
   408         wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap)).append(", ");
   410         wrapperMethodBodies.append(mMembersToIds.get(theCtor))
   411         // Tack on the arguments, if any..
   412                            .append(argumentContent)
   413                            .append("), env);\n" +
   414                                    "    env->PopLocalFrame(nullptr);\n" +
   415                                    "}\n");
   416     }
   418     /**
   419      * Generates the method body of the C++ wrapper function for the Java method indicated.
   420      *
   421      * @param methodSignature The previously-generated C++ method signature for the method to be
   422      *                        generated.
   423      * @param aCMethodName    The C++ method name for the method to be generated.
   424      * @param aMethod         The Java method to be wrapped by the C++ method being generated.
   425      * @param aClass          The Java class to which the method belongs.
   426      */
   427     private void writeMethodBody(String methodSignature, String aCMethodName, Method aMethod,
   428             Class<?> aClass, boolean aIsStaticBridgeMethod, boolean aIsMultithreaded,
   429             boolean aNoThrow) {
   430         Class<?>[] argumentTypes = aMethod.getParameterTypes();
   431         Class<?> returnType = aMethod.getReturnType();
   433         writeFunctionStartupBoilerPlate(methodSignature, returnType, aIsStaticBridgeMethod, aIsMultithreaded);
   435         boolean isObjectReturningMethod = !returnType.getCanonicalName().equals("void") && Utils.isObjectType(returnType);
   437         writeFramePushBoilerplate(aMethod, isObjectReturningMethod, aNoThrow);
   439         // Marshall arguments, if we have any.
   440         boolean hasArguments = argumentTypes.length != 0;
   442         // We buffer the arguments to the call separately to avoid needing to repeatedly iterate the
   443         // argument list while building this line. In the coming code block, we simultaneously
   444         // construct any argument marshalling code (Creation of jstrings, placement of arguments
   445         // into an argument array, etc. and the actual argument list passed to the function (in
   446         // argumentContent).
   447         StringBuilder argumentContent = new StringBuilder();
   448         if (hasArguments) {
   449             argumentContent = getArgumentMarshalling(argumentTypes);
   450         }
   452         // Allocate a temporary variable to hold the return type from Java.
   453         wrapperMethodBodies.append("    ");
   454         if (!returnType.getCanonicalName().equals("void")) {
   455             if (isObjectReturningMethod) {
   456                 wrapperMethodBodies.append("jobject");
   457             } else {
   458                 wrapperMethodBodies.append(Utils.getCReturnType(returnType));
   459             }
   460             wrapperMethodBodies.append(" temp = ");
   461         }
   463         boolean isStaticJavaMethod = Utils.isMemberStatic(aMethod);
   465         // The call into Java
   466         wrapperMethodBodies.append("env->")
   467                            .append(Utils.getCallPrefix(returnType, isStaticJavaMethod));
   468         if (argumentTypes.length > 2) {
   469             wrapperMethodBodies.append('A');
   470         }
   472         wrapperMethodBodies.append('(');
   473         // If the underlying Java method is nonstatic, we provide the target object to the JNI.
   474         if (!isStaticJavaMethod) {
   475             wrapperMethodBodies.append("wrapped_obj, ");
   476         } else {
   477             // If this is a static underlying Java method, we need to use the class reference in our
   478             // call.
   479             wrapperMethodBodies.append(Utils.getClassReferenceName(aClass)).append(", ");
   480         }
   482         wrapperMethodBodies.append(mMembersToIds.get(aMethod));
   484         // Tack on the arguments, if any..
   485         wrapperMethodBodies.append(argumentContent)
   486                            .append(");\n");
   488         // Check for exception and crash if any...
   489         if (!aNoThrow) {
   490             wrapperMethodBodies.append("    AndroidBridge::HandleUncaughtException(env);\n");
   491         }
   493         // If we're returning an object, pop the callee's stack frame extracting our ref as the return
   494         // value.
   495         if (isObjectReturningMethod) {
   496             wrapperMethodBodies.append("    ")
   497                                .append(Utils.getCReturnType(returnType))
   498                                .append(" ret = static_cast<").append(Utils.getCReturnType(returnType)).append(">(env->PopLocalFrame(temp));\n" +
   499                                        "    return ret;\n");
   500         } else if (!returnType.getCanonicalName().equals("void")) {
   501             // If we're a primitive-returning function, just return the directly-obtained primative
   502             // from the call to Java.
   503             wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n" +
   504                                        "    return temp;\n");
   505         } else {
   506             // If we don't return anything, just pop the stack frame and move on with life.
   507             wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n");
   508         }
   509         wrapperMethodBodies.append("}\n");
   510     }
   512     /**
   513      * Generates the code to get the id of the given member on startup.
   514      *
   515      * @param aMember         The Java member being wrapped.
   516      */
   517     private void writeStartupCode(Member aMember) {
   518         wrapperStartupCode.append("    ")
   519                           .append(mMembersToIds.get(aMember))
   520                           .append(" = get");
   521         if (Utils.isMemberStatic(aMember)) {
   522             wrapperStartupCode.append("Static");
   523         }
   525         boolean isField = aMember instanceof Field;
   526         if (isField) {
   527             wrapperStartupCode.append("Field(\"");
   528         } else {
   529             wrapperStartupCode.append("Method(\"");
   530         }
   531         if (aMember instanceof Constructor) {
   532             wrapperStartupCode.append("<init>");
   533         } else {
   534             wrapperStartupCode.append(aMember.getName());
   535         }
   537         wrapperStartupCode.append("\", \"")
   538                           .append(Utils.getTypeSignatureStringForMember(aMember))
   539                           .append("\");\n");
   540     }
   542     private void writeZeroingFor(Member aMember, final String aMemberName) {
   543         if (aMember instanceof Field) {
   544             zeroingCode.append("jfieldID ");
   545         } else {
   546             zeroingCode.append("jmethodID ");
   547         }
   548         zeroingCode.append(mCClassName)
   549                    .append("::")
   550                    .append(aMemberName)
   551                    .append(" = 0;\n");
   552     }
   554     /**
   555      * Write the field declaration for the C++ id field of the given member.
   556      *
   557      * @param aMember Member for which an id field needs to be generated.
   558      */
   559     private void writeMemberIdField(Member aMember, final String aCMethodName) {
   560         String memberName = 'j'+ aCMethodName;
   562         if (aMember instanceof Field) {
   563             headerProtected.append("    static jfieldID ");
   564         } else {
   565             headerProtected.append("    static jmethodID ");
   566         }
   568         while(mTakenMemberNames.contains(memberName)) {
   569             memberName = 'j' + aCMethodName + mNameMunger;
   570             mNameMunger++;
   571         }
   573         writeZeroingFor(aMember, memberName);
   574         mMembersToIds.put(aMember, memberName);
   575         mTakenMemberNames.add(memberName);
   577         headerProtected.append(memberName)
   578                        .append(";\n");
   579     }
   581     /**
   582      * Helper function to add a provided method signature to the public section of the generated header.
   583      *
   584      * @param aSignature The header to add.
   585      */
   586     private void writeSignatureToHeader(String aSignature) {
   587         headerPublic.append("    ")
   588                     .append(aSignature)
   589                     .append(";\n");
   590     }
   592     /**
   593      * Get the finalised bytes to go into the generated wrappers file.
   594      *
   595      * @return The bytes to be written to the wrappers file.
   596      */
   597     public String getWrapperFileContents() {
   598         wrapperStartupCode.append("}\n");
   599         zeroingCode.append(wrapperStartupCode)
   600                    .append(wrapperMethodBodies);
   601         wrapperMethodBodies.setLength(0);
   602         wrapperStartupCode.setLength(0);
   603         return zeroingCode.toString();
   604     }
   606     /**
   607      * Get the finalised bytes to go into the generated header file.
   608      *
   609      * @return The bytes to be written to the header file.
   610      */
   611     public String getHeaderFileContents() {
   612         if (!mHasEncounteredDefaultConstructor) {
   613             headerPublic.append("    ").append(mCClassName).append("() : AutoGlobalWrappedJavaObject() {};\n");
   614         }
   615         headerProtected.append("};\n\n");
   616         headerPublic.append(headerProtected);
   617         headerProtected.setLength(0);
   618         return headerPublic.toString();
   619     }
   620 }

mercurial