1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
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
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.
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.
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
35 #include <google/protobuf/compiler/java/java_file.h>
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>
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.
68 bool CollectExtensions(const Message& message,
69 vector<const FieldDescriptor*>* extensions) {
70 const Reflection* reflection = message.GetReflection();
72 // There are unknown fields that could be extensions, thus this call fails.
73 if (reflection->GetUnknownFields(message).field_count() > 0) return false;
75 vector<const FieldDescriptor*> fields;
76 reflection->ListFields(message, &fields);
78 for (int i = 0; i < fields.size(); i++) {
79 if (fields[i]->is_extension()) extensions->push_back(fields[i]);
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;
90 const Message& sub_message = reflection->GetMessage(message, fields[i]);
91 if (!CollectExtensions(sub_message, extensions)) return false;
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.
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 "
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));
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.
130 GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions))
131 << "Find unknown fields in FileDescriptorProto when building "
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.";
142 FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
144 java_package_(FileJavaPackage(file, immutable_api)),
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)));
159 for (int i = 0; i < file_->extension_count(); ++i) {
160 extension_generators_[i].reset(
161 generator_factory_->NewExtensionGenerator(file_->extension(i)));
165 FileGenerator::~FileGenerator() {}
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());
175 ": Cannot generate Java output because the file's outer class name, \"");
176 error->append(classname_);
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.");
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.";
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.
213 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
214 "// source: $filename$\n"
216 "filename", file_->name());
217 if (!java_package_.empty()) {
219 "package $package$;\n"
221 "package", java_package_);
224 "public final class $classname$ {\n"
225 " private $classname$() {}\n",
226 "classname", classname_);
229 // -----------------------------------------------------------------
232 "public static void registerAllExtensions(\n"
233 " com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
234 "lite", HasDescriptorMethods(file_) ? "" : "Lite");
238 for (int i = 0; i < file_->extension_count(); i++) {
239 extension_generators_[i]->GenerateRegistrationCode(printer);
242 for (int i = 0; i < file_->message_type_count(); i++) {
243 message_generators_[i]->GenerateExtensionRegistrationCode(printer);
250 // -----------------------------------------------------------------
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())
257 for (int i = 0; i < file_->message_type_count(); i++) {
258 message_generators_[i]->GenerateInterface(printer);
259 message_generators_[i]->Generate(printer);
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);
270 // Extensions must be generated in the outer class since they are values,
272 for (int i = 0; i < file_->extension_count(); i++) {
273 extension_generators_[i]->Generate(printer);
277 for (int i = 0; i < file_->message_type_count(); i++) {
278 message_generators_[i]->GenerateStaticVariables(printer);
281 printer->Print("\n");
283 if (HasDescriptorMethods(file_)) {
284 if (immutable_api_) {
285 GenerateDescriptorInitializationCodeForImmutable(printer);
287 GenerateDescriptorInitializationCodeForMutable(printer);
294 for (int i = 0; i < file_->message_type_count(); i++) {
295 message_generators_[i]->GenerateStaticVariableInitializers(printer);
305 "// @@protoc_insertion_point(outer_class_scope)\n");
308 printer->Print("}\n");
311 void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
312 io::Printer* printer) {
314 "public static com.google.protobuf.Descriptors.FileDescriptor\n"
315 " getDescriptor() {\n"
316 " return descriptor;\n"
318 "private static com.google.protobuf.Descriptors.FileDescriptor\n"
323 SharedCodeGenerator shared_code_generator(file_);
324 shared_code_generator.GenerateDescriptors(printer);
326 for (int i = 0; i < file_->message_type_count(); i++) {
327 message_generators_[i]->GenerateStaticVariableInitializers(printer);
329 for (int i = 0; i < file_->extension_count(); i++) {
330 extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
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()).
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.
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.
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);
351 file_proto.SerializeToString(&file_data);
352 vector<const FieldDescriptor*> extensions;
353 CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
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.
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);
367 "com.google.protobuf.Descriptors.FileDescriptor\n"
368 " .internalUpdateFileDescriptor(descriptor, registry);\n");
371 // Force descriptor initialization of all dependencies.
372 for (int i = 0; i < file_->dependency_count(); i++) {
373 if (ShouldIncludeDependency(file_->dependency(i), true)) {
375 name_resolver_->GetImmutableClassName(file_->dependency(i));
377 "$dependency$.getDescriptor();\n",
378 "dependency", dependency);
387 void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer* printer) {
389 "public static com.google.protobuf.Descriptors.FileDescriptor\n"
390 " getDescriptor() {\n"
391 " return descriptor;\n"
393 "private static com.google.protobuf.Descriptors.FileDescriptor\n"
399 "descriptor = $immutable_package$.$descriptor_classname$.descriptor;\n",
400 "immutable_package", FileJavaPackage(file_, true),
401 "descriptor_classname", name_resolver_->GetDescriptorClassName(file_));
403 for (int i = 0; i < file_->message_type_count(); i++) {
404 message_generators_[i]->GenerateStaticVariableInitializers(printer);
406 for (int i = 0; i < file_->extension_count(); i++) {
407 extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
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);
415 file_proto.SerializeToString(&file_data);
416 vector<const FieldDescriptor*> extensions;
417 CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
419 if (extensions.size() > 0) {
420 // Try to load immutable messages' outer class. Its initialization code
421 // will take care of interpreting custom options.
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?
435 "immutable_classname", name_resolver_->GetImmutableClassName(file_));
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));
444 "$dependency$.getDescriptor();\n",
445 "dependency", dependency);
454 template<typename GeneratorClass, typename DescriptorClass>
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);
466 scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
467 io::Printer printer(output.get(), '$');
470 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
471 "// source: $filename$\n"
473 "filename", descriptor->file()->name());
474 if (!java_package.empty()) {
476 "package $package$;\n"
478 "package", java_package);
481 (generator->*pfn)(&printer);
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_,
491 GenerateSibling<EnumGenerator>(package_dir, java_package_,
493 context, file_list, "",
495 &EnumGenerator::Generate);
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),
503 message_generators_[i].get(),
504 &MessageGenerator::GenerateInterface);
506 GenerateSibling<MessageGenerator>(package_dir, java_package_,
507 file_->message_type(i),
508 context, file_list, "",
509 message_generators_[i].get(),
510 &MessageGenerator::Generate);
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_,
518 context, file_list, "",
520 &ServiceGenerator::Generate);
526 bool FileGenerator::ShouldIncludeDependency(
527 const FileDescriptor* descriptor, bool immutable_api) {
532 } // namespace compiler
533 } // namespace protobuf
534 } // namespace google