/** * Writes a method to produce a map of class name to type string for Java. * * <pre> * private static Map<String<?>, String> loadSignaturesJava() { * Map<String<?>, String> result = new HashMap<String<?>, String>(); * result.put( * com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer.concreteType(), * "java.lang.String/2004016611"); * ... * return result; * } * </pre> */ private void writeLoadSignaturesJava() { srcWriter.println("@SuppressWarnings(\"deprecation\")"); srcWriter.println("private static Map<String, String> loadSignaturesJava() {"); srcWriter.indent(); srcWriter.println("Map<String, String> result = new HashMap<String, String>();"); for (JType type : getSerializableTypes()) { String typeString = typeStrings.get(type); if (!serializationOracle.maybeInstantiated(type) && !deserializationOracle.maybeInstantiated(type)) { continue; } String typeRef; JClassType customSerializer = SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type); if (customSerializer != null && CustomFieldSerializerValidator.getConcreteTypeMethod(customSerializer) != null) { typeRef = customSerializer.getQualifiedSourceName() + ".concreteType()"; } else { typeRef = '"' + SerializationUtils.getRpcTypeName(type) + '"'; } srcWriter.println("result.put(" + typeRef + ", \"" + typeString + "\");"); } srcWriter.println("return result;"); srcWriter.outdent(); srcWriter.println("}"); srcWriter.println(); }
/** * @param type * @return */ private String getTypeString(JType type) { String typeString = SerializationUtils.getRpcTypeName(type) + "/" + SerializationUtils.getSerializationSignature(typeOracle, type); return typeString; }
protected String computeTypeNameExpression(JType paramType) { String typeName; if (typeStrings.containsKey(paramType)) { typeName = typeStrings.get(paramType); } else { typeName = SerializationUtils.getRpcTypeName(paramType); } return typeName == null ? null : ('"' + typeName + '"'); }
protected String writeSerializationPolicyFile( TreeLogger logger, GeneratorContextExt ctx, SerializableTypeOracle serializationSto, SerializableTypeOracle deserializationSto) throws UnableToCompleteException { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStreamWriter osw = new OutputStreamWriter( baos, SerializationPolicyLoader.SERIALIZATION_POLICY_FILE_ENCODING); TypeOracle oracle = ctx.getTypeOracle(); PrintWriter pw = new PrintWriter(osw); JType[] serializableTypes = unionOfTypeArrays( serializationSto.getSerializableTypes(), deserializationSto.getSerializableTypes(), new JType[] {serviceIntf}); for (int i = 0; i < serializableTypes.length; ++i) { JType type = serializableTypes[i]; String binaryTypeName = SerializationUtils.getRpcTypeName(type); pw.print(binaryTypeName); pw.print(", " + Boolean.toString(deserializationSto.isSerializable(type))); pw.print(", " + Boolean.toString(deserializationSto.maybeInstantiated(type))); pw.print(", " + Boolean.toString(serializationSto.isSerializable(type))); pw.print(", " + Boolean.toString(serializationSto.maybeInstantiated(type))); pw.print(", " + typeStrings.get(type)); /* * Include the serialization signature to bump the RPC file name if * obfuscated identifiers are used. */ pw.print(", " + SerializationUtils.getSerializationSignature(oracle, type)); pw.print('\n'); /* * Emit client-side field information for classes that may be enhanced * on the server. Each line consists of a comma-separated list * containing the keyword '@ClientFields', the class name, and a list of * all potentially serializable client-visible fields. */ if ((type instanceof JClassType) && ((JClassType) type).isEnhanced()) { JField[] fields = ((JClassType) type).getFields(); JField[] rpcFields = new JField[fields.length]; int numRpcFields = 0; for (JField f : fields) { if (f.isTransient() || f.isStatic() || f.isFinal()) { continue; } rpcFields[numRpcFields++] = f; } pw.print(SerializationPolicyLoader.CLIENT_FIELDS_KEYWORD); pw.print(','); pw.print(binaryTypeName); for (int idx = 0; idx < numRpcFields; idx++) { pw.print(','); pw.print(rpcFields[idx].getName()); } pw.print('\n'); } } // Closes the wrapped streams. pw.close(); byte[] serializationPolicyFileContents = baos.toByteArray(); String serializationPolicyName = Util.computeStrongName(serializationPolicyFileContents); String serializationPolicyFileName = SerializationPolicyLoader.getSerializationPolicyFileName(serializationPolicyName); OutputStream os = ctx.tryCreateResource(logger, serializationPolicyFileName); if (os != null) { os.write(serializationPolicyFileContents); GeneratedResource resource = ctx.commitResource(logger, os); /* * Record which proxy class created the resource. A manifest will be * emitted by the RpcPolicyManifestLinker. */ emitPolicyFileArtifact(logger, ctx, resource.getPartialPath()); } else { if (logger.isLoggable(TreeLogger.TRACE)) { logger.log( TreeLogger.TRACE, "SerializationPolicy file for RemoteService '" + serviceIntf.getQualifiedSourceName() + "' already exists; no need to rewrite it.", null); } } return serializationPolicyName; } catch (UnsupportedEncodingException e) { logger.log( TreeLogger.ERROR, SerializationPolicyLoader.SERIALIZATION_POLICY_FILE_ENCODING + " is not supported", e); throw new UnableToCompleteException(); } catch (IOException e) { logger.log(TreeLogger.ERROR, null, e); throw new UnableToCompleteException(); } }
/** * Creates the client-side proxy class. * * @throws UnableToCompleteException */ public String create(TreeLogger logger, GeneratorContextExt context) throws UnableToCompleteException { TypeOracle typeOracle = context.getTypeOracle(); JClassType serviceAsync = typeOracle.findType(serviceIntf.getQualifiedSourceName() + "Async"); if (serviceAsync == null) { logger.branch( TreeLogger.ERROR, "Could not find an asynchronous version for the service interface " + serviceIntf.getQualifiedSourceName(), null); RemoteServiceAsyncValidator.logValidAsyncInterfaceDeclaration(logger, serviceIntf); throw new UnableToCompleteException(); } SourceWriter srcWriter = getSourceWriter(logger, context, serviceAsync); if (srcWriter == null) { return getProxyQualifiedName(); } // Make sure that the async and synchronous versions of the RemoteService // agree with one another // RemoteServiceAsyncValidator rsav = new RemoteServiceAsyncValidator(logger, typeOracle); Map<JMethod, JMethod> syncMethToAsyncMethMap = rsav.validate(logger, serviceIntf, serviceAsync); final PropertyOracle propertyOracle = context.getPropertyOracle(); // Load the blacklist/whitelist TypeFilter blacklistTypeFilter = new BlacklistTypeFilter(logger, propertyOracle); // Determine the set of serializable types Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_STOB); SerializableTypeOracleBuilder typesSentFromBrowserBuilder = new SerializableTypeOracleBuilder(logger, propertyOracle, context); typesSentFromBrowserBuilder.setTypeFilter(blacklistTypeFilter); SerializableTypeOracleBuilder typesSentToBrowserBuilder = new SerializableTypeOracleBuilder(logger, propertyOracle, context); typesSentToBrowserBuilder.setTypeFilter(blacklistTypeFilter); addRoots(logger, typeOracle, typesSentFromBrowserBuilder, typesSentToBrowserBuilder); try { ConfigurationProperty prop = context .getPropertyOracle() .getConfigurationProperty(TypeSerializerCreator.GWT_ELIDE_TYPE_NAMES_FROM_RPC); elideTypeNames = Boolean.parseBoolean(prop.getValues().get(0)); } catch (BadPropertyValueException e) { logger.log( TreeLogger.ERROR, "Configuration property " + TypeSerializerCreator.GWT_ELIDE_TYPE_NAMES_FROM_RPC + " is not defined. Is RemoteService.gwt.xml inherited?"); throw new UnableToCompleteException(); } // Decide what types to send in each direction. // Log the decisions to a string that will be written later in this method SerializableTypeOracle typesSentFromBrowser; SerializableTypeOracle typesSentToBrowser; String rpcLog; { StringWriter stringWriter = new StringWriter(); PrintWriter writer = new PrintWriter(stringWriter); typesSentFromBrowserBuilder.setLogOutputWriter(writer); typesSentToBrowserBuilder.setLogOutputWriter(writer); writer.write("====================================\n"); writer.write("Types potentially sent from browser:\n"); writer.write("====================================\n\n"); writer.flush(); typesSentFromBrowser = typesSentFromBrowserBuilder.build(logger); writer.write("===================================\n"); writer.write("Types potentially sent from server:\n"); writer.write("===================================\n\n"); writer.flush(); typesSentToBrowser = typesSentToBrowserBuilder.build(logger); writer.close(); rpcLog = stringWriter.toString(); } event.end(); generateTypeHandlers(logger, context, typesSentFromBrowser, typesSentToBrowser); String serializationPolicyStrongName = writeSerializationPolicyFile(logger, context, typesSentFromBrowser, typesSentToBrowser); String remoteServiceInterfaceName = elideTypeNames ? TypeNameObfuscator.SERVICE_INTERFACE_ID : SerializationUtils.getRpcTypeName(serviceIntf); generateProxyFields( srcWriter, typesSentFromBrowser, serializationPolicyStrongName, remoteServiceInterfaceName); generateProxyContructor(srcWriter); generateProxyMethods(srcWriter, typesSentFromBrowser, typeOracle, syncMethToAsyncMethMap); generateStreamWriterOverride(srcWriter); generateCheckRpcTokenTypeOverride(srcWriter, typeOracle, typesSentFromBrowser); srcWriter.commit(logger); if (context.isProdMode() || logger.isLoggable(TreeLogger.DEBUG)) { // Create an artifact explaining STOB's decisions. It will be emitted by // RpcLogLinker context.commitArtifact( logger, new RpcLogArtifact( serviceIntf.getQualifiedSourceName(), serializationPolicyStrongName, rpcLog)); } return getProxyQualifiedName(); }