KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > user > rebind > rpc > FieldSerializerCreator


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.user.rebind.rpc;
17
18 import com.google.gwt.core.ext.GeneratorContext;
19 import com.google.gwt.core.ext.TreeLogger;
20 import com.google.gwt.core.ext.typeinfo.JArrayType;
21 import com.google.gwt.core.ext.typeinfo.JClassType;
22 import com.google.gwt.core.ext.typeinfo.JField;
23 import com.google.gwt.core.ext.typeinfo.JType;
24 import com.google.gwt.user.client.rpc.SerializationException;
25 import com.google.gwt.user.client.rpc.SerializationStreamReader;
26 import com.google.gwt.user.client.rpc.SerializationStreamWriter;
27 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
28 import com.google.gwt.user.rebind.SourceWriter;
29
30 import java.io.PrintWriter JavaDoc;
31
32 /**
33  * <p>
34  * This class creates field serializers for a particular class. If the class has
35  * a custom serializer then that class is used rather than creating one.
36  *
37  * <p>
38  * Generated field serializers are emitted into the same package as the class
39  * that they serialize.
40  *
41  * <p>
42  * Fields are considered serializable if:
43  * <ul>
44  * <li>Field is not static
45  * <li>Field is not transient
46  * </ul>
47  *
48  * TODO(mmendez): Need to make the generated field serializers final
49  * TODO(mmendez): Would be nice to be able to have imports, rather than using
50  * fully qualified type names everywhere
51  */

52 public class FieldSerializerCreator {
53
54   private final JClassType serializableClass;
55
56   private final JField[] serializableFields;
57
58   private final SerializableTypeOracle serializationOracle;
59
60   private SourceWriter sourceWriter;
61
62   /**
63    * Constructs a field serializer for the class.
64    *
65    * @param serializationOracle
66    * @param requestedClass
67    */

68   public FieldSerializerCreator(SerializableTypeOracle serializationOracle,
69       JClassType requestedClass) {
70     assert (requestedClass != null);
71     assert (requestedClass.isClass() != null);
72
73     this.serializationOracle = serializationOracle;
74     serializableClass = requestedClass;
75     serializableFields = serializationOracle.getSerializableFields(requestedClass);
76   }
77
78   public String JavaDoc realize(TreeLogger logger, GeneratorContext ctx) {
79     assert (ctx != null);
80     assert (serializationOracle.isSerializable(serializableClass));
81
82     logger = logger.branch(TreeLogger.DEBUG,
83         "Generating a field serializer for type '"
84             + serializableClass.getQualifiedSourceName() + "'", null);
85     String JavaDoc fieldSerializerName = serializationOracle.getFieldSerializerName(serializableClass);
86
87     sourceWriter = getSourceWriter(logger, ctx);
88     if (sourceWriter == null) {
89       return fieldSerializerName;
90     }
91     assert sourceWriter != null;
92
93     writeFieldAccessors();
94
95     writeSerializeMethod();
96
97     writeDeserializeMethod();
98
99     sourceWriter.commit(logger);
100
101     return fieldSerializerName;
102   }
103
104   /**
105    * Returns the name of the field serializer which will deal with this class.
106    *
107    * @return name of the field serializer
108    */

109   private String JavaDoc getFieldSerializerClassName() {
110     String JavaDoc sourceName = serializationOracle.getFieldSerializerName(serializableClass);
111
112     int qualifiedSourceNameStart = sourceName.lastIndexOf('.');
113     if (qualifiedSourceNameStart >= 0) {
114       sourceName = sourceName.substring(qualifiedSourceNameStart + 1);
115     }
116
117     return sourceName;
118   }
119
120   private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) {
121     String JavaDoc packageName = serializableClass.getPackage().getName();
122     String JavaDoc className = getFieldSerializerClassName();
123
124     PrintWriter JavaDoc printWriter = ctx.tryCreate(logger, packageName, className);
125     if (printWriter == null) {
126       return null;
127     }
128
129     ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(
130         packageName, className);
131
132     return composerFactory.createSourceWriter(ctx, printWriter);
133   }
134
135   /**
136    * Returns true if we will need a get/set method pair for a field.
137    *
138    * @return true if the the field requires accessor methods
139    */

140   private boolean needsAccessorMethods(JField field) {
141     /*
142      * Field serializers are always emitted into the the same package as the
143      * class that they serialize. This enables the serializer class to access
144      * all fields except those that are private.
145      *
146      * Java Access Levels: default - package private - class only protected -
147      * package and all subclasses public - all
148      */

149     return field.isPrivate();
150   }
151
152   private void writeDeserializeMethod() {
153     sourceWriter.print("public static void deserialize(");
154     sourceWriter.print(SerializationStreamReader.class.getName());
155     sourceWriter.print(" streamReader, ");
156     sourceWriter.print(serializableClass.getQualifiedSourceName());
157     sourceWriter.println(" instance) throws "
158         + SerializationException.class.getName() + "{");
159     sourceWriter.indent();
160
161     writeFieldDeserializationStatements();
162
163     JClassType superClass = serializableClass.getSuperclass();
164     if (superClass != null && serializationOracle.isSerializable(superClass)) {
165       String JavaDoc fieldSerializerName = serializationOracle.getFieldSerializerName(superClass);
166       sourceWriter.print(fieldSerializerName);
167       sourceWriter.println(".deserialize(streamReader, instance);");
168     }
169
170     sourceWriter.outdent();
171     sourceWriter.println("}");
172     sourceWriter.println();
173   }
174
175   /**
176    * This method will generate a native JSNI accessor method for every field
177    * that is protected, private using the "Violator" pattern to allow an
178    * external class to access the field's value.
179    */

180   private void writeFieldAccessors() {
181     JField[] jFields = serializableFields;
182     int fieldCount = jFields.length;
183
184     for (int fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex) {
185       JField serializableField = jFields[fieldIndex];
186
187       if (!needsAccessorMethods(serializableField)) {
188         continue;
189       }
190
191       writeFieldGet(serializableField);
192       writeFieldSet(serializableField);
193     }
194   }
195
196   private void writeFieldDeserializationStatements() {
197     JType type = serializableClass;
198     JArrayType isArray = type.isArray();
199     if (isArray != null) {
200       sourceWriter.println("for (int itemIndex = 0; itemIndex < instance.length; ++itemIndex) {");
201       sourceWriter.indent();
202
203       JType componentType = isArray.getComponentType();
204
205       sourceWriter.print("instance[itemIndex] = ");
206       if (Shared.typeNeedsCast(componentType)) {
207         sourceWriter.print("(" + componentType.getQualifiedSourceName() + ") ");
208       }
209       String JavaDoc readMethodName = "streamReader.read"
210           + Shared.getCallSuffix(componentType);
211       sourceWriter.println(readMethodName + "();");
212       sourceWriter.outdent();
213       sourceWriter.println("}");
214     } else {
215       JField[] jFields = serializableFields;
216       int fieldCount = jFields.length;
217
218       for (int fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex) {
219         JField serializableField = jFields[fieldIndex];
220         JType fieldType = serializableField.getType();
221         boolean needsAccessor = needsAccessorMethods(serializableField);
222
223         String JavaDoc readMethodName = "read" + Shared.getCallSuffix(fieldType);
224         String JavaDoc streamReadExpression = "streamReader." + readMethodName + "()";
225         if (Shared.typeNeedsCast(fieldType)) {
226           streamReadExpression = "(" + fieldType.getQualifiedSourceName()
227               + ") " + streamReadExpression;
228         }
229
230         if (needsAccessor) {
231           sourceWriter.print("set");
232           sourceWriter.print(Shared.capitalize(serializableField.getName()));
233           sourceWriter.print("(instance, ");
234           sourceWriter.print(streamReadExpression);
235           sourceWriter.println(");");
236         } else {
237           sourceWriter.print("instance.");
238           sourceWriter.print(serializableField.getName());
239           sourceWriter.print(" = ");
240           sourceWriter.print(streamReadExpression);
241           sourceWriter.println(";");
242         }
243       }
244     }
245
246     sourceWriter.println();
247   }
248
249   /**
250    * Write a getter method for an instance field.
251    */

252   private void writeFieldGet(JField serializableField) {
253     JType fieldType = serializableField.getType();
254     String JavaDoc fieldTypeQualifiedSourceName = fieldType.getQualifiedSourceName();
255     String JavaDoc fieldName = serializableField.getName();
256
257     sourceWriter.print("private static native ");
258     sourceWriter.print(fieldTypeQualifiedSourceName);
259     sourceWriter.print(" get");
260     sourceWriter.print(Shared.capitalize(fieldName));
261     sourceWriter.print("(");
262     sourceWriter.print(serializableClass.getQualifiedSourceName());
263     sourceWriter.println(" instance) /*-{");
264     sourceWriter.indent();
265
266     sourceWriter.print("return instance.@");
267     sourceWriter.print(serializationOracle.getSerializedTypeName(serializableClass));
268     sourceWriter.print("::");
269     sourceWriter.print(fieldName);
270     sourceWriter.println(";");
271
272     sourceWriter.outdent();
273     sourceWriter.println("}-*/;");
274     sourceWriter.println();
275   }
276
277   private void writeFieldSerializationStatements() {
278     JType type = serializableClass;
279     JArrayType isArray = type.isArray();
280     if (isArray != null) {
281       sourceWriter.println("int itemCount = instance.length;");
282       sourceWriter.println();
283       sourceWriter.println("streamWriter.writeInt(itemCount);");
284       sourceWriter.println();
285       sourceWriter.println("for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex) {");
286       sourceWriter.indent();
287       String JavaDoc writeMethodName = "write"
288           + Shared.getCallSuffix(isArray.getComponentType());
289       sourceWriter.print("streamWriter.");
290       sourceWriter.print(writeMethodName);
291       sourceWriter.println("(instance[itemIndex]);");
292       sourceWriter.outdent();
293       sourceWriter.println("}");
294     } else {
295       JField[] jFields = serializableFields;
296       int fieldCount = jFields.length;
297
298       for (int fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex) {
299         JField serializableField = jFields[fieldIndex];
300         JType fieldType = serializableField.getType();
301
302         String JavaDoc writeMethodName = "write" + Shared.getCallSuffix(fieldType);
303         sourceWriter.print("streamWriter.");
304         sourceWriter.print(writeMethodName);
305         sourceWriter.print("(");
306
307         if (needsAccessorMethods(serializableField)) {
308           sourceWriter.print("get");
309           sourceWriter.print(Shared.capitalize(serializableField.getName()));
310           sourceWriter.println("(instance));");
311         } else {
312           sourceWriter.print("instance.");
313           sourceWriter.print(serializableField.getName());
314           sourceWriter.println(");");
315         }
316       }
317     }
318
319     sourceWriter.println();
320   }
321
322   /**
323    * Write a setter method for an instance field.
324    */

325   private void writeFieldSet(JField serializableField) {
326     JType fieldType = serializableField.getType();
327     String JavaDoc fieldTypeQualifiedSourceName = fieldType.getQualifiedSourceName();
328     String JavaDoc serializableClassQualifedName = serializableClass.getQualifiedSourceName();
329     String JavaDoc fieldName = serializableField.getName();
330
331     sourceWriter.print("private static native void ");
332     sourceWriter.print(" set");
333     sourceWriter.print(Shared.capitalize(fieldName));
334     sourceWriter.print("(");
335     sourceWriter.print(serializableClassQualifedName);
336     sourceWriter.print(" instance, ");
337     sourceWriter.print(fieldTypeQualifiedSourceName);
338     sourceWriter.println(" value) /*-{");
339     sourceWriter.indent();
340
341     sourceWriter.print("instance.@");
342     sourceWriter.print(serializationOracle.getSerializedTypeName(serializableClass));
343     sourceWriter.print("::");
344     sourceWriter.print(fieldName);
345     sourceWriter.println(" = value;");
346
347     sourceWriter.outdent();
348     sourceWriter.println("}-*/;");
349     sourceWriter.println();
350   }
351
352   private void writeSerializeMethod() {
353     sourceWriter.print("public static void serialize(");
354     sourceWriter.print(SerializationStreamWriter.class.getName());
355     sourceWriter.print(" streamWriter, ");
356     sourceWriter.print(serializableClass.getQualifiedSourceName());
357     sourceWriter.println(" instance) throws "
358         + SerializationException.class.getName() + " {");
359     sourceWriter.indent();
360
361     writeFieldSerializationStatements();
362
363     JClassType superClass = serializableClass.getSuperclass();
364     if (superClass != null && serializationOracle.isSerializable(superClass)) {
365       String JavaDoc fieldSerializerName = serializationOracle.getFieldSerializerName(superClass);
366       sourceWriter.print(fieldSerializerName);
367       sourceWriter.println(".serialize(streamWriter, instance);");
368     }
369     
370     sourceWriter.outdent();
371     sourceWriter.println("}");
372     sourceWriter.println();
373   }
374
375 }
376
Popular Tags