java_file.cc revision afb4b72037e3f13db208590fc782c4bc8e27f862
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
55namespace google {
56namespace protobuf {
57namespace compiler {
58namespace java {
59
60namespace {
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.
68bool 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.
104void 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
142FileGenerator::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
165FileGenerator::~FileGenerator() {}
166
167bool 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
209void 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
311void 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
387void 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
454template<typename GeneratorClass, typename DescriptorClass>
455static 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
484void 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
526bool 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