// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // http://code.google.com/p/protobuf/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: xiaofeng@google.com (Feng Xiao) #include #include #include #include #include #include #include #include #include #include namespace google { namespace protobuf { namespace compiler { namespace java { SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file) : name_resolver_(new ClassNameResolver), file_(file) { } SharedCodeGenerator::~SharedCodeGenerator() { } void SharedCodeGenerator::Generate(GeneratorContext* context, vector* file_list) { string java_package = FileJavaPackage(file_); string package_dir = JavaPackageToDir(java_package); if (HasDescriptorMethods(file_)) { // Generate descriptors. string classname = name_resolver_->GetDescriptorClassName(file_); string filename = package_dir + classname + ".java"; file_list->push_back(filename); scoped_ptr output(context->Open(filename)); scoped_ptr printer(new io::Printer(output.get(), '$')); printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" "\n", "filename", file_->name()); if (!java_package.empty()) { printer->Print( "package $package$;\n" "\n", "package", java_package); } printer->Print( "public final class $classname$ {\n" " public static com.google.protobuf.Descriptors.FileDescriptor\n" " descriptor;\n" " static {\n", "classname", classname); printer->Indent(); printer->Indent(); GenerateDescriptors(printer.get()); printer->Outdent(); printer->Outdent(); printer->Print( " }\n" "}\n"); printer.reset(); output.reset(); } } void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) { // Embed the descriptor. We simply serialize the entire FileDescriptorProto // and embed it as a string literal, which is parsed and built into real // descriptors at initialization time. We unfortunately have to put it in // a string literal, not a byte array, because apparently using a literal // byte array causes the Java compiler to generate *instructions* to // initialize each and every byte of the array, e.g. as if you typed: // b[0] = 123; b[1] = 456; b[2] = 789; // This makes huge bytecode files and can easily hit the compiler's internal // code size limits (error "code to large"). String literals are apparently // embedded raw, which is what we want. FileDescriptorProto file_proto; file_->CopyTo(&file_proto); string file_data; file_proto.SerializeToString(&file_data); printer->Print( "java.lang.String[] descriptorData = {\n"); printer->Indent(); // Only write 40 bytes per line. static const int kBytesPerLine = 40; for (int i = 0; i < file_data.size(); i += kBytesPerLine) { if (i > 0) { // Every 400 lines, start a new string literal, in order to avoid the // 64k length limit. if (i % 400 == 0) { printer->Print(",\n"); } else { printer->Print(" +\n"); } } printer->Print("\"$data$\"", "data", CEscape(file_data.substr(i, kBytesPerLine))); } printer->Outdent(); printer->Print("\n};\n"); // ----------------------------------------------------------------- // Create the InternalDescriptorAssigner. printer->Print( "com.google.protobuf.Descriptors.FileDescriptor." "InternalDescriptorAssigner assigner =\n" " new com.google.protobuf.Descriptors.FileDescriptor." " InternalDescriptorAssigner() {\n" " public com.google.protobuf.ExtensionRegistry assignDescriptors(\n" " com.google.protobuf.Descriptors.FileDescriptor root) {\n" " descriptor = root;\n" // Custom options will be handled when immutable messages' outer class is // loaded. Here we just return null and let custom options be unknown // fields. " return null;\n" " }\n" " };\n"); // ----------------------------------------------------------------- // Find out all dependencies. vector > dependencies; for (int i = 0; i < file_->dependency_count(); i++) { if (ShouldIncludeDependency(file_->dependency(i))) { string filename = file_->dependency(i)->name(); string classname = FileJavaPackage(file_->dependency(i)) + "." + name_resolver_->GetDescriptorClassName( file_->dependency(i)); dependencies.push_back(make_pair(filename, classname)); } } // ----------------------------------------------------------------- // Invoke internalBuildGeneratedFileFrom() to build the file. printer->Print( "com.google.protobuf.Descriptors.FileDescriptor\n" " .internalBuildGeneratedFileFrom(descriptorData,\n" " new com.google.protobuf.Descriptors.FileDescriptor[] {\n"); for (int i = 0; i < dependencies.size(); i++) { const string& dependency = dependencies[i].second; printer->Print( " $dependency$.getDescriptor(),\n", "dependency", dependency); } printer->Print( " }, assigner);\n"); } bool SharedCodeGenerator::ShouldIncludeDependency( const FileDescriptor* descriptor) { return true; } } // namespace java } // namespace compiler } // namespace protobuf } // namespace google