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: 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 
37 #include <memory>
38 
39 #include <google/protobuf/compiler/java/java_context.h>
40 #include <google/protobuf/compiler/java/java_enum.h>
41 #include <google/protobuf/compiler/java/java_extension.h>
42 #include <google/protobuf/compiler/java/java_generator_factory.h>
43 #include <google/protobuf/compiler/java/java_helpers.h>
44 #include <google/protobuf/compiler/java/java_message.h>
45 #include <google/protobuf/compiler/java/java_name_resolver.h>
46 #include <google/protobuf/compiler/java/java_service.h>
47 #include <google/protobuf/compiler/java/java_shared_code_generator.h>
48 #include <google/protobuf/compiler/code_generator.h>
49 #include <google/protobuf/io/printer.h>
50 #include <google/protobuf/io/zero_copy_stream.h>
51 #include <google/protobuf/descriptor.pb.h>
52 #include <google/protobuf/dynamic_message.h>
53 #include <google/protobuf/stubs/strutil.h>
54 
55 namespace google {
56 namespace protobuf {
57 namespace compiler {
58 namespace java {
59 
60 namespace {
61 
62 
63 // Recursively searches the given message to collect extensions.
64 // Returns true if all the extensions can be recognized. The extensions will be
65 // appended in to the extensions parameter.
66 // Returns false when there are unknown fields, in which case the data in the
67 // extensions output parameter is not reliable and should be discarded.
CollectExtensions(const Message & message,vector<const FieldDescriptor * > * extensions)68 bool CollectExtensions(const Message& message,
69                        vector<const FieldDescriptor*>* extensions) {
70   const Reflection* reflection = message.GetReflection();
71 
72   // There are unknown fields that could be extensions, thus this call fails.
73   if (reflection->GetUnknownFields(message).field_count() > 0) return false;
74 
75   vector<const FieldDescriptor*> fields;
76   reflection->ListFields(message, &fields);
77 
78   for (int i = 0; i < fields.size(); i++) {
79     if (fields[i]->is_extension()) extensions->push_back(fields[i]);
80 
81     if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
82       if (fields[i]->is_repeated()) {
83         int size = reflection->FieldSize(message, fields[i]);
84         for (int j = 0; j < size; j++) {
85           const Message& sub_message =
86             reflection->GetRepeatedMessage(message, fields[i], j);
87           if (!CollectExtensions(sub_message, extensions)) return false;
88         }
89       } else {
90         const Message& sub_message = reflection->GetMessage(message, fields[i]);
91         if (!CollectExtensions(sub_message, extensions)) return false;
92       }
93     }
94   }
95 
96   return true;
97 }
98 
99 // Finds all extensions in the given message and its sub-messages.  If the
100 // message contains unknown fields (which could be extensions), then those
101 // extensions are defined in alternate_pool.
102 // The message will be converted to a DynamicMessage backed by alternate_pool
103 // in order to handle this case.
CollectExtensions(const FileDescriptorProto & file_proto,const DescriptorPool & alternate_pool,vector<const FieldDescriptor * > * extensions,const string & file_data)104 void CollectExtensions(const FileDescriptorProto& file_proto,
105                        const DescriptorPool& alternate_pool,
106                        vector<const FieldDescriptor*>* extensions,
107                        const string& file_data) {
108   if (!CollectExtensions(file_proto, extensions)) {
109     // There are unknown fields in the file_proto, which are probably
110     // extensions. We need to parse the data into a dynamic message based on the
111     // builder-pool to find out all extensions.
112     const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName(
113         file_proto.GetDescriptor()->full_name());
114     GOOGLE_CHECK(file_proto_desc)
115         << "Find unknown fields in FileDescriptorProto when building "
116         << file_proto.name()
117         << ". It's likely that those fields are custom options, however, "
118            "descriptor.proto is not in the transitive dependencies. "
119            "This normally should not happen. Please report a bug.";
120     DynamicMessageFactory factory;
121     scoped_ptr<Message> dynamic_file_proto(
122         factory.GetPrototype(file_proto_desc)->New());
123     GOOGLE_CHECK(dynamic_file_proto.get() != NULL);
124     GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data));
125 
126     // Collect the extensions again from the dynamic message. There should be no
127     // more unknown fields this time, i.e. all the custom options should be
128     // parsed as extensions now.
129     extensions->clear();
130     GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions))
131         << "Find unknown fields in FileDescriptorProto when building "
132         << file_proto.name()
133         << ". It's likely that those fields are custom options, however, "
134            "those options cannot be recognized in the builder pool. "
135            "This normally should not happen. Please report a bug.";
136   }
137 }
138 
139 
140 }  // namespace
141 
FileGenerator(const FileDescriptor * file,bool immutable_api)142 FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
143     : file_(file),
144       java_package_(FileJavaPackage(file, immutable_api)),
145       message_generators_(
146           new scoped_ptr<MessageGenerator>[file->message_type_count()]),
147       extension_generators_(
148           new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
149       context_(new Context(file)),
150       name_resolver_(context_->GetNameResolver()),
151       immutable_api_(immutable_api) {
152   classname_ = name_resolver_->GetFileClassName(file, immutable_api);
153   generator_factory_.reset(
154       new ImmutableGeneratorFactory(context_.get()));
155   for (int i = 0; i < file_->message_type_count(); ++i) {
156     message_generators_[i].reset(
157         generator_factory_->NewMessageGenerator(file_->message_type(i)));
158   }
159   for (int i = 0; i < file_->extension_count(); ++i) {
160     extension_generators_[i].reset(
161         generator_factory_->NewExtensionGenerator(file_->extension(i)));
162   }
163 }
164 
~FileGenerator()165 FileGenerator::~FileGenerator() {}
166 
Validate(string * error)167 bool FileGenerator::Validate(string* error) {
168   // Check that no class name matches the file's class name.  This is a common
169   // problem that leads to Java compile errors that can be hard to understand.
170   // It's especially bad when using the java_multiple_files, since we would
171   // end up overwriting the outer class with one of the inner ones.
172   if (name_resolver_->HasConflictingClassName(file_, classname_)) {
173     error->assign(file_->name());
174     error->append(
175       ": Cannot generate Java output because the file's outer class name, \"");
176     error->append(classname_);
177     error->append(
178       "\", matches the name of one of the types declared inside it.  "
179       "Please either rename the type or use the java_outer_classname "
180       "option to specify a different outer class name for the .proto file.");
181     return false;
182   }
183   // If java_outer_classname option is not set and the default outer class name
184   // conflicts with a type defined in the message, we will append a suffix to
185   // avoid the conflict. This allows proto1 API protos to be dual-compiled into
186   // proto2 API without code change. When this happens we'd like to issue an
187   // warning to let the user know that the outer class name has been changed.
188   // Although we only do this automatic naming fix for immutable API, mutable
189   // outer class name will also be affected as it's contructed from immutable
190   // outer class name with an additional "Mutable" prefix. Since the naming
191   // change in mutable API is not caused by a naming conflict, we generate the
192   // warning for immutable API only.
193   if (immutable_api_ && !file_->options().has_java_outer_classname()) {
194     string default_classname =
195         name_resolver_->GetFileDefaultImmutableClassName(file_);
196     if (default_classname != classname_) {
197       GOOGLE_LOG(WARNING) << file_->name() << ": The default outer class name, \""
198                    << default_classname << "\", conflicts with a type "
199                    << "declared in the proto file and an alternative outer "
200                    << "class name is used: \"" << classname_ << "\". To avoid "
201                    << "this warning, please use the java_outer_classname "
202                    << "option to specify a different outer class name for "
203                    << "the .proto file.";
204     }
205   }
206   return true;
207 }
208 
Generate(io::Printer * printer)209 void FileGenerator::Generate(io::Printer* printer) {
210   // We don't import anything because we refer to all classes by their
211   // fully-qualified names in the generated source.
212   printer->Print(
213     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
214     "// source: $filename$\n"
215     "\n",
216     "filename", file_->name());
217   if (!java_package_.empty()) {
218     printer->Print(
219       "package $package$;\n"
220       "\n",
221       "package", java_package_);
222   }
223   printer->Print(
224     "public final class $classname$ {\n"
225     "  private $classname$() {}\n",
226     "classname", classname_);
227   printer->Indent();
228 
229   // -----------------------------------------------------------------
230 
231   printer->Print(
232     "public static void registerAllExtensions(\n"
233     "    com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
234     "lite", HasDescriptorMethods(file_) ? "" : "Lite");
235 
236   printer->Indent();
237 
238   for (int i = 0; i < file_->extension_count(); i++) {
239     extension_generators_[i]->GenerateRegistrationCode(printer);
240   }
241 
242   for (int i = 0; i < file_->message_type_count(); i++) {
243     message_generators_[i]->GenerateExtensionRegistrationCode(printer);
244   }
245 
246   printer->Outdent();
247   printer->Print(
248     "}\n");
249 
250   // -----------------------------------------------------------------
251 
252   if (!MultipleJavaFiles(file_, immutable_api_)) {
253     for (int i = 0; i < file_->enum_type_count(); i++) {
254       EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
255           .Generate(printer);
256     }
257     for (int i = 0; i < file_->message_type_count(); i++) {
258       message_generators_[i]->GenerateInterface(printer);
259       message_generators_[i]->Generate(printer);
260     }
261     if (HasGenericServices(file_)) {
262       for (int i = 0; i < file_->service_count(); i++) {
263         scoped_ptr<ServiceGenerator> generator(
264             generator_factory_->NewServiceGenerator(file_->service(i)));
265         generator->Generate(printer);
266       }
267     }
268   }
269 
270   // Extensions must be generated in the outer class since they are values,
271   // not classes.
272   for (int i = 0; i < file_->extension_count(); i++) {
273     extension_generators_[i]->Generate(printer);
274   }
275 
276   // Static variables.
277   for (int i = 0; i < file_->message_type_count(); i++) {
278     message_generators_[i]->GenerateStaticVariables(printer);
279   }
280 
281   printer->Print("\n");
282 
283   if (HasDescriptorMethods(file_)) {
284     if (immutable_api_) {
285       GenerateDescriptorInitializationCodeForImmutable(printer);
286     } else {
287       GenerateDescriptorInitializationCodeForMutable(printer);
288     }
289   } else {
290     printer->Print(
291       "static {\n");
292     printer->Indent();
293 
294     for (int i = 0; i < file_->message_type_count(); i++) {
295       message_generators_[i]->GenerateStaticVariableInitializers(printer);
296     }
297 
298     printer->Outdent();
299     printer->Print(
300       "}\n");
301   }
302 
303   printer->Print(
304     "\n"
305     "// @@protoc_insertion_point(outer_class_scope)\n");
306 
307   printer->Outdent();
308   printer->Print("}\n");
309 }
310 
GenerateDescriptorInitializationCodeForImmutable(io::Printer * printer)311 void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
312     io::Printer* printer) {
313   printer->Print(
314     "public static com.google.protobuf.Descriptors.FileDescriptor\n"
315     "    getDescriptor() {\n"
316     "  return descriptor;\n"
317     "}\n"
318     "private static com.google.protobuf.Descriptors.FileDescriptor\n"
319     "    descriptor;\n"
320     "static {\n");
321   printer->Indent();
322 
323   SharedCodeGenerator shared_code_generator(file_);
324   shared_code_generator.GenerateDescriptors(printer);
325 
326   for (int i = 0; i < file_->message_type_count(); i++) {
327     message_generators_[i]->GenerateStaticVariableInitializers(printer);
328   }
329   for (int i = 0; i < file_->extension_count(); i++) {
330     extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
331   }
332 
333   // Proto compiler builds a DescriptorPool, which holds all the descriptors to
334   // generate, when processing the ".proto" files. We call this DescriptorPool
335   // the parsed pool (a.k.a. file_->pool()).
336   //
337   // Note that when users try to extend the (.*)DescriptorProto in their
338   // ".proto" files, it does not affect the pre-built FileDescriptorProto class
339   // in proto compiler. When we put the descriptor data in the file_proto, those
340   // extensions become unknown fields.
341   //
342   // Now we need to find out all the extension value to the (.*)DescriptorProto
343   // in the file_proto message, and prepare an ExtensionRegistry to return.
344   //
345   // To find those extensions, we need to parse the data into a dynamic message
346   // of the FileDescriptor based on the builder-pool, then we can use
347   // reflections to find all extension fields
348   FileDescriptorProto file_proto;
349   file_->CopyTo(&file_proto);
350   string file_data;
351   file_proto.SerializeToString(&file_data);
352   vector<const FieldDescriptor*> extensions;
353   CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
354 
355   if (extensions.size() > 0) {
356     // Must construct an ExtensionRegistry containing all existing extensions
357     // and use it to parse the descriptor data again to recognize extensions.
358     printer->Print(
359       "com.google.protobuf.ExtensionRegistry registry =\n"
360       "    com.google.protobuf.ExtensionRegistry.newInstance();\n");
361     for (int i = 0; i < extensions.size(); i++) {
362       scoped_ptr<ExtensionGenerator> generator(
363           generator_factory_->NewExtensionGenerator(extensions[i]));
364       generator->GenerateRegistrationCode(printer);
365     }
366     printer->Print(
367       "com.google.protobuf.Descriptors.FileDescriptor\n"
368       "    .internalUpdateFileDescriptor(descriptor, registry);\n");
369   }
370 
371   // Force descriptor initialization of all dependencies.
372   for (int i = 0; i < file_->dependency_count(); i++) {
373     if (ShouldIncludeDependency(file_->dependency(i), true)) {
374       string dependency =
375           name_resolver_->GetImmutableClassName(file_->dependency(i));
376       printer->Print(
377         "$dependency$.getDescriptor();\n",
378         "dependency", dependency);
379     }
380   }
381 
382   printer->Outdent();
383   printer->Print(
384     "}\n");
385 }
386 
GenerateDescriptorInitializationCodeForMutable(io::Printer * printer)387 void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer* printer) {
388   printer->Print(
389     "public static com.google.protobuf.Descriptors.FileDescriptor\n"
390     "    getDescriptor() {\n"
391     "  return descriptor;\n"
392     "}\n"
393     "private static com.google.protobuf.Descriptors.FileDescriptor\n"
394     "    descriptor;\n"
395     "static {\n");
396   printer->Indent();
397 
398   printer->Print(
399     "descriptor = $immutable_package$.$descriptor_classname$.descriptor;\n",
400     "immutable_package", FileJavaPackage(file_, true),
401     "descriptor_classname", name_resolver_->GetDescriptorClassName(file_));
402 
403   for (int i = 0; i < file_->message_type_count(); i++) {
404     message_generators_[i]->GenerateStaticVariableInitializers(printer);
405   }
406   for (int i = 0; i < file_->extension_count(); i++) {
407     extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
408   }
409 
410   // Check if custom options exist. If any, try to load immutable classes since
411   // custom options are only represented with immutable messages.
412   FileDescriptorProto file_proto;
413   file_->CopyTo(&file_proto);
414   string file_data;
415   file_proto.SerializeToString(&file_data);
416   vector<const FieldDescriptor*> extensions;
417   CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
418 
419   if (extensions.size() > 0) {
420     // Try to load immutable messages' outer class. Its initialization code
421     // will take care of interpreting custom options.
422     printer->Print(
423       "try {\n"
424       // Note that we have to load the immutable class dynamically here as
425       // we want the mutable code to be independent from the immutable code
426       // at compile time. It is required to implement dual-compile for
427       // mutable and immutable API in blaze.
428       "  java.lang.Class immutableClass = java.lang.Class.forName(\n"
429       "      \"$immutable_classname$\");\n"
430       "} catch (java.lang.ClassNotFoundException e) {\n"
431       // The immutable class can not be found. Custom options are left
432       // as unknown fields.
433       // TODO(xiaofeng): inform the user with a warning?
434       "}\n",
435       "immutable_classname", name_resolver_->GetImmutableClassName(file_));
436   }
437 
438   // Force descriptor initialization of all dependencies.
439   for (int i = 0; i < file_->dependency_count(); i++) {
440     if (ShouldIncludeDependency(file_->dependency(i), false)) {
441       string dependency = name_resolver_->GetMutableClassName(
442           file_->dependency(i));
443       printer->Print(
444         "$dependency$.getDescriptor();\n",
445         "dependency", dependency);
446     }
447   }
448 
449   printer->Outdent();
450   printer->Print(
451     "}\n");
452 }
453 
454 template<typename GeneratorClass, typename DescriptorClass>
GenerateSibling(const string & package_dir,const string & java_package,const DescriptorClass * descriptor,GeneratorContext * context,vector<string> * file_list,const string & name_suffix,GeneratorClass * generator,void (GeneratorClass::* pfn)(io::Printer * printer))455 static void GenerateSibling(const string& package_dir,
456                             const string& java_package,
457                             const DescriptorClass* descriptor,
458                             GeneratorContext* context,
459                             vector<string>* file_list,
460                             const string& name_suffix,
461                             GeneratorClass* generator,
462                             void (GeneratorClass::*pfn)(io::Printer* printer)) {
463   string filename = package_dir + descriptor->name() + name_suffix + ".java";
464   file_list->push_back(filename);
465 
466   scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
467   io::Printer printer(output.get(), '$');
468 
469   printer.Print(
470     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
471     "// source: $filename$\n"
472     "\n",
473     "filename", descriptor->file()->name());
474   if (!java_package.empty()) {
475     printer.Print(
476       "package $package$;\n"
477       "\n",
478       "package", java_package);
479   }
480 
481   (generator->*pfn)(&printer);
482 }
483 
GenerateSiblings(const string & package_dir,GeneratorContext * context,vector<string> * file_list)484 void FileGenerator::GenerateSiblings(const string& package_dir,
485                                      GeneratorContext* context,
486                                      vector<string>* file_list) {
487   if (MultipleJavaFiles(file_, immutable_api_)) {
488     for (int i = 0; i < file_->enum_type_count(); i++) {
489       EnumGenerator generator(file_->enum_type(i), immutable_api_,
490                               context_.get());
491       GenerateSibling<EnumGenerator>(package_dir, java_package_,
492                                      file_->enum_type(i),
493                                      context, file_list, "",
494                                      &generator,
495                                      &EnumGenerator::Generate);
496     }
497     for (int i = 0; i < file_->message_type_count(); i++) {
498       if (immutable_api_) {
499         GenerateSibling<MessageGenerator>(package_dir, java_package_,
500                                           file_->message_type(i),
501                                           context, file_list,
502                                           "OrBuilder",
503                                           message_generators_[i].get(),
504                                           &MessageGenerator::GenerateInterface);
505       }
506       GenerateSibling<MessageGenerator>(package_dir, java_package_,
507                                         file_->message_type(i),
508                                         context, file_list, "",
509                                         message_generators_[i].get(),
510                                         &MessageGenerator::Generate);
511     }
512     if (HasGenericServices(file_)) {
513       for (int i = 0; i < file_->service_count(); i++) {
514         scoped_ptr<ServiceGenerator> generator(
515             generator_factory_->NewServiceGenerator(file_->service(i)));
516         GenerateSibling<ServiceGenerator>(package_dir, java_package_,
517                                           file_->service(i),
518                                           context, file_list, "",
519                                           generator.get(),
520                                           &ServiceGenerator::Generate);
521       }
522     }
523   }
524 }
525 
ShouldIncludeDependency(const FileDescriptor * descriptor,bool immutable_api)526 bool FileGenerator::ShouldIncludeDependency(
527     const FileDescriptor* descriptor, bool immutable_api) {
528   return true;
529 }
530 
531 }  // namespace java
532 }  // namespace compiler
533 }  // namespace protobuf
534 }  // namespace google
535