• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // Author: xiaofeng@google.com (Feng Xiao)
32 
33 #include <google/protobuf/compiler/java/java_shared_code_generator.h>
34 
35 #include <memory>
36 
37 #include <google/protobuf/compiler/code_generator.h>
38 #include <google/protobuf/io/printer.h>
39 #include <google/protobuf/io/zero_copy_stream.h>
40 #include <google/protobuf/descriptor.h>
41 #include <google/protobuf/stubs/strutil.h>
42 #include <google/protobuf/compiler/java/java_helpers.h>
43 #include <google/protobuf/compiler/java/java_name_resolver.h>
44 #include <google/protobuf/compiler/java/java_names.h>
45 #include <google/protobuf/descriptor.pb.h>
46 
47 namespace google {
48 namespace protobuf {
49 namespace compiler {
50 namespace java {
51 
SharedCodeGenerator(const FileDescriptor * file,const Options & options)52 SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file,
53                                          const Options& options)
54     : name_resolver_(new ClassNameResolver), file_(file), options_(options) {}
55 
~SharedCodeGenerator()56 SharedCodeGenerator::~SharedCodeGenerator() {}
57 
Generate(GeneratorContext * context,std::vector<std::string> * file_list,std::vector<std::string> * annotation_file_list)58 void SharedCodeGenerator::Generate(
59     GeneratorContext* context, std::vector<std::string>* file_list,
60     std::vector<std::string>* annotation_file_list) {
61   std::string java_package = FileJavaPackage(file_);
62   std::string package_dir = JavaPackageToDir(java_package);
63 
64   if (HasDescriptorMethods(file_, options_.enforce_lite)) {
65     // Generate descriptors.
66     std::string classname = name_resolver_->GetDescriptorClassName(file_);
67     std::string filename = package_dir + classname + ".java";
68     file_list->push_back(filename);
69     std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
70     GeneratedCodeInfo annotations;
71     io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
72         &annotations);
73     std::unique_ptr<io::Printer> printer(
74         new io::Printer(output.get(), '$',
75                         options_.annotate_code ? &annotation_collector : NULL));
76     std::string info_relative_path = classname + ".java.pb.meta";
77     std::string info_full_path = filename + ".pb.meta";
78     printer->Print(
79         "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
80         "// source: $filename$\n"
81         "\n",
82         "filename", file_->name());
83     if (!java_package.empty()) {
84       printer->Print(
85           "package $package$;\n"
86           "\n",
87           "package", java_package);
88     }
89     PrintGeneratedAnnotation(printer.get(), '$',
90                              options_.annotate_code ? info_relative_path : "");
91     printer->Print(
92         "public final class $classname$ {\n"
93         "  public static com.google.protobuf.Descriptors.FileDescriptor\n"
94         "      descriptor;\n"
95         "  static {\n",
96         "classname", classname);
97     printer->Annotate("classname", file_->name());
98     printer->Indent();
99     printer->Indent();
100     GenerateDescriptors(printer.get());
101     printer->Outdent();
102     printer->Outdent();
103     printer->Print(
104         "  }\n"
105         "}\n");
106 
107     if (options_.annotate_code) {
108       std::unique_ptr<io::ZeroCopyOutputStream> info_output(
109           context->Open(info_full_path));
110       annotations.SerializeToZeroCopyStream(info_output.get());
111       annotation_file_list->push_back(info_full_path);
112     }
113 
114     printer.reset();
115     output.reset();
116   }
117 }
118 
GenerateDescriptors(io::Printer * printer)119 void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) {
120   // Embed the descriptor.  We simply serialize the entire FileDescriptorProto
121   // and embed it as a string literal, which is parsed and built into real
122   // descriptors at initialization time.  We unfortunately have to put it in
123   // a string literal, not a byte array, because apparently using a literal
124   // byte array causes the Java compiler to generate *instructions* to
125   // initialize each and every byte of the array, e.g. as if you typed:
126   //   b[0] = 123; b[1] = 456; b[2] = 789;
127   // This makes huge bytecode files and can easily hit the compiler's internal
128   // code size limits (error "code to large").  String literals are apparently
129   // embedded raw, which is what we want.
130   FileDescriptorProto file_proto;
131   file_->CopyTo(&file_proto);
132 
133   std::string file_data;
134   file_proto.SerializeToString(&file_data);
135 
136   printer->Print("java.lang.String[] descriptorData = {\n");
137   printer->Indent();
138 
139   // Limit the number of bytes per line.
140   static const int kBytesPerLine = 40;
141   // Limit the number of lines per string part.
142   static const int kLinesPerPart = 400;
143   // Every block of bytes, start a new string literal, in order to avoid the
144   // 64k length limit. Note that this value needs to be <64k.
145   static const int kBytesPerPart = kBytesPerLine * kLinesPerPart;
146   for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
147     if (i > 0) {
148       if (i % kBytesPerPart == 0) {
149         printer->Print(",\n");
150       } else {
151         printer->Print(" +\n");
152       }
153     }
154     printer->Print("\"$data$\"", "data",
155                    CEscape(file_data.substr(i, kBytesPerLine)));
156   }
157 
158   printer->Outdent();
159   printer->Print("\n};\n");
160 
161   // -----------------------------------------------------------------
162   // Find out all dependencies.
163   std::vector<std::pair<std::string, std::string> > dependencies;
164   for (int i = 0; i < file_->dependency_count(); i++) {
165     std::string filename = file_->dependency(i)->name();
166     std::string package = FileJavaPackage(file_->dependency(i));
167     std::string classname =
168         name_resolver_->GetDescriptorClassName(file_->dependency(i));
169     std::string full_name;
170     if (package.empty()) {
171       full_name = classname;
172     } else {
173       full_name = package + "." + classname;
174     }
175     dependencies.push_back(std::make_pair(filename, full_name));
176   }
177 
178   // -----------------------------------------------------------------
179   // Invoke internalBuildGeneratedFileFrom() to build the file.
180   printer->Print(
181       "descriptor = com.google.protobuf.Descriptors.FileDescriptor\n"
182       "  .internalBuildGeneratedFileFrom(descriptorData,\n");
183   printer->Print(
184       "    new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
185 
186   for (int i = 0; i < dependencies.size(); i++) {
187     const std::string& dependency = dependencies[i].second;
188     printer->Print("      $dependency$.getDescriptor(),\n", "dependency",
189                    dependency);
190   }
191 
192   printer->Print("    });\n");
193 }
194 
195 }  // namespace java
196 }  // namespace compiler
197 }  // namespace protobuf
198 }  // namespace google
199