OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // http://code.google.com/p/protobuf/ | 3 // http://code.google.com/p/protobuf/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 24 matching lines...) Expand all Loading... |
35 #include <google/protobuf/compiler/java/java_file.h> | 35 #include <google/protobuf/compiler/java/java_file.h> |
36 #include <google/protobuf/compiler/java/java_enum.h> | 36 #include <google/protobuf/compiler/java/java_enum.h> |
37 #include <google/protobuf/compiler/java/java_service.h> | 37 #include <google/protobuf/compiler/java/java_service.h> |
38 #include <google/protobuf/compiler/java/java_extension.h> | 38 #include <google/protobuf/compiler/java/java_extension.h> |
39 #include <google/protobuf/compiler/java/java_helpers.h> | 39 #include <google/protobuf/compiler/java/java_helpers.h> |
40 #include <google/protobuf/compiler/java/java_message.h> | 40 #include <google/protobuf/compiler/java/java_message.h> |
41 #include <google/protobuf/compiler/code_generator.h> | 41 #include <google/protobuf/compiler/code_generator.h> |
42 #include <google/protobuf/io/printer.h> | 42 #include <google/protobuf/io/printer.h> |
43 #include <google/protobuf/io/zero_copy_stream.h> | 43 #include <google/protobuf/io/zero_copy_stream.h> |
44 #include <google/protobuf/descriptor.pb.h> | 44 #include <google/protobuf/descriptor.pb.h> |
| 45 #include <google/protobuf/dynamic_message.h> |
45 #include <google/protobuf/stubs/strutil.h> | 46 #include <google/protobuf/stubs/strutil.h> |
46 | 47 |
47 namespace google { | 48 namespace google { |
48 namespace protobuf { | 49 namespace protobuf { |
49 namespace compiler { | 50 namespace compiler { |
50 namespace java { | 51 namespace java { |
51 | 52 |
52 namespace { | 53 namespace { |
53 | 54 |
54 // Recursively searches the given message to see if it contains any extensions. | 55 |
55 bool UsesExtensions(const Message& message) { | 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. |
| 61 bool CollectExtensions(const Message& message, |
| 62 vector<const FieldDescriptor*>* extensions) { |
56 const Reflection* reflection = message.GetReflection(); | 63 const Reflection* reflection = message.GetReflection(); |
57 | 64 |
58 // We conservatively assume that unknown fields are extensions. | 65 // There are unknown fields that could be extensions, thus this call fails. |
59 if (reflection->GetUnknownFields(message).field_count() > 0) return true; | 66 if (reflection->GetUnknownFields(message).field_count() > 0) return false; |
60 | 67 |
61 vector<const FieldDescriptor*> fields; | 68 vector<const FieldDescriptor*> fields; |
62 reflection->ListFields(message, &fields); | 69 reflection->ListFields(message, &fields); |
63 | 70 |
64 for (int i = 0; i < fields.size(); i++) { | 71 for (int i = 0; i < fields.size(); i++) { |
65 if (fields[i]->is_extension()) return true; | 72 if (fields[i]->is_extension()) extensions->push_back(fields[i]); |
66 | 73 |
67 if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { | 74 if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { |
68 if (fields[i]->is_repeated()) { | 75 if (fields[i]->is_repeated()) { |
69 int size = reflection->FieldSize(message, fields[i]); | 76 int size = reflection->FieldSize(message, fields[i]); |
70 for (int j = 0; j < size; j++) { | 77 for (int j = 0; j < size; j++) { |
71 const Message& sub_message = | 78 const Message& sub_message = |
72 reflection->GetRepeatedMessage(message, fields[i], j); | 79 reflection->GetRepeatedMessage(message, fields[i], j); |
73 if (UsesExtensions(sub_message)) return true; | 80 if (!CollectExtensions(sub_message, extensions)) return false; |
74 } | 81 } |
75 } else { | 82 } else { |
76 const Message& sub_message = reflection->GetMessage(message, fields[i]); | 83 const Message& sub_message = reflection->GetMessage(message, fields[i]); |
77 if (UsesExtensions(sub_message)) return true; | 84 if (!CollectExtensions(sub_message, extensions)) return false; |
78 } | 85 } |
79 } | 86 } |
80 } | 87 } |
81 | 88 |
82 return false; | 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. |
| 97 void 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 } |
83 } | 130 } |
84 | 131 |
85 | 132 |
86 } // namespace | 133 } // namespace |
87 | 134 |
88 FileGenerator::FileGenerator(const FileDescriptor* file) | 135 FileGenerator::FileGenerator(const FileDescriptor* file) |
89 : file_(file), | 136 : file_(file), |
90 java_package_(FileJavaPackage(file)), | 137 java_package_(FileJavaPackage(file)), |
91 classname_(FileClassName(file)) { | 138 classname_(FileClassName(file)) { |
92 } | 139 } |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 // TODO(kenton): Reuse MessageGenerator objects? | 346 // TODO(kenton): Reuse MessageGenerator objects? |
300 MessageGenerator(file_->message_type(i)) | 347 MessageGenerator(file_->message_type(i)) |
301 .GenerateStaticVariableInitializers(printer); | 348 .GenerateStaticVariableInitializers(printer); |
302 } | 349 } |
303 for (int i = 0; i < file_->extension_count(); i++) { | 350 for (int i = 0; i < file_->extension_count(); i++) { |
304 // TODO(kenton): Reuse ExtensionGenerator objects? | 351 // TODO(kenton): Reuse ExtensionGenerator objects? |
305 ExtensionGenerator(file_->extension(i)) | 352 ExtensionGenerator(file_->extension(i)) |
306 .GenerateNonNestedInitializationCode(printer); | 353 .GenerateNonNestedInitializationCode(printer); |
307 } | 354 } |
308 | 355 |
309 if (UsesExtensions(file_proto)) { | 356 // Proto compiler builds a DescriptorPool, which holds all the descriptors to |
310 // Must construct an ExtensionRegistry containing all possible extensions | 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 |
311 // and return it. | 376 // and return it. |
312 printer->Print( | 377 printer->Print( |
313 "com.google.protobuf.ExtensionRegistry registry =\n" | 378 "com.google.protobuf.ExtensionRegistry registry =\n" |
314 " com.google.protobuf.ExtensionRegistry.newInstance();\n" | 379 " com.google.protobuf.ExtensionRegistry.newInstance();\n"); |
315 "registerAllExtensions(registry);\n"); | 380 for (int i = 0; i < extensions.size(); i++) { |
316 for (int i = 0; i < file_->dependency_count(); i++) { | 381 ExtensionGenerator(extensions[i]).GenerateRegistrationCode(printer); |
317 if (ShouldIncludeDependency(file_->dependency(i))) { | |
318 printer->Print( | |
319 "$dependency$.registerAllExtensions(registry);\n", | |
320 "dependency", ClassName(file_->dependency(i))); | |
321 } | |
322 } | 382 } |
323 printer->Print( | 383 printer->Print( |
324 "return registry;\n"); | 384 "return registry;\n"); |
325 } else { | 385 } else { |
326 printer->Print( | 386 printer->Print( |
327 "return null;\n"); | 387 "return null;\n"); |
328 } | 388 } |
329 | 389 |
330 printer->Outdent(); | 390 printer->Outdent(); |
331 printer->Outdent(); | 391 printer->Outdent(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 const string& name_suffix, | 428 const string& name_suffix, |
369 void (GeneratorClass::*pfn)(io::Printer* printer)) { | 429 void (GeneratorClass::*pfn)(io::Printer* printer)) { |
370 string filename = package_dir + descriptor->name() + name_suffix + ".java"; | 430 string filename = package_dir + descriptor->name() + name_suffix + ".java"; |
371 file_list->push_back(filename); | 431 file_list->push_back(filename); |
372 | 432 |
373 scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); | 433 scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); |
374 io::Printer printer(output.get(), '$'); | 434 io::Printer printer(output.get(), '$'); |
375 | 435 |
376 printer.Print( | 436 printer.Print( |
377 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" | 437 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
378 "\n"); | 438 "// source: $filename$\n" |
| 439 "\n", |
| 440 "filename", descriptor->file()->name()); |
379 if (!java_package.empty()) { | 441 if (!java_package.empty()) { |
380 printer.Print( | 442 printer.Print( |
381 "package $package$;\n" | 443 "package $package$;\n" |
382 "\n", | 444 "\n", |
383 "package", java_package); | 445 "package", java_package); |
384 } | 446 } |
385 | 447 |
386 GeneratorClass generator(descriptor); | 448 GeneratorClass generator(descriptor); |
387 (generator.*pfn)(&printer); | 449 (generator.*pfn)(&printer); |
388 } | 450 } |
(...skipping 30 matching lines...) Expand all Loading... |
419 } | 481 } |
420 | 482 |
421 bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) { | 483 bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) { |
422 return true; | 484 return true; |
423 } | 485 } |
424 | 486 |
425 } // namespace java | 487 } // namespace java |
426 } // namespace compiler | 488 } // namespace compiler |
427 } // namespace protobuf | 489 } // namespace protobuf |
428 } // namespace google | 490 } // namespace google |
OLD | NEW |