* Writes common boilerplate code for all implementations.
*/
protected void writeBoilerplate(TreeLogger logger,
FragmentGeneratorContext context) throws UnableToCompleteException {
SourceWriter sw = context.sw;
TypeOracle typeOracle = context.typeOracle;
JType returnType = context.returnType;
// The backing object
sw.print("private JavaScriptObject ");
sw.print(OBJ);
sw.println(";");
// Build a constructor to initialize state.
sw.print("public ");
sw.print(context.simpleTypeName);
sw.println("() {");
sw.indent();
sw.println("setJavaScriptObject(__nativeInit());");
sw.outdent();
sw.println("}");
// Determine the correct expression to use to initialize the object
JClassType asClass = context.returnType.isClassOrInterface();
Constructor constructorAnnotation = hasTag(logger, asClass,
Constructor.class);
Global globalAnnotation = hasTag(logger, asClass, Global.class);
String constructor;
if (globalAnnotation != null) {
constructor = globalAnnotation.value();
} else if (constructorAnnotation != null) {
constructor = "new " + constructorAnnotation.value() + "()";
} else {
boolean hasImports = false;
for (Task t : context.tasks) {
hasImports |= t.imported != null;
if (hasImports) {
break;
}
}
if (!hasImports) {
// Probably a JSON or pojo-style object
constructor = "{}";
} else {
constructor = "null";
}
}
JClassType parameterization = findJSWrapperParameterization(
context.typeOracle, asClass);
if (parameterization == null) {
parameterization = asClass;
}
// Initialize native state of the wrapper
sw.println("private native JavaScriptObject __nativeInit() /*-{");
sw.indent();
sw.print("return ");
sw.print(constructor);
sw.println(";");
sw.outdent();
sw.println("}-*/;");
// Allow the backing JSONObject to be accessed
sw.println("public JavaScriptObject getJavaScriptObject() {");
sw.indent();
sw.print("return ");
sw.print(OBJ);
sw.println(";");
sw.outdent();
sw.println("}");
// Defer actual parsing to JSONWrapperUtil to take advantage of using
// a common function implementation between generated classes.
sw.println("public void setJSONData(String data)");
sw.println("throws JSONWrapperException {");
sw.indent();
sw.println("setJavaScriptObject(JSONWrapperUtil.evaluate(data));");
sw.outdent();
sw.println("}");
// Satisfies JSWrapper and allows generated implementations to
// efficiently initialize new objects.
// Method declaration
sw.print("public " + parameterization.getParameterizedQualifiedSourceName()
+ " setJavaScriptObject(");
sw.println("JavaScriptObject obj) {");
sw.indent();
sw.println("if (obj != null) {");
sw.indent();
for (Task t : context.tasks) {
if (t.imported != null) {
String fieldName = t.getFieldName(logger);
sw.print("assert JSONWrapperUtil.hasField(obj, \"");
sw.print(fieldName);
sw.print("\") : \"Backing JSO missing imported function ");
sw.print(fieldName);
sw.println("\";");
}
}
sw.outdent();
sw.println("}");
sw.println("return setJavaScriptObjectNative(obj);");
sw.outdent();
sw.println("}");
// Method declaration
sw.print("public native " + context.simpleTypeName
+ " setJavaScriptObjectNative(JavaScriptObject obj) /*-{");
sw.indent();
if (context.maintainIdentity) {
// Delete the backing object's reference to the current wrapper
sw.print("if (");
sw.print(context.objRef);
sw.println(") {");
sw.indent();
sw.print("delete ");
sw.print(context.objRef);
sw.print(".");
sw.print(BACKREF);
sw.println(";");
sw.outdent();
sw.println("}");
}
// If the incoming JSO is null or undefined, reset the JSWrapper
sw.println("if (!obj) {");
sw.indent();
sw.print(context.objRef);
sw.println(" = null;");
sw.println("return this;");
sw.outdent();
sw.println("}");
if (context.maintainIdentity) {
// Verify that the incoming object doesn't already have a wrapper object.
// If there is a backreference, throw an exception.
sw.print("if (obj.");
sw.print(BACKREF);
sw.println(") {");
sw.indent();
sw.println("@com.google.gwt.jsio.client.impl.JSONWrapperUtil::throwMultipleWrapperException()();");
sw.outdent();
sw.println("}");
}
// Capture the object in the wrapper
sw.print(context.objRef);
sw.println(" = obj;");
if (context.maintainIdentity) {
// Assign the backreference from the wrapped object to the wrapper
sw.print(context.objRef);
sw.print(".");
sw.print(BACKREF);
sw.println(" = this;");
}
if (!context.readOnly) {
// Initialize any other fields if the JSWrapper is read-write
sw.print("this.@");
sw.print(context.qualifiedTypeName);
sw.print("::__initializeEmptyFields(Lcom/google/gwt/core/client/JavaScriptObject;)(");
sw.print(context.objRef);
sw.println(");");
}
sw.println("return this;");
sw.outdent();
sw.println("}-*/;");
// If the generated class will be used with a JSList, we need an Extractor
// implementation. We'll create an implementation per generated
// class to ensure that if the class is used with a JSList, only one
// instance of the Extractor will ever exist.
sw.println("public final Extractor<"
+ parameterization.getParameterizedQualifiedSourceName()
+ "> getExtractor() {");
sw.indent();
sw.print("return ");
sw.print(EXTRACTOR);
sw.println(";");
sw.outdent();
sw.println("}");
// The one instance of the Extractor
sw.print("private final static Extractor ");
sw.print(EXTRACTOR);
sw.print(" = new Extractor() {");
sw.indent();
FragmentGeneratorContext subParams = new FragmentGeneratorContext(context);
subParams.parameterName = "obj";
FragmentGenerator fragmentGenerator = context.fragmentGeneratorOracle.findFragmentGenerator(
logger, typeOracle, returnType);
sw.println("public native Object fromJS(JavaScriptObject obj) /*-{");
sw.indent();
sw.print("return ");
fragmentGenerator.fromJS(subParams);
sw.println(";");
sw.outdent();
sw.println("}-*/;");
// Write the Extracor's toJS function and close the Extractor
// implementation.
sw.println("public native JavaScriptObject toJS(Object obj) /*-{");
sw.indent();
sw.print("return ");
fragmentGenerator.toJS(subParams);
sw.println(";");
sw.outdent();
sw.println("}-*/;");
// Finish the class
sw.outdent();
sw.println("};");
}