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/dynamic_message.h>
46#include <google/protobuf/stubs/strutil.h>
47
48namespace google {
49namespace protobuf {
50namespace compiler {
51namespace java {
52
53namespace {
54
55
56// Recursively searches the given message to collect extensions.
57// Returns true if all the extensions can be recognized. The extensions will be
58// appended in to the extensions parameter.
59// Returns false when there are unknown fields, in which case the data in the
60// extensions output parameter is not reliable and should be discarded.
61bool CollectExtensions(const Message& message,
62                       vector<const FieldDescriptor*>* extensions) {
63  const Reflection* reflection = message.GetReflection();
64
65  // There are unknown fields that could be extensions, thus this call fails.
66  if (reflection->GetUnknownFields(message).field_count() > 0) return false;
67
68  vector<const FieldDescriptor*> fields;
69  reflection->ListFields(message, &fields);
70
71  for (int i = 0; i < fields.size(); i++) {
72    if (fields[i]->is_extension()) extensions->push_back(fields[i]);
73
74    if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
75      if (fields[i]->is_repeated()) {
76        int size = reflection->FieldSize(message, fields[i]);
77        for (int j = 0; j < size; j++) {
78          const Message& sub_message =
79            reflection->GetRepeatedMessage(message, fields[i], j);
80          if (!CollectExtensions(sub_message, extensions)) return false;
81        }
82      } else {
83        const Message& sub_message = reflection->GetMessage(message, fields[i]);
84        if (!CollectExtensions(sub_message, extensions)) return false;
85      }
86    }
87  }
88
89  return true;
90}
91
92// Finds all extensions in the given message and its sub-messages.  If the
93// message contains unknown fields (which could be extensions), then those
94// extensions are defined in alternate_pool.
95// The message will be converted to a DynamicMessage backed by alternate_pool
96// in order to handle this case.
97void CollectExtensions(const FileDescriptorProto& file_proto,
98                       const DescriptorPool& alternate_pool,
99                       vector<const FieldDescriptor*>* extensions,
100                       const string& file_data) {
101  if (!CollectExtensions(file_proto, extensions)) {
102    // There are unknown fields in the file_proto, which are probably
103    // extensions. We need to parse the data into a dynamic message based on the
104    // builder-pool to find out all extensions.
105    const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName(
106        file_proto.GetDescriptor()->full_name());
107    GOOGLE_CHECK(file_proto_desc)
108        << "Find unknown fields in FileDescriptorProto when building "
109        << file_proto.name()
110        << ". It's likely that those fields are custom options, however, "
111           "descriptor.proto is not in the transitive dependencies. "
112           "This normally should not happen. Please report a bug.";
113    DynamicMessageFactory factory;
114    scoped_ptr<Message> dynamic_file_proto(
115        factory.GetPrototype(file_proto_desc)->New());
116    GOOGLE_CHECK(dynamic_file_proto.get() != NULL);
117    GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data));
118
119    // Collect the extensions again from the dynamic message. There should be no
120    // more unknown fields this time, i.e. all the custom options should be
121    // parsed as extensions now.
122    extensions->clear();
123    GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions))
124        << "Find unknown fields in FileDescriptorProto when building "
125        << file_proto.name()
126        << ". It's likely that those fields are custom options, however, "
127           "those options cannot be recognized in the builder pool. "
128           "This normally should not happen. Please report a bug.";
129  }
130}
131
132
133}  // namespace
134
135FileGenerator::FileGenerator(const FileDescriptor* file)
136  : file_(file),
137    java_package_(FileJavaPackage(file)),
138    classname_(FileClassName(file)) {
139}
140
141FileGenerator::~FileGenerator() {}
142
143bool FileGenerator::Validate(string* error) {
144  // Check that no class name matches the file's class name.  This is a common
145  // problem that leads to Java compile errors that can be hard to understand.
146  // It's especially bad when using the java_multiple_files, since we would
147  // end up overwriting the outer class with one of the inner ones.
148
149  bool found_conflict = false;
150  for (int i = 0; i < file_->enum_type_count() && !found_conflict; i++) {
151    if (file_->enum_type(i)->name() == classname_) {
152      found_conflict = true;
153    }
154  }
155  for (int i = 0; i < file_->message_type_count() && !found_conflict; i++) {
156    if (file_->message_type(i)->name() == classname_) {
157      found_conflict = true;
158    }
159  }
160  for (int i = 0; i < file_->service_count() && !found_conflict; i++) {
161    if (file_->service(i)->name() == classname_) {
162      found_conflict = true;
163    }
164  }
165
166  if (found_conflict) {
167    error->assign(file_->name());
168    error->append(
169      ": Cannot generate Java output because the file's outer class name, \"");
170    error->append(classname_);
171    error->append(
172      "\", matches the name of one of the types declared inside it.  "
173      "Please either rename the type or use the java_outer_classname "
174      "option to specify a different outer class name for the .proto file.");
175    return false;
176  }
177
178  return true;
179}
180
181void FileGenerator::Generate(io::Printer* printer) {
182  // We don't import anything because we refer to all classes by their
183  // fully-qualified names in the generated source.
184  printer->Print(
185    "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
186    "// source: $filename$\n"
187    "\n",
188    "filename", file_->name());
189  if (!java_package_.empty()) {
190    printer->Print(
191      "package $package$;\n"
192      "\n",
193      "package", java_package_);
194  }
195  printer->Print(
196    "public final class $classname$ {\n"
197    "  private $classname$() {}\n",
198    "classname", classname_);
199  printer->Indent();
200
201  // -----------------------------------------------------------------
202
203  printer->Print(
204    "public static void registerAllExtensions(\n"
205    "    com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
206    "lite", HasDescriptorMethods(file_) ? "" : "Lite");
207
208  printer->Indent();
209
210  for (int i = 0; i < file_->extension_count(); i++) {
211    ExtensionGenerator(file_->extension(i)).GenerateRegistrationCode(printer);
212  }
213
214  for (int i = 0; i < file_->message_type_count(); i++) {
215    MessageGenerator(file_->message_type(i))
216      .GenerateExtensionRegistrationCode(printer);
217  }
218
219  printer->Outdent();
220  printer->Print(
221    "}\n");
222
223  // -----------------------------------------------------------------
224
225  if (!file_->options().java_multiple_files()) {
226    for (int i = 0; i < file_->enum_type_count(); i++) {
227      EnumGenerator(file_->enum_type(i)).Generate(printer);
228    }
229    for (int i = 0; i < file_->message_type_count(); i++) {
230      MessageGenerator messageGenerator(file_->message_type(i));
231      messageGenerator.GenerateInterface(printer);
232      messageGenerator.Generate(printer);
233    }
234    if (HasGenericServices(file_)) {
235      for (int i = 0; i < file_->service_count(); i++) {
236        ServiceGenerator(file_->service(i)).Generate(printer);
237      }
238    }
239  }
240
241  // Extensions must be generated in the outer class since they are values,
242  // not classes.
243  for (int i = 0; i < file_->extension_count(); i++) {
244    ExtensionGenerator(file_->extension(i)).Generate(printer);
245  }
246
247  // Static variables.
248  for (int i = 0; i < file_->message_type_count(); i++) {
249    // TODO(kenton):  Reuse MessageGenerator objects?
250    MessageGenerator(file_->message_type(i)).GenerateStaticVariables(printer);
251  }
252
253  printer->Print("\n");
254
255  if (HasDescriptorMethods(file_)) {
256    GenerateEmbeddedDescriptor(printer);
257  } else {
258    printer->Print(
259      "static {\n");
260    printer->Indent();
261
262    for (int i = 0; i < file_->message_type_count(); i++) {
263      // TODO(kenton):  Reuse MessageGenerator objects?
264      MessageGenerator(file_->message_type(i))
265        .GenerateStaticVariableInitializers(printer);
266    }
267
268    printer->Outdent();
269    printer->Print(
270      "}\n");
271  }
272
273  printer->Print(
274    "\n"
275    "// @@protoc_insertion_point(outer_class_scope)\n");
276
277  printer->Outdent();
278  printer->Print("}\n");
279}
280
281void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
282  // Embed the descriptor.  We simply serialize the entire FileDescriptorProto
283  // and embed it as a string literal, which is parsed and built into real
284  // descriptors at initialization time.  We unfortunately have to put it in
285  // a string literal, not a byte array, because apparently using a literal
286  // byte array causes the Java compiler to generate *instructions* to
287  // initialize each and every byte of the array, e.g. as if you typed:
288  //   b[0] = 123; b[1] = 456; b[2] = 789;
289  // This makes huge bytecode files and can easily hit the compiler's internal
290  // code size limits (error "code to large").  String literals are apparently
291  // embedded raw, which is what we want.
292  FileDescriptorProto file_proto;
293  file_->CopyTo(&file_proto);
294
295  string file_data;
296  file_proto.SerializeToString(&file_data);
297
298  printer->Print(
299    "public static com.google.protobuf.Descriptors.FileDescriptor\n"
300    "    getDescriptor() {\n"
301    "  return descriptor;\n"
302    "}\n"
303    "private static com.google.protobuf.Descriptors.FileDescriptor\n"
304    "    descriptor;\n"
305    "static {\n"
306    "  java.lang.String[] descriptorData = {\n");
307  printer->Indent();
308  printer->Indent();
309
310  // Only write 40 bytes per line.
311  static const int kBytesPerLine = 40;
312  for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
313    if (i > 0) {
314      // Every 400 lines, start a new string literal, in order to avoid the
315      // 64k length limit.
316      if (i % 400 == 0) {
317        printer->Print(",\n");
318      } else {
319        printer->Print(" +\n");
320      }
321    }
322    printer->Print("\"$data$\"",
323      "data", CEscape(file_data.substr(i, kBytesPerLine)));
324  }
325
326  printer->Outdent();
327  printer->Print("\n};\n");
328
329  // -----------------------------------------------------------------
330  // Create the InternalDescriptorAssigner.
331
332  printer->Print(
333    "com.google.protobuf.Descriptors.FileDescriptor."
334      "InternalDescriptorAssigner assigner =\n"
335    "  new com.google.protobuf.Descriptors.FileDescriptor."
336      "InternalDescriptorAssigner() {\n"
337    "    public com.google.protobuf.ExtensionRegistry assignDescriptors(\n"
338    "        com.google.protobuf.Descriptors.FileDescriptor root) {\n"
339    "      descriptor = root;\n");
340
341  printer->Indent();
342  printer->Indent();
343  printer->Indent();
344
345  for (int i = 0; i < file_->message_type_count(); i++) {
346    // TODO(kenton):  Reuse MessageGenerator objects?
347    MessageGenerator(file_->message_type(i))
348      .GenerateStaticVariableInitializers(printer);
349  }
350  for (int i = 0; i < file_->extension_count(); i++) {
351    // TODO(kenton):  Reuse ExtensionGenerator objects?
352    ExtensionGenerator(file_->extension(i))
353        .GenerateNonNestedInitializationCode(printer);
354  }
355
356  // Proto compiler builds a DescriptorPool, which holds all the descriptors to
357  // generate, when processing the ".proto" files. We call this DescriptorPool
358  // the parsed pool (a.k.a. file_->pool()).
359  //
360  // Note that when users try to extend the (.*)DescriptorProto in their
361  // ".proto" files, it does not affect the pre-built FileDescriptorProto class
362  // in proto compiler. When we put the descriptor data in the file_proto, those
363  // extensions become unknown fields.
364  //
365  // Now we need to find out all the extension value to the (.*)DescriptorProto
366  // in the file_proto message, and prepare an ExtensionRegistry to return.
367  //
368  // To find those extensions, we need to parse the data into a dynamic message
369  // of the FileDescriptor based on the builder-pool, then we can use
370  // reflections to find all extension fields
371  vector<const FieldDescriptor*> extensions;
372  CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
373
374  if (extensions.size() > 0) {
375    // Must construct an ExtensionRegistry containing all existing extensions
376    // and return it.
377    printer->Print(
378      "com.google.protobuf.ExtensionRegistry registry =\n"
379      "  com.google.protobuf.ExtensionRegistry.newInstance();\n");
380    for (int i = 0; i < extensions.size(); i++) {
381      ExtensionGenerator(extensions[i]).GenerateRegistrationCode(printer);
382    }
383    printer->Print(
384      "return registry;\n");
385  } else {
386    printer->Print(
387      "return null;\n");
388  }
389
390  printer->Outdent();
391  printer->Outdent();
392  printer->Outdent();
393
394  printer->Print(
395    "    }\n"
396    "  };\n");
397
398  // -----------------------------------------------------------------
399  // Invoke internalBuildGeneratedFileFrom() to build the file.
400
401  printer->Print(
402    "com.google.protobuf.Descriptors.FileDescriptor\n"
403    "  .internalBuildGeneratedFileFrom(descriptorData,\n"
404    "    new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
405
406  for (int i = 0; i < file_->dependency_count(); i++) {
407    if (ShouldIncludeDependency(file_->dependency(i))) {
408      printer->Print(
409        "      $dependency$.getDescriptor(),\n",
410        "dependency", ClassName(file_->dependency(i)));
411    }
412  }
413
414  printer->Print(
415    "    }, assigner);\n");
416
417  printer->Outdent();
418  printer->Print(
419    "}\n");
420}
421
422template<typename GeneratorClass, typename DescriptorClass>
423static void GenerateSibling(const string& package_dir,
424                            const string& java_package,
425                            const DescriptorClass* descriptor,
426                            GeneratorContext* context,
427                            vector<string>* file_list,
428                            const string& name_suffix,
429                            void (GeneratorClass::*pfn)(io::Printer* printer)) {
430  string filename = package_dir + descriptor->name() + name_suffix + ".java";
431  file_list->push_back(filename);
432
433  scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
434  io::Printer printer(output.get(), '$');
435
436  printer.Print(
437    "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
438    "// source: $filename$\n"
439    "\n",
440    "filename", descriptor->file()->name());
441  if (!java_package.empty()) {
442    printer.Print(
443      "package $package$;\n"
444      "\n",
445      "package", java_package);
446  }
447
448  GeneratorClass generator(descriptor);
449  (generator.*pfn)(&printer);
450}
451
452void FileGenerator::GenerateSiblings(const string& package_dir,
453                                     GeneratorContext* context,
454                                     vector<string>* file_list) {
455  if (file_->options().java_multiple_files()) {
456    for (int i = 0; i < file_->enum_type_count(); i++) {
457      GenerateSibling<EnumGenerator>(package_dir, java_package_,
458                                     file_->enum_type(i),
459                                     context, file_list, "",
460                                     &EnumGenerator::Generate);
461    }
462    for (int i = 0; i < file_->message_type_count(); i++) {
463      GenerateSibling<MessageGenerator>(package_dir, java_package_,
464                                        file_->message_type(i),
465                                        context, file_list, "OrBuilder",
466                                        &MessageGenerator::GenerateInterface);
467      GenerateSibling<MessageGenerator>(package_dir, java_package_,
468                                        file_->message_type(i),
469                                        context, file_list, "",
470                                        &MessageGenerator::Generate);
471    }
472    if (HasGenericServices(file_)) {
473      for (int i = 0; i < file_->service_count(); i++) {
474        GenerateSibling<ServiceGenerator>(package_dir, java_package_,
475                                          file_->service(i),
476                                          context, file_list, "",
477                                          &ServiceGenerator::Generate);
478      }
479    }
480  }
481}
482
483bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) {
484  return true;
485}
486
487}  // namespace java
488}  // namespace compiler
489}  // namespace protobuf
490}  // namespace google
491