diff options
author | Wink Saville <wink@google.com> | 2013-08-07 19:57:30 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2013-08-07 19:57:30 +0000 |
commit | e7b778b99f607460ed9ea88a13ec91164cda8537 (patch) | |
tree | f7d79f8de4666a66a09928fbc3468516b1c4ec76 /src | |
parent | 87c8e31b8c0baa78f979863a9ed10654a1cdca1f (diff) | |
parent | 624c448fbef20a1a2fad2289f622b468c25763d1 (diff) | |
download | external_protobuf-e7b778b99f607460ed9ea88a13ec91164cda8537.zip external_protobuf-e7b778b99f607460ed9ea88a13ec91164cda8537.tar.gz external_protobuf-e7b778b99f607460ed9ea88a13ec91164cda8537.tar.bz2 |
Merge "Fix outer classname for javamicro/javanano."
Diffstat (limited to 'src')
23 files changed, 384 insertions, 405 deletions
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_file.cc b/src/google/protobuf/compiler/javamicro/javamicro_file.cc index 9513aec..43bf012 100644 --- a/src/google/protobuf/compiler/javamicro/javamicro_file.cc +++ b/src/google/protobuf/compiler/javamicro/javamicro_file.cc @@ -32,6 +32,8 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <iostream> + #include <google/protobuf/compiler/javamicro/javamicro_file.h> #include <google/protobuf/compiler/javamicro/javamicro_enum.h> #include <google/protobuf/compiler/javamicro/javamicro_helpers.h> @@ -101,56 +103,48 @@ bool FileGenerator::Validate(string* error) { return false; } - // If there is no outer class name then there must be only - // message and no enums defined in the file scope. - if (!params_.has_java_outer_classname(file_->name())) { - if (file_->message_type_count() != 1) { - error->assign(file_->name()); - error->append( - ": Java MICRO_RUNTIME may only have 1 message if there is no 'option java_outer_classname'\""); - return false; - } + if (file_->service_count() != 0) { + error->assign(file_->name()); + error->append( + ": Java MICRO_RUNTIME does not support services\""); + return false; + } - if (file_->enum_type_count() != 0) { - error->assign(file_->name()); - error->append( - ": Java MICRO_RUNTIME must have an 'option java_outer_classname' if file scope enums are present\""); - return false; - } + if (!IsOuterClassNeeded(params_, file_)) { + return true; + } + + // Check whether legacy javamicro generator would omit the outer class. + if (!params_.has_java_outer_classname(file_->name()) + && file_->message_type_count() == 1 + && file_->enum_type_count() == 0 && file_->extension_count() == 0) { + cout << "INFO: " << file_->name() << ":" << endl; + cout << "Javamicro generator has changed to align with java generator. " + "An outer class will be created for this file and the single message " + "in the file will become a nested class. Use java_multiple_files to " + "skip generating the outer class, or set an explicit " + "java_outer_classname to suppress this message." << endl; } // Check that no class name matches the file's class name. This is a common // problem that leads to Java compile errors that can be hard to understand. // It's especially bad when using the java_multiple_files, since we would // end up overwriting the outer class with one of the inner ones. - int found_fileName = 0; - for (int i = 0; i < file_->enum_type_count(); i++) { - if (file_->enum_type(i)->name() == classname_) { - found_fileName += 1; - } - } - for (int i = 0; i < file_->message_type_count(); i++) { + bool found_conflict = false; + for (int i = 0; !found_conflict && i < file_->message_type_count(); i++) { if (file_->message_type(i)->name() == classname_) { - found_fileName += 1; + found_conflict = true; } } - if (file_->service_count() != 0) { + if (found_conflict) { error->assign(file_->name()); error->append( - ": Java MICRO_RUNTIME does not support services\""); - return false; - } - - if (found_fileName > 1) { - error->assign(file_->name()); - error->append( - ": Cannot generate Java output because there is more than one class name, \""); + ": Cannot generate Java output because the file's outer class name, \""); error->append(classname_); error->append( "\", matches the name of one of the types declared inside it. " "Please either rename the type or use the java_outer_classname " - "option to specify a different outer class name for the .proto file." - " -- FIX THIS MESSAGE"); + "option to specify a different outer class name for the .proto file."); return false; } return true; @@ -169,20 +163,19 @@ void FileGenerator::Generate(io::Printer* printer) { "package", java_package_); } - if (params_.has_java_outer_classname(file_->name())) { - printer->Print( - "public final class $classname$ {\n" - " private $classname$() {}\n", - "classname", classname_); - printer->Indent(); - } + printer->Print( + "public final class $classname$ {\n" + " private $classname$() {}\n", + "classname", classname_); + printer->Indent(); // ----------------------------------------------------------------- + for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator(file_->enum_type(i), params_).Generate(printer); + } + if (!params_.java_multiple_files(file_->name())) { - for (int i = 0; i < file_->enum_type_count(); i++) { - EnumGenerator(file_->enum_type(i), params_).Generate(printer); - } for (int i = 0; i < file_->message_type_count(); i++) { MessageGenerator(file_->message_type(i), params_).Generate(printer); } @@ -194,11 +187,9 @@ void FileGenerator::Generate(io::Printer* printer) { MessageGenerator(file_->message_type(i), params_).GenerateStaticVariables(printer); } - if (params_.has_java_outer_classname(file_->name())) { - printer->Outdent(); - printer->Print( - "}\n"); - } + printer->Outdent(); + printer->Print( + "}\n"); } template<typename GeneratorClass, typename DescriptorClass> @@ -232,11 +223,6 @@ void FileGenerator::GenerateSiblings(const string& package_dir, OutputDirectory* output_directory, vector<string>* file_list) { if (params_.java_multiple_files(file_->name())) { - for (int i = 0; i < file_->enum_type_count(); i++) { - GenerateSibling<EnumGenerator>(package_dir, java_package_, - file_->enum_type(i), - output_directory, file_list, params_); - } for (int i = 0; i < file_->message_type_count(); i++) { GenerateSibling<MessageGenerator>(package_dir, java_package_, file_->message_type(i), diff --git a/src/google/protobuf/compiler/javamicro/javamicro_generator.cc b/src/google/protobuf/compiler/javamicro/javamicro_generator.cc index 4643899..1b74509 100644 --- a/src/google/protobuf/compiler/javamicro/javamicro_generator.cc +++ b/src/google/protobuf/compiler/javamicro/javamicro_generator.cc @@ -173,16 +173,18 @@ bool JavaMicroGenerator::Generate(const FileDescriptor* file, vector<string> all_files; - string java_filename = package_dir; - java_filename += file_generator.classname(); - java_filename += ".java"; - all_files.push_back(java_filename); - - // Generate main java file. - scoped_ptr<io::ZeroCopyOutputStream> output( - output_directory->Open(java_filename)); - io::Printer printer(output.get(), '$'); - file_generator.Generate(&printer); + if (IsOuterClassNeeded(params, file)) { + string java_filename = package_dir; + java_filename += file_generator.classname(); + java_filename += ".java"; + all_files.push_back(java_filename); + + // Generate main java file. + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->Open(java_filename)); + io::Printer printer(output.get(), '$'); + file_generator.Generate(&printer); + } // Generate sibling files. file_generator.GenerateSiblings(package_dir, output_directory, &all_files); diff --git a/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc b/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc index 3647ec3..f6ce653 100644 --- a/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc +++ b/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc @@ -120,31 +120,20 @@ string StripProto(const string& filename) { } string FileClassName(const Params& params, const FileDescriptor* file) { - string name; - if (params.has_java_outer_classname(file->name())) { - name = params.java_outer_classname(file->name()); + return params.java_outer_classname(file->name()); } else { - if ((file->message_type_count() == 1) - || (file->enum_type_count() == 0)) { - // If no outer calls and only one message then - // use the message name as the file name - name = file->message_type(0)->name(); + // Use the filename itself with underscores removed + // and a CamelCase style name. + string basename; + string::size_type last_slash = file->name().find_last_of('/'); + if (last_slash == string::npos) { + basename = file->name(); } else { - // Use the filename it self with underscores removed - // and a CamelCase style name. - string basename; - string::size_type last_slash = file->name().find_last_of('/'); - if (last_slash == string::npos) { - basename = file->name(); - } else { - basename = file->name().substr(last_slash + 1); - } - name = UnderscoresToCamelCaseImpl(StripProto(basename), true); + basename = file->name().substr(last_slash + 1); } + return UnderscoresToCamelCaseImpl(StripProto(basename), true); } - - return name; } string FileJavaPackage(const Params& params, const FileDescriptor* file) { @@ -160,38 +149,27 @@ string FileJavaPackage(const Params& params, const FileDescriptor* file) { } } -string ToJavaName(const Params& params, const string& full_name, - const FileDescriptor* file) { - string result; - if (params.java_multiple_files(file->name())) { - result = FileJavaPackage(params, file); - } else { - result = ClassName(params, file); +bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) { + // Enums and extensions need the outer class as the scope. + if (file->enum_type_count() != 0 || file->extension_count() != 0) { + return true; } - if (file->package().empty()) { - result += '.'; - result += full_name; + // Messages need the outer class only if java_multiple_files is false. + return !params.java_multiple_files(file->name()); +} + +string ToJavaName(const Params& params, const string& name, bool is_class, + const Descriptor* parent, const FileDescriptor* file) { + string result; + if (parent != NULL) { + result.append(ClassName(params, parent)); + } else if (is_class && params.java_multiple_files(file->name())) { + result.append(FileJavaPackage(params, file)); } else { - // Strip the proto package from full_name since we've replaced it with - // the Java package. If there isn't an outer classname then strip it too. - int sizeToSkipPackageName = file->package().size(); - int sizeToSkipOutClassName; - if (params.has_java_outer_classname(file->name())) { - sizeToSkipOutClassName = 0; - } else { - sizeToSkipOutClassName = - full_name.find_first_of('.', sizeToSkipPackageName + 1); - } - int sizeToSkip = sizeToSkipOutClassName > 0 ? - sizeToSkipOutClassName : sizeToSkipPackageName; - string class_name = full_name.substr(sizeToSkip + 1); - if (class_name == FileClassName(params, file)) { - // Done class_name is already present. - } else { - result += '.'; - result += class_name; - } + result.append(ClassName(params, file)); } + if (!result.empty()) result.append(1, '.'); + result.append(name); // TODO(maxtroy): add '_' if name is a Java keyword. return result; } @@ -203,51 +181,14 @@ string ClassName(const Params& params, const FileDescriptor* descriptor) { } string ClassName(const Params& params, const EnumDescriptor* descriptor) { - string result; - const FileDescriptor* file = descriptor->file(); - const string file_name = file->name(); - const string full_name = descriptor->full_name(); - - // Remove enum class name as we use int's for enums - string base_name = full_name.substr(0, full_name.find_last_of('.')); - - if (!file->package().empty()) { - if (file->package() == base_name.substr(0, file->package().size())) { - // Remove package name leaving just the parent class of the enum - int offset = file->package().size(); - if (base_name.size() > offset) { - // Remove period between package and class name if there is a classname - offset += 1; - } - base_name = base_name.substr(offset); - } else { - GOOGLE_LOG(FATAL) << "Expected package name to start an enum"; - } - } - - // Construct the path name from the package and outer class - - // Add the java package name if it exsits - if (params.has_java_package(file_name)) { - result += params.java_package(file_name); - } - - // Add the outer classname if it exists - if (params.has_java_outer_classname(file_name)) { - if (!result.empty()) { - result += "."; - } - result += params.java_outer_classname(file_name); - } - - // Create the full class name from the base and path - if (!base_name.empty()) { - if (!result.empty()) { - result += "."; - } - result += base_name; + // An enum's class name is the enclosing message's class name or the outer + // class name. + const Descriptor* parent = descriptor->containing_type(); + if (parent != NULL) { + return ClassName(params, parent); + } else { + return ClassName(params, descriptor->file()); } - return result; } string FieldConstantName(const FieldDescriptor *field) { diff --git a/src/google/protobuf/compiler/javamicro/javamicro_helpers.h b/src/google/protobuf/compiler/javamicro/javamicro_helpers.h index eeddbf9..6131c15 100644 --- a/src/google/protobuf/compiler/javamicro/javamicro_helpers.h +++ b/src/google/protobuf/compiler/javamicro/javamicro_helpers.h @@ -69,25 +69,35 @@ string FileClassName(const Params& params, const FileDescriptor* file); // Returns the file's Java package name. string FileJavaPackage(const Params& params, const FileDescriptor* file); -// Converts the given fully-qualified name in the proto namespace to its -// fully-qualified name in the Java namespace, given that it is in the given -// file. -string ToJavaName(const Params& params, const string& full_name, - const FileDescriptor* file); +// Returns whether the Java outer class is needed, i.e. whether the option +// java_multiple_files is false, or the proto file contains any file-scope +// enums/extensions. +bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file); + +// Converts the given simple name of a proto entity to its fully-qualified name +// in the Java namespace, given that it is in the given file enclosed in the +// given parent message (or NULL for file-scope entities). Whether the file's +// outer class name should be included in the return value depends on factors +// inferrable from the given arguments, including is_class which indicates +// whether the entity translates to a Java class. +string ToJavaName(const Params& params, const string& name, bool is_class, + const Descriptor* parent, const FileDescriptor* file); // These return the fully-qualified class name corresponding to the given // descriptor. inline string ClassName(const Params& params, const Descriptor* descriptor) { - return ToJavaName(params, descriptor->full_name(), descriptor->file()); + return ToJavaName(params, descriptor->name(), true, + descriptor->containing_type(), descriptor->file()); } string ClassName(const Params& params, const EnumDescriptor* descriptor); inline string ClassName(const Params& params, const ServiceDescriptor* descriptor) { - return ToJavaName(params, descriptor->full_name(), descriptor->file()); + return ToJavaName(params, descriptor->name(), true, NULL, descriptor->file()); } inline string ExtensionIdentifierName(const Params& params, const FieldDescriptor* descriptor) { - return ToJavaName(params, descriptor->full_name(), descriptor->file()); + return ToJavaName(params, descriptor->name(), false, + descriptor->extension_scope(), descriptor->file()); } string ClassName(const Params& params, const FileDescriptor* descriptor); diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message.cc b/src/google/protobuf/compiler/javamicro/javamicro_message.cc index 6f67e74..cf48b3c 100644 --- a/src/google/protobuf/compiler/javamicro/javamicro_message.cc +++ b/src/google/protobuf/compiler/javamicro/javamicro_message.cc @@ -173,15 +173,7 @@ void MessageGenerator::Generate(io::Printer* printer) { const string& file_name = descriptor_->file()->name(); bool is_own_file = params_.java_multiple_files(file_name) - || ((descriptor_->containing_type() == NULL) - && !params_.has_java_outer_classname(file_name)); - -#if 0 - GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file; - GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null"); - GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files(); - GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name()); -#endif + && descriptor_->containing_type() == NULL; if ((descriptor_->extension_count() != 0) || (descriptor_->extension_range_count() != 0)) { @@ -362,25 +354,21 @@ void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) { void MessageGenerator:: GenerateParseFromMethods(io::Printer* printer) { - bool is_own_file = - descriptor_->containing_type() == NULL; - // Note: These are separate from GenerateMessageSerializationMethods() // because they need to be generated even for messages that are optimized // for code size. printer->Print( - "public $static$ $classname$ parseFrom(byte[] data)\n" + "public static $classname$ parseFrom(byte[] data)\n" " throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n" " return ($classname$) (new $classname$().mergeFrom(data));\n" "}\n" "\n" - "public $static$ $classname$ parseFrom(\n" + "public static $classname$ parseFrom(\n" " com.google.protobuf.micro.CodedInputStreamMicro input)\n" " throws java.io.IOException {\n" " return new $classname$().mergeFrom(input);\n" "}\n" "\n", - "static", (is_own_file ? "static" : ""), "classname", descriptor_->name()); } diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.cc b/src/google/protobuf/compiler/javanano/javanano_enum.cc index 973ef68..634943b 100644 --- a/src/google/protobuf/compiler/javanano/javanano_enum.cc +++ b/src/google/protobuf/compiler/javanano/javanano_enum.cc @@ -69,18 +69,6 @@ EnumGenerator::~EnumGenerator() {} void EnumGenerator::Generate(io::Printer* printer) { printer->Print("// enum $classname$\n", "classname", descriptor_->name()); - const string& file_name = descriptor_->file()->name(); - bool is_own_file = params_.java_multiple_files(file_name) || - ((descriptor_->containing_type() == NULL) && - !params_.has_java_outer_classname(file_name)); - - if (is_own_file) { - printer->Print("public final class $classname$ {\n", "classname", - descriptor_->name()); - printer->Indent(); - printer->Print("private $classname$() {}\n", "classname", - descriptor_->name()); - } for (int i = 0; i < canonical_values_.size(); i++) { map<string, string> vars; vars["name"] = RenameJavaKeywords(canonical_values_[i]->name()); @@ -99,10 +87,6 @@ void EnumGenerator::Generate(io::Printer* printer) { "public static final int $name$ = $canonical_name$;\n"); } - if (is_own_file) { - printer->Outdent(); - printer->Print("}"); - } printer->Print("\n"); } diff --git a/src/google/protobuf/compiler/javanano/javanano_file.cc b/src/google/protobuf/compiler/javanano/javanano_file.cc index 7113699..1a7b2a7 100644 --- a/src/google/protobuf/compiler/javanano/javanano_file.cc +++ b/src/google/protobuf/compiler/javanano/javanano_file.cc @@ -32,6 +32,8 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <iostream> + #include <google/protobuf/compiler/javanano/javanano_file.h> #include <google/protobuf/compiler/javanano/javanano_enum.h> #include <google/protobuf/compiler/javanano/javanano_extension.h> @@ -103,56 +105,48 @@ bool FileGenerator::Validate(string* error) { return false; } - // If there is no outer class name then there must be only - // message and no enums defined in the file scope. - if (!params_.has_java_outer_classname(file_->name())) { - if (file_->message_type_count() != 1) { - error->assign(file_->name()); - error->append( - ": Java NANO_RUNTIME may only have 1 message if there is no 'option java_outer_classname'\""); - return false; - } + if (file_->service_count() != 0) { + error->assign(file_->name()); + error->append( + ": Java NANO_RUNTIME does not support services\""); + return false; + } - if (file_->enum_type_count() != 0) { - error->assign(file_->name()); - error->append( - ": Java NANO_RUNTIME must have an 'option java_outer_classname' if file scope enums are present\""); - return false; - } + if (!IsOuterClassNeeded(params_, file_)) { + return true; + } + + // Check whether legacy javanano generator would omit the outer class. + if (!params_.has_java_outer_classname(file_->name()) + && file_->message_type_count() == 1 + && file_->enum_type_count() == 0 && file_->extension_count() == 0) { + cout << "INFO: " << file_->name() << ":" << endl; + cout << "Javanano generator has changed to align with java generator. " + "An outer class will be created for this file and the single message " + "in the file will become a nested class. Use java_multiple_files to " + "skip generating the outer class, or set an explicit " + "java_outer_classname to suppress this message." << endl; } // Check that no class name matches the file's class name. This is a common // problem that leads to Java compile errors that can be hard to understand. // It's especially bad when using the java_multiple_files, since we would // end up overwriting the outer class with one of the inner ones. - int found_fileName = 0; - for (int i = 0; i < file_->enum_type_count(); i++) { - if (file_->enum_type(i)->name() == classname_) { - found_fileName += 1; - } - } - for (int i = 0; i < file_->message_type_count(); i++) { + bool found_conflict = false; + for (int i = 0; !found_conflict && i < file_->message_type_count(); i++) { if (file_->message_type(i)->name() == classname_) { - found_fileName += 1; + found_conflict = true; } } - if (file_->service_count() != 0) { + if (found_conflict) { error->assign(file_->name()); error->append( - ": Java NANO_RUNTIME does not support services\""); - return false; - } - - if (found_fileName > 1) { - error->assign(file_->name()); - error->append( - ": Cannot generate Java output because there is more than one class name, \""); + ": Cannot generate Java output because the file's outer class name, \""); error->append(classname_); error->append( "\", matches the name of one of the types declared inside it. " "Please either rename the type or use the java_outer_classname " - "option to specify a different outer class name for the .proto file." - " -- FIX THIS MESSAGE"); + "option to specify a different outer class name for the .proto file."); return false; } return true; @@ -171,13 +165,11 @@ void FileGenerator::Generate(io::Printer* printer) { "package", java_package_); } - if (params_.has_java_outer_classname(file_->name())) { - printer->Print( - "public final class $classname$ {\n" - " private $classname$() {}\n", - "classname", classname_); - printer->Indent(); - } + printer->Print( + "public final class $classname$ {\n" + " private $classname$() {}\n", + "classname", classname_); + printer->Indent(); // ----------------------------------------------------------------- @@ -186,10 +178,13 @@ void FileGenerator::Generate(io::Printer* printer) { ExtensionGenerator(file_->extension(i), params_).Generate(printer); } + // Enums. + for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator(file_->enum_type(i), params_).Generate(printer); + } + + // Messages. if (!params_.java_multiple_files(file_->name())) { - for (int i = 0; i < file_->enum_type_count(); i++) { - EnumGenerator(file_->enum_type(i), params_).Generate(printer); - } for (int i = 0; i < file_->message_type_count(); i++) { MessageGenerator(file_->message_type(i), params_).Generate(printer); } @@ -201,11 +196,9 @@ void FileGenerator::Generate(io::Printer* printer) { MessageGenerator(file_->message_type(i), params_).GenerateStaticVariables(printer); } - if (params_.has_java_outer_classname(file_->name())) { - printer->Outdent(); - printer->Print( - "}\n"); - } + printer->Outdent(); + printer->Print( + "}\n"); } template<typename GeneratorClass, typename DescriptorClass> @@ -239,11 +232,6 @@ void FileGenerator::GenerateSiblings(const string& package_dir, OutputDirectory* output_directory, vector<string>* file_list) { if (params_.java_multiple_files(file_->name())) { - for (int i = 0; i < file_->enum_type_count(); i++) { - GenerateSibling<EnumGenerator>(package_dir, java_package_, - file_->enum_type(i), - output_directory, file_list, params_); - } for (int i = 0; i < file_->message_type_count(); i++) { GenerateSibling<MessageGenerator>(package_dir, java_package_, file_->message_type(i), diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc index 76e7263..5bed1b1 100644 --- a/src/google/protobuf/compiler/javanano/javanano_generator.cc +++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc @@ -138,16 +138,18 @@ bool JavaNanoGenerator::Generate(const FileDescriptor* file, vector<string> all_files; - string java_filename = package_dir; - java_filename += file_generator.classname(); - java_filename += ".java"; - all_files.push_back(java_filename); - - // Generate main java file. - scoped_ptr<io::ZeroCopyOutputStream> output( - output_directory->Open(java_filename)); - io::Printer printer(output.get(), '$'); - file_generator.Generate(&printer); + if (IsOuterClassNeeded(params, file)) { + string java_filename = package_dir; + java_filename += file_generator.classname(); + java_filename += ".java"; + all_files.push_back(java_filename); + + // Generate main java file. + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->Open(java_filename)); + io::Printer printer(output.get(), '$'); + file_generator.Generate(&printer); + } // Generate sibling files. file_generator.GenerateSiblings(package_dir, output_directory, &all_files); diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc index 525b9dd..22b4302 100644 --- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc +++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc @@ -167,31 +167,20 @@ string StripProto(const string& filename) { } string FileClassName(const Params& params, const FileDescriptor* file) { - string name; - if (params.has_java_outer_classname(file->name())) { - name = params.java_outer_classname(file->name()); + return params.java_outer_classname(file->name()); } else { - if ((file->message_type_count() == 1) - || (file->enum_type_count() == 0)) { - // If no outer calls and only one message then - // use the message name as the file name - name = file->message_type(0)->name(); + // Use the filename itself with underscores removed + // and a CamelCase style name. + string basename; + string::size_type last_slash = file->name().find_last_of('/'); + if (last_slash == string::npos) { + basename = file->name(); } else { - // Use the filename it self with underscores removed - // and a CamelCase style name. - string basename; - string::size_type last_slash = file->name().find_last_of('/'); - if (last_slash == string::npos) { - basename = file->name(); - } else { - basename = file->name().substr(last_slash + 1); - } - name = UnderscoresToCamelCaseImpl(StripProto(basename), true); + basename = file->name().substr(last_slash + 1); } + return UnderscoresToCamelCaseImpl(StripProto(basename), true); } - - return name; } string FileJavaPackage(const Params& params, const FileDescriptor* file) { @@ -207,38 +196,27 @@ string FileJavaPackage(const Params& params, const FileDescriptor* file) { } } -string ToJavaName(const Params& params, const string& full_name, - const FileDescriptor* file) { - string result; - if (params.java_multiple_files(file->name())) { - result = FileJavaPackage(params, file); - } else { - result = ClassName(params, file); +bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) { + // Enums and extensions need the outer class as the scope. + if (file->enum_type_count() != 0 || file->extension_count() != 0) { + return true; } - if (file->package().empty()) { - result += '.'; - result += full_name; + // Messages need the outer class only if java_multiple_files is false. + return !params.java_multiple_files(file->name()); +} + +string ToJavaName(const Params& params, const string& name, bool is_class, + const Descriptor* parent, const FileDescriptor* file) { + string result; + if (parent != NULL) { + result.append(ClassName(params, parent)); + } else if (is_class && params.java_multiple_files(file->name())) { + result.append(FileJavaPackage(params, file)); } else { - // Strip the proto package from full_name since we've replaced it with - // the Java package. If there isn't an outer classname then strip it too. - int sizeToSkipPackageName = file->package().size(); - int sizeToSkipOutClassName; - if (params.has_java_outer_classname(file->name())) { - sizeToSkipOutClassName = 0; - } else { - sizeToSkipOutClassName = - full_name.find_first_of('.', sizeToSkipPackageName + 1); - } - int sizeToSkip = sizeToSkipOutClassName > 0 ? - sizeToSkipOutClassName : sizeToSkipPackageName; - string class_name = full_name.substr(sizeToSkip + 1); - if (class_name == FileClassName(params, file)) { - // Done class_name is already present. - } else { - result += '.'; - result += class_name; - } + result.append(ClassName(params, file)); } + if (!result.empty()) result.append(1, '.'); + result.append(RenameJavaKeywords(name)); return result; } @@ -250,61 +228,14 @@ string ClassName(const Params& params, const FileDescriptor* descriptor) { } string ClassName(const Params& params, const EnumDescriptor* descriptor) { - string result; - const FileDescriptor* file = descriptor->file(); - const string file_name = file->name(); - const string full_name = descriptor->full_name(); - - // Remove enum class name as we use int's for enums - int last_dot_in_name = full_name.find_last_of('.'); - string base_name = full_name.substr(0, last_dot_in_name); - - if (!file->package().empty()) { - if (file->package() == base_name.substr(0, file->package().size())) { - // Remove package name leaving just the parent class of the enum - int offset = file->package().size(); - if (base_name.size() > offset) { - // Remove period between package and class name if there is a classname - offset += 1; - } - base_name = base_name.substr(offset); - } else { - GOOGLE_LOG(FATAL) << "Expected package name to start an enum"; - } - } - - // Construct the path name from the package and outer class - - // Add the java package name if it exists - if (params.has_java_package(file_name)) { - result += params.java_package(file_name); - } - - // If the java_multiple_files option is present, we will generate enums into separate - // classes, each named after the original enum type. This takes precedence over - // any outer_classname. - if (params.java_multiple_files(file_name) && last_dot_in_name != string::npos) { - string enum_simple_name = full_name.substr(last_dot_in_name + 1); - if (!result.empty()) { - result += "."; - } - result += enum_simple_name; - } else if (params.has_java_outer_classname(file_name)) { - // Add the outer classname if it exists - if (!result.empty()) { - result += "."; - } - result += params.java_outer_classname(file_name); - } - - // Create the full class name from the base and path - if (!base_name.empty()) { - if (!result.empty()) { - result += "."; - } - result += base_name; + // An enum's class name is the enclosing message's class name or the outer + // class name. + const Descriptor* parent = descriptor->containing_type(); + if (parent != NULL) { + return ClassName(params, parent); + } else { + return ClassName(params, descriptor->file()); } - return result; } string FieldConstantName(const FieldDescriptor *field) { diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.h b/src/google/protobuf/compiler/javanano/javanano_helpers.h index afadf60..430969b 100644 --- a/src/google/protobuf/compiler/javanano/javanano_helpers.h +++ b/src/google/protobuf/compiler/javanano/javanano_helpers.h @@ -73,25 +73,35 @@ string FileClassName(const Params& params, const FileDescriptor* file); // Returns the file's Java package name. string FileJavaPackage(const Params& params, const FileDescriptor* file); -// Converts the given fully-qualified name in the proto namespace to its -// fully-qualified name in the Java namespace, given that it is in the given -// file. -string ToJavaName(const Params& params, const string& full_name, - const FileDescriptor* file); +// Returns whether the Java outer class is needed, i.e. whether the option +// java_multiple_files is false, or the proto file contains any file-scope +// enums/extensions. +bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file); + +// Converts the given simple name of a proto entity to its fully-qualified name +// in the Java namespace, given that it is in the given file enclosed in the +// given parent message (or NULL for file-scope entities). Whether the file's +// outer class name should be included in the return value depends on factors +// inferrable from the given arguments, including is_class which indicates +// whether the entity translates to a Java class. +string ToJavaName(const Params& params, const string& name, bool is_class, + const Descriptor* parent, const FileDescriptor* file); // These return the fully-qualified class name corresponding to the given // descriptor. inline string ClassName(const Params& params, const Descriptor* descriptor) { - return ToJavaName(params, descriptor->full_name(), descriptor->file()); + return ToJavaName(params, descriptor->name(), true, + descriptor->containing_type(), descriptor->file()); } string ClassName(const Params& params, const EnumDescriptor* descriptor); inline string ClassName(const Params& params, const ServiceDescriptor* descriptor) { - return ToJavaName(params, descriptor->full_name(), descriptor->file()); + return ToJavaName(params, descriptor->name(), true, NULL, descriptor->file()); } inline string ExtensionIdentifierName(const Params& params, const FieldDescriptor* descriptor) { - return ToJavaName(params, descriptor->full_name(), descriptor->file()); + return ToJavaName(params, descriptor->name(), false, + descriptor->extension_scope(), descriptor->file()); } string ClassName(const Params& params, const FileDescriptor* descriptor); diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc index de56944..851c443 100644 --- a/src/google/protobuf/compiler/javanano/javanano_message.cc +++ b/src/google/protobuf/compiler/javanano/javanano_message.cc @@ -114,7 +114,7 @@ void MessageGenerator::GenerateStaticVariableInitializers( io::Printer* printer) { // Generate static member initializers for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { - // TODO(kenton): Reuse MessageGenerator objects? + // TODO(kenton): Reuse MessageGenerator objects? MessageGenerator(descriptor_->nested_type(i), params_) .GenerateStaticVariableInitializers(printer); } @@ -124,15 +124,7 @@ void MessageGenerator::Generate(io::Printer* printer) { const string& file_name = descriptor_->file()->name(); bool is_own_file = params_.java_multiple_files(file_name) - || ((descriptor_->containing_type() == NULL) - && !params_.has_java_outer_classname(file_name)); - -#if 0 - GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file; - GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null"); - GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files(); - GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name()); -#endif + && descriptor_->containing_type() == NULL; if (!params_.store_unknown_fields() && (descriptor_->extension_count() != 0 || descriptor_->extension_range_count() != 0)) { @@ -355,25 +347,21 @@ void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) { void MessageGenerator:: GenerateParseFromMethods(io::Printer* printer) { - bool is_own_file = - descriptor_->containing_type() == NULL; - // Note: These are separate from GenerateMessageSerializationMethods() // because they need to be generated even for messages that are optimized // for code size. printer->Print( - "public $static$ $classname$ parseFrom(byte[] data)\n" + "public static $classname$ parseFrom(byte[] data)\n" " throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {\n" " return com.google.protobuf.nano.MessageNano.mergeFrom(new $classname$(), data);\n" "}\n" "\n" - "public $static$ $classname$ parseFrom(\n" + "public static $classname$ parseFrom(\n" " com.google.protobuf.nano.CodedInputByteBufferNano input)\n" " throws java.io.IOException {\n" " return new $classname$().mergeFrom(input);\n" "}\n" "\n", - "static", (is_own_file ? "static" : ""), "classname", descriptor_->name()); } diff --git a/src/google/protobuf/unittest_multiple_micro.proto b/src/google/protobuf/unittest_multiple_micro.proto index 0b64283..fee8edc 100644 --- a/src/google/protobuf/unittest_multiple_micro.proto +++ b/src/google/protobuf/unittest_multiple_micro.proto @@ -35,9 +35,25 @@ package protobuf_unittest_import; import "google/protobuf/unittest_import_micro.proto"; option java_package = "com.google.protobuf.micro"; -option java_outer_classname = "MicroMultipleImportingNonMultiple"; option java_multiple_files = true; +enum FileScopeEnum { + ONE = 1; + TWO = 2; +} + +message FileScopeEnumRefMicro { + optional FileScopeEnum enum_field = 1; +} + +message MessageScopeEnumRefMicro { + enum MessageScopeEnum { + ONE = 1; + TWO = 2; + } + optional MessageScopeEnum enum_field = 1; +} + message MultipleImportingNonMultipleMicro1 { optional ImportMessageMicro field = 1; } diff --git a/src/google/protobuf/unittest_multiple_nameclash_micro.proto b/src/google/protobuf/unittest_multiple_nameclash_micro.proto new file mode 100644 index 0000000..089fd85 --- /dev/null +++ b/src/google/protobuf/unittest_multiple_nameclash_micro.proto @@ -0,0 +1,41 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: maxtroy@google.com (Max Cai) + +package protobuf_unittest_import; + +option java_package = "com.google.protobuf.micro"; +option java_outer_classname = "MultipleNameClashMicro"; +option java_multiple_files = true; + +message MultipleNameClashMicro { + optional int32 field = 1; +} diff --git a/src/google/protobuf/unittest_enum_multiplejava_nano.proto b/src/google/protobuf/unittest_multiple_nameclash_nano.proto index adf017d..f2f62c4 100644 --- a/src/google/protobuf/unittest_enum_multiplejava_nano.proto +++ b/src/google/protobuf/unittest_multiple_nameclash_nano.proto @@ -28,26 +28,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Author: bduff@google.com (Brian Duff) -// +// Author: maxtroy@google.com (Max Cai) package protobuf_unittest_import; option java_package = "com.google.protobuf.nano"; -option java_outer_classname = "NanoEnumsWithMultipleFiles"; +option java_outer_classname = "MultipleNameClashNano"; option java_multiple_files = true; -enum FirstTopLevelEnum { - FIRST_TOP_LEVEL_FIRST = 1; - FIRST_TOP_LEVEL_SECOND = 2; -} - -enum SecondTopLevelEnum { - SECOND_TOP_LEVEL_FIRST = 1; - SECOND_TOP_LEVEL_SECOND = 2; -} - -message SomeMessage { - optional FirstTopLevelEnum first = 1; - optional SecondTopLevelEnum second = 2; +message MultipleNameClashNano { + optional int32 field = 1; } diff --git a/src/google/protobuf/unittest_multiple_nano.proto b/src/google/protobuf/unittest_multiple_nano.proto index bd174c2..5ae790b 100644 --- a/src/google/protobuf/unittest_multiple_nano.proto +++ b/src/google/protobuf/unittest_multiple_nano.proto @@ -35,9 +35,25 @@ package protobuf_unittest_import; import "google/protobuf/unittest_import_nano.proto"; option java_package = "com.google.protobuf.nano"; -option java_outer_classname = "NanoMultipleImportingNonMultiple"; option java_multiple_files = true; +enum FileScopeEnum { + ONE = 1; + TWO = 2; +} + +message FileScopeEnumRefNano { + optional FileScopeEnum enum_field = 1; +} + +message MessageScopeEnumRefNano { + enum MessageScopeEnum { + ONE = 1; + TWO = 2; + } + optional MessageScopeEnum enum_field = 1; +} + message MultipleImportingNonMultipleNano1 { optional ImportMessageNano field = 1; } diff --git a/src/google/protobuf/unittest_recursive_micro.proto b/src/google/protobuf/unittest_recursive_micro.proto index a256852..078ca9c 100644 --- a/src/google/protobuf/unittest_recursive_micro.proto +++ b/src/google/protobuf/unittest_recursive_micro.proto @@ -34,6 +34,8 @@ package protobuf_unittest_import; option java_package = "com.google.protobuf.micro"; +// Explicit outer classname to suppress legacy info. +option java_outer_classname = "UnittestRecursiveMicro"; message RecursiveMessageMicro { message NestedMessage { diff --git a/src/google/protobuf/unittest_recursive_nano.proto b/src/google/protobuf/unittest_recursive_nano.proto index a62613e..3d3a6aa 100644 --- a/src/google/protobuf/unittest_recursive_nano.proto +++ b/src/google/protobuf/unittest_recursive_nano.proto @@ -34,6 +34,8 @@ package protobuf_unittest_import; option java_package = "com.google.protobuf.nano"; +// Explicit outer classname to suppress legacy info. +option java_outer_classname = "UnittestRecursiveNano"; message RecursiveMessageNano { message NestedMessage { diff --git a/src/google/protobuf/unittest_simple_micro.proto b/src/google/protobuf/unittest_simple_micro.proto index 057bf3d..09d4aab 100644 --- a/src/google/protobuf/unittest_simple_micro.proto +++ b/src/google/protobuf/unittest_simple_micro.proto @@ -34,6 +34,8 @@ package protobuf_unittest_import; option java_package = "com.google.protobuf.micro"; +// Explicit outer classname to suppress legacy info +option java_outer_classname = "UnittestSimpleMicro"; message SimpleMessageMicro { message NestedMessage { diff --git a/src/google/protobuf/unittest_simple_nano.proto b/src/google/protobuf/unittest_simple_nano.proto index 287e962..0c780c7 100644 --- a/src/google/protobuf/unittest_simple_nano.proto +++ b/src/google/protobuf/unittest_simple_nano.proto @@ -34,6 +34,8 @@ package protobuf_unittest_import; option java_package = "com.google.protobuf.nano"; +// Explicit outer classname to suppress legacy info. +option java_outer_classname = "UnittestSimpleNano"; message SimpleMessageNano { message NestedMessage { diff --git a/src/google/protobuf/unittest_single_micro.proto b/src/google/protobuf/unittest_single_micro.proto new file mode 100644 index 0000000..17e0645 --- /dev/null +++ b/src/google/protobuf/unittest_single_micro.proto @@ -0,0 +1,38 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: maxtroy@google.com (Max Cai) + +package protobuf_unittest_import; + +option java_package = "com.google.protobuf.micro"; + +message SingleMessageMicro { +} diff --git a/src/google/protobuf/unittest_single_nano.proto b/src/google/protobuf/unittest_single_nano.proto new file mode 100644 index 0000000..fcb1539 --- /dev/null +++ b/src/google/protobuf/unittest_single_nano.proto @@ -0,0 +1,38 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: maxtroy@google.com (Max Cai) + +package protobuf_unittest_import; + +option java_package = "com.google.protobuf.nano"; + +message SingleMessageNano { +} diff --git a/src/google/protobuf/unittest_stringutf8_micro.proto b/src/google/protobuf/unittest_stringutf8_micro.proto index e4bbe3d..68bd5ef 100644 --- a/src/google/protobuf/unittest_stringutf8_micro.proto +++ b/src/google/protobuf/unittest_stringutf8_micro.proto @@ -34,6 +34,8 @@ package protobuf_unittest_import; option java_package = "com.google.protobuf.micro"; +// Explicit outer classname to suppress legacy info. +option java_outer_classname = "UnittestStringutf8Micro"; message StringUtf8 { optional string id = 1; diff --git a/src/google/protobuf/unittest_stringutf8_nano.proto b/src/google/protobuf/unittest_stringutf8_nano.proto index da624b0..2bbf2b7 100644 --- a/src/google/protobuf/unittest_stringutf8_nano.proto +++ b/src/google/protobuf/unittest_stringutf8_nano.proto @@ -34,6 +34,8 @@ package protobuf_unittest_import; option java_package = "com.google.protobuf.nano"; +// Explicit outer classname to suppress legacy info. +option java_outer_classname = "UnittestStringutf8Nano"; message StringUtf8 { optional string id = 1; |