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