• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
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: kenton@google.com (Kenton Varda)
32 //  Based on original Protocol Buffers design by
33 //  Sanjay Ghemawat, Jeff Dean, and others.
34 
35 #include <google/protobuf/compiler/java/java_file.h>
36 #include <google/protobuf/compiler/java/java_enum.h>
37 #include <google/protobuf/compiler/java/java_service.h>
38 #include <google/protobuf/compiler/java/java_extension.h>
39 #include <google/protobuf/compiler/java/java_helpers.h>
40 #include <google/protobuf/compiler/java/java_message.h>
41 #include <google/protobuf/compiler/code_generator.h>
42 #include <google/protobuf/io/printer.h>
43 #include <google/protobuf/io/zero_copy_stream.h>
44 #include <google/protobuf/descriptor.pb.h>
45 #include <google/protobuf/stubs/strutil.h>
46 
47 namespace google {
48 namespace protobuf {
49 namespace compiler {
50 namespace java {
51 
52 namespace {
53 
54 // Recursively searches the given message to see if it contains any extensions.
UsesExtensions(const Message & message)55 bool UsesExtensions(const Message& message) {
56   const Reflection* reflection = message.GetReflection();
57 
58   // We conservatively assume that unknown fields are extensions.
59   if (reflection->GetUnknownFields(message).field_count() > 0) return true;
60 
61   vector<const FieldDescriptor*> fields;
62   reflection->ListFields(message, &fields);
63 
64   for (int i = 0; i < fields.size(); i++) {
65     if (fields[i]->is_extension()) return true;
66 
67     if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
68       if (fields[i]->is_repeated()) {
69         int size = reflection->FieldSize(message, fields[i]);
70         for (int j = 0; j < size; j++) {
71           const Message& sub_message =
72             reflection->GetRepeatedMessage(message, fields[i], j);
73           if (UsesExtensions(sub_message)) return true;
74         }
75       } else {
76         const Message& sub_message = reflection->GetMessage(message, fields[i]);
77         if (UsesExtensions(sub_message)) return true;
78       }
79     }
80   }
81 
82   return false;
83 }
84 
85 
86 }  // namespace
87 
FileGenerator(const FileDescriptor * file)88 FileGenerator::FileGenerator(const FileDescriptor* file)
89   : file_(file),
90     java_package_(FileJavaPackage(file)),
91     classname_(FileClassName(file)) {}
92 
~FileGenerator()93 FileGenerator::~FileGenerator() {}
94 
Validate(string * error)95 bool FileGenerator::Validate(string* error) {
96   // Check that no class name matches the file's class name.  This is a common
97   // problem that leads to Java compile errors that can be hard to understand.
98   // It's especially bad when using the java_multiple_files, since we would
99   // end up overwriting the outer class with one of the inner ones.
100 
101   bool found_conflict = false;
102   for (int i = 0; i < file_->enum_type_count() && !found_conflict; i++) {
103     if (file_->enum_type(i)->name() == classname_) {
104       found_conflict = true;
105     }
106   }
107   for (int i = 0; i < file_->message_type_count() && !found_conflict; i++) {
108     if (file_->message_type(i)->name() == classname_) {
109       found_conflict = true;
110     }
111   }
112   for (int i = 0; i < file_->service_count() && !found_conflict; i++) {
113     if (file_->service(i)->name() == classname_) {
114       found_conflict = true;
115     }
116   }
117 
118   if (found_conflict) {
119     error->assign(file_->name());
120     error->append(
121       ": Cannot generate Java output because the file's outer class name, \"");
122     error->append(classname_);
123     error->append(
124       "\", matches the name of one of the types declared inside it.  "
125       "Please either rename the type or use the java_outer_classname "
126       "option to specify a different outer class name for the .proto file.");
127     return false;
128   }
129 
130   return true;
131 }
132 
Generate(io::Printer * printer)133 void FileGenerator::Generate(io::Printer* printer) {
134   // We don't import anything because we refer to all classes by their
135   // fully-qualified names in the generated source.
136   printer->Print(
137     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
138     "// source: $filename$\n"
139     "\n",
140     "filename", file_->name());
141   if (!java_package_.empty()) {
142     printer->Print(
143       "package $package$;\n"
144       "\n",
145       "package", java_package_);
146   }
147   printer->Print(
148     "public final class $classname$ {\n"
149     "  private $classname$() {}\n",
150     "classname", classname_);
151   printer->Indent();
152 
153   // -----------------------------------------------------------------
154 
155   printer->Print(
156     "public static void registerAllExtensions(\n"
157     "    com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
158     "lite", HasDescriptorMethods(file_) ? "" : "Lite");
159 
160   printer->Indent();
161 
162   for (int i = 0; i < file_->extension_count(); i++) {
163     ExtensionGenerator(file_->extension(i)).GenerateRegistrationCode(printer);
164   }
165 
166   for (int i = 0; i < file_->message_type_count(); i++) {
167     MessageGenerator(file_->message_type(i))
168       .GenerateExtensionRegistrationCode(printer);
169   }
170 
171   printer->Outdent();
172   printer->Print(
173     "}\n");
174 
175   // -----------------------------------------------------------------
176 
177   if (!file_->options().java_multiple_files()) {
178     for (int i = 0; i < file_->enum_type_count(); i++) {
179       EnumGenerator(file_->enum_type(i)).Generate(printer);
180     }
181     for (int i = 0; i < file_->message_type_count(); i++) {
182       MessageGenerator(file_->message_type(i)).Generate(printer);
183     }
184     if (HasGenericServices(file_)) {
185       for (int i = 0; i < file_->service_count(); i++) {
186         ServiceGenerator(file_->service(i)).Generate(printer);
187       }
188     }
189   }
190 
191   // Extensions must be generated in the outer class since they are values,
192   // not classes.
193   for (int i = 0; i < file_->extension_count(); i++) {
194     ExtensionGenerator(file_->extension(i)).Generate(printer);
195   }
196 
197   // Static variables.
198   for (int i = 0; i < file_->message_type_count(); i++) {
199     // TODO(kenton):  Reuse MessageGenerator objects?
200     MessageGenerator(file_->message_type(i)).GenerateStaticVariables(printer);
201   }
202 
203   printer->Print("\n");
204 
205   if (HasDescriptorMethods(file_)) {
206     GenerateEmbeddedDescriptor(printer);
207   } else {
208     printer->Print(
209       "static {\n");
210     printer->Indent();
211 
212     for (int i = 0; i < file_->message_type_count(); i++) {
213       // TODO(kenton):  Reuse MessageGenerator objects?
214       MessageGenerator(file_->message_type(i))
215         .GenerateStaticVariableInitializers(printer);
216     }
217 
218     for (int i = 0; i < file_->extension_count(); i++) {
219       // TODO(kenton):  Reuse ExtensionGenerator objects?
220       ExtensionGenerator(file_->extension(i))
221         .GenerateInitializationCode(printer);
222     }
223 
224     printer->Outdent();
225     printer->Print(
226       "}\n");
227   }
228 
229   // Dummy function we can use to force the static initialization block to
230   // run.  Needed by inner classes.  Cannot be private due to
231   // java_multiple_files option.
232   printer->Print(
233     "\n"
234     "public static void internalForceInit() {}\n");
235 
236   printer->Print(
237     "\n"
238     "// @@protoc_insertion_point(outer_class_scope)\n");
239 
240   printer->Outdent();
241   printer->Print("}\n");
242 }
243 
GenerateEmbeddedDescriptor(io::Printer * printer)244 void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
245   // Embed the descriptor.  We simply serialize the entire FileDescriptorProto
246   // and embed it as a string literal, which is parsed and built into real
247   // descriptors at initialization time.  We unfortunately have to put it in
248   // a string literal, not a byte array, because apparently using a literal
249   // byte array causes the Java compiler to generate *instructions* to
250   // initialize each and every byte of the array, e.g. as if you typed:
251   //   b[0] = 123; b[1] = 456; b[2] = 789;
252   // This makes huge bytecode files and can easily hit the compiler's internal
253   // code size limits (error "code to large").  String literals are apparently
254   // embedded raw, which is what we want.
255   FileDescriptorProto file_proto;
256   file_->CopyTo(&file_proto);
257 
258   string file_data;
259   file_proto.SerializeToString(&file_data);
260 
261   printer->Print(
262     "public static com.google.protobuf.Descriptors.FileDescriptor\n"
263     "    getDescriptor() {\n"
264     "  return descriptor;\n"
265     "}\n"
266     "private static com.google.protobuf.Descriptors.FileDescriptor\n"
267     "    descriptor;\n"
268     "static {\n"
269     "  java.lang.String[] descriptorData = {\n");
270   printer->Indent();
271   printer->Indent();
272 
273   // Only write 40 bytes per line.
274   static const int kBytesPerLine = 40;
275   for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
276     if (i > 0) {
277       // Every 400 lines, start a new string literal, in order to avoid the
278       // 64k length limit.
279       if (i % 400 == 0) {
280         printer->Print(",\n");
281       } else {
282         printer->Print(" +\n");
283       }
284     }
285     printer->Print("\"$data$\"",
286       "data", CEscape(file_data.substr(i, kBytesPerLine)));
287   }
288 
289   printer->Outdent();
290   printer->Print("\n};\n");
291 
292   // -----------------------------------------------------------------
293   // Create the InternalDescriptorAssigner.
294 
295   printer->Print(
296     "com.google.protobuf.Descriptors.FileDescriptor."
297       "InternalDescriptorAssigner assigner =\n"
298     "  new com.google.protobuf.Descriptors.FileDescriptor."
299       "InternalDescriptorAssigner() {\n"
300     "    public com.google.protobuf.ExtensionRegistry assignDescriptors(\n"
301     "        com.google.protobuf.Descriptors.FileDescriptor root) {\n"
302     "      descriptor = root;\n");
303 
304   printer->Indent();
305   printer->Indent();
306   printer->Indent();
307 
308   for (int i = 0; i < file_->message_type_count(); i++) {
309     // TODO(kenton):  Reuse MessageGenerator objects?
310     MessageGenerator(file_->message_type(i))
311       .GenerateStaticVariableInitializers(printer);
312   }
313 
314   for (int i = 0; i < file_->extension_count(); i++) {
315     // TODO(kenton):  Reuse ExtensionGenerator objects?
316     ExtensionGenerator(file_->extension(i))
317       .GenerateInitializationCode(printer);
318   }
319 
320   if (UsesExtensions(file_proto)) {
321     // Must construct an ExtensionRegistry containing all possible extensions
322     // and return it.
323     printer->Print(
324       "com.google.protobuf.ExtensionRegistry registry =\n"
325       "  com.google.protobuf.ExtensionRegistry.newInstance();\n"
326       "registerAllExtensions(registry);\n");
327     for (int i = 0; i < file_->dependency_count(); i++) {
328       printer->Print(
329         "$dependency$.registerAllExtensions(registry);\n",
330         "dependency", ClassName(file_->dependency(i)));
331     }
332     printer->Print(
333       "return registry;\n");
334   } else {
335     printer->Print(
336       "return null;\n");
337   }
338 
339   printer->Outdent();
340   printer->Outdent();
341   printer->Outdent();
342 
343   printer->Print(
344     "    }\n"
345     "  };\n");
346 
347   // -----------------------------------------------------------------
348   // Invoke internalBuildGeneratedFileFrom() to build the file.
349 
350   printer->Print(
351     "com.google.protobuf.Descriptors.FileDescriptor\n"
352     "  .internalBuildGeneratedFileFrom(descriptorData,\n"
353     "    new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
354 
355   for (int i = 0; i < file_->dependency_count(); i++) {
356     if (ShouldIncludeDependency(file_->dependency(i))) {
357       printer->Print(
358         "      $dependency$.getDescriptor(),\n",
359         "dependency", ClassName(file_->dependency(i)));
360     }
361   }
362 
363   printer->Print(
364     "    }, assigner);\n");
365 
366   printer->Outdent();
367   printer->Print(
368     "}\n");
369 }
370 
371 template<typename GeneratorClass, typename DescriptorClass>
GenerateSibling(const string & package_dir,const string & java_package,const DescriptorClass * descriptor,OutputDirectory * output_directory,vector<string> * file_list)372 static void GenerateSibling(const string& package_dir,
373                             const string& java_package,
374                             const DescriptorClass* descriptor,
375                             OutputDirectory* output_directory,
376                             vector<string>* file_list) {
377   string filename = package_dir + descriptor->name() + ".java";
378   file_list->push_back(filename);
379 
380   scoped_ptr<io::ZeroCopyOutputStream> output(
381     output_directory->Open(filename));
382   io::Printer printer(output.get(), '$');
383 
384   printer.Print(
385     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
386     "\n");
387   if (!java_package.empty()) {
388     printer.Print(
389       "package $package$;\n"
390       "\n",
391       "package", java_package);
392   }
393 
394   GeneratorClass(descriptor).Generate(&printer);
395 }
396 
GenerateSiblings(const string & package_dir,OutputDirectory * output_directory,vector<string> * file_list)397 void FileGenerator::GenerateSiblings(const string& package_dir,
398                                      OutputDirectory* output_directory,
399                                      vector<string>* file_list) {
400   if (file_->options().java_multiple_files()) {
401     for (int i = 0; i < file_->enum_type_count(); i++) {
402       GenerateSibling<EnumGenerator>(package_dir, java_package_,
403                                      file_->enum_type(i),
404                                      output_directory, file_list);
405     }
406     for (int i = 0; i < file_->message_type_count(); i++) {
407       GenerateSibling<MessageGenerator>(package_dir, java_package_,
408                                         file_->message_type(i),
409                                         output_directory, file_list);
410     }
411     if (HasGenericServices(file_)) {
412       for (int i = 0; i < file_->service_count(); i++) {
413         GenerateSibling<ServiceGenerator>(package_dir, java_package_,
414                                           file_->service(i),
415                                           output_directory, file_list);
416       }
417     }
418   }
419 }
420 
ShouldIncludeDependency(const FileDescriptor * descriptor)421 bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) {
422   return true;
423 }
424 
425 }  // namespace java
426 }  // namespace compiler
427 }  // namespace protobuf
428 }  // namespace google
429