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