com.google.gwt.user.rebind.rpc.FieldSerializerCreator Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.user.rebind.rpc;
import com.google.gwt.core.client.UnsafeNativeLong;
import com.google.gwt.core.client.impl.WeakMapping;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JConstructor;
import com.google.gwt.core.ext.typeinfo.JEnumType;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.JTypeParameter;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
import com.google.gwt.user.client.rpc.core.java.lang.Object_Array_CustomFieldSerializer;
import com.google.gwt.user.client.rpc.impl.ReflectionHelper;
import com.google.gwt.user.client.rpc.impl.TypeHandler;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import java.io.PrintWriter;
/**
* Creates a field serializer for a class that implements
* {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
* {@link java.io.Serializable Serializable}. The field serializer is emitted
* into the same package as the class that it serializes.
*
* TODO(mmendez): Need to make the generated field serializers final
* TODO(mmendez): Would be nice to be able to have imports, rather than using
* fully qualified type names everywhere
*/
public class FieldSerializerCreator {
/*
* NB: FieldSerializerCreator generates two different sets of code for DevMode
* and ProdMode. In ProdMode, the generated code uses the JSNI violator
* pattern to access private class members. In DevMode, the generated code
* uses ReflectionHelper instead of JSNI to avoid the many JSNI
* boundary-crossings which are slow in DevMode.
*/
private static final String WEAK_MAPPING_CLASS_NAME = WeakMapping.class.getName();
private final TreeLogger logger;
private final GeneratorContext context;
private final JClassType customFieldSerializer;
private final boolean customFieldSerializerHasInstantiate;
private final String fieldSerializerName;
private final boolean isJRE;
private final boolean isProd;
private final String methodEnd;
private final String methodStart;
private final JClassType serializableClass;
private final JField[] serializableFields;
private SourceWriter sourceWriter;
private final SerializableTypeOracle typesSentFromBrowser;
private final SerializableTypeOracle typesSentToBrowser;
private final TypeOracle typeOracle;
/**
* Constructs a field serializer for the class.
*/
public FieldSerializerCreator(TreeLogger logger, GeneratorContext context,
SerializableTypeOracle typesSentFromBrowser, SerializableTypeOracle typesSentToBrowser,
JClassType requestedClass, JClassType customFieldSerializer) {
this.logger = logger;
this.context = context;
this.isProd = context.isProdMode();
methodStart = isProd ? "/*-{" : "{";
methodEnd = isProd ? "}-*/;" : "}";
this.customFieldSerializer = customFieldSerializer;
assert (requestedClass != null);
assert (requestedClass.isClass() != null || requestedClass.isArray() != null);
this.typeOracle = context.getTypeOracle();
this.typesSentFromBrowser = typesSentFromBrowser;
this.typesSentToBrowser = typesSentToBrowser;
serializableClass = requestedClass;
serializableFields = SerializationUtils.getSerializableFields(context, requestedClass);
this.fieldSerializerName = SerializationUtils.getStandardSerializerName(serializableClass);
this.isJRE =
SerializableTypeOracleBuilder.isInStandardJavaPackage(serializableClass
.getQualifiedSourceName());
this.customFieldSerializerHasInstantiate =
(customFieldSerializer != null && CustomFieldSerializerValidator.hasInstantiationMethod(
customFieldSerializer, serializableClass));
}
public String realize(TreeLogger logger, GeneratorContext ctx) {
assert (ctx != null);
assert (typesSentFromBrowser.isSerializable(serializableClass) || typesSentToBrowser
.isSerializable(serializableClass));
logger =
logger.branch(TreeLogger.DEBUG, "Generating a field serializer for type '"
+ serializableClass.getQualifiedSourceName() + "'", null);
sourceWriter = getSourceWriter(logger, ctx);
if (sourceWriter == null) {
return fieldSerializerName;
}
assert sourceWriter != null;
writeFieldAccessors();
writeDeserializeMethod();
maybeWriteInstatiateMethod();
writeSerializeMethod();
maybeWriteTypeHandlerImpl();
sourceWriter.commit(logger);
return fieldSerializerName;
}
private boolean classIsAccessible() {
JClassType testClass = serializableClass;
while (testClass != null) {
if (testClass.isPrivate() || (isJRE && !testClass.isPublic())) {
return false;
}
testClass = testClass.getEnclosingType();
}
return true;
}
private String createArrayInstantiationExpression(JArrayType array) {
StringBuilder sb = new StringBuilder();
sb.append("new ");
sb.append(array.getLeafType().getQualifiedSourceName());
sb.append("[size]");
for (int i = 0; i < array.getRank() - 1; ++i) {
sb.append("[]");
}
return sb.toString();
}
private boolean ctorIsAccessible() {
JConstructor ctor = serializableClass.findConstructor(new JType[0]);
if (ctor.isPrivate() || (isJRE && !ctor.isPublic())) {
return false;
}
return true;
}
/**
* Returns the depth of the given class in the class hierarchy (where the
* depth of java.lang.Object == 0).
*/
private int getDepth(JClassType clazz) {
int depth = 0;
while ((clazz = clazz.getSuperclass()) != null) {
depth++;
}
return depth;
}
private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) {
int packageNameEnd = fieldSerializerName.lastIndexOf('.');
String className;
String packageName;
if (packageNameEnd != -1) {
className = fieldSerializerName.substring(packageNameEnd + 1);
packageName = fieldSerializerName.substring(0, packageNameEnd);
} else {
className = fieldSerializerName;
packageName = "";
}
PrintWriter printWriter = ctx.tryCreate(logger, packageName, className);
if (printWriter == null) {
return null;
}
ClassSourceFileComposerFactory composerFactory =
new ClassSourceFileComposerFactory(packageName, className);
composerFactory.addImport(SerializationException.class.getCanonicalName());
composerFactory.addImport(SerializationStreamReader.class.getCanonicalName());
composerFactory.addImport(SerializationStreamWriter.class.getCanonicalName());
composerFactory.addImport(ReflectionHelper.class.getCanonicalName());
composerFactory.addAnnotationDeclaration("@SuppressWarnings(\"deprecation\")");
if (needsTypeHandler()) {
composerFactory.addImplementedInterface(TypeHandler.class.getCanonicalName());
}
return composerFactory.createSourceWriter(ctx, printWriter);
}
private String getTypeSig(JMethod deserializationMethod) {
JTypeParameter[] typeParameters = deserializationMethod.getTypeParameters();
String typeSig = "";
if (typeParameters.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append('<');
for (JTypeParameter typeParameter : typeParameters) {
sb.append(typeParameter.getFirstBound().getQualifiedSourceName());
sb.append(',');
}
sb.setCharAt(sb.length() - 1, '>');
typeSig = sb.toString();
}
return typeSig;
}
private void maybeSuppressLongWarnings(JType fieldType) {
if (fieldType == JPrimitiveType.LONG) {
/**
* Accessing long from JSNI causes a error, but field serializers need to
* be able to do just that in order to bypass java accessibility
* restrictions.
*/
sourceWriter.println("@" + UnsafeNativeLong.class.getName());
}
}
/**
* Writes an instantiate method. Examples:
*
* Class
*
*
* public static com.google.gwt.sample.client.Student instantiate(
* SerializationStreamReader streamReader) throws SerializationException {
* return new com.google.gwt.sample.client.Student();
* }
*
*
* Class with private ctor
*
*
* public static native com.google.gwt.sample.client.Student instantiate(
* SerializationStreamReader streamReader) throws SerializationException /*-{
* return @com.google.gwt.sample.client.Student::new()();
* }-*/;
*
*
* Array
*
*
* public static com.google.gwt.sample.client.Student[] instantiate(
* SerializationStreamReader streamReader) throws SerializationException {
* int size = streamReader.readInt();
* return new com.google.gwt.sample.client.Student[size];
* }
*
*
* Enum
*
*
* public static com.google.gwt.sample.client.Role instantiate(
* SerializationStreamReader streamReader) throws SerializationException {
* int ordinal = streamReader.readInt();
* com.google.gwt.sample.client.Role[] values = com.google.gwt.sample.client.Role.values();
* assert (ordinal >= 0 && ordinal < values.length);
* return values[ordinal];
* }
*
*/
private void maybeWriteInstatiateMethod() {
if (serializableClass.isEnum() == null
&& (serializableClass.isAbstract() || !serializableClass.isDefaultInstantiable())) {
/*
* Field serializers are shared by all of the RemoteService proxies in a
* compilation. Therefore, we have to generate an instantiate method even
* if the type is not instantiable relative to the RemoteService which
* caused this field serializer to be created. If the type is not
* instantiable relative to any of the RemoteService proxies, dead code
* optimizations will cause the method to be removed from the compiled
* output.
*
* Enumerated types require an instantiate method even if they are
* abstract. You will have an abstract enum in cases where the enum type
* is sub-classed. Non-default instantiable classes cannot have
* instantiate methods.
*/
return;
}
if (customFieldSerializerHasInstantiate) {
// The custom field serializer already defined it.
return;
}
JArrayType isArray = serializableClass.isArray();
JEnumType isEnum = serializableClass.isEnum();
JClassType isClass = serializableClass.isClass();
boolean useViolator = false;
boolean isAccessible = true;
if (isEnum == null && isClass != null) {
isAccessible = classIsAccessible() && ctorIsAccessible();
useViolator = !isAccessible && isProd;
}
sourceWriter.print("public static" + (useViolator ? " native " : " "));
String qualifiedSourceName = serializableClass.getQualifiedSourceName();
sourceWriter.print(qualifiedSourceName);
sourceWriter
.println(" instantiate(SerializationStreamReader streamReader) throws SerializationException "
+ (useViolator ? "/*-{" : "{"));
sourceWriter.indent();
if (isArray != null) {
sourceWriter.println("int size = streamReader.readInt();");
sourceWriter.println("return " + createArrayInstantiationExpression(isArray) + ";");
} else if (isEnum != null) {
sourceWriter.println("int ordinal = streamReader.readInt();");
sourceWriter.println(qualifiedSourceName + "[] values = " + qualifiedSourceName
+ ".values();");
sourceWriter.println("assert (ordinal >= 0 && ordinal < values.length);");
sourceWriter.println("return values[ordinal];");
} else if (!isAccessible) {
if (isProd) {
sourceWriter.println("return @" + qualifiedSourceName + "::new()();");
} else {
sourceWriter.println("return ReflectionHelper.newInstance(" + qualifiedSourceName
+ ".class);");
}
} else {
sourceWriter.println("return new " + qualifiedSourceName + "();");
}
sourceWriter.outdent();
sourceWriter.println(useViolator ? "}-*/;" : "}");
sourceWriter.println();
}
/**
* Implement {@link TypeHandler} for the class, used by Java.
*
*
* public void deserial(SerializationStreamReader reader, Object object)
* throws SerializationException {
* com.google.gwt.sample.client.Student_FieldSerializer.deserialize(
* reader, (com.google.gwt.sample.client.Student) object);
* }
*
* public Object create(SerializationStreamReader reader)
* throws SerializationException {
* return com.google.gwt.sample.client.Student_FieldSerializer.instantiate(reader);
* }
*
* public void serial(SerializationStreamWriter writer, Object object)
* throws SerializationException {
* com.google.gwt.sample.client.Student_FieldSerializer.serialize(
* writer, (com.google.gwt.sample.client.Student) object);
* }
*
*/
private void maybeWriteTypeHandlerImpl() {
if (!needsTypeHandler()) {
return;
}
// Create method
sourceWriter
.println("public Object create(SerializationStreamReader reader) throws SerializationException {");
sourceWriter.indent();
if (serializableClass.isEnum() != null || serializableClass.isDefaultInstantiable()
|| customFieldSerializerHasInstantiate) {
sourceWriter.print("return ");
String typeSig;
if (customFieldSerializer != null && customFieldSerializerHasInstantiate) {
sourceWriter.print(customFieldSerializer.getQualifiedSourceName());
JMethod instantiationMethod =
CustomFieldSerializerValidator.getInstantiationMethod(customFieldSerializer,
serializableClass);
typeSig = getTypeSig(instantiationMethod);
} else {
sourceWriter.print(fieldSerializerName);
typeSig = "";
}
sourceWriter.print("." + typeSig + "instantiate");
sourceWriter.println("(reader);");
} else {
sourceWriter.println("return null;");
}
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.println();
// Deserial method
sourceWriter
.println("public void deserial(SerializationStreamReader reader, Object object) throws SerializationException {");
if (customFieldSerializer != null) {
JMethod deserializationMethod =
CustomFieldSerializerValidator.getDeserializationMethod(customFieldSerializer,
serializableClass);
JType castType = deserializationMethod.getParameters()[1].getType();
String typeSig = getTypeSig(deserializationMethod);
sourceWriter.indentln(customFieldSerializer.getQualifiedSourceName() + "." + typeSig
+ "deserialize(reader, (" + castType.getQualifiedSourceName() + ")object);");
} else {
sourceWriter.indentln(fieldSerializerName + ".deserialize(reader, ("
+ serializableClass.getQualifiedSourceName() + ")object);");
}
sourceWriter.println("}");
sourceWriter.println();
// Serial method
sourceWriter
.println("public void serial(SerializationStreamWriter writer, Object object) throws SerializationException {");
if (customFieldSerializer != null) {
JMethod serializationMethod =
CustomFieldSerializerValidator.getSerializationMethod(customFieldSerializer,
serializableClass);
JType castType = serializationMethod.getParameters()[1].getType();
String typeSig = getTypeSig(serializationMethod);
sourceWriter.indentln(customFieldSerializer.getQualifiedSourceName() + "." + typeSig
+ "serialize(writer, (" + castType.getQualifiedSourceName() + ")object);");
} else {
sourceWriter.indentln(fieldSerializerName + ".serialize(writer, ("
+ serializableClass.getQualifiedSourceName() + ")object);");
}
sourceWriter.println("}");
sourceWriter.println();
}
/**
* Returns true if we will need a get/set method pair for a field.
*
* @return true if the field requires accessor methods
*/
private boolean needsAccessorMethods(JField field) {
/*
* Field serializers are always emitted into the same package as the
* class that they serialize. This enables the serializer class to access
* all fields except those that are private or final.
*
* Java Access Levels: default - package private - class only protected -
* package and all subclasses public - all
*/
if (Shared.shouldSerializeFinalFields(logger, context)) {
return field.isPrivate() || field.isFinal();
} else {
return field.isPrivate();
}
}
/**
* Enumerated types can be instantiated even if they are abstract. You will
* have an abstract enum in cases where the enum type is sub-classed.
* Non-default instantiable classes cannot have instantiate methods.
*/
private boolean needsTypeHandler() {
return serializableClass.isEnum() != null || !serializableClass.isAbstract();
}
private void writeArrayDeserializationStatements(JArrayType isArray) {
JType componentType = isArray.getComponentType();
String readMethodName = Shared.getStreamReadMethodNameFor(componentType);
if ("readObject".equals(readMethodName)) {
// Optimize and use the default object custom serializer...
sourceWriter.println(Object_Array_CustomFieldSerializer.class.getName()
+ ".deserialize(streamReader, instance);");
} else {
sourceWriter.println("for (int i = 0, n = instance.length; i < n; ++i) {");
sourceWriter.indent();
sourceWriter.print("instance[i] = streamReader.");
sourceWriter.println(readMethodName + "();");
sourceWriter.outdent();
sourceWriter.println("}");
}
}
private void writeArraySerializationStatements(JArrayType isArray) {
JType componentType = isArray.getComponentType();
String writeMethodName = Shared.getStreamWriteMethodNameFor(componentType);
if ("writeObject".equals(writeMethodName)) {
// Optimize and use the default object custom serializer...
sourceWriter.println(Object_Array_CustomFieldSerializer.class.getName()
+ ".serialize(streamWriter, instance);");
} else {
sourceWriter.println("streamWriter.writeInt(instance.length);");
sourceWriter.println();
sourceWriter.println("for (int i = 0, n = instance.length; i < n; ++i) {");
sourceWriter.indent();
sourceWriter.print("streamWriter.");
sourceWriter.print(writeMethodName);
sourceWriter.println("(instance[i]);");
sourceWriter.outdent();
sourceWriter.println("}");
}
}
private void writeClassDeserializationStatements() {
/**
* If the type is capable of making a round trip between the client and
* server, store additional server-only field data using {@link WeakMapping}
* .
*/
if (serializableClass.isEnhanced()) {
sourceWriter.println(WEAK_MAPPING_CLASS_NAME + ".set(instance, " + "\"server-enhanced-data-"
+ getDepth(serializableClass) + "\", streamReader.readString());");
}
for (JField serializableField : serializableFields) {
JType fieldType = serializableField.getType();
String readMethodName = Shared.getStreamReadMethodNameFor(fieldType);
String streamReadExpression = "streamReader." + readMethodName + "()";
if (Shared.typeNeedsCast(fieldType)) {
streamReadExpression =
"(" + fieldType.getQualifiedSourceName() + ") " + streamReadExpression;
}
if (needsAccessorMethods(serializableField)) {
sourceWriter.print("set");
sourceWriter.print(Shared.capitalize(serializableField.getName()));
sourceWriter.print("(instance, ");
sourceWriter.print(streamReadExpression);
sourceWriter.println(");");
} else {
sourceWriter.print("instance.");
sourceWriter.print(serializableField.getName());
sourceWriter.print(" = ");
sourceWriter.print(streamReadExpression);
sourceWriter.println(";");
}
}
sourceWriter.println();
JClassType superClass = serializableClass.getSuperclass();
if (superClass != null
&& (typesSentFromBrowser.isSerializable(superClass) || typesSentToBrowser
.isSerializable(superClass))) {
String superFieldSerializer =
SerializationUtils.getFieldSerializerName(typeOracle, superClass);
sourceWriter.print(superFieldSerializer);
sourceWriter.println(".deserialize(streamReader, instance);");
}
}
private void writeClassSerializationStatements() {
/**
* If the type is capable of making a round trip between the client and
* server, retrieve the additional server-only field data from
* {@link WeakMapping}.
*/
if (serializableClass.isEnhanced()) {
sourceWriter.println("streamWriter.writeString((String) " + WEAK_MAPPING_CLASS_NAME
+ ".get(instance, \"server-enhanced-data-" + getDepth(serializableClass) + "\"));");
}
for (JField serializableField : serializableFields) {
JType fieldType = serializableField.getType();
String writeMethodName = Shared.getStreamWriteMethodNameFor(fieldType);
sourceWriter.print("streamWriter.");
sourceWriter.print(writeMethodName);
sourceWriter.print("(");
if (needsAccessorMethods(serializableField)) {
sourceWriter.print("get");
sourceWriter.print(Shared.capitalize(serializableField.getName()));
sourceWriter.println("(instance));");
} else {
sourceWriter.print("instance.");
sourceWriter.print(serializableField.getName());
sourceWriter.println(");");
}
}
sourceWriter.println();
JClassType superClass = serializableClass.getSuperclass();
if (superClass != null
&& (typesSentFromBrowser.isSerializable(superClass) || typesSentToBrowser
.isSerializable(superClass))) {
String superFieldSerializer =
SerializationUtils.getFieldSerializerName(typeOracle, superClass);
sourceWriter.print(superFieldSerializer);
sourceWriter.println(".serialize(streamWriter, instance);");
}
}
private void writeDeserializeMethod() {
if (customFieldSerializer != null) {
return;
}
sourceWriter.print("public static void deserialize(SerializationStreamReader streamReader, ");
sourceWriter.print(serializableClass.getQualifiedSourceName());
sourceWriter.println(" instance) throws SerializationException {");
sourceWriter.indent();
JArrayType isArray = serializableClass.isArray();
if (isArray != null) {
writeArrayDeserializationStatements(isArray);
} else if (serializableClass.isEnum() != null) {
writeEnumDeserializationStatements();
} else {
writeClassDeserializationStatements();
}
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.println();
}
private void writeEnumDeserializationStatements() {
sourceWriter.println("// Enum deserialization is handled via the instantiate method");
}
private void writeEnumSerializationStatements() {
sourceWriter.println("assert (instance != null);");
sourceWriter.println("streamWriter.writeInt(instance.ordinal());");
}
/**
* This method will generate a native JSNI accessor method for every field
* that is protected, private using the "Violator" pattern to allow an
* external class to access the field's value.
*/
private void writeFieldAccessors() {
if (customFieldSerializer != null) {
return;
}
for (JField serializableField : serializableFields) {
if (!needsAccessorMethods(serializableField)) {
continue;
}
writeFieldGet(serializableField);
writeFieldSet(serializableField);
}
}
/**
* Write a getter method for an instance field.
*/
private void writeFieldGet(JField serializableField) {
JType fieldType = serializableField.getType();
String fieldTypeQualifiedSourceName = fieldType.getQualifiedSourceName();
String serializableClassQualifedName = serializableClass.getQualifiedSourceName();
String fieldName = serializableField.getName();
maybeSuppressLongWarnings(fieldType);
sourceWriter.print("private static " + (isProd ? "native " : ""));
sourceWriter.print(fieldTypeQualifiedSourceName);
sourceWriter.print(" get");
sourceWriter.print(Shared.capitalize(fieldName));
sourceWriter.print("(");
sourceWriter.print(serializableClassQualifedName);
sourceWriter.print(" instance) ");
sourceWriter.println(methodStart);
sourceWriter.indent();
if (context.isProdMode()) {
sourceWriter.print("return instance.@");
sourceWriter.print(SerializationUtils.getRpcTypeName(serializableClass));
sourceWriter.print("::");
sourceWriter.print(fieldName);
sourceWriter.println(";");
} else {
sourceWriter.print("return ");
JPrimitiveType primType = fieldType.isPrimitive();
if (primType != null) {
sourceWriter.print("(" + primType.getQualifiedBoxedSourceName() + ") ");
} else {
sourceWriter.print("(" + fieldTypeQualifiedSourceName + ") ");
}
sourceWriter.println("ReflectionHelper.getField(" + serializableClassQualifedName
+ ".class, instance, \"" + fieldName + "\");");
}
sourceWriter.outdent();
sourceWriter.println(methodEnd);
sourceWriter.println();
}
/**
* Write a setter method for an instance field.
*/
private void writeFieldSet(JField serializableField) {
JType fieldType = serializableField.getType();
String fieldTypeQualifiedSourceName = fieldType.getQualifiedSourceName();
String serializableClassQualifedName = serializableClass.getQualifiedSourceName();
String fieldName = serializableField.getName();
maybeSuppressLongWarnings(fieldType);
sourceWriter.print("private static " + (isProd ? "native " : "") + "void");
sourceWriter.print(" set");
sourceWriter.print(Shared.capitalize(fieldName));
sourceWriter.print("(");
sourceWriter.print(serializableClassQualifedName);
sourceWriter.print(" instance, ");
sourceWriter.print(fieldTypeQualifiedSourceName);
sourceWriter.println(" value) ");
sourceWriter.println(methodStart);
sourceWriter.indent();
if (context.isProdMode()) {
sourceWriter.print("instance.@");
sourceWriter.print(SerializationUtils.getRpcTypeName(serializableClass));
sourceWriter.print("::");
sourceWriter.print(fieldName);
sourceWriter.println(" = value;");
} else {
sourceWriter.println("ReflectionHelper.setField(" + serializableClassQualifedName
+ ".class, instance, \"" + fieldName + "\", value);");
}
sourceWriter.outdent();
sourceWriter.println(methodEnd);
sourceWriter.println();
}
private void writeSerializeMethod() {
if (customFieldSerializer != null) {
return;
}
sourceWriter.print("public static void serialize(SerializationStreamWriter streamWriter, ");
sourceWriter.print(serializableClass.getQualifiedSourceName());
sourceWriter.println(" instance) throws SerializationException {");
sourceWriter.indent();
JArrayType isArray = serializableClass.isArray();
if (isArray != null) {
writeArraySerializationStatements(isArray);
} else if (serializableClass.isEnum() != null) {
writeEnumSerializationStatements();
} else {
writeClassSerializationStatements();
}
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.println();
}
}