// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // 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, const Options& options) : name_resolver_(new ClassNameResolver), file_(file), options_(options) {} SharedCodeGenerator::~SharedCodeGenerator() { } void SharedCodeGenerator::Generate(GeneratorContext* context, std::vector* file_list, std::vector* annotation_file_list) { string java_package = FileJavaPackage(file_); string package_dir = JavaPackageToDir(java_package); if (HasDescriptorMethods(file_, options_.enforce_lite)) { // Generate descriptors. string classname = name_resolver_->GetDescriptorClassName(file_); string filename = package_dir + classname + ".java"; file_list->push_back(filename); std::unique_ptr output(context->Open(filename)); GeneratedCodeInfo annotations; io::AnnotationProtoCollector annotation_collector( &annotations); std::unique_ptr printer( new io::Printer(output.get(), '$', options_.annotate_code ? &annotation_collector : NULL)); string info_relative_path = classname + ".java.pb.meta"; string info_full_path = filename + ".pb.meta"; 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); } PrintGeneratedAnnotation(printer.get(), '$', options_.annotate_code ? info_relative_path : ""); printer->Print( "public final class $classname$ {\n" " public static com.google.protobuf.Descriptors.FileDescriptor\n" " descriptor;\n" " static {\n", "classname", classname); printer->Annotate("classname", file_->name()); printer->Indent(); printer->Indent(); GenerateDescriptors(printer.get()); printer->Outdent(); printer->Outdent(); printer->Print( " }\n" "}\n"); if (options_.annotate_code) { std::unique_ptr info_output( context->Open(info_full_path)); annotations.SerializeToZeroCopyStream(info_output.get()); annotation_file_list->push_back(info_full_path); } 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(); // Limit the number of bytes per line. static const int kBytesPerLine = 40; // Limit the number of lines per string part. static const int kLinesPerPart = 400; // Every block of bytes, start a new string literal, in order to avoid the // 64k length limit. Note that this value needs to be <64k. static const int kBytesPerPart = kBytesPerLine * kLinesPerPart; for (int i = 0; i < file_data.size(); i += kBytesPerLine) { if (i > 0) { if (i % kBytesPerPart == 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. std::vector > dependencies; for (int i = 0; i < file_->dependency_count(); i++) { string filename = file_->dependency(i)->name(); string package = FileJavaPackage(file_->dependency(i)); string classname = name_resolver_->GetDescriptorClassName( file_->dependency(i)); string full_name; if (package.empty()) { full_name = classname; } else { full_name = package + "." + classname; } dependencies.push_back(std::make_pair(filename, full_name)); } // ----------------------------------------------------------------- // Invoke internalBuildGeneratedFileFrom() to build the file. printer->Print( "com.google.protobuf.Descriptors.FileDescriptor\n" " .internalBuildGeneratedFileFrom(descriptorData,\n"); printer->Print( " 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"); } } // namespace java } // namespace compiler } // namespace protobuf } // namespace google