1 16 17 package com.google.gwt.user.rebind.rpc; 18 19 import com.google.gwt.core.client.JavaScriptObject; 20 import com.google.gwt.core.ext.GeneratorContext; 21 import com.google.gwt.core.ext.TreeLogger; 22 import com.google.gwt.core.ext.typeinfo.JArrayType; 23 import com.google.gwt.core.ext.typeinfo.JClassType; 24 import com.google.gwt.core.ext.typeinfo.JMethod; 25 import com.google.gwt.core.ext.typeinfo.JPackage; 26 import com.google.gwt.core.ext.typeinfo.JParameterizedType; 27 import com.google.gwt.core.ext.typeinfo.JPrimitiveType; 28 import com.google.gwt.core.ext.typeinfo.JType; 29 import com.google.gwt.core.ext.typeinfo.TypeOracle; 30 import com.google.gwt.user.client.rpc.SerializationException; 31 import com.google.gwt.user.client.rpc.SerializationStreamReader; 32 import com.google.gwt.user.client.rpc.SerializationStreamWriter; 33 import com.google.gwt.user.client.rpc.impl.Serializer; 34 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; 35 import com.google.gwt.user.rebind.SourceWriter; 36 37 import java.io.PrintWriter ; 38 39 43 public class TypeSerializerCreator { 44 45 private static final String DESERIALIZE_METHOD_SIGNATURE = "public native void deserialize(" 46 + "SerializationStreamReader streamReader, Object instance, String typeSignature)" 47 + " throws SerializationException"; 48 49 private static final String INSTANTIATE_METHOD_SIGNATURE = "public native Object instantiate(" 50 + "SerializationStreamReader streamReader, String typeSignature)" 51 + " throws SerializationException"; 52 53 private static final String SERIALIZE_METHOD_SIGNATURE = "public native void serialize(" 54 + "SerializationStreamWriter streamWriter, Object instance, String typeSignature)" 55 + " throws SerializationException"; 56 57 private final GeneratorContext context; 58 59 private final boolean enforceTypeVersioning; 60 61 private final JClassType remoteService; 62 63 private final JType[] serializableTypes; 64 65 private final SerializableTypeOracle serializationOracle; 66 67 private final SourceWriter srcWriter; 68 69 private final TypeOracle typeOracle; 70 71 public TypeSerializerCreator(TreeLogger logger, 72 SerializableTypeOracle serializationOracle, GeneratorContext context, 73 JClassType remoteService) { 74 this.context = context; 75 this.remoteService = remoteService; 76 this.serializationOracle = serializationOracle; 77 this.typeOracle = context.getTypeOracle(); 78 79 enforceTypeVersioning = Shared.shouldEnforceTypeVersioning(logger, 80 context.getPropertyOracle()); 81 82 serializableTypes = serializationOracle.getSerializableTypes(); 83 84 srcWriter = getSourceWriter(logger, context); 85 } 86 87 public String realize(TreeLogger logger) { 88 logger = logger.branch(TreeLogger.DEBUG, 89 "Generating TypeSerializer for service interface '" 90 + getServiceInterface().getQualifiedSourceName() + "'", null); 91 String typeSerializerName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface()); 92 if (srcWriter == null) { 93 return typeSerializerName; 94 } 95 96 createFieldSerializers(logger, context); 97 98 writeStaticFields(); 99 100 writeCreateMethods(); 101 102 writeCreateMethodMapMethod(); 103 104 if (shouldEnforceTypeVersioning()) { 105 writeCreateSignatureMapMethod(); 106 } 107 108 writeRaiseSerializationException(); 109 110 writeDeserializeMethod(); 111 112 writeGetSerializationSignatureMethod(); 113 114 writeInstantiateMethod(); 115 116 writeSerializeMethod(); 117 118 srcWriter.commit(logger); 119 120 return typeSerializerName; 121 } 122 123 private String buildArrayInstantiationExpression(JArrayType array) { 124 String expression = "[rank]"; 125 JType componentType = array.getComponentType(); 126 while (true) { 127 array = componentType.isArray(); 128 if (array == null) { 129 break; 130 } 131 132 expression += "[0]"; 133 134 componentType = array.getComponentType(); 135 } 136 137 expression = componentType.getQualifiedSourceName() + expression; 138 139 return expression; 140 } 141 142 146 private void createFieldSerializer(TreeLogger logger, GeneratorContext ctx, 147 JType type) { 148 assert (type != null); 149 assert (serializationOracle.isSerializable(type)); 150 151 JParameterizedType parameterizedType = type.isParameterized(); 152 if (parameterizedType != null) { 153 createFieldSerializer(logger, ctx, parameterizedType.getRawType()); 154 return; 155 } 156 157 JClassType customFieldSerializer = serializationOracle.hasCustomFieldSerializer(type); 158 if (customFieldSerializer != null) { 159 customFieldSerializer.getQualifiedSourceName(); 160 return; 161 } 162 163 170 assert (type.isClass() != null); 171 172 FieldSerializerCreator creator = new FieldSerializerCreator( 173 serializationOracle, type.isClass()); 174 creator.realize(logger, ctx); 175 } 176 177 180 private void createFieldSerializers(TreeLogger logger, GeneratorContext ctx) { 181 JType[] types = getSerializableTypes(); 182 int typeCount = types.length; 183 for (int typeIndex = 0; typeIndex < typeCount; ++typeIndex) { 184 JType type = types[typeIndex]; 185 assert (type != null); 186 187 createFieldSerializer(logger, ctx, type); 188 } 189 } 190 191 private JMethod getCustomInstantiateMethod(JType type) { 192 JClassType serializer = serializationOracle.hasCustomFieldSerializer(type); 193 if (serializer == null) { 194 return null; 195 } 196 197 JMethod instantiate = serializer.findMethod( 198 "instantiate", 199 new JType[] {typeOracle.findType(SerializationStreamReader.class.getName())}); 200 return instantiate; 201 } 202 203 private String getInstantiationMethodName(JType type) { 204 JArrayType arrayType = type.isArray(); 205 if (arrayType != null) { 206 JType leafType = arrayType.getLeafType(); 207 return "create_" + leafType.getQualifiedSourceName().replace('.', '_') 208 + "_Array_Rank_" + arrayType.getRank(); 209 } 210 211 return "create_" 212 + serializationOracle.getFieldSerializerName(type).replace('.', '_'); 213 } 214 215 private JType[] getSerializableTypes() { 216 return serializableTypes; 217 } 218 219 private JClassType getServiceInterface() { 220 return remoteService; 221 } 222 223 private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx) { 224 JClassType serviceIntf = getServiceInterface(); 225 JPackage serviceIntfPackage = serviceIntf.getPackage(); 226 String packageName = serviceIntfPackage != null 227 ? serviceIntfPackage.getName() : ""; 228 String className = serializationOracle.getTypeSerializerSimpleName(getServiceInterface()); 229 PrintWriter printWriter = ctx.tryCreate(logger, packageName, className); 230 if (printWriter == null) { 231 return null; 232 } 233 234 ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory( 235 packageName, className); 236 237 composerFactory.addImport(JavaScriptObject.class.getName()); 238 composerFactory.addImport(Serializer.class.getName()); 239 composerFactory.addImport(SerializationException.class.getName()); 240 composerFactory.addImport(SerializationStreamReader.class.getName()); 241 composerFactory.addImport(SerializationStreamWriter.class.getName()); 242 243 composerFactory.addImplementedInterface("Serializer"); 244 return composerFactory.createSourceWriter(ctx, printWriter); 245 } 246 247 private boolean isAbstractType(JType type) { 248 JClassType classType = type.isClassOrInterface(); 249 if (classType != null) { 250 if (classType.isAbstract()) { 251 return true; 252 } 253 } 254 255 return false; 258 } 259 260 266 private String normalizeJSNIInstanceSerializationMethodSignature(JType type) { 267 String jsniSignature; 268 JArrayType arrayType = type.isArray(); 269 270 if (arrayType != null) { 271 JType componentType = arrayType.getComponentType(); 272 JPrimitiveType primitiveType = componentType.isPrimitive(); 273 if (primitiveType != null) { 274 jsniSignature = "[" + primitiveType.getJNISignature(); 275 } else { 276 jsniSignature = "[" + "Ljava/lang/Object;"; 277 } 278 } else { 279 jsniSignature = type.getJNISignature(); 280 } 281 282 return jsniSignature; 283 } 284 285 private boolean shouldEnforceTypeVersioning() { 286 return enforceTypeVersioning; 287 } 288 289 private void writeArrayInstantiationMethod(JArrayType array) { 290 srcWriter.println("int rank = streamReader.readInt();"); 291 srcWriter.println("return new " + buildArrayInstantiationExpression(array) 292 + ";"); 293 } 294 295 private void writeCreateMethodMapMethod() { 296 srcWriter.println("private static native JavaScriptObject createMethodMap() /*-" + '{'); 297 { 298 srcWriter.indent(); 299 srcWriter.println("return {"); 300 JType[] types = getSerializableTypes(); 301 boolean needComma = false; 302 for (int index = 0; index < types.length; ++index) { 303 JType type = types[index]; 304 if (isAbstractType(type)) { 305 continue; 306 } 307 308 if (needComma) { 309 srcWriter.println(","); 310 } else { 311 needComma = true; 312 } 313 314 String typeString = serializationOracle.getSerializedTypeName(type); 315 if (shouldEnforceTypeVersioning()) { 316 typeString += "/" 317 + serializationOracle.getSerializationSignature(type); 318 } 319 320 srcWriter.print("\"" + typeString + "\":"); 321 322 srcWriter.println("["); 324 { 325 srcWriter.indent(); 326 { 327 JMethod instantiationMethod = getCustomInstantiateMethod(type); 329 srcWriter.print("function(x){ return "); 330 if (instantiationMethod != null) { 331 srcWriter.print("@" 332 + instantiationMethod.getEnclosingType().getQualifiedSourceName()); 333 srcWriter.print("::"); 334 srcWriter.print(instantiationMethod.getName()); 335 } else { 336 srcWriter.print("@" 337 + serializationOracle.getTypeSerializerQualifiedName(getServiceInterface())); 338 srcWriter.print("::"); 339 srcWriter.print(getInstantiationMethodName(type)); 340 } 341 srcWriter.print("(L" 342 + SerializationStreamReader.class.getName().replace('.', '/') 343 + ";)"); 344 srcWriter.print("(x);}"); 345 srcWriter.println(","); 346 } 347 348 String jsniSignature = normalizeJSNIInstanceSerializationMethodSignature(type); 349 String serializerName = serializationOracle.getFieldSerializerName(type); 350 { 351 srcWriter.print("function(x,y){"); 353 srcWriter.print("@" + serializerName); 354 srcWriter.print("::deserialize(L" 355 + SerializationStreamReader.class.getName().replace('.', '/') 356 + ";" + jsniSignature + ")"); 357 srcWriter.print("(x,y);}"); 358 srcWriter.println(","); 359 } 360 { 361 srcWriter.print("function(x,y){"); 363 srcWriter.print("@" + serializerName); 364 srcWriter.print("::serialize(L" 365 + SerializationStreamWriter.class.getName().replace('.', '/') 366 + ";" + jsniSignature + ")"); 367 srcWriter.print("(x,y);}"); 368 srcWriter.println(); 369 } 370 srcWriter.outdent(); 371 } 372 srcWriter.print("]"); 373 } 374 srcWriter.println(); 375 srcWriter.println("};"); 376 srcWriter.outdent(); 377 } 378 srcWriter.println("}-*/;"); 379 srcWriter.println(); 380 } 381 382 private void writeCreateMethods() { 383 JType[] types = getSerializableTypes(); 384 for (int typeIndex = 0; typeIndex < types.length; ++typeIndex) { 385 JType type = types[typeIndex]; 386 assert (serializationOracle.isSerializable(type)); 387 388 if (isAbstractType(type)) { 391 continue; 392 } 393 394 JMethod customInstantiate = getCustomInstantiateMethod(type); 395 if (customInstantiate != null) { 396 continue; 397 } 398 399 srcWriter.print("private static "); 400 srcWriter.print(type.getQualifiedSourceName()); 401 srcWriter.print(" "); 402 srcWriter.print(getInstantiationMethodName(type)); 403 srcWriter.println("(SerializationStreamReader streamReader) throws SerializationException {"); 404 srcWriter.indent(); 405 406 JArrayType array = type.isArray(); 407 if (array != null) { 408 writeArrayInstantiationMethod(array); 409 } else { 410 srcWriter.print("return new "); 411 srcWriter.print(type.getQualifiedSourceName()); 412 srcWriter.println("();"); 413 } 414 415 srcWriter.outdent(); 416 srcWriter.println("}"); 417 418 srcWriter.println(); 419 } 420 } 421 422 private void writeCreateSignatureMapMethod() { 423 srcWriter.println("private static native JavaScriptObject createSignatureMap() /*-" + '{'); 424 { 425 srcWriter.indent(); 426 srcWriter.println("return {"); 427 JType[] types = getSerializableTypes(); 428 boolean needComma = false; 429 for (int index = 0; index < types.length; ++index) { 430 JType type = types[index]; 431 if (isAbstractType(type)) { 432 continue; 433 } 434 if (needComma) { 435 srcWriter.println(","); 436 } else { 437 needComma = true; 438 } 439 440 srcWriter.print("\"" + serializationOracle.getSerializedTypeName(type) 441 + "\":\"" + serializationOracle.getSerializationSignature(type) 442 + "\""); 443 } 444 srcWriter.println(); 445 srcWriter.println("};"); 446 srcWriter.outdent(); 447 } 448 srcWriter.println("}-*/;"); 449 srcWriter.println(); 450 } 451 452 private void writeDeserializeMethod() { 453 srcWriter.print(DESERIALIZE_METHOD_SIGNATURE); 454 srcWriter.println(" /*-" + '{'); 455 { 456 String serializerTypeName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface()); 457 srcWriter.indent(); 458 srcWriter.println("var methodTable = @" + serializerTypeName 459 + "::methodMap[typeSignature];"); 460 srcWriter.println("if (!methodTable) {"); 461 srcWriter.indentln("@" + serializerTypeName 462 + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);"); 463 srcWriter.println("}"); 464 srcWriter.println("methodTable[1](streamReader, instance);"); 465 srcWriter.outdent(); 466 } 467 srcWriter.println("}-*/;"); 468 srcWriter.println(); 469 } 470 471 private void writeGetSerializationSignatureMethod() { 472 if (!shouldEnforceTypeVersioning()) { 473 srcWriter.println("public String getSerializationSignature(String typeName) {"); 474 srcWriter.indentln("return null;"); 475 srcWriter.println("};"); 476 } else { 477 String serializerTypeName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface()); 478 srcWriter.println("public native String getSerializationSignature(String typeName) /*-" + '{'); 479 srcWriter.indent(); 480 srcWriter.println("var signature = @" + serializerTypeName 481 + "::signatureMap[typeName];"); 482 srcWriter.println("return (signature == null) ? typeName : signature;"); 483 srcWriter.outdent(); 484 srcWriter.println("}-*/;"); 485 } 486 srcWriter.println(); 487 } 488 489 private void writeInstantiateMethod() { 490 srcWriter.print(INSTANTIATE_METHOD_SIGNATURE); 491 srcWriter.println(" /*-" + '{'); 492 { 493 String serializerTypeName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface()); 494 srcWriter.indent(); 495 srcWriter.println("var methodTable = @" + serializerTypeName 496 + "::methodMap[typeSignature];"); 497 srcWriter.println("if (!methodTable) {"); 498 srcWriter.indentln("@" + serializerTypeName 499 + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);"); 500 srcWriter.println("}"); 501 srcWriter.println("return methodTable[0](streamReader);"); 502 srcWriter.outdent(); 503 } 504 srcWriter.println("}-*/;"); 505 srcWriter.println(); 506 } 507 508 private void writeRaiseSerializationException() { 509 srcWriter.println("private static void raiseSerializationException(String msg) throws SerializationException {"); 510 srcWriter.indentln("throw new SerializationException(msg);"); 511 srcWriter.println("}"); 512 srcWriter.println(); 513 } 514 515 private void writeSerializeMethod() { 516 srcWriter.print(SERIALIZE_METHOD_SIGNATURE); 517 srcWriter.println(" /*-" + '{'); 518 { 519 String serializerTypeName = serializationOracle.getTypeSerializerQualifiedName(getServiceInterface()); 520 srcWriter.indent(); 521 srcWriter.println("var methodTable = @" + serializerTypeName 522 + "::methodMap[typeSignature];"); 523 srcWriter.println("if (!methodTable) {"); 524 srcWriter.indentln("@" + serializerTypeName 525 + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);"); 526 srcWriter.println("}"); 527 srcWriter.println("methodTable[2](streamWriter, instance);"); 528 srcWriter.outdent(); 529 } 530 srcWriter.println("}-*/;"); 531 srcWriter.println(); 532 } 533 534 private void writeStaticFields() { 535 srcWriter.println("private static final JavaScriptObject methodMap = createMethodMap();"); 536 if (shouldEnforceTypeVersioning()) { 537 srcWriter.println("private static final JavaScriptObject signatureMap = createSignatureMap();"); 538 } 539 srcWriter.println(); 540 } 541 } | Popular Tags |