diff options
author | jieluo@google.com <jieluo@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2014-07-18 00:47:59 +0000 |
---|---|---|
committer | jieluo@google.com <jieluo@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2014-07-18 00:47:59 +0000 |
commit | 4de8f55113007fdc8e34107950e605fc0209d465 (patch) | |
tree | 92b7da8757a7740d9e1f2d3ead233542947d8c8c /src/google/protobuf/compiler/java | |
parent | c5553a3d18f80132b9079c5504bc0aa1f7f950a0 (diff) |
down integrate to svn
Diffstat (limited to 'src/google/protobuf/compiler/java')
36 files changed, 5488 insertions, 1296 deletions
diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc new file mode 100644 index 00000000..67ac0ef3 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_context.cc @@ -0,0 +1,195 @@ +// 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. + +#include <google/protobuf/compiler/java/java_context.h> + +#include <google/protobuf/compiler/java/java_field.h> +#include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/map_util.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +Context::Context(const FileDescriptor* file) + : name_resolver_(new ClassNameResolver) { + InitializeFieldGeneratorInfo(file); +} + +Context::~Context() { +} + +ClassNameResolver* Context::GetNameResolver() { + return name_resolver_.get(); +} + +namespace { +// Whether two fields have conflicting accessors (assuming name1 and name2 +// are different). name1 and name2 are field1 and field2's camel-case name +// respectively. +bool IsConflicting(const FieldDescriptor* field1, const string& name1, + const FieldDescriptor* field2, const string& name2, + string* info) { + if (field1->is_repeated()) { + if (field2->is_repeated()) { + // Both fields are repeated. + return false; + } else { + // field1 is repeated, and field2 is not. + if (name1 + "Count" == name2) { + *info = "both repeated field \"" + field1->name() + "\" and singular " + + "field \"" + field2->name() + "\" generates the method \"" + + "get" + name1 + "Count()\""; + return true; + } + if (name1 + "List" == name2) { + *info = "both repeated field \"" + field1->name() + "\" and singular " + + "field \"" + field2->name() + "\" generates the method \"" + + "get" + name1 + "List()\""; + return true; + } + // Well, there are obviously many more conflicting cases, but it probably + // doesn't worth the effort to exhaust all of them because they rarely + // happen and as we are continuing adding new methods/changing existing + // methods the number of different conflicting cases will keep growing. + // We can just add more cases here when they are found in the real world. + return false; + } + } else { + if (field2->is_repeated()) { + return IsConflicting(field2, name2, field1, name1, info); + } else { + // None of the two fields are repeated. + return false; + } + } +} +} // namespace + +void Context::InitializeFieldGeneratorInfo(const FileDescriptor* file) { + for (int i = 0; i < file->message_type_count(); ++i) { + InitializeFieldGeneratorInfoForMessage(file->message_type(i)); + } +} + +void Context::InitializeFieldGeneratorInfoForMessage( + const Descriptor* message) { + for (int i = 0; i < message->nested_type_count(); ++i) { + InitializeFieldGeneratorInfoForMessage(message->nested_type(i)); + } + vector<const FieldDescriptor*> fields; + for (int i = 0; i < message->field_count(); ++i) { + fields.push_back(message->field(i)); + } + InitializeFieldGeneratorInfoForFields(fields); + + for (int i = 0; i < message->oneof_decl_count(); ++i) { + const OneofDescriptor* oneof = message->oneof_decl(i); + OneofGeneratorInfo info; + info.name = UnderscoresToCamelCase(oneof->name(), false); + info.capitalized_name = UnderscoresToCamelCase(oneof->name(), true); + oneof_generator_info_map_[oneof] = info; + } +} + +void Context::InitializeFieldGeneratorInfoForFields( + const vector<const FieldDescriptor*>& fields) { + // Find out all fields that conflict with some other field in the same + // message. + vector<bool> is_conflict(fields.size()); + vector<string> conflict_reason(fields.size()); + for (int i = 0; i < fields.size(); ++i) { + const FieldDescriptor* field = fields[i]; + const string& name = UnderscoresToCapitalizedCamelCase(field); + for (int j = i + 1; j < fields.size(); ++j) { + const FieldDescriptor* other = fields[j]; + const string& other_name = UnderscoresToCapitalizedCamelCase(other); + if (name == other_name) { + is_conflict[i] = is_conflict[j] = true; + conflict_reason[i] = conflict_reason[j] = + "capitalized name of field \"" + field->name() + + "\" conflicts with field \"" + other->name() + "\""; + } else if (IsConflicting(field, name, other, other_name, + &conflict_reason[j])) { + is_conflict[i] = is_conflict[j] = true; + conflict_reason[i] = conflict_reason[j]; + } + } + if (is_conflict[i]) { + GOOGLE_LOG(WARNING) << "field \"" << field->full_name() << "\" is conflicting " + << "with another field: " << conflict_reason[i]; + } + } + for (int i = 0; i < fields.size(); ++i) { + const FieldDescriptor* field = fields[i]; + FieldGeneratorInfo info; + info.name = UnderscoresToCamelCase(field); + info.capitalized_name = UnderscoresToCapitalizedCamelCase(field); + // For fields conflicting with some other fields, we append the field + // number to their field names in generated code to avoid conflicts. + if (is_conflict[i]) { + info.name += SimpleItoa(field->number()); + info.capitalized_name += SimpleItoa(field->number()); + info.disambiguated_reason = conflict_reason[i]; + } + field_generator_info_map_[field] = info; + } +} + +const FieldGeneratorInfo* Context::GetFieldGeneratorInfo( + const FieldDescriptor* field) const { + const FieldGeneratorInfo* result = + FindOrNull(field_generator_info_map_, field); + if (result == NULL) { + GOOGLE_LOG(FATAL) << "Can not find FieldGeneratorInfo for field: " + << field->full_name(); + } + return result; +} + +const OneofGeneratorInfo* Context::GetOneofGeneratorInfo( + const OneofDescriptor* oneof) const { + const OneofGeneratorInfo* result = + FindOrNull(oneof_generator_info_map_, oneof); + if (result == NULL) { + GOOGLE_LOG(FATAL) << "Can not find OneofGeneratorInfo for oneof: " + << oneof->name(); + } + return result; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h new file mode 100644 index 00000000..c622b319 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_context.h @@ -0,0 +1,95 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__ + +#include <map> +#include <memory> +#include <vector> + +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { + class FileDescriptor; + class FieldDescriptor; + class OneofDescriptor; + class Descriptor; + namespace compiler { + namespace java { + class ClassNameResolver; // name_resolver.h + } + } +} // namespace protobuf + +namespace protobuf { +namespace compiler { +namespace java { + +struct FieldGeneratorInfo; +struct OneofGeneratorInfo; +// A context object holds the information that is shared among all code +// generators. +class Context { + public: + explicit Context(const FileDescriptor* file); + ~Context(); + + // Get the name resolver associated with this context. The resolver + // can be used to map descriptors to Java class names. + ClassNameResolver* GetNameResolver(); + + // Get the FieldGeneratorInfo for a given field. + const FieldGeneratorInfo* GetFieldGeneratorInfo( + const FieldDescriptor* field) const; + + // Get the OneofGeneratorInfo for a given oneof. + const OneofGeneratorInfo* GetOneofGeneratorInfo( + const OneofDescriptor* oneof) const; + + private: + void InitializeFieldGeneratorInfo(const FileDescriptor* file); + void InitializeFieldGeneratorInfoForMessage(const Descriptor* message); + void InitializeFieldGeneratorInfoForFields( + const vector<const FieldDescriptor*>& fields); + + scoped_ptr<ClassNameResolver> name_resolver_; + map<const FieldDescriptor*, FieldGeneratorInfo> field_generator_info_map_; + map<const OneofDescriptor*, OneofGeneratorInfo> oneof_generator_info_map_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_CONTEXT_H__ diff --git a/src/google/protobuf/compiler/java/java_doc_comment.cc b/src/google/protobuf/compiler/java/java_doc_comment.cc index 60b4f2ac..23127b7f 100644 --- a/src/google/protobuf/compiler/java/java_doc_comment.cc +++ b/src/google/protobuf/compiler/java/java_doc_comment.cc @@ -70,12 +70,10 @@ string EscapeJavadoc(const string& input) { } break; case '@': - // "{@" starts Javadoc markup. - if (prev == '{') { - result.append("@"); - } else { - result.push_back(c); - } + // '@' starts javadoc tags including the @deprecated tag, which will + // cause a compile-time error if inserted before a declaration that + // does not have a corresponding @Deprecated annotation. + result.append("@"); break; case '<': // Avoid interpretation as HTML. @@ -117,8 +115,7 @@ static void WriteDocCommentBodyForLocation( // HTML-escape them so that they don't accidentally close the doc comment. comments = EscapeJavadoc(comments); - vector<string> lines; - SplitStringAllowEmpty(comments, "\n", &lines); + vector<string> lines = Split(comments, "\n"); while (!lines.empty() && lines.back().empty()) { lines.pop_back(); } diff --git a/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc b/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc index 28b6d8b4..41ea9f42 100644 --- a/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc +++ b/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc @@ -46,6 +46,7 @@ TEST(JavaDocCommentTest, Escaping) { EXPECT_EQ("{@foo}", EscapeJavadoc("{@foo}")); EXPECT_EQ("<i>&</i>", EscapeJavadoc("<i>&</i>")); EXPECT_EQ("foo\u1234bar", EscapeJavadoc("foo\\u1234bar")); + EXPECT_EQ("@deprecated", EscapeJavadoc("@deprecated")); } // TODO(kenton): It's hard to write a robust test of the doc comments -- we diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index cfed815f..6bebe213 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -35,9 +35,11 @@ #include <map> #include <string> +#include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum.h> #include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/strutil.h> @@ -47,8 +49,22 @@ namespace protobuf { namespace compiler { namespace java { -EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) - : descriptor_(descriptor) { +namespace { +bool EnumHasCustomOptions(const EnumDescriptor* descriptor) { + if (descriptor->options().unknown_fields().field_count() > 0) return true; + for (int i = 0; i < descriptor->value_count(); ++i) { + const EnumValueDescriptor* value = descriptor->value(i); + if (value->options().unknown_fields().field_count() > 0) return true; + } + return false; +} +} // namespace + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, + bool immutable_api, + Context* context) + : descriptor_(descriptor), immutable_api_(immutable_api), + name_resolver_(context->GetNameResolver()) { for (int i = 0; i < descriptor_->value_count(); i++) { const EnumValueDescriptor* value = descriptor_->value(i); const EnumValueDescriptor* canonical_value = @@ -88,6 +104,9 @@ void EnumGenerator::Generate(io::Printer* printer) { vars["index"] = SimpleItoa(canonical_values_[i]->index()); vars["number"] = SimpleItoa(canonical_values_[i]->number()); WriteEnumValueDocComment(printer, canonical_values_[i]); + if (canonical_values_[i]->options().deprecated()) { + printer->Print("@java.lang.Deprecated\n"); + } printer->Print(vars, "$name$($index$, $number$),\n"); } @@ -178,15 +197,58 @@ void EnumGenerator::Generate(io::Printer* printer) { // at module init time because it wouldn't work with descriptor.proto, but // we can cache the value the first time getDescriptor() is called. if (descriptor_->containing_type() == NULL) { - printer->Print( - " return $file$.getDescriptor().getEnumTypes().get($index$);\n", - "file", ClassName(descriptor_->file()), - "index", SimpleItoa(descriptor_->index())); + if (!MultipleJavaFiles(descriptor_->file(), immutable_api_)) { + printer->Print( + " return $file$.getDescriptor().getEnumTypes().get($index$);\n", + "file", name_resolver_->GetClassName(descriptor_->file(), + immutable_api_), + "index", SimpleItoa(descriptor_->index())); + } else { + printer->Indent(); + if (EnumHasCustomOptions(descriptor_)) { + // We need to load the immutable classes in order to parse custom + // options. However, since file level enums (no outer class) are + // shared by immutable code and mutable code, the immutable classes + // may not exist. So we try to use Java reflection to retrieve the + // descriptor from immutable classes. + printer->Print( + "try {\n" + " java.lang.Class immutableFileClass =\n" + " java.lang.Class.forName(\"$immutable_file_class_name$\");\n" + " @java.lang.SuppressWarnings(\"unchecked\")\n" + " java.lang.reflect.Method m =\n" + " immutableFileClass.getMethod(\"getDescriptor\");\n" + " com.google.protobuf.Descriptors.FileDescriptor file =\n" + " (com.google.protobuf.Descriptors.FileDescriptor)\n" + " m.invoke(immutableFileClass);\n" + " return file.getEnumTypes().get($index$);\n" + "} catch (Exception e) {\n" + // Immutable classes cannot be found. Proceed as if custom options + // don't exist. + "}\n", + "immutable_file_class_name", + name_resolver_->GetImmutableClassName(descriptor_->file()), + "index", SimpleItoa(descriptor_->index())); + } + printer->Print( + "return $immutable_package$.$descriptor_class$.descriptor\n" + " .getEnumTypes().get($index$);\n", + "immutable_package", FileJavaPackage(descriptor_->file(), true), + "descriptor_class", + name_resolver_->GetDescriptorClassName(descriptor_->file()), + "index", SimpleItoa(descriptor_->index())); + printer->Outdent(); + } } else { printer->Print( - " return $parent$.getDescriptor().getEnumTypes().get($index$);\n", - "parent", ClassName(descriptor_->containing_type()), - "index", SimpleItoa(descriptor_->index())); + " return $parent$.$descriptor$.getEnumTypes().get($index$);\n", + "parent", name_resolver_->GetClassName(descriptor_->containing_type(), + immutable_api_), + "descriptor", descriptor_->containing_type()->options() + .no_standard_descriptor_accessor() + ? "getDefaultInstance().getDescriptorForType()" + : "getDescriptor()", + "index", SimpleItoa(descriptor_->index())); } printer->Print( diff --git a/src/google/protobuf/compiler/java/java_enum.h b/src/google/protobuf/compiler/java/java_enum.h index 9a9e5742..af0cd15d 100644 --- a/src/google/protobuf/compiler/java/java_enum.h +++ b/src/google/protobuf/compiler/java/java_enum.h @@ -41,6 +41,12 @@ namespace google { namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } namespace io { class Printer; // printer.h } @@ -52,7 +58,9 @@ namespace java { class EnumGenerator { public: - explicit EnumGenerator(const EnumDescriptor* descriptor); + explicit EnumGenerator(const EnumDescriptor* descriptor, + bool immutable_api, + Context* context); ~EnumGenerator(); void Generate(io::Printer* printer); @@ -73,6 +81,11 @@ class EnumGenerator { }; vector<Alias> aliases_; + bool immutable_api_; + + Context* context_; + ClassNameResolver* name_resolver_; + bool CanUseEnumValues(); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index ec0b067e..cab9bd0e 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -35,10 +35,12 @@ #include <map> #include <string> -#include <google/protobuf/compiler/java/java_enum_field.h> -#include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/java/java_context.h> +#include <google/protobuf/compiler/java/java_doc_comment.h> +#include <google/protobuf/compiler/java/java_enum_field.h> #include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> @@ -50,20 +52,19 @@ namespace java { namespace { -// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of -// repeat code between this and the other field types. void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, map<string, string>* variables) { - (*variables)["name"] = - UnderscoresToCamelCase(descriptor); - (*variables)["capitalized_name"] = - UnderscoresToCapitalizedCamelCase(descriptor); - (*variables)["constant_name"] = FieldConstantName(descriptor); - (*variables)["number"] = SimpleItoa(descriptor->number()); - (*variables)["type"] = ClassName(descriptor->enum_type()); - (*variables)["default"] = DefaultValue(descriptor); + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->enum_type()); + (*variables)["mutable_type"] = + name_resolver->GetMutableClassName(descriptor->enum_type()); + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); @@ -74,14 +75,28 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["on_changed"] = HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; - // For singular messages and builders, one bit is used for the hasField bit. - (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); - (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex); + if (SupportFieldPresence(descriptor->file())) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["set_has_field_bit_builder"] = + GenerateSetBit(builderBitIndex) + ";"; + (*variables)["clear_has_field_bit_builder"] = + GenerateClearBit(builderBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_builder"] = ""; + (*variables)["clear_has_field_bit_builder"] = ""; - (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); - (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); - (*variables)["clear_has_field_bit_builder"] = - GenerateClearBit(builderBitIndex); + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + (*variables)["default"]; + } // For repated builders, one bit is used for whether the array is immutable. (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); @@ -105,44 +120,53 @@ void SetEnumVariables(const FieldDescriptor* descriptor, // =================================================================== -EnumFieldGenerator:: -EnumFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, - int builderBitIndex) +ImmutableEnumFieldGenerator:: +ImmutableEnumFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) : descriptor_(descriptor), messageBitIndex_(messageBitIndex), - builderBitIndex_(builderBitIndex) { - SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_); + builderBitIndex_(builderBitIndex), + name_resolver_(context->GetNameResolver()) { + SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); } -EnumFieldGenerator::~EnumFieldGenerator() {} +ImmutableEnumFieldGenerator::~ImmutableEnumFieldGenerator() {} -int EnumFieldGenerator::GetNumBitsForMessage() const { +int ImmutableEnumFieldGenerator::GetNumBitsForMessage() const { return 1; } -int EnumFieldGenerator::GetNumBitsForBuilder() const { +int ImmutableEnumFieldGenerator::GetNumBitsForBuilder() const { return 1; } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$boolean has$capitalized_name$();\n"); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private $type$ $name$_;\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public boolean has$capitalized_name$() {\n" - " return $get_has_field_bit_message$;\n" - "}\n"); + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" @@ -150,15 +174,17 @@ GenerateMembers(io::Printer* printer) const { "}\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "private $type$ $name$_ = $default$;\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public boolean has$capitalized_name$() {\n" - " return $get_has_field_bit_builder$;\n" - "}\n"); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_builder$;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" @@ -170,7 +196,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " if (value == null) {\n" " throw new NullPointerException();\n" " }\n" - " $set_has_field_bit_builder$;\n" + " $set_has_field_bit_builder$\n" " $name$_ = value;\n" " $on_changed$\n" " return this;\n" @@ -178,129 +204,274 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" - " $clear_has_field_bit_builder$;\n" + " $clear_has_field_bit_builder$\n" " $name$_ = $default$;\n" " $on_changed$\n" " return this;\n" "}\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateFieldBuilderInitializationCode(io::Printer* printer) const { // noop for enums } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = $default$;\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { printer->Print(variables_, - "$name$_ = $default$;\n" - "$clear_has_field_bit_builder$;\n"); + "$name$_ = $default$;\n" + "$clear_has_field_bit_builder$\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } else { + printer->Print(variables_, + "if (other.get$capitalized_name$() != $default$) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateBuildingCode(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "if ($get_has_field_bit_from_local$) {\n" + " $set_has_field_bit_to_local$;\n" + "}\n"); + } printer->Print(variables_, - "if ($get_has_field_bit_from_local$) {\n" - " $set_has_field_bit_to_local$;\n" - "}\n" "result.$name$_ = $name$_;\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n"); - if (HasUnknownFields(descriptor_->containing_type())) { + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (UseUnknownFieldSet(descriptor_->containing_type())) { printer->Print(variables_, - "if (value == null) {\n" - " unknownFields.mergeVarintField($number$, rawValue);\n" - "} else {\n"); + " unknownFields.mergeVarintField($number$, rawValue);\n"); } else { printer->Print(variables_, - "if (value != null) {\n"); + " unknownFieldsCodedOutput.writeRawVarint32(tag);\n" + " unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n"); } printer->Print(variables_, - " $set_has_field_bit_message$;\n" + "} else {\n" + " $set_has_field_bit_message$\n" " $name$_ = value;\n" "}\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { // noop for enums } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, - "if ($get_has_field_bit_message$) {\n" + "if ($is_field_present_message$) {\n" " output.writeEnum($number$, $name$_.getNumber());\n" "}\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, - "if ($get_has_field_bit_message$) {\n" + "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" " .computeEnumSize($number$, $name$_.getNumber());\n" "}\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "result = result &&\n" " (get$capitalized_name$() == other.get$capitalized_name$());\n"); } -void EnumFieldGenerator:: +void ImmutableEnumFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "hash = (37 * hash) + $constant_name$;\n" - "hash = (53 * hash) + hashEnum(get$capitalized_name$());\n"); + "hash = (53 * hash) + com.google.protobuf.Internal.hashEnum(\n" + " get$capitalized_name$());\n"); +} + +string ImmutableEnumFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->enum_type()); +} + +// =================================================================== + +ImmutableEnumOneofFieldGenerator:: +ImmutableEnumOneofFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableEnumFieldGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableEnumOneofFieldGenerator:: +~ImmutableEnumOneofFieldGenerator() {} + +void ImmutableEnumOneofFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $default$;\n" + "}\n"); } -string EnumFieldGenerator::GetBoxedType() const { - return ClassName(descriptor_->enum_type()); +void ImmutableEnumOneofFieldGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $default$;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " $on_changed$\n" + " }\n" + " return this;\n" + "}\n"); +} + +void ImmutableEnumOneofFieldGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " result.$oneof_name$_ = $oneof_name$_;\n" + "}\n"); +} + +void ImmutableEnumOneofFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "set$capitalized_name$(other.get$capitalized_name$());\n"); +} + +void ImmutableEnumOneofFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (UseUnknownFieldSet(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } else { + printer->Print(variables_, + " unknownFieldsCodedOutput.writeRawVarint32(tag);\n" + " unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + "}\n"); +} + +void ImmutableEnumOneofFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.writeEnum($number$, (($type$) $oneof_name$_).getNumber());\n" + "}\n"); +} + +void ImmutableEnumOneofFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeEnumSize($number$, (($type$) $oneof_name$_).getNumber());\n" + "}\n"); } // =================================================================== -RepeatedEnumFieldGenerator:: -RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, - int builderBitIndex) +RepeatedImmutableEnumFieldGenerator:: +RepeatedImmutableEnumFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) : descriptor_(descriptor), messageBitIndex_(messageBitIndex), - builderBitIndex_(builderBitIndex) { - SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_); + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); } -RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} +RepeatedImmutableEnumFieldGenerator::~RepeatedImmutableEnumFieldGenerator() {} -int RepeatedEnumFieldGenerator::GetNumBitsForMessage() const { +int RepeatedImmutableEnumFieldGenerator::GetNumBitsForMessage() const { return 0; } -int RepeatedEnumFieldGenerator::GetNumBitsForBuilder() const { +int RepeatedImmutableEnumFieldGenerator::GetNumBitsForBuilder() const { return 1; } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -313,10 +484,11 @@ GenerateInterfaceMembers(io::Printer* printer) const { "$deprecation$$type$ get$capitalized_name$(int index);\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private java.util.List<$type$> $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" @@ -340,7 +512,7 @@ GenerateMembers(io::Printer* printer) const { } } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, // One field is the list and the other field keeps track of whether the @@ -409,7 +581,8 @@ GenerateBuilderMembers(io::Printer* printer) const { "$deprecation$public Builder addAll$capitalized_name$(\n" " java.lang.Iterable<? extends $type$> values) {\n" " ensure$capitalized_name$IsMutable();\n" - " super.addAll(values, $name$_);\n" + " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" + " values, $name$_);\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -423,24 +596,24 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateFieldBuilderInitializationCode(io::Printer* printer) const { // noop for enums } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n" "$clear_mutable_bit_builder$;\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { // The code below does two optimizations: // 1. If the other list is empty, there's nothing to do. This ensures we @@ -460,7 +633,7 @@ GenerateMergingCode(io::Printer* printer) const { "}\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateBuildingCode(io::Printer* printer) const { // The code below ensures that the result has an immutable list. If our // list is immutable, we can just reuse it. If not, we make it immutable. @@ -472,22 +645,23 @@ GenerateBuildingCode(io::Printer* printer) const { "result.$name$_ = $name$_;\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { // Read and store the enum printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n"); - if (HasUnknownFields(descriptor_->containing_type())) { + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (UseUnknownFieldSet(descriptor_->containing_type())) { printer->Print(variables_, - "if (value == null) {\n" - " unknownFields.mergeVarintField($number$, rawValue);\n" - "} else {\n"); + " unknownFields.mergeVarintField($number$, rawValue);\n"); } else { printer->Print(variables_, - "if (value != null) {\n"); + " unknownFieldsCodedOutput.writeRawVarint32(tag);\n" + " unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n"); } printer->Print(variables_, + " } else {\n" " if (!$get_mutable_bit_parser$) {\n" " $name$_ = new java.util.ArrayList<$type$>();\n" " $set_mutable_bit_parser$;\n" @@ -496,7 +670,7 @@ GenerateParsingCode(io::Printer* printer) const { "}\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateParsingCodeFromPacked(io::Printer* printer) const { // Wrap GenerateParsingCode's contents with a while loop. @@ -514,7 +688,7 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { "input.popLimit(oldLimit);\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { printer->Print(variables_, "if ($get_mutable_bit_parser$) {\n" @@ -522,7 +696,7 @@ GenerateParsingDoneCode(io::Printer* printer) const { "}\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { if (descriptor_->options().packed()) { printer->Print(variables_, @@ -541,7 +715,7 @@ GenerateSerializationCode(io::Printer* printer) const { } } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "{\n" @@ -577,24 +751,25 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print("}\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "result = result && get$capitalized_name$List()\n" " .equals(other.get$capitalized_name$List());\n"); } -void RepeatedEnumFieldGenerator:: +void RepeatedImmutableEnumFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "if (get$capitalized_name$Count() > 0) {\n" " hash = (37 * hash) + $constant_name$;\n" - " hash = (53 * hash) + hashEnumList(get$capitalized_name$List());\n" + " hash = (53 * hash) + com.google.protobuf.Internal.hashEnumList(\n" + " get$capitalized_name$List());\n" "}\n"); } -string RepeatedEnumFieldGenerator::GetBoxedType() const { - return ClassName(descriptor_->enum_type()); +string RepeatedImmutableEnumFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->enum_type()); } } // namespace java diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h index 90fae639..a3afb160 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.h +++ b/src/google/protobuf/compiler/java/java_enum_field.h @@ -41,16 +41,26 @@ namespace google { namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } +} + +namespace protobuf { namespace compiler { namespace java { -class EnumFieldGenerator : public FieldGenerator { +class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator { public: - explicit EnumFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, int builderBitIndex); - ~EnumFieldGenerator(); + explicit ImmutableEnumFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableEnumFieldGenerator(); - // implements FieldGenerator --------------------------------------- + // implements ImmutableFieldGenerator --------------------------------------- int GetNumBitsForMessage() const; int GetNumBitsForBuilder() const; void GenerateInterfaceMembers(io::Printer* printer) const; @@ -70,22 +80,45 @@ class EnumFieldGenerator : public FieldGenerator { string GetBoxedType() const; - private: + protected: const FieldDescriptor* descriptor_; map<string, string> variables_; const int messageBitIndex_; const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldGenerator); +}; + +class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator { + public: + ImmutableEnumOneofFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableEnumOneofFieldGenerator(); + + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldGenerator); }; -class RepeatedEnumFieldGenerator : public FieldGenerator { +class RepeatedImmutableEnumFieldGenerator : public ImmutableFieldGenerator { public: - explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, int builderBitIndex); - ~RepeatedEnumFieldGenerator(); + explicit RepeatedImmutableEnumFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableEnumFieldGenerator(); - // implements FieldGenerator --------------------------------------- + // implements ImmutableFieldGenerator --------------------------------------- int GetNumBitsForMessage() const; int GetNumBitsForBuilder() const; void GenerateInterfaceMembers(io::Printer* printer) const; @@ -111,8 +144,10 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { map<string, string> variables_; const int messageBitIndex_; const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableEnumFieldGenerator); }; } // namespace java diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc index 921fe658..c62dbfaf 100644 --- a/src/google/protobuf/compiler/java/java_extension.cc +++ b/src/google/protobuf/compiler/java/java_extension.cc @@ -33,74 +33,50 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/java/java_extension.h> + +#include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/compiler/java/java_helpers.h> -#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/strutil.h> namespace google { namespace protobuf { namespace compiler { namespace java { -namespace { - -const char* TypeName(FieldDescriptor::Type field_type) { - switch (field_type) { - case FieldDescriptor::TYPE_INT32 : return "INT32"; - case FieldDescriptor::TYPE_UINT32 : return "UINT32"; - case FieldDescriptor::TYPE_SINT32 : return "SINT32"; - case FieldDescriptor::TYPE_FIXED32 : return "FIXED32"; - case FieldDescriptor::TYPE_SFIXED32: return "SFIXED32"; - case FieldDescriptor::TYPE_INT64 : return "INT64"; - case FieldDescriptor::TYPE_UINT64 : return "UINT64"; - case FieldDescriptor::TYPE_SINT64 : return "SINT64"; - case FieldDescriptor::TYPE_FIXED64 : return "FIXED64"; - case FieldDescriptor::TYPE_SFIXED64: return "SFIXED64"; - case FieldDescriptor::TYPE_FLOAT : return "FLOAT"; - case FieldDescriptor::TYPE_DOUBLE : return "DOUBLE"; - case FieldDescriptor::TYPE_BOOL : return "BOOL"; - case FieldDescriptor::TYPE_STRING : return "STRING"; - case FieldDescriptor::TYPE_BYTES : return "BYTES"; - case FieldDescriptor::TYPE_ENUM : return "ENUM"; - case FieldDescriptor::TYPE_GROUP : return "GROUP"; - case FieldDescriptor::TYPE_MESSAGE : return "MESSAGE"; - - // No default because we want the compiler to complain if any new - // types are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; -} - -} - -ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor) - : descriptor_(descriptor) { +ImmutableExtensionGenerator::ImmutableExtensionGenerator( + const FieldDescriptor* descriptor, Context* context) + : descriptor_(descriptor), context_(context), + name_resolver_(context->GetNameResolver()) { if (descriptor_->extension_scope() != NULL) { - scope_ = ClassName(descriptor_->extension_scope()); + scope_ = name_resolver_->GetImmutableClassName( + descriptor_->extension_scope()); } else { - scope_ = ClassName(descriptor_->file()); + scope_ = name_resolver_->GetImmutableClassName(descriptor_->file()); } } -ExtensionGenerator::~ExtensionGenerator() {} +ImmutableExtensionGenerator::~ImmutableExtensionGenerator() {} // Initializes the vars referenced in the generated code templates. -void InitTemplateVars(const FieldDescriptor* descriptor, - const string& scope, - map<string, string>* vars_pointer) { +void ExtensionGenerator::InitTemplateVars(const FieldDescriptor* descriptor, + const string& scope, + bool immutable, + ClassNameResolver* name_resolver, + map<string, string>* vars_pointer) { map<string, string> &vars = *vars_pointer; vars["scope"] = scope; vars["name"] = UnderscoresToCamelCase(descriptor); - vars["containing_type"] = ClassName(descriptor->containing_type()); + vars["containing_type"] = + name_resolver->GetClassName(descriptor->containing_type(), immutable); vars["number"] = SimpleItoa(descriptor->number()); vars["constant_name"] = FieldConstantName(descriptor); vars["index"] = SimpleItoa(descriptor->index()); - vars["default"] = - descriptor->is_repeated() ? "" : DefaultValue(descriptor); - vars["type_constant"] = TypeName(GetType(descriptor)); + vars["default"] = descriptor->is_repeated() ? + "" : DefaultValue(descriptor, immutable, name_resolver); + vars["type_constant"] = FieldTypeName(GetType(descriptor)); vars["packed"] = descriptor->options().packed() ? "true" : "false"; vars["enum_map"] = "null"; vars["prototype"] = "null"; @@ -109,13 +85,21 @@ void InitTemplateVars(const FieldDescriptor* descriptor, string singular_type; switch (java_type) { case JAVATYPE_MESSAGE: - singular_type = ClassName(descriptor->message_type()); + singular_type = name_resolver->GetClassName(descriptor->message_type(), + immutable); vars["prototype"] = singular_type + ".getDefaultInstance()"; break; case JAVATYPE_ENUM: - singular_type = ClassName(descriptor->enum_type()); + singular_type = name_resolver->GetClassName(descriptor->enum_type(), + immutable); vars["enum_map"] = singular_type + ".internalGetValueMap()"; break; + case JAVATYPE_STRING: + singular_type = "java.lang.String"; + break; + case JAVATYPE_BYTES: + singular_type = immutable ? "com.google.protobuf.ByteString" : "byte[]"; + break; default: singular_type = BoxedPrimitiveTypeName(java_type); break; @@ -125,9 +109,11 @@ void InitTemplateVars(const FieldDescriptor* descriptor, vars["singular_type"] = singular_type; } -void ExtensionGenerator::Generate(io::Printer* printer) { +void ImmutableExtensionGenerator::Generate(io::Printer* printer) { map<string, string> vars; - InitTemplateVars(descriptor_, scope_, &vars); + const bool kUseImmutableNames = true; + InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_, + &vars); printer->Print(vars, "public static final int $constant_name$ = $number$;\n"); @@ -174,7 +160,8 @@ void ExtensionGenerator::Generate(io::Printer* printer) { " $enum_map$,\n" " $number$,\n" " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" - " $packed$);\n"); + " $packed$,\n" + " $singular_type$.class);\n"); } else { printer->Print( vars, @@ -188,12 +175,13 @@ void ExtensionGenerator::Generate(io::Printer* printer) { " $prototype$,\n" " $enum_map$,\n" " $number$,\n" - " com.google.protobuf.WireFormat.FieldType.$type_constant$);\n"); + " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" + " $singular_type$.class);\n"); } } } -void ExtensionGenerator::GenerateNonNestedInitializationCode( +void ImmutableExtensionGenerator::GenerateNonNestedInitializationCode( io::Printer* printer) { if (descriptor_->extension_scope() == NULL && HasDescriptorMethods(descriptor_->file())) { @@ -205,7 +193,8 @@ void ExtensionGenerator::GenerateNonNestedInitializationCode( } } -void ExtensionGenerator::GenerateRegistrationCode(io::Printer* printer) { +void ImmutableExtensionGenerator::GenerateRegistrationCode( + io::Printer* printer) { printer->Print( "registry.add($scope$.$name$);\n", "scope", scope_, diff --git a/src/google/protobuf/compiler/java/java_extension.h b/src/google/protobuf/compiler/java/java_extension.h index 009ed9ff..69686ef2 100644 --- a/src/google/protobuf/compiler/java/java_extension.h +++ b/src/google/protobuf/compiler/java/java_extension.h @@ -35,6 +35,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__ #define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__ +#include <map> #include <string> #include <google/protobuf/stubs/common.h> @@ -42,6 +43,12 @@ namespace google { namespace protobuf { class FieldDescriptor; // descriptor.h + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } namespace io { class Printer; // printer.h } @@ -56,17 +63,42 @@ namespace java { // since extensions are just simple identifiers with interesting types. class ExtensionGenerator { public: - explicit ExtensionGenerator(const FieldDescriptor* descriptor); - ~ExtensionGenerator(); + explicit ExtensionGenerator() {} + virtual ~ExtensionGenerator() {} + + virtual void Generate(io::Printer* printer) = 0; + virtual void GenerateNonNestedInitializationCode(io::Printer* printer) = 0; + virtual void GenerateRegistrationCode(io::Printer* printer) = 0; - void Generate(io::Printer* printer); - void GenerateNonNestedInitializationCode(io::Printer* printer); - void GenerateRegistrationCode(io::Printer* printer); + protected: + static void InitTemplateVars(const FieldDescriptor* descriptor, + const string& scope, + bool immutable, + ClassNameResolver* name_resolver, + map<string, string>* vars_pointer); private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); +}; + +class ImmutableExtensionGenerator : public ExtensionGenerator { + public: + explicit ImmutableExtensionGenerator(const FieldDescriptor* descriptor, + Context* context); + virtual ~ImmutableExtensionGenerator(); + + virtual void Generate(io::Printer* printer); + virtual void GenerateNonNestedInitializationCode(io::Printer* printer); + virtual void GenerateRegistrationCode(io::Printer* printer); + + protected: const FieldDescriptor* descriptor_; + Context* context_; + ClassNameResolver* name_resolver_; string scope_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionGenerator); }; } // namespace java @@ -74,4 +106,4 @@ class ExtensionGenerator { } // namespace protobuf } // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__ diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index c7d433c8..f670477c 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -33,102 +33,178 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/java/java_field.h> -#include <google/protobuf/compiler/java/java_helpers.h> -#include <google/protobuf/compiler/java/java_primitive_field.h> + +#include <memory> + +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum_field.h> +#include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_lazy_message_field.h> #include <google/protobuf/compiler/java/java_message_field.h> +#include <google/protobuf/compiler/java/java_primitive_field.h> #include <google/protobuf/compiler/java/java_string_field.h> -#include <google/protobuf/stubs/common.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> namespace google { namespace protobuf { namespace compiler { namespace java { -FieldGenerator::~FieldGenerator() {} +namespace { + +ImmutableFieldGenerator* MakeImmutableGenerator( + const FieldDescriptor* field, int messageBitIndex, int builderBitIndex, + Context* context) { + if (field->is_repeated()) { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + if (IsLazy(field)) { + return new RepeatedImmutableLazyMessageFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } else { + return new RepeatedImmutableMessageFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } + case JAVATYPE_ENUM: + return new RepeatedImmutableEnumFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + case JAVATYPE_STRING: + return new RepeatedImmutableStringFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + default: + return new RepeatedImmutablePrimitiveFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } + } else { + if (field->containing_oneof()) { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + if (IsLazy(field)) { + return new ImmutableLazyMessageOneofFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } else { + return new ImmutableMessageOneofFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } + case JAVATYPE_ENUM: + return new ImmutableEnumOneofFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + case JAVATYPE_STRING: + return new ImmutableStringOneofFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + default: + return new ImmutablePrimitiveOneofFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } + } else { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + if (IsLazy(field)) { + return new ImmutableLazyMessageFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } else { + return new ImmutableMessageFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } + case JAVATYPE_ENUM: + return new ImmutableEnumFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + case JAVATYPE_STRING: + return new ImmutableStringFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + default: + return new ImmutablePrimitiveFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } + } + } +} + -void FieldGenerator::GenerateParsingCodeFromPacked(io::Printer* printer) const { +static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) { // Reaching here indicates a bug. Cases are: - // - This FieldGenerator should support packing, but this method should be - // overridden. - // - This FieldGenerator doesn't support packing, and this method should - // never have been called. + // - This FieldGenerator should support packing, + // but this method should be overridden. + // - This FieldGenerator doesn't support packing, and this method + // should never have been called. GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() " << "called on field generator that does not support packing."; } -FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) - : descriptor_(descriptor), - field_generators_( - new scoped_ptr<FieldGenerator>[descriptor->field_count()]), - extension_generators_( - new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) { +} // namespace + +ImmutableFieldGenerator::~ImmutableFieldGenerator() {} + +void ImmutableFieldGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + ReportUnexpectedPackedFieldsCall(printer); +} + +// =================================================================== + +template <> +FieldGeneratorMap<ImmutableFieldGenerator>::FieldGeneratorMap( + const Descriptor* descriptor, Context* context) + : descriptor_(descriptor), + field_generators_(new scoped_ptr< + ImmutableFieldGenerator>[descriptor->field_count()]) { // Construct all the FieldGenerators and assign them bit indices for their // bit fields. int messageBitIndex = 0; int builderBitIndex = 0; for (int i = 0; i < descriptor->field_count(); i++) { - FieldGenerator* generator = MakeGenerator(descriptor->field(i), - messageBitIndex, builderBitIndex); + ImmutableFieldGenerator* generator = MakeImmutableGenerator( + descriptor->field(i), messageBitIndex, builderBitIndex, context); field_generators_[i].reset(generator); messageBitIndex += generator->GetNumBitsForMessage(); builderBitIndex += generator->GetNumBitsForBuilder(); } - for (int i = 0; i < descriptor->extension_count(); i++) { - FieldGenerator* generator = MakeGenerator(descriptor->extension(i), - messageBitIndex, builderBitIndex); - extension_generators_[i].reset(generator); - messageBitIndex += generator->GetNumBitsForMessage(); - builderBitIndex += generator->GetNumBitsForBuilder(); - } } -FieldGenerator* FieldGeneratorMap::MakeGenerator( - const FieldDescriptor* field, int messageBitIndex, int builderBitIndex) { - if (field->is_repeated()) { - switch (GetJavaType(field)) { - case JAVATYPE_MESSAGE: - return new RepeatedMessageFieldGenerator( - field, messageBitIndex, builderBitIndex); - case JAVATYPE_ENUM: - return new RepeatedEnumFieldGenerator( - field, messageBitIndex, builderBitIndex); - case JAVATYPE_STRING: - return new RepeatedStringFieldGenerator( - field, messageBitIndex, builderBitIndex); - default: - return new RepeatedPrimitiveFieldGenerator( - field, messageBitIndex, builderBitIndex); - } - } else { - switch (GetJavaType(field)) { - case JAVATYPE_MESSAGE: - return new MessageFieldGenerator( - field, messageBitIndex, builderBitIndex); - case JAVATYPE_ENUM: - return new EnumFieldGenerator( - field, messageBitIndex, builderBitIndex); - case JAVATYPE_STRING: - return new StringFieldGenerator( - field, messageBitIndex, builderBitIndex); - default: - return new PrimitiveFieldGenerator( - field, messageBitIndex, builderBitIndex); - } - } -} +template<> +FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap() {} -FieldGeneratorMap::~FieldGeneratorMap() {} -const FieldGenerator& FieldGeneratorMap::get( - const FieldDescriptor* field) const { - GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); - return *field_generators_[field->index()]; +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + const FieldGeneratorInfo* info, + map<string, string>* variables) { + (*variables)["field_name"] = descriptor->name(); + (*variables)["name"] = info->name; + (*variables)["capitalized_name"] = info->capitalized_name; + (*variables)["disambiguated_reason"] = info->disambiguated_reason; + (*variables)["constant_name"] = FieldConstantName(descriptor); + (*variables)["number"] = SimpleItoa(descriptor->number()); } -const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { - return *extension_generators_[index]; +void SetCommonOneofVariables(const FieldDescriptor* descriptor, + const OneofGeneratorInfo* info, + map<string, string>* variables) { + (*variables)["oneof_name"] = info->name; + (*variables)["oneof_capitalized_name"] = info->capitalized_name; + (*variables)["oneof_index"] = + SimpleItoa(descriptor->containing_oneof()->index()); + (*variables)["set_oneof_case_message"] = info->name + + "Case_ = " + SimpleItoa(descriptor->number()); + (*variables)["clear_oneof_case_message"] = info->name + + "Case_ = 0"; + (*variables)["has_oneof_case_message"] = info->name + + "Case_ == " + SimpleItoa(descriptor->number()); +} + +void PrintExtraFieldInfo(const map<string, string>& variables, + io::Printer* printer) { + const map<string, string>::const_iterator it = + variables.find("disambiguated_reason"); + if (it != variables.end() && !it->second.empty()) { + printer->Print( + variables, + "// An alternative name is used for field \"$field_name$\" because:\n" + "// $disambiguated_reason$\n"); + } } } // namespace java diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index 4dd0efd6..a4aa3bce 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -35,14 +35,23 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ #define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ +#include <map> +#include <memory> #include <string> + #include <google/protobuf/stubs/common.h> #include <google/protobuf/descriptor.h> namespace google { namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } namespace io { - class Printer; // printer.h + class Printer; // printer.h } } @@ -50,10 +59,10 @@ namespace protobuf { namespace compiler { namespace java { -class FieldGenerator { +class ImmutableFieldGenerator { public: - FieldGenerator() {} - virtual ~FieldGenerator(); + ImmutableFieldGenerator() {} + virtual ~ImmutableFieldGenerator(); virtual int GetNumBitsForMessage() const = 0; virtual int GetNumBitsForBuilder() const = 0; @@ -78,29 +87,73 @@ class FieldGenerator { virtual string GetBoxedType() const = 0; private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldGenerator); }; + // Convenience class which constructs FieldGenerators for a Descriptor. +template<typename FieldGeneratorType> class FieldGeneratorMap { public: - explicit FieldGeneratorMap(const Descriptor* descriptor); + explicit FieldGeneratorMap(const Descriptor* descriptor, + Context* context); ~FieldGeneratorMap(); - const FieldGenerator& get(const FieldDescriptor* field) const; - const FieldGenerator& get_extension(int index) const; + const FieldGeneratorType& get(const FieldDescriptor* field) const; private: const Descriptor* descriptor_; - scoped_array<scoped_ptr<FieldGenerator> > field_generators_; - scoped_array<scoped_ptr<FieldGenerator> > extension_generators_; - - static FieldGenerator* MakeGenerator(const FieldDescriptor* field, - int messageBitIndex, int builderBitIndex); + Context* context_; + ClassNameResolver* name_resolver_; + scoped_array<scoped_ptr<FieldGeneratorType> > field_generators_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); }; +template<typename FieldGeneratorType> +inline const FieldGeneratorType& +FieldGeneratorMap<FieldGeneratorType>::get(const FieldDescriptor* field) const { + GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); + return *field_generators_[field->index()]; +} + +// Instantiate template for mutable and immutable maps. +template<> +FieldGeneratorMap<ImmutableFieldGenerator>:: +FieldGeneratorMap(const Descriptor* descriptor, + Context* context); + +template<> +FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap(); + + +// Field information used in FieldGeneartors. +struct FieldGeneratorInfo { + string name; + string capitalized_name; + string disambiguated_reason; +}; + +// Oneof information used in OneofFieldGeneartors. +struct OneofGeneratorInfo { + string name; + string capitalized_name; +}; + +// Set some common variables used in variable FieldGenerators. +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + const FieldGeneratorInfo* info, + map<string, string>* variables); + +// Set some common oneof variables used in OneofFieldGenerators. +void SetCommonOneofVariables(const FieldDescriptor* descriptor, + const OneofGeneratorInfo* info, + map<string, string>* variables); + +// Print useful comments before a field's accessors. +void PrintExtraFieldInfo(const map<string, string>& variables, + io::Printer* printer); + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index f43e5500..deec0e71 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -33,11 +33,17 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/java/java_file.h> + +#include <memory> + +#include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum.h> -#include <google/protobuf/compiler/java/java_service.h> #include <google/protobuf/compiler/java/java_extension.h> +#include <google/protobuf/compiler/java/java_generator_factory.h> #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/compiler/java/java_message.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> +#include <google/protobuf/compiler/java/java_service.h> #include <google/protobuf/compiler/code_generator.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> @@ -132,10 +138,27 @@ void CollectExtensions(const FileDescriptorProto& file_proto, } // namespace -FileGenerator::FileGenerator(const FileDescriptor* file) - : file_(file), - java_package_(FileJavaPackage(file)), - classname_(FileClassName(file)) { +FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api) + : file_(file), + java_package_(FileJavaPackage(file, immutable_api)), + message_generators_( + new scoped_ptr<MessageGenerator>[file->message_type_count()]), + extension_generators_( + new scoped_ptr<ExtensionGenerator>[file->extension_count()]), + context_(new Context(file)), + name_resolver_(context_->GetNameResolver()), + immutable_api_(immutable_api) { + classname_ = name_resolver_->GetFileClassName(file, immutable_api); + generator_factory_.reset( + new ImmutableGeneratorFactory(context_.get())); + for (int i = 0; i < file_->message_type_count(); ++i) { + message_generators_[i].reset( + generator_factory_->NewMessageGenerator(file_->message_type(i))); + } + for (int i = 0; i < file_->extension_count(); ++i) { + extension_generators_[i].reset( + generator_factory_->NewExtensionGenerator(file_->extension(i))); + } } FileGenerator::~FileGenerator() {} @@ -145,25 +168,7 @@ bool FileGenerator::Validate(string* error) { // 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. - - bool found_conflict = false; - for (int i = 0; i < file_->enum_type_count() && !found_conflict; i++) { - if (file_->enum_type(i)->name() == classname_) { - found_conflict = true; - } - } - for (int i = 0; i < file_->message_type_count() && !found_conflict; i++) { - if (file_->message_type(i)->name() == classname_) { - found_conflict = true; - } - } - for (int i = 0; i < file_->service_count() && !found_conflict; i++) { - if (file_->service(i)->name() == classname_) { - found_conflict = true; - } - } - - if (found_conflict) { + if (name_resolver_->HasConflictingClassName(file_, classname_)) { error->assign(file_->name()); error->append( ": Cannot generate Java output because the file's outer class name, \""); @@ -174,7 +179,29 @@ bool FileGenerator::Validate(string* error) { "option to specify a different outer class name for the .proto file."); return false; } - + // If java_outer_classname option is not set and the default outer class name + // conflicts with a type defined in the message, we will append a suffix to + // avoid the conflict. This allows proto1 API protos to be dual-compiled into + // proto2 API without code change. When this happens we'd like to issue an + // warning to let the user know that the outer class name has been changed. + // Although we only do this automatic naming fix for immutable API, mutable + // outer class name will also be affected as it's contructed from immutable + // outer class name with an additional "Mutable" prefix. Since the naming + // change in mutable API is not caused by a naming conflict, we generate the + // warning for immutable API only. + if (immutable_api_ && !file_->options().has_java_outer_classname()) { + string default_classname = + name_resolver_->GetFileDefaultImmutableClassName(file_); + if (default_classname != classname_) { + GOOGLE_LOG(WARNING) << file_->name() << ": The default outer class name, \"" + << default_classname << "\", conflicts with a type " + << "declared in the proto file and an alternative outer " + << "class name is used: \"" << classname_ << "\". To avoid " + << "this warning, please use the java_outer_classname " + << "option to specify a different outer class name for " + << "the .proto file."; + } + } return true; } @@ -208,12 +235,11 @@ void FileGenerator::Generate(io::Printer* printer) { printer->Indent(); for (int i = 0; i < file_->extension_count(); i++) { - ExtensionGenerator(file_->extension(i)).GenerateRegistrationCode(printer); + extension_generators_[i]->GenerateRegistrationCode(printer); } for (int i = 0; i < file_->message_type_count(); i++) { - MessageGenerator(file_->message_type(i)) - .GenerateExtensionRegistrationCode(printer); + message_generators_[i]->GenerateExtensionRegistrationCode(printer); } printer->Outdent(); @@ -222,18 +248,20 @@ void FileGenerator::Generate(io::Printer* printer) { // ----------------------------------------------------------------- - if (!file_->options().java_multiple_files()) { + if (!MultipleJavaFiles(file_, immutable_api_)) { for (int i = 0; i < file_->enum_type_count(); i++) { - EnumGenerator(file_->enum_type(i)).Generate(printer); + EnumGenerator(file_->enum_type(i), immutable_api_, context_.get()) + .Generate(printer); } for (int i = 0; i < file_->message_type_count(); i++) { - MessageGenerator messageGenerator(file_->message_type(i)); - messageGenerator.GenerateInterface(printer); - messageGenerator.Generate(printer); + message_generators_[i]->GenerateInterface(printer); + message_generators_[i]->Generate(printer); } if (HasGenericServices(file_)) { for (int i = 0; i < file_->service_count(); i++) { - ServiceGenerator(file_->service(i)).Generate(printer); + scoped_ptr<ServiceGenerator> generator( + generator_factory_->NewServiceGenerator(file_->service(i))); + generator->Generate(printer); } } } @@ -241,28 +269,29 @@ void FileGenerator::Generate(io::Printer* printer) { // Extensions must be generated in the outer class since they are values, // not classes. for (int i = 0; i < file_->extension_count(); i++) { - ExtensionGenerator(file_->extension(i)).Generate(printer); + extension_generators_[i]->Generate(printer); } // Static variables. for (int i = 0; i < file_->message_type_count(); i++) { - // TODO(kenton): Reuse MessageGenerator objects? - MessageGenerator(file_->message_type(i)).GenerateStaticVariables(printer); + message_generators_[i]->GenerateStaticVariables(printer); } printer->Print("\n"); if (HasDescriptorMethods(file_)) { - GenerateEmbeddedDescriptor(printer); + if (immutable_api_) { + GenerateDescriptorInitializationCodeForImmutable(printer); + } else { + GenerateDescriptorInitializationCodeForMutable(printer); + } } else { printer->Print( "static {\n"); printer->Indent(); for (int i = 0; i < file_->message_type_count(); i++) { - // TODO(kenton): Reuse MessageGenerator objects? - MessageGenerator(file_->message_type(i)) - .GenerateStaticVariableInitializers(printer); + message_generators_[i]->GenerateStaticVariableInitializers(printer); } printer->Outdent(); @@ -278,23 +307,8 @@ void FileGenerator::Generate(io::Printer* printer) { printer->Print("}\n"); } -void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { - // Embed the descriptor. We simply serialize the entire FileDescriptorProto - // and embed it as a string literal, which is parsed and built into real - // descriptors at initialization time. We unfortunately have to put it in - // a string literal, not a byte array, because apparently using a literal - // byte array causes the Java compiler to generate *instructions* to - // initialize each and every byte of the array, e.g. as if you typed: - // b[0] = 123; b[1] = 456; b[2] = 789; - // This makes huge bytecode files and can easily hit the compiler's internal - // code size limits (error "code to large"). String literals are apparently - // embedded raw, which is what we want. - FileDescriptorProto file_proto; - file_->CopyTo(&file_proto); - - string file_data; - file_proto.SerializeToString(&file_data); - +void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( + io::Printer* printer) { printer->Print( "public static com.google.protobuf.Descriptors.FileDescriptor\n" " getDescriptor() {\n" @@ -302,55 +316,18 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { "}\n" "private static com.google.protobuf.Descriptors.FileDescriptor\n" " descriptor;\n" - "static {\n" - " java.lang.String[] descriptorData = {\n"); + "static {\n"); printer->Indent(); - printer->Indent(); - - // Only write 40 bytes per line. - static const int kBytesPerLine = 40; - for (int i = 0; i < file_data.size(); i += kBytesPerLine) { - if (i > 0) { - // Every 400 lines, start a new string literal, in order to avoid the - // 64k length limit. - if (i % 400 == 0) { - printer->Print(",\n"); - } else { - printer->Print(" +\n"); - } - } - printer->Print("\"$data$\"", - "data", CEscape(file_data.substr(i, kBytesPerLine))); - } - - printer->Outdent(); - printer->Print("\n};\n"); - - // ----------------------------------------------------------------- - // Create the InternalDescriptorAssigner. printer->Print( - "com.google.protobuf.Descriptors.FileDescriptor." - "InternalDescriptorAssigner assigner =\n" - " new com.google.protobuf.Descriptors.FileDescriptor." - "InternalDescriptorAssigner() {\n" - " public com.google.protobuf.ExtensionRegistry assignDescriptors(\n" - " com.google.protobuf.Descriptors.FileDescriptor root) {\n" - " descriptor = root;\n"); - - printer->Indent(); - printer->Indent(); - printer->Indent(); + "descriptor = $descriptor_classname$.descriptor;\n", + "descriptor_classname", name_resolver_->GetDescriptorClassName(file_)); for (int i = 0; i < file_->message_type_count(); i++) { - // TODO(kenton): Reuse MessageGenerator objects? - MessageGenerator(file_->message_type(i)) - .GenerateStaticVariableInitializers(printer); + message_generators_[i]->GenerateStaticVariableInitializers(printer); } for (int i = 0; i < file_->extension_count(); i++) { - // TODO(kenton): Reuse ExtensionGenerator objects? - ExtensionGenerator(file_->extension(i)) - .GenerateNonNestedInitializationCode(printer); + extension_generators_[i]->GenerateNonNestedInitializationCode(printer); } // Proto compiler builds a DescriptorPool, which holds all the descriptors to @@ -368,52 +345,107 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { // To find those extensions, we need to parse the data into a dynamic message // of the FileDescriptor based on the builder-pool, then we can use // reflections to find all extension fields + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + string file_data; + file_proto.SerializeToString(&file_data); vector<const FieldDescriptor*> extensions; CollectExtensions(file_proto, *file_->pool(), &extensions, file_data); if (extensions.size() > 0) { // Must construct an ExtensionRegistry containing all existing extensions - // and return it. + // and use it to parse the descriptor data again to recognize extensions. printer->Print( "com.google.protobuf.ExtensionRegistry registry =\n" - " com.google.protobuf.ExtensionRegistry.newInstance();\n"); + " com.google.protobuf.ExtensionRegistry.newInstance();\n"); for (int i = 0; i < extensions.size(); i++) { - ExtensionGenerator(extensions[i]).GenerateRegistrationCode(printer); + scoped_ptr<ExtensionGenerator> generator( + generator_factory_->NewExtensionGenerator(extensions[i])); + generator->GenerateRegistrationCode(printer); } printer->Print( - "return registry;\n"); - } else { - printer->Print( - "return null;\n"); + "com.google.protobuf.Descriptors.FileDescriptor\n" + " .internalUpdateFileDescriptor(descriptor, registry);\n"); } - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); + // Force descriptor initialization of all dependencies. + for (int i = 0; i < file_->dependency_count(); i++) { + if (ShouldIncludeDependency(file_->dependency(i), true)) { + string dependency = + name_resolver_->GetImmutableClassName(file_->dependency(i)); + printer->Print( + "$dependency$.getDescriptor();\n", + "dependency", dependency); + } + } + printer->Outdent(); printer->Print( - " }\n" - " };\n"); + "}\n"); +} - // ----------------------------------------------------------------- - // Invoke internalBuildGeneratedFileFrom() to build the file. +void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer* printer) { + printer->Print( + "public static com.google.protobuf.Descriptors.FileDescriptor\n" + " getDescriptor() {\n" + " return descriptor;\n" + "}\n" + "private static com.google.protobuf.Descriptors.FileDescriptor\n" + " descriptor;\n" + "static {\n"); + printer->Indent(); printer->Print( - "com.google.protobuf.Descriptors.FileDescriptor\n" - " .internalBuildGeneratedFileFrom(descriptorData,\n" - " new com.google.protobuf.Descriptors.FileDescriptor[] {\n"); + "descriptor = $immutable_package$.$descriptor_classname$.descriptor;\n", + "immutable_package", FileJavaPackage(file_, true), + "descriptor_classname", name_resolver_->GetDescriptorClassName(file_)); + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateStaticVariableInitializers(printer); + } + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateNonNestedInitializationCode(printer); + } + + // Check if custom options exist. If any, try to load immutable classes since + // custom options are only represented with immutable messages. + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + string file_data; + file_proto.SerializeToString(&file_data); + vector<const FieldDescriptor*> extensions; + CollectExtensions(file_proto, *file_->pool(), &extensions, file_data); + + if (extensions.size() > 0) { + // Try to load immutable messages' outer class. Its initialization code + // will take care of interpreting custom options. + printer->Print( + "try {\n" + // Note that we have to load the immutable class dynamically here as + // we want the mutable code to be independent from the immutable code + // at compile time. It is required to implement dual-compile for + // mutable and immutable API in blaze. + " java.lang.Class immutableClass = java.lang.Class.forName(\n" + " \"$immutable_classname$\");\n" + "} catch (java.lang.ClassNotFoundException e) {\n" + // The immutable class can not be found. Custom options are left + // as unknown fields. + // TODO(xiaofeng): inform the user with a warning? + "}\n", + "immutable_classname", name_resolver_->GetImmutableClassName(file_)); + } + + // Force descriptor initialization of all dependencies. for (int i = 0; i < file_->dependency_count(); i++) { - if (ShouldIncludeDependency(file_->dependency(i))) { + if (ShouldIncludeDependency(file_->dependency(i), false)) { + string dependency = name_resolver_->GetMutableClassName( + file_->dependency(i)); printer->Print( - " $dependency$.getDescriptor(),\n", - "dependency", ClassName(file_->dependency(i))); + "$dependency$.getDescriptor();\n", + "dependency", dependency); } } - printer->Print( - " }, assigner);\n"); - printer->Outdent(); printer->Print( "}\n"); @@ -426,6 +458,7 @@ static void GenerateSibling(const string& package_dir, GeneratorContext* context, vector<string>* file_list, const string& name_suffix, + GeneratorClass* generator, void (GeneratorClass::*pfn)(io::Printer* printer)) { string filename = package_dir + descriptor->name() + name_suffix + ".java"; file_list->push_back(filename); @@ -445,42 +478,53 @@ static void GenerateSibling(const string& package_dir, "package", java_package); } - GeneratorClass generator(descriptor); - (generator.*pfn)(&printer); + (generator->*pfn)(&printer); } void FileGenerator::GenerateSiblings(const string& package_dir, GeneratorContext* context, vector<string>* file_list) { - if (file_->options().java_multiple_files()) { + if (MultipleJavaFiles(file_, immutable_api_)) { for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator generator(file_->enum_type(i), immutable_api_, + context_.get()); GenerateSibling<EnumGenerator>(package_dir, java_package_, file_->enum_type(i), context, file_list, "", + &generator, &EnumGenerator::Generate); } for (int i = 0; i < file_->message_type_count(); i++) { - GenerateSibling<MessageGenerator>(package_dir, java_package_, - file_->message_type(i), - context, file_list, "OrBuilder", - &MessageGenerator::GenerateInterface); + if (immutable_api_) { + GenerateSibling<MessageGenerator>(package_dir, java_package_, + file_->message_type(i), + context, file_list, + "OrBuilder", + message_generators_[i].get(), + &MessageGenerator::GenerateInterface); + } GenerateSibling<MessageGenerator>(package_dir, java_package_, file_->message_type(i), context, file_list, "", + message_generators_[i].get(), &MessageGenerator::Generate); } if (HasGenericServices(file_)) { for (int i = 0; i < file_->service_count(); i++) { + scoped_ptr<ServiceGenerator> generator( + generator_factory_->NewServiceGenerator(file_->service(i))); GenerateSibling<ServiceGenerator>(package_dir, java_package_, file_->service(i), context, file_list, "", + generator.get(), &ServiceGenerator::Generate); } } } } -bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) { +bool FileGenerator::ShouldIncludeDependency( + const FileDescriptor* descriptor, bool immutable_api) { return true; } diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h index 59911462..7f289491 100644 --- a/src/google/protobuf/compiler/java/java_file.h +++ b/src/google/protobuf/compiler/java/java_file.h @@ -35,18 +35,26 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ #define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ +#include <memory> #include <string> #include <vector> #include <google/protobuf/stubs/common.h> namespace google { namespace protobuf { - class FileDescriptor; // descriptor.h + class FileDescriptor; // descriptor.h namespace io { - class Printer; // printer.h + class Printer; // printer.h } namespace compiler { - class GeneratorContext; // code_generator.h + class GeneratorContext; // code_generator.h + namespace java { + class Context; // context.h + class MessageGenerator; // message.h + class GeneratorFactory; // generator_factory.h + class ExtensionGenerator; // extension.h + class ClassNameResolver; // name_resolver.h + } } } @@ -56,7 +64,7 @@ namespace java { class FileGenerator { public: - explicit FileGenerator(const FileDescriptor* file); + FileGenerator(const FileDescriptor* file, bool immutable_api = true); ~FileGenerator(); // Checks for problems that would otherwise lead to cryptic compile errors. @@ -78,17 +86,23 @@ class FileGenerator { private: - // Returns whether the dependency should be included in the output file. - // Always returns true for opensource, but used internally at Google to help - // improve compatibility with version 1 of protocol buffers. - bool ShouldIncludeDependency(const FileDescriptor* descriptor); + void GenerateDescriptorInitializationCodeForImmutable(io::Printer* printer); + void GenerateDescriptorInitializationCodeForMutable(io::Printer* printer); + + bool ShouldIncludeDependency(const FileDescriptor* descriptor, + bool immutable_api_); const FileDescriptor* file_; string java_package_; string classname_; + scoped_array<scoped_ptr<MessageGenerator> > message_generators_; + scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_; + scoped_ptr<GeneratorFactory> generator_factory_; + scoped_ptr<Context> context_; + ClassNameResolver* name_resolver_; + bool immutable_api_; - void GenerateEmbeddedDescriptor(io::Printer* printer); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); }; diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc index e6c79abc..b713797b 100644 --- a/src/google/protobuf/compiler/java/java_generator.cc +++ b/src/google/protobuf/compiler/java/java_generator.cc @@ -33,8 +33,13 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/java/java_generator.h> + +#include <memory> + #include <google/protobuf/compiler/java/java_file.h> +#include <google/protobuf/compiler/java/java_generator_factory.h> #include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_shared_code_generator.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/descriptor.pb.h> @@ -64,55 +69,89 @@ bool JavaGenerator::Generate(const FileDescriptor* file, vector<pair<string, string> > options; ParseGeneratorParameter(parameter, &options); + bool generate_immutable_code = false; + bool generate_mutable_code = false; + bool generate_shared_code = false; for (int i = 0; i < options.size(); i++) { if (options[i].first == "output_list_file") { output_list_file = options[i].second; + } else if (options[i].first == "immutable") { + generate_immutable_code = true; + } else if (options[i].first == "mutable") { + generate_mutable_code = true; + } else if (options[i].first == "shared") { + generate_shared_code = true; } else { *error = "Unknown generator option: " + options[i].first; return false; } } + // By default we generate immutable code and shared code for immutable API. + if (!generate_immutable_code && !generate_mutable_code && + !generate_shared_code) { + generate_immutable_code = true; + generate_shared_code = true; + } + // ----------------------------------------------------------------- - if (file->options().optimize_for() == FileOptions::LITE_RUNTIME && - file->options().java_generate_equals_and_hash()) { - *error = "The \"java_generate_equals_and_hash\" option is incompatible " - "with \"optimize_for = LITE_RUNTIME\". You must optimize for " - "SPEED or CODE_SIZE if you want to use this option."; - return false; + vector<string> all_files; + + if (generate_shared_code) { + // Generate code shared between immutable and mutable API. + SharedCodeGenerator shared_code_generator(file); + shared_code_generator.Generate(context, &all_files); } - FileGenerator file_generator(file); - if (!file_generator.Validate(error)) { - return false; + vector<FileGenerator*> file_generators; + if (generate_immutable_code) { + file_generators.push_back(new FileGenerator(file, /* immutable = */ true)); + } + if (generate_mutable_code) { + file_generators.push_back(new FileGenerator(file, /* mutable = */ false)); + } + for (int i = 0; i < file_generators.size(); ++i) { + if (!file_generators[i]->Validate(error)) { + for (int j = 0; j < file_generators.size(); ++j) { + delete file_generators[j]; + } + return false; + } } - string package_dir = JavaPackageToDir(file_generator.java_package()); + for (int i = 0; i < file_generators.size(); ++i) { + FileGenerator* file_generator = file_generators[i]; - vector<string> all_files; + string package_dir = JavaPackageToDir(file_generator->java_package()); - string java_filename = package_dir; - java_filename += file_generator.classname(); - java_filename += ".java"; - all_files.push_back(java_filename); + 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( - context->Open(java_filename)); - io::Printer printer(output.get(), '$'); - file_generator.Generate(&printer); + // Generate main java file. + scoped_ptr<io::ZeroCopyOutputStream> output( + context->Open(java_filename)); + io::Printer printer(output.get(), '$'); + file_generator->Generate(&printer); - // Generate sibling files. - file_generator.GenerateSiblings(package_dir, context, &all_files); + // Generate sibling files. + file_generator->GenerateSiblings(package_dir, context, &all_files); + } + + for (int i = 0; i < file_generators.size(); ++i) { + delete file_generators[i]; + } + file_generators.clear(); // Generate output list if requested. if (!output_list_file.empty()) { // Generate output list. This is just a simple text file placed in a // deterministic location which lists the .java files being generated. scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output( - context->Open(output_list_file)); + context->Open(output_list_file)); io::Printer srclist_printer(srclist_raw_output.get(), '$'); for (int i = 0; i < all_files.size(); i++) { srclist_printer.Print("$filename$\n", "filename", all_files[i]); diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc new file mode 100644 index 00000000..ce71d436 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_generator_factory.cc @@ -0,0 +1,77 @@ +// 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: liujisi@google.com (Pherl Liu) + +#include <google/protobuf/compiler/java/java_generator_factory.h> + +#include <google/protobuf/compiler/java/java_context.h> +#include <google/protobuf/compiler/java/java_enum_field.h> +#include <google/protobuf/compiler/java/java_extension.h> +#include <google/protobuf/compiler/java/java_field.h> +#include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_message.h> +#include <google/protobuf/compiler/java/java_service.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +GeneratorFactory::GeneratorFactory() {} +GeneratorFactory::~GeneratorFactory() {} + +// =================================================================== + +ImmutableGeneratorFactory::ImmutableGeneratorFactory( + Context* context) : context_(context) { +} +ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {} + +MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator( + const Descriptor* descriptor) const { + return new ImmutableMessageGenerator(descriptor, context_); +} + +ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator( + const FieldDescriptor* descriptor) const { + return new ImmutableExtensionGenerator(descriptor, context_); +} + +ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator( + const ServiceDescriptor* descriptor) const { + return new ImmutableServiceGenerator(descriptor, context_); +} + + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_generator_factory.h b/src/google/protobuf/compiler/java/java_generator_factory.h new file mode 100644 index 00000000..abf894f6 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_generator_factory.h @@ -0,0 +1,101 @@ +// 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: liujisi@google.com (Pherl Liu) + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__ + +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { + class FieldDescriptor; // descriptor.h + class Descriptor; // descriptor.h + class ServiceDescriptor; // descriptor.h + namespace compiler { + namespace java { + class MessageGenerator; // message.h + class ExtensionGenerator; // extension.h + class ServiceGenerator; // service.h + class Context; // context.h + } + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class GeneratorFactory { + public: + GeneratorFactory(); + virtual ~GeneratorFactory(); + + virtual MessageGenerator* NewMessageGenerator( + const Descriptor* descriptor) const = 0; + + virtual ExtensionGenerator* NewExtensionGenerator( + const FieldDescriptor* descriptor) const = 0; + + virtual ServiceGenerator* NewServiceGenerator( + const ServiceDescriptor* descriptor) const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorFactory); +}; + +// Factory that creates generators for immutable-default messages. +class ImmutableGeneratorFactory : public GeneratorFactory { + public: + ImmutableGeneratorFactory(Context* context); + virtual ~ImmutableGeneratorFactory(); + + virtual MessageGenerator* NewMessageGenerator( + const Descriptor* descriptor) const; + + virtual ExtensionGenerator* NewExtensionGenerator( + const FieldDescriptor* descriptor) const; + + virtual ServiceGenerator* NewServiceGenerator( + const ServiceDescriptor* descriptor) const; + + private: + Context* context_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableGeneratorFactory); +}; + + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__ diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index cf241b8a..fdd4e5e5 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -32,11 +32,15 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <algorithm> +#include <google/protobuf/stubs/hash.h> #include <limits> #include <vector> #include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> @@ -45,6 +49,9 @@ namespace protobuf { namespace compiler { namespace java { +using internal::WireFormat; +using internal::WireFormatLite; + const char kThickSeparator[] = "// ===================================================================\n"; const char kThinSeparator[] = @@ -54,18 +61,47 @@ namespace { const char* kDefaultPackage = ""; -const string& FieldName(const FieldDescriptor* field) { +// Names that should be avoided as field names. +// Using them will cause the compiler to generate accessors whose names are +// colliding with methods defined in base classes. +const char* kForbiddenWordList[] = { + // message base class: + "cached_size", "serialized_size", + // java.lang.Object: + "class", +}; + +bool IsForbidden(const string& field_name) { + for (int i = 0; i < GOOGLE_ARRAYSIZE(kForbiddenWordList); ++i) { + if (field_name == kForbiddenWordList[i]) { + return true; + } + } + return false; +} + +string FieldName(const FieldDescriptor* field) { + string field_name; // Groups are hacky: The name of the field is just the lower-cased name // of the group type. In Java, though, we would like to retain the original // capitalization of the type name. if (GetType(field) == FieldDescriptor::TYPE_GROUP) { - return field->message_type()->name(); + field_name = field->message_type()->name(); } else { - return field->name(); + field_name = field->name(); + } + if (IsForbidden(field_name)) { + // Append a trailing "#" to indicate that the name should be decorated to + // avoid collision with other names. + field_name += "#"; } + return field_name; } -string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) { + +} // namespace + +string UnderscoresToCamelCase(const string& input, bool cap_next_letter) { string result; // Note: I distrust ctype.h due to locales. for (int i = 0; i < input.size(); i++) { @@ -93,21 +129,27 @@ string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) { cap_next_letter = true; } } + // Add a trailing "_" if the name should be altered. + if (input[input.size() - 1] == '#') { + result += '_'; + } return result; } -} // namespace - string UnderscoresToCamelCase(const FieldDescriptor* field) { - return UnderscoresToCamelCaseImpl(FieldName(field), false); + return UnderscoresToCamelCase(FieldName(field), false); } string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) { - return UnderscoresToCamelCaseImpl(FieldName(field), true); + return UnderscoresToCamelCase(FieldName(field), true); } string UnderscoresToCamelCase(const MethodDescriptor* method) { - return UnderscoresToCamelCaseImpl(method->name(), false); + return UnderscoresToCamelCase(method->name(), false); +} + +string UniqueFileScopeIdentifier(const Descriptor* descriptor) { + return "static_" + StringReplace(descriptor->full_name(), ".", "_", true); } string StripProto(const string& filename) { @@ -118,22 +160,12 @@ string StripProto(const string& filename) { } } -string FileClassName(const FileDescriptor* file) { - if (file->options().has_java_outer_classname()) { - return file->options().java_outer_classname(); - } else { - 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); - } - return UnderscoresToCamelCaseImpl(StripProto(basename), true); - } +string FileClassName(const FileDescriptor* file, bool immutable) { + ClassNameResolver name_resolver; + return name_resolver.GetFileClassName(file, immutable); } -string FileJavaPackage(const FileDescriptor* file) { +string FileJavaPackage(const FileDescriptor* file, bool immutable) { string result; if (file->options().has_java_package()) { @@ -146,7 +178,6 @@ string FileJavaPackage(const FileDescriptor* file) { } } - return result; } @@ -157,7 +188,10 @@ string JavaPackageToDir(string package_name) { return package_dir; } -string ToJavaName(const string& full_name, const FileDescriptor* file) { +// TODO(xiaofeng): This function is only kept for it's publicly referenced. +// It should be removed after mutable API up-integration. +string ToJavaName(const string& full_name, + const FileDescriptor* file) { string result; if (file->options().java_multiple_files()) { result = FileJavaPackage(file); @@ -178,22 +212,42 @@ string ToJavaName(const string& full_name, const FileDescriptor* file) { } string ClassName(const Descriptor* descriptor) { - return ToJavaName(descriptor->full_name(), descriptor->file()); + ClassNameResolver name_resolver; + return name_resolver.GetClassName(descriptor, true); } string ClassName(const EnumDescriptor* descriptor) { - return ToJavaName(descriptor->full_name(), descriptor->file()); + ClassNameResolver name_resolver; + return name_resolver.GetClassName(descriptor, true); } string ClassName(const ServiceDescriptor* descriptor) { - return ToJavaName(descriptor->full_name(), descriptor->file()); + ClassNameResolver name_resolver; + return name_resolver.GetClassName(descriptor, true); } string ClassName(const FileDescriptor* descriptor) { - string result = FileJavaPackage(descriptor); - if (!result.empty()) result += '.'; - result += FileClassName(descriptor); - return result; + ClassNameResolver name_resolver; + return name_resolver.GetClassName(descriptor, true); +} + +string ExtraMessageInterfaces(const Descriptor* descriptor) { + string interfaces = "// @@protoc_insertion_point(message_implements:" + + descriptor->full_name() + ")"; + return interfaces; +} + + +string ExtraBuilderInterfaces(const Descriptor* descriptor) { + string interfaces = "// @@protoc_insertion_point(builder_implements:" + + descriptor->full_name() + ")"; + return interfaces; +} + +string ExtraMessageOrBuilderInterfaces(const Descriptor* descriptor) { + string interfaces = "// @@protoc_insertion_point(interface_extends:" + + descriptor->full_name() + ")"; + return interfaces; } string FieldConstantName(const FieldDescriptor *field) { @@ -272,6 +326,35 @@ const char* BoxedPrimitiveTypeName(JavaType type) { return NULL; } +const char* FieldTypeName(FieldDescriptor::Type field_type) { + switch (field_type) { + case FieldDescriptor::TYPE_INT32 : return "INT32"; + case FieldDescriptor::TYPE_UINT32 : return "UINT32"; + case FieldDescriptor::TYPE_SINT32 : return "SINT32"; + case FieldDescriptor::TYPE_FIXED32 : return "FIXED32"; + case FieldDescriptor::TYPE_SFIXED32: return "SFIXED32"; + case FieldDescriptor::TYPE_INT64 : return "INT64"; + case FieldDescriptor::TYPE_UINT64 : return "UINT64"; + case FieldDescriptor::TYPE_SINT64 : return "SINT64"; + case FieldDescriptor::TYPE_FIXED64 : return "FIXED64"; + case FieldDescriptor::TYPE_SFIXED64: return "SFIXED64"; + case FieldDescriptor::TYPE_FLOAT : return "FLOAT"; + case FieldDescriptor::TYPE_DOUBLE : return "DOUBLE"; + case FieldDescriptor::TYPE_BOOL : return "BOOL"; + case FieldDescriptor::TYPE_STRING : return "STRING"; + case FieldDescriptor::TYPE_BYTES : return "BYTES"; + case FieldDescriptor::TYPE_ENUM : return "ENUM"; + case FieldDescriptor::TYPE_GROUP : return "GROUP"; + case FieldDescriptor::TYPE_MESSAGE : return "MESSAGE"; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + bool AllAscii(const string& text) { for (int i = 0; i < text.size(); i++) { if ((text[i] & 0x80) != 0) { @@ -281,7 +364,8 @@ bool AllAscii(const string& text) { return true; } -string DefaultValue(const FieldDescriptor* field) { +string DefaultValue(const FieldDescriptor* field, bool immutable, + ClassNameResolver* name_resolver) { // Switch on CppType since we need to know which default_value_* method // of FieldDescriptor to call. switch (field->cpp_type()) { @@ -344,11 +428,12 @@ string DefaultValue(const FieldDescriptor* field) { } case FieldDescriptor::CPPTYPE_ENUM: - return ClassName(field->enum_type()) + "." + + return name_resolver->GetClassName(field->enum_type(), immutable) + "." + field->default_value_enum()->name(); case FieldDescriptor::CPPTYPE_MESSAGE: - return ClassName(field->message_type()) + ".getDefaultInstance()"; + return name_resolver->GetClassName(field->message_type(), immutable) + + ".getDefaultInstance()"; // No default because we want the compiler to complain if any new // types are added. @@ -494,6 +579,158 @@ string GenerateSetBitMutableLocal(int bitIndex) { return GenerateSetBitInternal("mutable_", bitIndex); } +bool IsReferenceType(JavaType type) { + switch (type) { + case JAVATYPE_INT : return false; + case JAVATYPE_LONG : return false; + case JAVATYPE_FLOAT : return false; + case JAVATYPE_DOUBLE : return false; + case JAVATYPE_BOOLEAN: return false; + case JAVATYPE_STRING : return true; + case JAVATYPE_BYTES : return true; + case JAVATYPE_ENUM : return true; + case JAVATYPE_MESSAGE: return true; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +const char* GetCapitalizedType(const FieldDescriptor* field, bool immutable) { + switch (GetType(field)) { + case FieldDescriptor::TYPE_INT32 : return "Int32"; + case FieldDescriptor::TYPE_UINT32 : return "UInt32"; + case FieldDescriptor::TYPE_SINT32 : return "SInt32"; + case FieldDescriptor::TYPE_FIXED32 : return "Fixed32"; + case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; + case FieldDescriptor::TYPE_INT64 : return "Int64"; + case FieldDescriptor::TYPE_UINT64 : return "UInt64"; + case FieldDescriptor::TYPE_SINT64 : return "SInt64"; + case FieldDescriptor::TYPE_FIXED64 : return "Fixed64"; + case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; + case FieldDescriptor::TYPE_FLOAT : return "Float"; + case FieldDescriptor::TYPE_DOUBLE : return "Double"; + case FieldDescriptor::TYPE_BOOL : return "Bool"; + case FieldDescriptor::TYPE_STRING : return "String"; + case FieldDescriptor::TYPE_BYTES : { + return "Bytes"; + } + case FieldDescriptor::TYPE_ENUM : return "Enum"; + case FieldDescriptor::TYPE_GROUP : return "Group"; + case FieldDescriptor::TYPE_MESSAGE : return "Message"; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int FixedSize(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32 : return -1; + case FieldDescriptor::TYPE_INT64 : return -1; + case FieldDescriptor::TYPE_UINT32 : return -1; + case FieldDescriptor::TYPE_UINT64 : return -1; + case FieldDescriptor::TYPE_SINT32 : return -1; + case FieldDescriptor::TYPE_SINT64 : return -1; + case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; + case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; + case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; + case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; + case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; + case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; + + case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; + case FieldDescriptor::TYPE_ENUM : return -1; + + case FieldDescriptor::TYPE_STRING : return -1; + case FieldDescriptor::TYPE_BYTES : return -1; + case FieldDescriptor::TYPE_GROUP : return -1; + case FieldDescriptor::TYPE_MESSAGE : return -1; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; +} + +// Sort the fields of the given Descriptor by number into a new[]'d array +// and return it. The caller should delete the returned array. +const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { + const FieldDescriptor** fields = + new const FieldDescriptor*[descriptor->field_count()]; + for (int i = 0; i < descriptor->field_count(); i++) { + fields[i] = descriptor->field(i); + } + sort(fields, fields + descriptor->field_count(), + FieldOrderingByNumber()); + return fields; +} + +// Returns true if the message type has any required fields. If it doesn't, +// we can optimize out calls to its isInitialized() method. +// +// already_seen is used to avoid checking the same type multiple times +// (and also to protect against recursion). +bool HasRequiredFields( + const Descriptor* type, + hash_set<const Descriptor*>* already_seen) { + if (already_seen->count(type) > 0) { + // The type is already in cache. This means that either: + // a. The type has no required fields. + // b. We are in the midst of checking if the type has required fields, + // somewhere up the stack. In this case, we know that if the type + // has any required fields, they'll be found when we return to it, + // and the whole call to HasRequiredFields() will return true. + // Therefore, we don't have to check if this type has required fields + // here. + return false; + } + already_seen->insert(type); + + // If the type has extensions, an extension with message type could contain + // required fields, so we have to be conservative and assume such an + // extension exists. + if (type->extension_range_count() > 0) return true; + + for (int i = 0; i < type->field_count(); i++) { + const FieldDescriptor* field = type->field(i); + if (field->is_required()) { + return true; + } + if (GetJavaType(field) == JAVATYPE_MESSAGE) { + if (HasRequiredFields(field->message_type(), already_seen)) { + return true; + } + } + } + + return false; +} + +bool HasRequiredFields(const Descriptor* type) { + hash_set<const Descriptor*> already_seen; + return HasRequiredFields(type, &already_seen); +} + +bool HasRepeatedFields(const Descriptor* descriptor) { + for (int i = 0; i < descriptor->field_count(); ++i) { + const FieldDescriptor* field = descriptor->field(i); + if (field->is_repeated()) { + return true; + } + } + return false; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 3937f069..6d1eae0a 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -49,6 +49,9 @@ namespace java { extern const char kThickSeparator[]; extern const char kThinSeparator[]; +// Converts a name to camel-case. If cap_first_letter is true, capitalize the +// first letter. +string UnderscoresToCamelCase(const string& name, bool cap_first_letter); // Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes // "fooBarBaz" or "FooBarBaz", respectively. string UnderscoresToCamelCase(const FieldDescriptor* field); @@ -58,15 +61,22 @@ string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field); // of lower-casing the first letter of the name.) string UnderscoresToCamelCase(const MethodDescriptor* method); +// Get an identifier that uniquely identifies this type within the file. +// This is used to declare static variables related to this type at the +// outermost file scope. +string UniqueFileScopeIdentifier(const Descriptor* descriptor); + // Strips ".proto" or ".protodevel" from the end of a filename. string StripProto(const string& filename); -// Gets the unqualified class name for the file. Each .proto file becomes a -// single Java class, with all its contents nested in that class. -string FileClassName(const FileDescriptor* file); +// Gets the unqualified class name for the file. For each .proto file, there +// will be one Java class containing all the immutable messages and another +// Java class containing all the mutable messages. +// TODO(xiaofeng): remove the default value after updating client code. +string FileClassName(const FileDescriptor* file, bool immutable = true); // Returns the file's Java package name. -string FileJavaPackage(const FileDescriptor* file); +string FileJavaPackage(const FileDescriptor* file, bool immutable = true); // Returns output directory for the given package name. string JavaPackageToDir(string package_name); @@ -74,17 +84,46 @@ string JavaPackageToDir(string package_name); // 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 string& full_name, const FileDescriptor* file); - -// These return the fully-qualified class name corresponding to the given -// descriptor. +// TODO(xiaofeng): this method is deprecated and should be removed in the +// future. +string ToJavaName(const string& full_name, + const FileDescriptor* file); + +// TODO(xiaofeng): the following methods are kept for they are exposed +// publicly in //google/protobuf/compiler/java/names.h. They return +// immutable names only and should be removed after mutable API is +// integrated into google3. string ClassName(const Descriptor* descriptor); string ClassName(const EnumDescriptor* descriptor); string ClassName(const ServiceDescriptor* descriptor); string ClassName(const FileDescriptor* descriptor); -inline string ExtensionIdentifierName(const FieldDescriptor* descriptor) { - return ToJavaName(descriptor->full_name(), descriptor->file()); +// Comma-separate list of option-specified interfaces implemented by the +// Message, to follow the "implements" declaration of the Message definition. +string ExtraMessageInterfaces(const Descriptor* descriptor); +// Comma-separate list of option-specified interfaces implemented by the +// MutableMessage, to follow the "implements" declaration of the MutableMessage +// definition. +string ExtraMutableMessageInterfaces(const Descriptor* descriptor); +// Comma-separate list of option-specified interfaces implemented by the +// Builder, to follow the "implements" declaration of the Builder definition. +string ExtraBuilderInterfaces(const Descriptor* descriptor); +// Comma-separate list of option-specified interfaces extended by the +// MessageOrBuilder, to follow the "extends" declaration of the +// MessageOrBuilder definition. +string ExtraMessageOrBuilderInterfaces(const Descriptor* descriptor); + +// Get the unqualified Java class name for mutable messages. i.e. without +// package or outer classnames. +inline string ShortMutableJavaClassName(const Descriptor* descriptor) { + return descriptor->name(); +} + + +// Whether we should generate multiple java files for messages. +inline bool MultipleJavaFiles( + const FileDescriptor* descriptor, bool immutable) { + return descriptor->options().java_multiple_files(); } // Get the unqualified name that should be used for a field's field @@ -115,11 +154,23 @@ JavaType GetJavaType(const FieldDescriptor* field); // types. const char* BoxedPrimitiveTypeName(JavaType type); -string DefaultValue(const FieldDescriptor* field); +// Get the name of the java enum constant representing this type. E.g., +// "INT32" for FieldDescriptor::TYPE_INT32. The enum constant's full +// name is "com.google.protobuf.WireFormat.FieldType.INT32". +const char* FieldTypeName(const FieldDescriptor::Type field_type); + +class ClassNameResolver; +string DefaultValue(const FieldDescriptor* field, bool immutable, + ClassNameResolver* name_resolver); +inline string ImmutableDefaultValue(const FieldDescriptor* field, + ClassNameResolver* name_resolver) { + return DefaultValue(field, true, name_resolver); +} bool IsDefaultValueJavaDefault(const FieldDescriptor* field); -// Does this message class keep track of unknown fields? -inline bool HasUnknownFields(const Descriptor* descriptor) { +// Does this message class use UnknownFieldSet? +// Otherwise, unknown fields will be stored in a ByteString object +inline bool UseUnknownFieldSet(const Descriptor* descriptor) { return descriptor->file()->options().optimize_for() != FileOptions::LITE_RUNTIME; } @@ -163,6 +214,15 @@ inline bool HasGenericServices(const FileDescriptor *file) { file->options().java_generic_services(); } +inline bool IsLazy(const FieldDescriptor* descriptor) { + // Currently, the proto-lite version suports lazy field. + // TODO(niwasaki): Support lazy fields also for other proto runtimes. + if (descriptor->file()->options().optimize_for() != + FileOptions::LITE_RUNTIME) { + return false; + } + return descriptor->options().lazy(); +} // Methods for shared bitfields. @@ -212,6 +272,48 @@ string GenerateGetBitMutableLocal(int bitIndex); // Example: "mutable_bitField1_ = (mutable_bitField1_ | 0x04)" string GenerateSetBitMutableLocal(int bitIndex); +// Returns whether the JavaType is a reference type. +bool IsReferenceType(JavaType type); + +// Returns the capitalized name for calling relative functions in +// CodedInputStream +const char* GetCapitalizedType(const FieldDescriptor* field, bool immutable); + +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int FixedSize(FieldDescriptor::Type type); + +// Comparators used to sort fields in MessageGenerator +struct FieldOrderingByNumber { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + return a->number() < b->number(); + } +}; + +struct ExtensionRangeOrdering { + bool operator()(const Descriptor::ExtensionRange* a, + const Descriptor::ExtensionRange* b) const { + return a->start < b->start; + } +}; + +// Sort the fields of the given Descriptor by number into a new[]'d array +// and return it. The caller should delete the returned array. +const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor); + +// Check a message type and its sub-message types recursively to see if any of +// them has a required field. Return true if a required field is found. +bool HasRequiredFields(const Descriptor* descriptor); + +// Whether a .proto file supports field presence test for non-message types. +inline bool SupportFieldPresence(const FileDescriptor* descriptor) { + return true; +} + +// Check whether a mesasge has repeated fields. +bool HasRepeatedFields(const Descriptor* descriptor); + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field.cc b/src/google/protobuf/compiler/java/java_lazy_message_field.cc new file mode 100644 index 00000000..32d97b6f --- /dev/null +++ b/src/google/protobuf/compiler/java/java_lazy_message_field.cc @@ -0,0 +1,826 @@ +// 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: niwasaki@google.com (Naoki Iwasaki) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <google/protobuf/compiler/java/java_context.h> +#include <google/protobuf/compiler/java/java_lazy_message_field.h> +#include <google/protobuf/compiler/java/java_doc_comment.h> +#include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +ImmutableLazyMessageFieldGenerator:: +ImmutableLazyMessageFieldGenerator( + const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableMessageFieldGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { +} + +ImmutableLazyMessageFieldGenerator::~ImmutableLazyMessageFieldGenerator() {} + +void ImmutableLazyMessageFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private com.google.protobuf.LazyFieldLite $name$_ =\n" + " new com.google.protobuf.LazyFieldLite();\n"); + + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return ($type$) $name$_.getValue($type$.getDefaultInstance());\n" + "}\n"); + if (HasNestedBuilders(descriptor_->containing_type())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + " return $name$_;\n" + "}\n"); + } +} + +void ImmutableLazyMessageFieldGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // When using nested-builders, the code initially works just like the + // non-nested builder case. It only creates a nested builder lazily on + // demand and then forever delegates to it after creation. + + printer->Print(variables_, + "private com.google.protobuf.LazyFieldLite $name$_ =\n" + " new com.google.protobuf.LazyFieldLite();\n"); + + if (HasNestedBuilders(descriptor_->containing_type())) { + printer->Print(variables_, + // If this builder is non-null, it is used and the other fields are + // ignored. + "private com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" + "\n"); + } + + // The comments above the methods below are based on a hypothetical + // field of type "Field" called "Field". + + // boolean hasField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_builder$;\n" + "}\n"); + + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return ($type$) $name$_.getValue($type$.getDefaultInstance());\n" + "}\n"); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder set$capitalized_name$($type$ value)", + + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "$name$_.setValue(value);\n" + "$on_changed$\n", + + NULL, // Lazy fields are supported only for lite-runtime. + + "$set_has_field_bit_builder$;\n" + "return this;\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder set$capitalized_name$(\n" + " $type$.Builder builderForValue)", + + "$name$_.setValue(builderForValue.build());\n" + "$on_changed$\n", + + NULL, + + "$set_has_field_bit_builder$;\n" + "return this;\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder merge$capitalized_name$($type$ value)", + + "if ($get_has_field_bit_builder$ &&\n" + " !$name$_.containsDefaultInstance()) {\n" + " $name$_.setValue(\n" + " $type$.newBuilder(\n" + " get$capitalized_name$()).mergeFrom(value).buildPartial());\n" + "} else {\n" + " $name$_.setValue(value);\n" + "}\n" + "$on_changed$\n", + + NULL, + + "$set_has_field_bit_builder$;\n" + "return this;\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder clear$capitalized_name$()", + + "$name$_.clear();\n" + "$on_changed$\n", + + NULL, + + "$clear_has_field_bit_builder$;\n" + "return this;\n"); + + if (HasNestedBuilders(descriptor_->containing_type())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" + " $set_has_field_bit_builder$;\n" + " $on_changed$\n" + " return get$capitalized_name$FieldBuilder().getBuilder();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + " if ($name$Builder_ != null) {\n" + " return $name$Builder_.getMessageOrBuilder();\n" + " } else {\n" + " return $name$_;\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " $name$_,\n" + " getParentForChildren(),\n" + " isClean());\n" + " $name$_ = null;\n" + " }\n" + " return $name$Builder_;\n" + "}\n"); + } +} + + +void ImmutableLazyMessageFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.clear();\n"); +} + +void ImmutableLazyMessageFieldGenerator:: +GenerateBuilderClearCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.clear();\n"); + printer->Print(variables_, "$clear_has_field_bit_builder$;\n"); +} + +void ImmutableLazyMessageFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " $name$_.merge(other.$name$_);\n" + " $set_has_field_bit_builder$;\n" + "}\n"); +} + +void ImmutableLazyMessageFieldGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_has_field_bit_from_local$) {\n" + " $set_has_field_bit_to_local$;\n" + "}\n"); + + printer->Print(variables_, + "result.$name$_.setByteString(\n" + " $name$_.toByteString(),\n" + " $name$_.getExtensionRegistry());\n"); +} + +void ImmutableLazyMessageFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_.setByteString(input.readBytes(), extensionRegistry);\n"); + printer->Print(variables_, + "$set_has_field_bit_message$;\n"); +} + +void ImmutableLazyMessageFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + // Do not de-serialize lazy fields. + printer->Print(variables_, + "if ($get_has_field_bit_message$) {\n" + " output.writeBytes($number$, $name$_.toByteString());\n" + "}\n"); +} + +void ImmutableLazyMessageFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_has_field_bit_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeLazyFieldSize($number$, $name$_);\n" + "}\n"); +} + +// =================================================================== + +ImmutableLazyMessageOneofFieldGenerator:: +ImmutableLazyMessageOneofFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableLazyMessageFieldGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); + variables_["lazy_type"] = "com.google.protobuf.LazyFieldLite"; +} + +ImmutableLazyMessageOneofFieldGenerator:: +~ImmutableLazyMessageOneofFieldGenerator() {} + +void ImmutableLazyMessageOneofFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) (($lazy_type$) $oneof_name$_).getValue(\n" + " $type$.getDefaultInstance());\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); +} + +void ImmutableLazyMessageOneofFieldGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // boolean hasField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) (($lazy_type$) $oneof_name$_).getValue(\n" + " $type$.getDefaultInstance());\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder set$capitalized_name$($type$ value)", + + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + " $set_oneof_case_message$;\n" + "}\n" + "(($lazy_type$) $oneof_name$_).setValue(value);\n" + "$on_changed$\n", + + NULL, // Lazy fields are supported only for lite-runtime. + + "return this;\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder set$capitalized_name$(\n" + " $type$.Builder builderForValue)", + + "if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + " $set_oneof_case_message$;\n" + "}\n" + "(($lazy_type$) $oneof_name$_).setValue(builderForValue.build());\n" + "$on_changed$\n", + + NULL, + + "return this;\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder merge$capitalized_name$($type$ value)", + + "if ($has_oneof_case_message$ &&\n" + " !(($lazy_type$) $oneof_name$_).containsDefaultInstance()) {\n" + " (($lazy_type$) $oneof_name$_).setValue(\n" + " $type$.newBuilder(\n" + " get$capitalized_name$()).mergeFrom(value).buildPartial());\n" + "} else {\n" + " if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + " $set_oneof_case_message$;\n" + " }\n" + " (($lazy_type$) $oneof_name$_).setValue(value);\n" + "}\n" + "$on_changed$\n", + + NULL, + + "return this;\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder clear$capitalized_name$()", + + "if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " $on_changed$\n" + "}\n", + + NULL, + + "return this;\n"); +} + +void ImmutableLazyMessageOneofFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + "}\n" + "(($lazy_type$) $oneof_name$_).merge(\n" + " ($lazy_type$) other.$oneof_name$_);\n" + "$set_oneof_case_message$;\n"); +} + +void ImmutableLazyMessageOneofFieldGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n"); + printer->Indent(); + + printer->Print(variables_, + "result.$oneof_name$_ = new $lazy_type$();\n" + "(($lazy_type$) result.$oneof_name$_).setByteString(\n" + " (($lazy_type$) $oneof_name$_).toByteString(),\n" + " (($lazy_type$) $oneof_name$_).getExtensionRegistry());\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableLazyMessageOneofFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + "}\n" + "(($lazy_type$) $oneof_name$_).setByteString(\n" + " input.readBytes(), extensionRegistry);\n" + "$set_oneof_case_message$;\n"); +} + +void ImmutableLazyMessageOneofFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + // Do not de-serialize lazy fields. + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.writeBytes(\n" + " $number$, (($lazy_type$) $oneof_name$_).toByteString());\n" + "}\n"); +} + +void ImmutableLazyMessageOneofFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeLazyFieldSize($number$, ($lazy_type$) $oneof_name$_);\n" + "}\n"); +} + +// =================================================================== + +RepeatedImmutableLazyMessageFieldGenerator:: +RepeatedImmutableLazyMessageFieldGenerator( + const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : RepeatedImmutableMessageFieldGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { +} + + +RepeatedImmutableLazyMessageFieldGenerator:: +~RepeatedImmutableLazyMessageFieldGenerator() {} + +void RepeatedImmutableLazyMessageFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private java.util.List<com.google.protobuf.LazyFieldLite> $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$>\n" + " get$capitalized_name$List() {\n" + " java.util.List<$type$> list =\n" + " new java.util.ArrayList<$type$>($name$_.size());\n" + " for (com.google.protobuf.LazyFieldLite lf : $name$_) {\n" + " list.add(($type$) lf.getValue($type$.getDefaultInstance()));\n" + " }\n" + " return list;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<? extends $type$OrBuilder>\n" + " get$capitalized_name$OrBuilderList() {\n" + " return get$capitalized_name$List();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return $name$_.size();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$(int index) {\n" + " return ($type$)\n" + " $name$_.get(index).getValue($type$.getDefaultInstance());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" + " int index) {\n" + " return ($type$OrBuilder)\n" + " $name$_.get(index).getValue($type$.getDefaultInstance());\n" + "}\n"); +} + +void RepeatedImmutableLazyMessageFieldGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // When using nested-builders, the code initially works just like the + // non-nested builder case. It only creates a nested builder lazily on + // demand and then forever delegates to it after creation. + + printer->Print(variables_, + "private java.util.List<com.google.protobuf.LazyFieldLite> $name$_ =\n" + " java.util.Collections.emptyList();\n" + + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$get_mutable_bit_builder$) {\n" + " $name$_ =\n" + " new java.util.ArrayList<com.google.protobuf.LazyFieldLite>(\n" + " $name$_);\n" + " $set_mutable_bit_builder$;\n" + " }\n" + "}\n" + "\n"); + + if (HasNestedBuilders(descriptor_->containing_type())) { + printer->Print(variables_, + // If this builder is non-null, it is used and the other fields are + // ignored. + "private com.google.protobuf.RepeatedFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n" + "\n"); + } + + // The comments above the methods below are based on a hypothetical + // repeated field of type "Field" called "RepeatedField". + + // List<Field> getRepeatedFieldList() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public java.util.List<$type$> get$capitalized_name$List()", + + "java.util.List<$type$> list =\n" + " new java.util.ArrayList<$type$>($name$_.size());\n" + "for (com.google.protobuf.LazyFieldLite lf : $name$_) {\n" + " list.add(($type$) lf.getValue($type$.getDefaultInstance()));\n" + "}\n" + "return java.util.Collections.unmodifiableList(list);\n", + + "return $name$Builder_.getMessageList();\n", + + NULL); + + // int getRepeatedFieldCount() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public int get$capitalized_name$Count()", + + "return $name$_.size();\n", + "return $name$Builder_.getCount();\n", + + NULL); + + // Field getRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public $type$ get$capitalized_name$(int index)", + + "return ($type$) $name$_.get(index).getValue(\n" + " $type$.getDefaultInstance());\n", + + "return $name$Builder_.getMessage(index);\n", + + NULL); + + // Builder setRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder set$capitalized_name$(\n" + " int index, $type$ value)", + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "ensure$capitalized_name$IsMutable();\n" + "$name$_.set(index, com.google.protobuf.LazyFieldLite.fromValue(value));\n" + "$on_changed$\n", + "$name$Builder_.setMessage(index, value);\n", + "return this;\n"); + + // Builder setRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder set$capitalized_name$(\n" + " int index, $type$.Builder builderForValue)", + + "ensure$capitalized_name$IsMutable();\n" + "$name$_.set(index, com.google.protobuf.LazyFieldLite.fromValue(\n" + " builderForValue.build()));\n" + "$on_changed$\n", + + "$name$Builder_.setMessage(index, builderForValue.build());\n", + + "return this;\n"); + + // Builder addRepeatedField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder add$capitalized_name$($type$ value)", + + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "ensure$capitalized_name$IsMutable();\n" + "$name$_.add(com.google.protobuf.LazyFieldLite.fromValue(value));\n" + + "$on_changed$\n", + + "$name$Builder_.addMessage(value);\n", + + "return this;\n"); + + // Builder addRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder add$capitalized_name$(\n" + " int index, $type$ value)", + + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "ensure$capitalized_name$IsMutable();\n" + "$name$_.add(index, com.google.protobuf.LazyFieldLite.fromValue(value));\n" + "$on_changed$\n", + + "$name$Builder_.addMessage(index, value);\n", + + "return this;\n"); + + // Builder addRepeatedField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder add$capitalized_name$(\n" + " $type$.Builder builderForValue)", + + "ensure$capitalized_name$IsMutable();\n" + "$name$_.add(com.google.protobuf.LazyFieldLite.fromValue(\n" + " builderForValue.build()));\n" + "$on_changed$\n", + + "$name$Builder_.addMessage(builderForValue.build());\n", + + "return this;\n"); + + // Builder addRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder add$capitalized_name$(\n" + " int index, $type$.Builder builderForValue)", + + "ensure$capitalized_name$IsMutable();\n" + "$name$_.add(index, com.google.protobuf.LazyFieldLite.fromValue(\n" + " builderForValue.build()));\n" + "$on_changed$\n", + + "$name$Builder_.addMessage(index, builderForValue.build());\n", + + "return this;\n"); + + // Builder addAllRepeatedField(Iterable<Field> values) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder addAll$capitalized_name$(\n" + " java.lang.Iterable<? extends $type$> values)", + + "ensure$capitalized_name$IsMutable();\n" + "for (com.google.protobuf.MessageLite v : values) {\n" + " $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(v));\n" + "}\n" + "$on_changed$\n", + + "$name$Builder_.addAllMessages(values);\n", + + "return this;\n"); + + // Builder clearAllRepeatedField() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder clear$capitalized_name$()", + + "$name$_ = java.util.Collections.emptyList();\n" + "$clear_mutable_bit_builder$;\n" + "$on_changed$\n", + + "$name$Builder_.clear();\n", + + "return this;\n"); + + // Builder removeRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder remove$capitalized_name$(int index)", + + "ensure$capitalized_name$IsMutable();\n" + "$name$_.remove(index);\n" + "$on_changed$\n", + + "$name$Builder_.remove(index);\n", + + "return this;\n"); + + if (HasNestedBuilders(descriptor_->containing_type())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n" + " int index) {\n" + " return get$capitalized_name$FieldBuilder().getBuilder(index);\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" + " int index) {\n" + " if ($name$Builder_ == null) {\n" + " return $name$_.get(index);" + " } else {\n" + " return $name$Builder_.getMessageOrBuilder(index);\n" + " }\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<? extends $type$OrBuilder> \n" + " get$capitalized_name$OrBuilderList() {\n" + " if ($name$Builder_ != null) {\n" + " return $name$Builder_.getMessageOrBuilderList();\n" + " } else {\n" + " return java.util.Collections.unmodifiableList($name$_);\n" + " }\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n" + " return get$capitalized_name$FieldBuilder().addBuilder(\n" + " $type$.getDefaultInstance());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n" + " int index) {\n" + " return get$capitalized_name$FieldBuilder().addBuilder(\n" + " index, $type$.getDefaultInstance());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$.Builder> \n" + " get$capitalized_name$BuilderList() {\n" + " return get$capitalized_name$FieldBuilder().getBuilderList();\n" + "}\n" + "private com.google.protobuf.RepeatedFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " $name$_,\n" + " $get_mutable_bit_builder$,\n" + " getParentForChildren(),\n" + " isClean());\n" + " $name$_ = null;\n" + " }\n" + " return $name$Builder_;\n" + "}\n"); + } +} + +void RepeatedImmutableLazyMessageFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ =\n" + " new java.util.ArrayList<com.google.protobuf.LazyFieldLite>();\n" + " $set_mutable_bit_parser$;\n" + "}\n" + "$name$_.add(new com.google.protobuf.LazyFieldLite(\n" + " extensionRegistry, input.readBytes()));\n"); +} + +void RepeatedImmutableLazyMessageFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.writeBytes($number$, $name$_.get(i).toByteString());\n" + "}\n"); +} + +void RepeatedImmutableLazyMessageFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeLazyFieldSize($number$, $name$_.get(i));\n" + "}\n"); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field.h b/src/google/protobuf/compiler/java/java_lazy_message_field.h new file mode 100644 index 00000000..2a1f8574 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_lazy_message_field.h @@ -0,0 +1,121 @@ +// 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: niwasaki@google.com (Naoki Iwasaki) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_H__ + +#include <google/protobuf/compiler/java/java_field.h> +#include <google/protobuf/compiler/java/java_message_field.h> + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + } + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableLazyMessageFieldGenerator + : public ImmutableMessageFieldGenerator { + public: + explicit ImmutableLazyMessageFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableLazyMessageFieldGenerator(); + + // overroads ImmutableMessageFieldGenerator --------------------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateBuilderClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageFieldGenerator); +}; + +class ImmutableLazyMessageOneofFieldGenerator + : public ImmutableLazyMessageFieldGenerator { + public: + ImmutableLazyMessageOneofFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableLazyMessageOneofFieldGenerator(); + + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageOneofFieldGenerator); +}; + +class RepeatedImmutableLazyMessageFieldGenerator + : public RepeatedImmutableMessageFieldGenerator { + public: + explicit RepeatedImmutableLazyMessageFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableLazyMessageFieldGenerator(); + + // overroads RepeatedImmutableMessageFieldGenerator ------------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableLazyMessageFieldGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_H__ diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 9322e242..1cd08f7d 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -37,12 +37,16 @@ #include <algorithm> #include <google/protobuf/stubs/hash.h> #include <map> +#include <memory> #include <vector> +#include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/compiler/java/java_enum.h> #include <google/protobuf/compiler/java/java_extension.h> +#include <google/protobuf/compiler/java/java_generator_factory.h> #include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> @@ -59,107 +63,31 @@ using internal::WireFormat; using internal::WireFormatLite; namespace { - -void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { - // Print the field's proto-syntax definition as a comment. We don't want to - // print group bodies so we cut off after the first line. - string def = field->DebugString(); - printer->Print("// $def$\n", - "def", def.substr(0, def.find_first_of('\n'))); +bool GenerateHasBits(const Descriptor* descriptor) { + return SupportFieldPresence(descriptor->file()) || + HasRepeatedFields(descriptor); } - -struct FieldOrderingByNumber { - inline bool operator()(const FieldDescriptor* a, - const FieldDescriptor* b) const { - return a->number() < b->number(); - } -}; - -struct ExtensionRangeOrdering { - bool operator()(const Descriptor::ExtensionRange* a, - const Descriptor::ExtensionRange* b) const { - return a->start < b->start; - } -}; - -// Sort the fields of the given Descriptor by number into a new[]'d array -// and return it. -const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { - const FieldDescriptor** fields = - new const FieldDescriptor*[descriptor->field_count()]; - for (int i = 0; i < descriptor->field_count(); i++) { - fields[i] = descriptor->field(i); - } - sort(fields, fields + descriptor->field_count(), - FieldOrderingByNumber()); - return fields; -} - -// Get an identifier that uniquely identifies this type within the file. -// This is used to declare static variables related to this type at the -// outermost file scope. -string UniqueFileScopeIdentifier(const Descriptor* descriptor) { - return "static_" + StringReplace(descriptor->full_name(), ".", "_", true); -} - -// Returns true if the message type has any required fields. If it doesn't, -// we can optimize out calls to its isInitialized() method. -// -// already_seen is used to avoid checking the same type multiple times -// (and also to protect against recursion). -static bool HasRequiredFields( - const Descriptor* type, - hash_set<const Descriptor*>* already_seen) { - if (already_seen->count(type) > 0) { - // The type is already in cache. This means that either: - // a. The type has no required fields. - // b. We are in the midst of checking if the type has required fields, - // somewhere up the stack. In this case, we know that if the type - // has any required fields, they'll be found when we return to it, - // and the whole call to HasRequiredFields() will return true. - // Therefore, we don't have to check if this type has required fields - // here. - return false; - } - already_seen->insert(type); - - // If the type has extensions, an extension with message type could contain - // required fields, so we have to be conservative and assume such an - // extension exists. - if (type->extension_range_count() > 0) return true; - - for (int i = 0; i < type->field_count(); i++) { - const FieldDescriptor* field = type->field(i); - if (field->is_required()) { - return true; - } - if (GetJavaType(field) == JAVATYPE_MESSAGE) { - if (HasRequiredFields(field->message_type(), already_seen)) { - return true; - } - } - } - - return false; -} - -static bool HasRequiredFields(const Descriptor* type) { - hash_set<const Descriptor*> already_seen; - return HasRequiredFields(type, &already_seen); -} - } // namespace // =================================================================== MessageGenerator::MessageGenerator(const Descriptor* descriptor) - : descriptor_(descriptor), - field_generators_(descriptor) { -} + : descriptor_(descriptor) {} MessageGenerator::~MessageGenerator() {} -void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { +// =================================================================== +// TODO(api): Move this class to a separate immutable_message.cc file. +ImmutableMessageGenerator::ImmutableMessageGenerator( + const Descriptor* descriptor, Context* context) + : MessageGenerator(descriptor), context_(context), + name_resolver_(context->GetNameResolver()), + field_generators_(descriptor, context_) { +} + +ImmutableMessageGenerator::~ImmutableMessageGenerator() {} + +void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) { if (HasDescriptorMethods(descriptor_)) { // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is // used in the construction of descriptors, we have a tricky bootstrapping @@ -171,12 +99,12 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { map<string, string> vars; vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); vars["index"] = SimpleItoa(descriptor_->index()); - vars["classname"] = ClassName(descriptor_); + vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_); if (descriptor_->containing_type() != NULL) { vars["parent"] = UniqueFileScopeIdentifier( descriptor_->containing_type()); } - if (descriptor_->file()->options().java_multiple_files()) { + if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) { // We can only make these package-private since the classes that use them // are in separate files. vars["private"] = ""; @@ -186,31 +114,28 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { // The descriptor for this type. printer->Print(vars, - "$private$static com.google.protobuf.Descriptors.Descriptor\n" + "$private$static final com.google.protobuf.Descriptors.Descriptor\n" " internal_$identifier$_descriptor;\n"); // And the FieldAccessorTable. - printer->Print(vars, - "$private$static\n" - " com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" - " internal_$identifier$_fieldAccessorTable;\n"); + GenerateFieldAccessorTable(printer); } // Generate static members for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { // TODO(kenton): Reuse MessageGenerator objects? - MessageGenerator(descriptor_->nested_type(i)) + ImmutableMessageGenerator(descriptor_->nested_type(i), context_) .GenerateStaticVariables(printer); } } -void MessageGenerator::GenerateStaticVariableInitializers( +void ImmutableMessageGenerator::GenerateStaticVariableInitializers( io::Printer* printer) { if (HasDescriptorMethods(descriptor_)) { map<string, string> vars; vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); vars["index"] = SimpleItoa(descriptor_->index()); - vars["classname"] = ClassName(descriptor_); + vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_); if (descriptor_->containing_type() != NULL) { vars["parent"] = UniqueFileScopeIdentifier( descriptor_->containing_type()); @@ -228,56 +153,95 @@ void MessageGenerator::GenerateStaticVariableInitializers( } // And the FieldAccessorTable. - printer->Print(vars, - "internal_$identifier$_fieldAccessorTable = new\n" - " com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n" - " internal_$identifier$_descriptor,\n" - " new java.lang.String[] { "); - for (int i = 0; i < descriptor_->field_count(); i++) { - printer->Print( - "\"$field_name$\", ", - "field_name", - UnderscoresToCapitalizedCamelCase(descriptor_->field(i))); - } - printer->Print( - "});\n"); + GenerateFieldAccessorTableInitializer(printer); } // Generate static member initializers for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { // TODO(kenton): Reuse MessageGenerator objects? - MessageGenerator(descriptor_->nested_type(i)) + ImmutableMessageGenerator(descriptor_->nested_type(i), context_) .GenerateStaticVariableInitializers(printer); } } +void ImmutableMessageGenerator:: +GenerateFieldAccessorTable(io::Printer* printer) { + map<string, string> vars; + vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); + if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) { + // We can only make these package-private since the classes that use them + // are in separate files. + vars["private"] = ""; + } else { + vars["private"] = "private "; + } + printer->Print(vars, + "$private$static\n" + " com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" + " internal_$identifier$_fieldAccessorTable;\n"); +} + +void ImmutableMessageGenerator:: +GenerateFieldAccessorTableInitializer(io::Printer* printer) { + printer->Print( + "internal_$identifier$_fieldAccessorTable = new\n" + " com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n" + " internal_$identifier$_descriptor,\n" + " new java.lang.String[] { ", + "identifier", + UniqueFileScopeIdentifier(descriptor_)); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + printer->Print( + "\"$field_name$\", ", + "field_name", info->capitalized_name); + } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = descriptor_->oneof_decl(i); + const OneofGeneratorInfo* info = context_->GetOneofGeneratorInfo(oneof); + printer->Print( + "\"$oneof_name$\", ", + "oneof_name", info->capitalized_name); + } + printer->Print("});\n"); +} + // =================================================================== -void MessageGenerator::GenerateInterface(io::Printer* printer) { +void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { if (HasDescriptorMethods(descriptor_)) { printer->Print( "public interface $classname$OrBuilder extends\n" + " $extra_interfaces$\n" " com.google.protobuf.GeneratedMessage.\n" " ExtendableMessageOrBuilder<$classname$> {\n", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), "classname", descriptor_->name()); } else { printer->Print( "public interface $classname$OrBuilder extends \n" + " $extra_interfaces$\n" " com.google.protobuf.GeneratedMessageLite.\n" " ExtendableMessageOrBuilder<$classname$> {\n", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), "classname", descriptor_->name()); } } else { if (HasDescriptorMethods(descriptor_)) { printer->Print( - "public interface $classname$OrBuilder\n" - " extends com.google.protobuf.MessageOrBuilder {\n", + "public interface $classname$OrBuilder extends\n" + " $extra_interfaces$\n" + " com.google.protobuf.MessageOrBuilder {\n", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), "classname", descriptor_->name()); } else { printer->Print( - "public interface $classname$OrBuilder\n" - " extends com.google.protobuf.MessageLiteOrBuilder {\n", + "public interface $classname$OrBuilder extends\n" + " $extra_interfaces$\n" + " com.google.protobuf.MessageLiteOrBuilder {\n", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), "classname", descriptor_->name()); } } @@ -285,7 +249,6 @@ void MessageGenerator::GenerateInterface(io::Printer* printer) { printer->Indent(); for (int i = 0; i < descriptor_->field_count(); i++) { printer->Print("\n"); - PrintFieldComment(printer, descriptor_->field(i)); field_generators_.get(descriptor_->field(i)) .GenerateInterfaceMembers(printer); } @@ -296,10 +259,10 @@ void MessageGenerator::GenerateInterface(io::Printer* printer) { // =================================================================== -void MessageGenerator::Generate(io::Printer* printer) { +void ImmutableMessageGenerator::Generate(io::Printer* printer) { bool is_own_file = descriptor_->containing_type() == NULL && - descriptor_->file()->options().java_multiple_files(); + MultipleJavaFiles(descriptor_->file(), /* immutable = */ true); WriteMessageDocComment(printer, descriptor_); @@ -308,41 +271,51 @@ void MessageGenerator::Generate(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { if (HasDescriptorMethods(descriptor_)) { printer->Print( - "public $static$ final class $classname$ extends\n" + "public$static$final class $classname$ extends\n" " com.google.protobuf.GeneratedMessage.ExtendableMessage<\n" - " $classname$> implements $classname$OrBuilder {\n", - "static", is_own_file ? "" : "static", - "classname", descriptor_->name()); + " $classname$> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "static", is_own_file ? " " : " static ", + "classname", descriptor_->name(), + "extra_interfaces", ExtraMessageInterfaces(descriptor_)); builder_type = strings::Substitute( "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>", - ClassName(descriptor_)); + name_resolver_->GetImmutableClassName(descriptor_)); } else { printer->Print( - "public $static$ final class $classname$ extends\n" + "public$static$final class $classname$ extends\n" " com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n" - " $classname$> implements $classname$OrBuilder {\n", - "static", is_own_file ? "" : "static", - "classname", descriptor_->name()); + " $classname$> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "static", is_own_file ? " " : " static ", + "classname", descriptor_->name(), + "extra_interfaces", ExtraMessageInterfaces(descriptor_)); builder_type = strings::Substitute( "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>", - ClassName(descriptor_)); + name_resolver_->GetImmutableClassName(descriptor_)); } } else { if (HasDescriptorMethods(descriptor_)) { printer->Print( - "public $static$ final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessage\n" - " implements $classname$OrBuilder {\n", - "static", is_own_file ? "" : "static", - "classname", descriptor_->name()); + "public$static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessage implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "static", is_own_file ? " " : " static ", + "classname", descriptor_->name(), + "extra_interfaces", ExtraMessageInterfaces(descriptor_)); builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>"; } else { printer->Print( - "public $static$ final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessageLite\n" - " implements $classname$OrBuilder {\n", - "static", is_own_file ? "" : "static", - "classname", descriptor_->name()); + "public$static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessageLite implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "static", is_own_file ? " " : " static ", + "classname", descriptor_->name(), + "extra_interfaces", ExtraMessageInterfaces(descriptor_)); builder_type = "com.google.protobuf.GeneratedMessageLite.Builder"; } } @@ -359,8 +332,8 @@ void MessageGenerator::Generate(io::Printer* printer) { "}\n", "classname", descriptor_->name(), "buildertype", builder_type, - "set_unknown_fields", HasUnknownFields(descriptor_) - ? " this.unknownFields = builder.getUnknownFields();" : ""); + "set_unknown_fields", + " this.unknownFields = builder.getUnknownFields();"); printer->Print( // Used when constructing the default instance, which cannot be initialized // immediately because it may cyclically refer to other default instances. @@ -376,11 +349,12 @@ void MessageGenerator::Generate(io::Printer* printer) { "}\n" "\n", "classname", descriptor_->name(), - "set_default_unknown_fields", HasUnknownFields(descriptor_) + "set_default_unknown_fields", UseUnknownFieldSet(descriptor_) ? " this.unknownFields =" - " com.google.protobuf.UnknownFieldSet.getDefaultInstance(); " : ""); + " com.google.protobuf.UnknownFieldSet.getDefaultInstance(); " + : " this.unknownFields = com.google.protobuf.ByteString.EMPTY;"); - if (HasUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_)) { printer->Print( "private final com.google.protobuf.UnknownFieldSet unknownFields;\n" "" @@ -389,6 +363,9 @@ void MessageGenerator::Generate(io::Printer* printer) { " getUnknownFields() {\n" " return this.unknownFields;\n" "}\n"); + } else { + printer->Print( + "private final com.google.protobuf.ByteString unknownFields;\n"); } if (HasGeneratedMethods(descriptor_)) { @@ -400,30 +377,102 @@ void MessageGenerator::Generate(io::Printer* printer) { // Nested types for (int i = 0; i < descriptor_->enum_type_count(); i++) { - EnumGenerator(descriptor_->enum_type(i)).Generate(printer); + EnumGenerator(descriptor_->enum_type(i), true, context_) + .Generate(printer); } for (int i = 0; i < descriptor_->nested_type_count(); i++) { - MessageGenerator messageGenerator(descriptor_->nested_type(i)); + ImmutableMessageGenerator messageGenerator( + descriptor_->nested_type(i), context_); messageGenerator.GenerateInterface(printer); messageGenerator.Generate(printer); } - // Integers for bit fields. - int totalBits = 0; - for (int i = 0; i < descriptor_->field_count(); i++) { - totalBits += field_generators_.get(descriptor_->field(i)) - .GetNumBitsForMessage(); + if (GenerateHasBits(descriptor_)) { + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += field_generators_.get(descriptor_->field(i)) + .GetNumBitsForMessage(); + } + int totalInts = (totalBits + 31) / 32; + for (int i = 0; i < totalInts; i++) { + printer->Print("private int $bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } } - int totalInts = (totalBits + 31) / 32; - for (int i = 0; i < totalInts; i++) { - printer->Print("private int $bit_field_name$;\n", - "bit_field_name", GetBitFieldName(i)); + + // oneof + map<string, string> vars; + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + vars["oneof_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name; + vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name; + vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); + // oneofCase_ and oneof_ + printer->Print(vars, + "private int $oneof_name$Case_ = 0;\n" + "private java.lang.Object $oneof_name$_;\n"); + // OneofCase enum + printer->Print(vars, + "public enum $oneof_capitalized_name$Case\n" + " implements com.google.protobuf.Internal.EnumLite {\n"); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + "$field_name$($field_number$),\n", + "field_name", + ToUpper(field->name()), + "field_number", + SimpleItoa(field->number())); + } + printer->Print( + "$cap_oneof_name$_NOT_SET(0);\n", + "cap_oneof_name", + ToUpper(vars["oneof_name"])); + printer->Print(vars, + "private int value = 0;\n" + "private $oneof_capitalized_name$Case(int value) {\n" + " this.value = value;\n" + "}\n"); + printer->Print(vars, + "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " switch (value) {\n"); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + " case $field_number$: return $field_name$;\n", + "field_number", + SimpleItoa(field->number()), + "field_name", + ToUpper(field->name())); + } + printer->Print( + " case 0: return $cap_oneof_name$_NOT_SET;\n" + " default: throw new java.lang.IllegalArgumentException(\n" + " \"Value is undefined for this oneof enum.\");\n" + " }\n" + "}\n" + "public int getNumber() {\n" + " return this.value;\n" + "}\n", + "cap_oneof_name", ToUpper(vars["oneof_name"])); + printer->Outdent(); + printer->Print("};\n\n"); + // oneofCase() + printer->Print(vars, + "public $oneof_capitalized_name$Case\n" + "get$oneof_capitalized_name$Case() {\n" + " return $oneof_capitalized_name$Case.valueOf(\n" + " $oneof_name$Case_);\n" + "}\n" + "\n"); } // Fields for (int i = 0; i < descriptor_->field_count(); i++) { - PrintFieldComment(printer, descriptor_->field(i)); printer->Print("public static final int $constant_name$ = $number$;\n", "constant_name", FieldConstantName(descriptor_->field(i)), "number", SimpleItoa(descriptor_->field(i)->number())); @@ -436,9 +485,12 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Print("private void initFields() {\n"); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateInitializationCode(printer); + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } } + printer->Outdent(); printer->Print("}\n"); @@ -451,6 +503,7 @@ void MessageGenerator::Generate(io::Printer* printer) { GenerateEqualsAndHashCode(printer); } + GenerateParseFromMethods(printer); GenerateBuilder(printer); @@ -471,7 +524,8 @@ void MessageGenerator::Generate(io::Printer* printer) { // because the defaultInstance is used by the extension to lazily retrieve // the outer class's FileDescriptor. for (int i = 0; i < descriptor_->extension_count(); i++) { - ExtensionGenerator(descriptor_->extension(i)).Generate(printer); + ImmutableExtensionGenerator(descriptor_->extension(i), context_) + .Generate(printer); } printer->Outdent(); @@ -481,10 +535,10 @@ void MessageGenerator::Generate(io::Printer* printer) { // =================================================================== -void MessageGenerator:: +void ImmutableMessageGenerator:: GenerateMessageSerializationMethods(io::Printer* printer) { scoped_array<const FieldDescriptor*> sorted_fields( - SortFieldsByNumber(descriptor_)); + SortFieldsByNumber(descriptor_)); vector<const Descriptor::ExtensionRange*> sorted_extensions; for (int i = 0; i < descriptor_->extension_range_count(); ++i) { @@ -513,14 +567,14 @@ GenerateMessageSerializationMethods(io::Printer* printer) { " .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n" " newMessageSetExtensionWriter();\n", "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } else { printer->Print( "com.google.protobuf.GeneratedMessage$lite$\n" " .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n" " newExtensionWriter();\n", "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } } @@ -539,7 +593,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { } } - if (HasUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_)) { if (descriptor_->options().message_set_wire_format()) { printer->Print( "getUnknownFields().writeAsMessageSetTo(output);\n"); @@ -547,6 +601,9 @@ GenerateMessageSerializationMethods(io::Printer* printer) { printer->Print( "getUnknownFields().writeTo(output);\n"); } + } else { + printer->Print( + "output.writeRawBytes(unknownFields);\n"); } printer->Outdent(); @@ -575,7 +632,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { } } - if (HasUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_)) { if (descriptor_->options().message_set_wire_format()) { printer->Print( "size += getUnknownFields().getSerializedSizeAsMessageSet();\n"); @@ -583,6 +640,9 @@ GenerateMessageSerializationMethods(io::Printer* printer) { printer->Print( "size += getUnknownFields().getSerializedSize();\n"); } + } else { + printer->Print( + "size += unknownFields.size();\n"); } printer->Outdent(); @@ -602,7 +662,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { "\n"); } -void MessageGenerator:: +void ImmutableMessageGenerator:: GenerateParseFromMethods(io::Printer* printer) { // Note: These are separate from GenerateMessageSerializationMethods() // because they need to be generated even for messages that are optimized @@ -661,15 +721,15 @@ GenerateParseFromMethods(io::Printer* printer) { " return PARSER.parseFrom(input, extensionRegistry);\n" "}\n" "\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } -void MessageGenerator::GenerateSerializeOneField( +void ImmutableMessageGenerator::GenerateSerializeOneField( io::Printer* printer, const FieldDescriptor* field) { field_generators_.get(field).GenerateSerializationCode(printer); } -void MessageGenerator::GenerateSerializeOneExtensionRange( +void ImmutableMessageGenerator::GenerateSerializeOneExtensionRange( io::Printer* printer, const Descriptor::ExtensionRange* range) { printer->Print( "extensionWriter.writeUntil($end$, output);\n", @@ -678,7 +738,7 @@ void MessageGenerator::GenerateSerializeOneExtensionRange( // =================================================================== -void MessageGenerator::GenerateBuilder(io::Printer* printer) { +void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { printer->Print( "public static Builder newBuilder() { return Builder.create(); }\n" "public Builder newBuilderForType() { return newBuilder(); }\n" @@ -687,7 +747,7 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) { "}\n" "public Builder toBuilder() { return newBuilder(this); }\n" "\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); if (HasNestedBuilders(descriptor_)) { printer->Print( @@ -706,29 +766,40 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) { printer->Print( "public static final class Builder extends\n" " com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n" - " $classname$, Builder> implements $classname$OrBuilder {\n", - "classname", ClassName(descriptor_)); + " $classname$, Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); } else { printer->Print( "public static final class Builder extends\n" " com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<\n" - " $classname$, Builder> implements $classname$OrBuilder {\n", - "classname", ClassName(descriptor_)); + " $classname$, Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); } } else { if (HasDescriptorMethods(descriptor_)) { printer->Print( "public static final class Builder extends\n" - " com.google.protobuf.GeneratedMessage.Builder<Builder>\n" - " implements $classname$OrBuilder {\n", - "classname", ClassName(descriptor_)); + " com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); } else { printer->Print( "public static final class Builder extends\n" " com.google.protobuf.GeneratedMessageLite.Builder<\n" " $classname$, Builder>\n" - " implements $classname$OrBuilder {\n", - "classname", ClassName(descriptor_)); + " implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); } } printer->Indent(); @@ -741,21 +812,54 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) { GenerateBuilderParsingMethods(printer); } - // Integers for bit fields. - int totalBits = 0; - for (int i = 0; i < descriptor_->field_count(); i++) { - totalBits += field_generators_.get(descriptor_->field(i)) - .GetNumBitsForBuilder(); + // oneof + map<string, string> vars; + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + vars["oneof_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name; + vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name; + vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); + // oneofCase_ and oneof_ + printer->Print(vars, + "private int $oneof_name$Case_ = 0;\n" + "private java.lang.Object $oneof_name$_;\n"); + // oneofCase() and clearOneof() + printer->Print(vars, + "public $oneof_capitalized_name$Case\n" + " get$oneof_capitalized_name$Case() {\n" + " return $oneof_capitalized_name$Case.valueOf(\n" + " $oneof_name$Case_);\n" + "}\n" + "\n" + "public Builder clear$oneof_capitalized_name$() {\n" + " $oneof_name$Case_ = 0;\n" + " $oneof_name$_ = null;\n"); + if (HasDescriptorMethods(descriptor_)) { + printer->Print(" onChanged();\n"); + } + printer->Print( + " return this;\n" + "}\n" + "\n"); } - int totalInts = (totalBits + 31) / 32; - for (int i = 0; i < totalInts; i++) { - printer->Print("private int $bit_field_name$;\n", - "bit_field_name", GetBitFieldName(i)); + + if (GenerateHasBits(descriptor_)) { + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += field_generators_.get(descriptor_->field(i)) + .GetNumBitsForBuilder(); + } + int totalInts = (totalBits + 31) / 32; + for (int i = 0; i < totalInts; i++) { + printer->Print("private int $bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } } for (int i = 0; i < descriptor_->field_count(); i++) { printer->Print("\n"); - PrintFieldComment(printer, descriptor_->field(i)); field_generators_.get(descriptor_->field(i)) .GenerateBuilderMembers(printer); } @@ -769,7 +873,8 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) { printer->Print("}\n"); } -void MessageGenerator::GenerateDescriptorMethods(io::Printer* printer) { +void ImmutableMessageGenerator:: +GenerateDescriptorMethods(io::Printer* printer) { if (HasDescriptorMethods(descriptor_)) { if (!descriptor_->options().no_standard_descriptor_accessor()) { printer->Print( @@ -778,7 +883,7 @@ void MessageGenerator::GenerateDescriptorMethods(io::Printer* printer) { " return $fileclass$.internal_$identifier$_descriptor;\n" "}\n" "\n", - "fileclass", ClassName(descriptor_->file()), + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), "identifier", UniqueFileScopeIdentifier(descriptor_)); } printer->Print( @@ -789,22 +894,23 @@ void MessageGenerator::GenerateDescriptorMethods(io::Printer* printer) { " $classname$.class, $classname$.Builder.class);\n" "}\n" "\n", - "classname", ClassName(descriptor_), - "fileclass", ClassName(descriptor_->file()), + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), "identifier", UniqueFileScopeIdentifier(descriptor_)); } } // =================================================================== -void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { +void ImmutableMessageGenerator:: +GenerateCommonBuilderMethods(io::Printer* printer) { printer->Print( "// Construct using $classname$.newBuilder()\n" "private Builder() {\n" " maybeForceBuilderInitialization();\n" "}\n" "\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); if (HasDescriptorMethods(descriptor_)) { printer->Print( @@ -813,7 +919,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { " super(parent);\n" " maybeForceBuilderInitialization();\n" "}\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } @@ -825,8 +931,10 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { printer->Indent(); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateFieldBuilderInitializationCode(printer); + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get(descriptor_->field(i)) + .GenerateFieldBuilderInitializationCode(printer); + } } printer->Outdent(); printer->Outdent(); @@ -847,13 +955,23 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { "\n" "public Builder clear() {\n" " super.clear();\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateBuilderClearCode(printer); + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get(descriptor_->field(i)) + .GenerateBuilderClearCode(printer); + } + } + + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "$oneof_name$Case_ = 0;\n" + "$oneof_name$_ = null;\n", + "oneof_name", context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); } printer->Outdent(); @@ -866,7 +984,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { " return create().mergeFrom(buildPartial());\n" "}\n" "\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); if (HasDescriptorMethods(descriptor_)) { printer->Print( "public com.google.protobuf.Descriptors.Descriptor\n" @@ -874,7 +992,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { " return $fileclass$.internal_$identifier$_descriptor;\n" "}\n" "\n", - "fileclass", ClassName(descriptor_->file()), + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), "identifier", UniqueFileScopeIdentifier(descriptor_)); } printer->Print( @@ -882,7 +1000,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { " return $classname$.getDefaultInstance();\n" "}\n" "\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); // ----------------------------------------------------------------- @@ -897,30 +1015,34 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { "\n" "public $classname$ buildPartial() {\n" " $classname$ result = new $classname$(this);\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Indent(); - // Local vars for from and to bit fields to avoid accessing the builder and - // message over and over for these fields. Seems to provide a slight - // perforamance improvement in micro benchmark and this is also what proto1 - // code does. int totalBuilderBits = 0; int totalMessageBits = 0; for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldGenerator& field = field_generators_.get(descriptor_->field(i)); + const ImmutableFieldGenerator& field = + field_generators_.get(descriptor_->field(i)); totalBuilderBits += field.GetNumBitsForBuilder(); totalMessageBits += field.GetNumBitsForMessage(); } int totalBuilderInts = (totalBuilderBits + 31) / 32; int totalMessageInts = (totalMessageBits + 31) / 32; - for (int i = 0; i < totalBuilderInts; i++) { - printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n", - "bit_field_name", GetBitFieldName(i)); - } - for (int i = 0; i < totalMessageInts; i++) { - printer->Print("int to_$bit_field_name$ = 0;\n", - "bit_field_name", GetBitFieldName(i)); + + if (GenerateHasBits(descriptor_)) { + // Local vars for from and to bit fields to avoid accessing the builder and + // message over and over for these fields. Seems to provide a slight + // perforamance improvement in micro benchmark and this is also what proto1 + // code does. + for (int i = 0; i < totalBuilderInts; i++) { + printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + for (int i = 0; i < totalMessageInts; i++) { + printer->Print("int to_$bit_field_name$ = 0;\n", + "bit_field_name", GetBitFieldName(i)); + } } // Output generation code for each field. @@ -928,10 +1050,18 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer); } - // Copy the bit field results to the generated message - for (int i = 0; i < totalMessageInts; i++) { - printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n", - "bit_field_name", GetBitFieldName(i)); + if (GenerateHasBits(descriptor_)) { + // Copy the bit field results to the generated message + for (int i = 0; i < totalMessageInts; i++) { + printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + } + + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n", + "oneof_name", context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); } printer->Outdent(); @@ -945,7 +1075,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { " return result;\n" "}\n" "\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); // ----------------------------------------------------------------- @@ -963,7 +1093,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { " }\n" "}\n" "\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } printer->Print( @@ -971,11 +1101,48 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { // Optimization: If other is the default instance, we know none of its // fields are set so we can skip the merge. " if (other == $classname$.getDefaultInstance()) return this;\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)).GenerateMergingCode(printer); + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get( + descriptor_->field(i)).GenerateMergingCode(printer); + } + } + + // Merge oneof fields. + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { + printer->Print( + "switch (other.get$oneof_capitalized_name$Case()) {\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + "case $field_name$: {\n", + "field_name", + ToUpper(field->name())); + printer->Indent(); + field_generators_.get(field).GenerateMergingCode(printer); + printer->Print( + "break;\n"); + printer->Outdent(); + printer->Print( + "}\n"); + } + printer->Print( + "case $cap_oneof_name$_NOT_SET: {\n" + " break;\n" + "}\n", + "cap_oneof_name", + ToUpper(context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name)); + printer->Outdent(); + printer->Print( + "}\n"); } printer->Outdent(); @@ -986,9 +1153,13 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { " this.mergeExtensionFields(other);\n"); } - if (HasUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_)) { printer->Print( " this.mergeUnknownFields(other.getUnknownFields());\n"); + } else { + printer->Print( + " setUnknownFields(\n" + " getUnknownFields().concat(other.unknownFields));\n"); } printer->Print( @@ -1000,7 +1171,8 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { // =================================================================== -void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { +void ImmutableMessageGenerator:: +GenerateBuilderParsingMethods(io::Printer* printer) { printer->Print( "public Builder mergeFrom(\n" " com.google.protobuf.CodedInputStream input,\n" @@ -1019,12 +1191,12 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { " }\n" " return this;\n" "}\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } // =================================================================== -void MessageGenerator::GenerateIsInitialized( +void ImmutableMessageGenerator::GenerateIsInitialized( io::Printer* printer, UseMemoization useMemoization) { bool memoization = useMemoization == MEMOIZE; if (memoization) { @@ -1039,9 +1211,11 @@ void MessageGenerator::GenerateIsInitialized( printer->Indent(); if (memoization) { + // Don't directly compare to -1 to avoid an Android x86 JIT bug. printer->Print( "byte isInitialized = memoizedIsInitialized;\n" - "if (isInitialized != -1) return isInitialized == 1;\n" + "if (isInitialized == 1) return true;\n" + "if (isInitialized == 0) return false;\n" "\n"); } @@ -1050,6 +1224,7 @@ void MessageGenerator::GenerateIsInitialized( // "has" fields into a single bitfield. for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); if (field->is_required()) { printer->Print( @@ -1057,7 +1232,7 @@ void MessageGenerator::GenerateIsInitialized( " $memoize$\n" " return false;\n" "}\n", - "name", UnderscoresToCapitalizedCamelCase(field), + "name", info->capitalized_name, "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); } } @@ -1065,6 +1240,7 @@ void MessageGenerator::GenerateIsInitialized( // Now check that all embedded messages are initialized. for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); if (GetJavaType(field) == JAVATYPE_MESSAGE && HasRequiredFields(field->message_type())) { switch (field->label()) { @@ -1074,8 +1250,9 @@ void MessageGenerator::GenerateIsInitialized( " $memoize$\n" " return false;\n" "}\n", - "type", ClassName(field->message_type()), - "name", UnderscoresToCapitalizedCamelCase(field), + "type", name_resolver_->GetImmutableClassName( + field->message_type()), + "name", info->capitalized_name, "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); break; case FieldDescriptor::LABEL_OPTIONAL: @@ -1086,8 +1263,9 @@ void MessageGenerator::GenerateIsInitialized( " return false;\n" " }\n" "}\n", - "type", ClassName(field->message_type()), - "name", UnderscoresToCapitalizedCamelCase(field), + "type", name_resolver_->GetImmutableClassName( + field->message_type()), + "name", info->capitalized_name, "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); break; case FieldDescriptor::LABEL_REPEATED: @@ -1098,8 +1276,9 @@ void MessageGenerator::GenerateIsInitialized( " return false;\n" " }\n" "}\n", - "type", ClassName(field->message_type()), - "name", UnderscoresToCapitalizedCamelCase(field), + "type", name_resolver_->GetImmutableClassName( + field->message_type()), + "name", info->capitalized_name, "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); break; } @@ -1130,7 +1309,21 @@ void MessageGenerator::GenerateIsInitialized( // =================================================================== -void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) { +namespace { +bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) { + if (field->is_repeated()) { + return false; + } + if (SupportFieldPresence(field->file())) { + return true; + } + return GetJavaType(field) == JAVATYPE_MESSAGE && + field->containing_oneof() == NULL; +} +} // namespace + +void ImmutableMessageGenerator:: +GenerateEqualsAndHashCode(io::Printer* printer) { printer->Print( "@java.lang.Override\n" "public boolean equals(final java.lang.Object obj) {\n"); @@ -1144,20 +1337,22 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) { "}\n" "$classname$ other = ($classname$) obj;\n" "\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Print("boolean result = true;\n"); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - if (!field->is_repeated()) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { printer->Print( "result = result && (has$name$() == other.has$name$());\n" "if (has$name$()) {\n", - "name", UnderscoresToCapitalizedCamelCase(field)); + "name", info->capitalized_name); printer->Indent(); } field_generators_.get(field).GenerateEqualsCode(printer); - if (!field->is_repeated()) { + if (check_has_bits) { printer->Outdent(); printer->Print( "}\n"); @@ -1181,8 +1376,6 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) { "\n"); printer->Print( - "private int memoizedHashCode = 0;\n"); - printer->Print( "@java.lang.Override\n" "public int hashCode() {\n"); printer->Indent(); @@ -1194,18 +1387,29 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) { printer->Outdent(); printer->Print( "}\n" - "int hash = 41;\n" - "hash = (19 * hash) + getDescriptorForType().hashCode();\n"); + "int hash = 41;\n"); + + if (HasDescriptorMethods(descriptor_)) { + printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n"); + } else { + // Include the hash of the class so that two objects with different types + // but the same field values will probably have different hashes. + printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + } + for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - if (!field->is_repeated()) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { printer->Print( "if (has$name$()) {\n", - "name", UnderscoresToCapitalizedCamelCase(field)); + "name", info->capitalized_name); printer->Indent(); } field_generators_.get(field).GenerateHashCode(printer); - if (!field->is_repeated()) { + if (check_has_bits) { printer->Outdent(); printer->Print("}\n"); } @@ -1216,8 +1420,15 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) { "hash = hashFields(hash, getExtensionFields());\n"); } } + + if (UseUnknownFieldSet(descriptor_)) { + printer->Print( + "hash = (29 * hash) + getUnknownFields().hashCode();\n"); + } else { + printer->Print( + "hash = (29 * hash) + unknownFields.hashCode();\n"); + } printer->Print( - "hash = (29 * hash) + getUnknownFields().hashCode();\n" "memoizedHashCode = hash;\n" "return hash;\n"); printer->Outdent(); @@ -1228,20 +1439,22 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) { // =================================================================== -void MessageGenerator::GenerateExtensionRegistrationCode(io::Printer* printer) { +void ImmutableMessageGenerator:: +GenerateExtensionRegistrationCode(io::Printer* printer) { for (int i = 0; i < descriptor_->extension_count(); i++) { - ExtensionGenerator(descriptor_->extension(i)) + ImmutableExtensionGenerator(descriptor_->extension(i), context_) .GenerateRegistrationCode(printer); } for (int i = 0; i < descriptor_->nested_type_count(); i++) { - MessageGenerator(descriptor_->nested_type(i)) + ImmutableMessageGenerator(descriptor_->nested_type(i), context_) .GenerateExtensionRegistrationCode(printer); } } // =================================================================== -void MessageGenerator::GenerateParsingConstructor(io::Printer* printer) { +void ImmutableMessageGenerator:: +GenerateParsingConstructor(io::Printer* printer) { scoped_array<const FieldDescriptor*> sorted_fields( SortFieldsByNumber(descriptor_)); @@ -1260,7 +1473,8 @@ void MessageGenerator::GenerateParsingConstructor(io::Printer* printer) { // Use builder bits to track mutable repeated fields. int totalBuilderBits = 0; for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldGenerator& field = field_generators_.get(descriptor_->field(i)); + const ImmutableFieldGenerator& field = + field_generators_.get(descriptor_->field(i)); totalBuilderBits += field.GetNumBitsForBuilder(); } int totalBuilderInts = (totalBuilderBits + 31) / 32; @@ -1269,10 +1483,17 @@ void MessageGenerator::GenerateParsingConstructor(io::Printer* printer) { "bit_field_name", GetBitFieldName(i)); } - if (HasUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_)) { printer->Print( "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n" " com.google.protobuf.UnknownFieldSet.newBuilder();\n"); + } else { + printer->Print( + "com.google.protobuf.ByteString.Output unknownFieldsOutput =\n" + " com.google.protobuf.ByteString.newOutput();\n" + "com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput =\n" + " com.google.protobuf.CodedOutputStream.newInstance(\n" + " unknownFieldsOutput);\n"); } printer->Print( @@ -1300,8 +1521,8 @@ void MessageGenerator::GenerateParsingConstructor(io::Printer* printer) { " }\n" " break;\n" "}\n", - "unknown_fields", HasUnknownFields(descriptor_) - ? " unknownFields," : ""); + "unknown_fields", UseUnknownFieldSet(descriptor_) + ? " unknownFields," : " unknownFieldsCodedOutput,"); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = sorted_fields[i]; @@ -1362,9 +1583,18 @@ void MessageGenerator::GenerateParsingConstructor(io::Printer* printer) { } // Make unknown fields immutable. - if (HasUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_)) { printer->Print( "this.unknownFields = unknownFields.build();\n"); + } else { + printer->Print( + "try {\n" + " unknownFieldsCodedOutput.flush();\n" + "} catch (java.io.IOException e) {\n" + "// Should not happen\n" + "} finally {\n" + " unknownFields = unknownFieldsOutput.toByteString();\n" + "}\n"); } // Make extensions immutable. @@ -1379,7 +1609,7 @@ void MessageGenerator::GenerateParsingConstructor(io::Printer* printer) { } // =================================================================== -void MessageGenerator::GenerateParser(io::Printer* printer) { +void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { printer->Print( "public static com.google.protobuf.Parser<$classname$> PARSER =\n" " new com.google.protobuf.AbstractParser<$classname$>() {\n", @@ -1429,6 +1659,7 @@ void MessageGenerator::GenerateParser(io::Printer* printer) { "classname", descriptor_->name()); } + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index a30f0202..406910dc 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -36,11 +36,17 @@ #define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ #include <string> -#include <google/protobuf/stubs/common.h> +#include <map> #include <google/protobuf/compiler/java/java_field.h> namespace google { namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } namespace io { class Printer; // printer.h } @@ -53,26 +59,45 @@ namespace java { class MessageGenerator { public: explicit MessageGenerator(const Descriptor* descriptor); - ~MessageGenerator(); + virtual ~MessageGenerator(); // All static variables have to be declared at the top-level of the file // so that we can control initialization order, which is important for // DescriptorProto bootstrapping to work. - void GenerateStaticVariables(io::Printer* printer); + virtual void GenerateStaticVariables(io::Printer* printer) = 0; // Output code which initializes the static variables generated by // GenerateStaticVariables(). - void GenerateStaticVariableInitializers(io::Printer* printer); + virtual void GenerateStaticVariableInitializers(io::Printer* printer) = 0; // Generate the class itself. - void Generate(io::Printer* printer); + virtual void Generate(io::Printer* printer) = 0; // Generates the base interface that both the class and its builder implement - void GenerateInterface(io::Printer* printer); + virtual void GenerateInterface(io::Printer* printer) = 0; // Generate code to register all contained extensions with an // ExtensionRegistry. - void GenerateExtensionRegistrationCode(io::Printer* printer); + virtual void GenerateExtensionRegistrationCode(io::Printer* printer) = 0; + + protected: + const Descriptor* descriptor_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; + +class ImmutableMessageGenerator : public MessageGenerator { + public: + explicit ImmutableMessageGenerator(const Descriptor* descriptor, + Context* context); + virtual ~ImmutableMessageGenerator(); + + virtual void Generate(io::Printer* printer); + virtual void GenerateInterface(io::Printer* printer); + virtual void GenerateExtensionRegistrationCode(io::Printer* printer); + virtual void GenerateStaticVariables(io::Printer* printer); + virtual void GenerateStaticVariableInitializers(io::Printer* printer); private: enum UseMemoization { @@ -80,6 +105,9 @@ class MessageGenerator { DONT_MEMOIZE }; + void GenerateFieldAccessorTable(io::Printer* printer); + void GenerateFieldAccessorTableInitializer(io::Printer* printer); + void GenerateMessageSerializationMethods(io::Printer* printer); void GenerateParseFromMethods(io::Printer* printer); void GenerateSerializeOneField(io::Printer* printer, @@ -94,14 +122,14 @@ class MessageGenerator { void GenerateIsInitialized(io::Printer* printer, UseMemoization useMemoization); void GenerateEqualsAndHashCode(io::Printer* printer); - void GenerateParser(io::Printer* printer); void GenerateParsingConstructor(io::Printer* printer); - const Descriptor* descriptor_; - FieldGeneratorMap field_generators_; + Context* context_; + ClassNameResolver* name_resolver_; + FieldGeneratorMap<ImmutableFieldGenerator> field_generators_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageGenerator); }; } // namespace java diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index b0b284f7..80b9a382 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -35,9 +35,11 @@ #include <map> #include <string> +#include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_message_field.h> #include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> @@ -49,19 +51,18 @@ namespace java { namespace { -// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of -// repeat code between this and the other field types. void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, map<string, string>* variables) { - (*variables)["name"] = - UnderscoresToCamelCase(descriptor); - (*variables)["capitalized_name"] = - UnderscoresToCapitalizedCamelCase(descriptor); - (*variables)["constant_name"] = FieldConstantName(descriptor); - (*variables)["number"] = SimpleItoa(descriptor->number()); - (*variables)["type"] = ClassName(descriptor->message_type()); + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->message_type()); + (*variables)["mutable_type"] = + name_resolver->GetMutableClassName(descriptor->message_type()); (*variables)["group_or_message"] = (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message"; @@ -72,14 +73,28 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["on_changed"] = HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; - // For singular messages and builders, one bit is used for the hasField bit. - (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); - (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex); + if (SupportFieldPresence(descriptor->file())) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["set_has_field_bit_builder"] = + GenerateSetBit(builderBitIndex) + ";"; + (*variables)["clear_has_field_bit_builder"] = + GenerateClearBit(builderBitIndex) + ";"; - (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); - (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); - (*variables)["clear_has_field_bit_builder"] = - GenerateClearBit(builderBitIndex); + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_builder"] = ""; + (*variables)["clear_has_field_bit_builder"] = ""; + + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != null"; + } // For repated builders, one bit is used for whether the array is immutable. (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); @@ -103,35 +118,41 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // =================================================================== -MessageFieldGenerator:: -MessageFieldGenerator(const FieldDescriptor* descriptor, +ImmutableMessageFieldGenerator:: +ImmutableMessageFieldGenerator(const FieldDescriptor* descriptor, int messageBitIndex, - int builderBitIndex) + int builderBitIndex, + Context* context) : descriptor_(descriptor), messageBitIndex_(messageBitIndex), - builderBitIndex_(builderBitIndex) { - SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, - &variables_); + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); } -MessageFieldGenerator::~MessageFieldGenerator() {} +ImmutableMessageFieldGenerator::~ImmutableMessageFieldGenerator() {} -int MessageFieldGenerator::GetNumBitsForMessage() const { +int ImmutableMessageFieldGenerator::GetNumBitsForMessage() const { return 1; } -int MessageFieldGenerator::GetNumBitsForBuilder() const { +int ImmutableMessageFieldGenerator::GetNumBitsForBuilder() const { return 1; } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { // TODO(jonp): In the future, consider having a method specific to the // interface so that builders can choose dynamically to either return a // message or a nested builder, so that asking for the interface doesn't // cause a message to ever be built. - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$boolean has$capitalized_name$();\n"); + if (SupportFieldPresence(descriptor_->file()) || + descriptor_->containing_oneof() == NULL) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); @@ -143,31 +164,56 @@ GenerateInterfaceMembers(io::Printer* printer) const { } } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private $type$ $name$_;\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public boolean has$capitalized_name$() {\n" - " return $get_has_field_bit_message$;\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$ get$capitalized_name$() {\n" - " return $name$_;\n" - "}\n"); + PrintExtraFieldInfo(variables_, printer); - if (HasNestedBuilders(descriptor_->containing_type())) { + if (SupportFieldPresence(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" " return $name$_;\n" "}\n"); + + if (HasNestedBuilders(descriptor_->containing_type())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder " + "get$capitalized_name$OrBuilder() {\n" + " return $name$_;\n" + "}\n"); + } + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $name$_ != null;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" + "}\n"); + + if (HasNestedBuilders(descriptor_->containing_type())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder " + "get$capitalized_name$OrBuilder() {\n" + " return get$capitalized_name$();\n" + "}\n"); + } } } -void MessageFieldGenerator::PrintNestedBuilderCondition( +void ImmutableMessageFieldGenerator::PrintNestedBuilderCondition( io::Printer* printer, const char* regular_case, const char* nested_builder_case) const { @@ -186,7 +232,7 @@ void MessageFieldGenerator::PrintNestedBuilderCondition( } } -void MessageFieldGenerator::PrintNestedBuilderFunction( +void ImmutableMessageFieldGenerator::PrintNestedBuilderFunction( io::Printer* printer, const char* method_prototype, const char* regular_case, @@ -203,15 +249,22 @@ void MessageFieldGenerator::PrintNestedBuilderFunction( printer->Print("}\n"); } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { // When using nested-builders, the code initially works just like the // non-nested builder case. It only creates a nested builder lazily on // demand and then forever delegates to it after creation. - printer->Print(variables_, - // Used when the builder is null. - "private $type$ $name$_ = $type$.getDefaultInstance();\n"); + bool support_field_presence = SupportFieldPresence(descriptor_->file()); + + if (support_field_presence) { + printer->Print(variables_, + // Used when the builder is null. + "private $type$ $name$_ = $type$.getDefaultInstance();\n"); + } else { + printer->Print(variables_, + "private $type$ $name$_ = null;\n"); + } if (HasNestedBuilders(descriptor_->containing_type())) { printer->Print(variables_, @@ -227,17 +280,26 @@ GenerateBuilderMembers(io::Printer* printer) const { // boolean hasField() WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public boolean has$capitalized_name$() {\n" - " return $get_has_field_bit_builder$;\n" - "}\n"); + if (support_field_presence) { + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_builder$;\n" + "}\n"); + } else { + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $name$Builder_ != null || $name$_ != null;\n" + "}\n"); + } // Field getField() WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public $type$ get$capitalized_name$()", - "return $name$_;\n", + support_field_presence + ? "return $name$_;\n" + : "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n", "return $name$Builder_.getMessage();\n", @@ -256,7 +318,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "$name$Builder_.setMessage(value);\n", - "$set_has_field_bit_builder$;\n" + "$set_has_field_bit_builder$\n" "return this;\n"); // Field.Builder setField(Field.Builder builderForValue) @@ -270,7 +332,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "$name$Builder_.setMessage(builderForValue.build());\n", - "$set_has_field_bit_builder$;\n" + "$set_has_field_bit_builder$\n" "return this;\n"); // Field.Builder mergeField(Field value) @@ -278,18 +340,26 @@ GenerateBuilderMembers(io::Printer* printer) const { PrintNestedBuilderFunction(printer, "$deprecation$public Builder merge$capitalized_name$($type$ value)", - "if ($get_has_field_bit_builder$ &&\n" - " $name$_ != $type$.getDefaultInstance()) {\n" - " $name$_ =\n" - " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" - "} else {\n" - " $name$_ = value;\n" - "}\n" - "$on_changed$\n", + support_field_presence + ? "if ($get_has_field_bit_builder$ &&\n" + " $name$_ != $type$.getDefaultInstance()) {\n" + " $name$_ =\n" + " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" + "} else {\n" + " $name$_ = value;\n" + "}\n" + "$on_changed$\n" + : "if ($name$_ != null) {\n" + " $name$_ =\n" + " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" + "} else {\n" + " $name$_ = value;\n" + "}\n" + "$on_changed$\n", "$name$Builder_.mergeFrom(value);\n", - "$set_has_field_bit_builder$;\n" + "$set_has_field_bit_builder$\n" "return this;\n"); // Field.Builder clearField() @@ -297,19 +367,25 @@ GenerateBuilderMembers(io::Printer* printer) const { PrintNestedBuilderFunction(printer, "$deprecation$public Builder clear$capitalized_name$()", - "$name$_ = $type$.getDefaultInstance();\n" - "$on_changed$\n", + support_field_presence + ? "$name$_ = $type$.getDefaultInstance();\n" + "$on_changed$\n" + : "$name$_ = null;\n" + "$on_changed$\n", - "$name$Builder_.clear();\n", + support_field_presence + ? "$name$Builder_.clear();\n" + : "$name$_ = null;\n" + "$name$Builder_ = null;\n", - "$clear_has_field_bit_builder$;\n" + "$clear_has_field_bit_builder$\n" "return this;\n"); if (HasNestedBuilders(descriptor_->containing_type())) { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" - " $set_has_field_bit_builder$;\n" + " $set_has_field_bit_builder$\n" " $on_changed$\n" " return get$capitalized_name$FieldBuilder().getBuilder();\n" "}\n"); @@ -318,8 +394,16 @@ GenerateBuilderMembers(io::Printer* printer) const { "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" " if ($name$Builder_ != null) {\n" " return $name$Builder_.getMessageOrBuilder();\n" - " } else {\n" - " return $name$_;\n" + " } else {\n"); + if (support_field_presence) { + printer->Print(variables_, + " return $name$_;\n"); + } else { + printer->Print(variables_, + " return $name$_ == null ?\n" + " $type$.getDefaultInstance() : $name$_;\n"); + } + printer->Print(variables_, " }\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -330,7 +414,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " if ($name$Builder_ == null) {\n" " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" " $type$, $type$.Builder, $type$OrBuilder>(\n" - " $name$_,\n" + " get$capitalized_name$(),\n" " getParentForChildren(),\n" " isClean());\n" " $name$_ = null;\n" @@ -340,28 +424,40 @@ GenerateBuilderMembers(io::Printer* printer) const { } } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateFieldBuilderInitializationCode(io::Printer* printer) const { - printer->Print(variables_, - "get$capitalized_name$FieldBuilder();\n"); + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "get$capitalized_name$FieldBuilder();\n"); + } } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n"); + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n"); + } } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { - PrintNestedBuilderCondition(printer, - "$name$_ = $type$.getDefaultInstance();\n", + if (SupportFieldPresence(descriptor_->file())) { + PrintNestedBuilderCondition(printer, + "$name$_ = $type$.getDefaultInstance();\n", - "$name$Builder_.clear();\n"); - printer->Print(variables_, "$clear_has_field_bit_builder$;\n"); + "$name$Builder_.clear();\n"); + printer->Print(variables_, "$clear_has_field_bit_builder$\n"); + } else { + PrintNestedBuilderCondition(printer, + "$name$_ = null;\n", + + "$name$_ = null;\n" + "$name$Builder_ = null;\n"); + } } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, "if (other.has$capitalized_name$()) {\n" @@ -369,13 +465,14 @@ GenerateMergingCode(io::Printer* printer) const { "}\n"); } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateBuildingCode(io::Printer* printer) const { - - printer->Print(variables_, - "if ($get_has_field_bit_from_local$) {\n" - " $set_has_field_bit_to_local$;\n" - "}\n"); + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "if ($get_has_field_bit_from_local$) {\n" + " $set_has_field_bit_to_local$;\n" + "}\n"); + } PrintNestedBuilderCondition(printer, "result.$name$_ = $name$_;\n", @@ -383,11 +480,11 @@ GenerateBuildingCode(io::Printer* printer) const { "result.$name$_ = $name$Builder_.build();\n"); } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "$type$.Builder subBuilder = null;\n" - "if ($get_has_field_bit_message$) {\n" + "if ($is_field_present_message$) {\n" " subBuilder = $name$_.toBuilder();\n" "}\n"); @@ -404,74 +501,344 @@ GenerateParsingCode(io::Printer* printer) const { "if (subBuilder != null) {\n" " subBuilder.mergeFrom($name$_);\n" " $name$_ = subBuilder.buildPartial();\n" - "}\n"); - printer->Print(variables_, - "$set_has_field_bit_message$;\n"); + "}\n" + "$set_has_field_bit_message$\n"); } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { // noop for messages. } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, - "if ($get_has_field_bit_message$) {\n" + "if ($is_field_present_message$) {\n" " output.write$group_or_message$($number$, $name$_);\n" "}\n"); } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, - "if ($get_has_field_bit_message$) {\n" + "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" " .compute$group_or_message$Size($number$, $name$_);\n" "}\n"); } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "result = result && get$capitalized_name$()\n" " .equals(other.get$capitalized_name$());\n"); } -void MessageFieldGenerator:: +void ImmutableMessageFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "hash = (37 * hash) + $constant_name$;\n" "hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); } -string MessageFieldGenerator::GetBoxedType() const { - return ClassName(descriptor_->message_type()); +string ImmutableMessageFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +// =================================================================== + +ImmutableMessageOneofFieldGenerator:: +ImmutableMessageOneofFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableMessageFieldGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableMessageOneofFieldGenerator:: +~ImmutableMessageOneofFieldGenerator() {} + +void ImmutableMessageOneofFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); + + if (HasNestedBuilders(descriptor_->containing_type())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); + } +} + +void ImmutableMessageOneofFieldGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // When using nested-builders, the code initially works just like the + // non-nested builder case. It only creates a nested builder lazily on + // demand and then forever delegates to it after creation. + if (HasNestedBuilders(descriptor_->containing_type())) { + printer->Print(variables_, + // If this builder is non-null, it is used and the other fields are + // ignored. + "private com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" + "\n"); + } + + // The comments above the methods below are based on a hypothetical + // field of type "Field" called "Field". + + if (SupportFieldPresence(descriptor_->file())) { + // boolean hasField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + + // Field getField() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public $type$ get$capitalized_name$()", + + "if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + "}\n" + "return $type$.getDefaultInstance();\n", + + "if ($has_oneof_case_message$) {\n" + " return $name$Builder_.getMessage();\n" + "}\n" + "return $type$.getDefaultInstance();\n", + + NULL); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder set$capitalized_name$($type$ value)", + + "if (value == null) {\n" + " throw new NullPointerException();\n" + "}\n" + "$oneof_name$_ = value;\n" + "$on_changed$\n", + + "$name$Builder_.setMessage(value);\n", + + "$set_oneof_case_message$;\n" + "return this;\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder set$capitalized_name$(\n" + " $type$.Builder builderForValue)", + + "$oneof_name$_ = builderForValue.build();\n" + "$on_changed$\n", + + "$name$Builder_.setMessage(builderForValue.build());\n", + + "$set_oneof_case_message$;\n" + "return this;\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder merge$capitalized_name$($type$ value)", + + "if ($has_oneof_case_message$ &&\n" + " $oneof_name$_ != $type$.getDefaultInstance()) {\n" + " $oneof_name$_ = $type$.newBuilder(($type$) $oneof_name$_)\n" + " .mergeFrom(value).buildPartial();\n" + "} else {\n" + " $oneof_name$_ = value;\n" + "}\n" + "$on_changed$\n", + + "if ($has_oneof_case_message$) {\n" + " $name$Builder_.mergeFrom(value);\n" + "}\n" + "$name$Builder_.setMessage(value);\n", + + "$set_oneof_case_message$;\n" + "return this;\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + PrintNestedBuilderFunction(printer, + "$deprecation$public Builder clear$capitalized_name$()", + + "if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " $on_changed$\n" + "}\n", + + "if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + "}\n" + "$name$Builder_.clear();\n", + + "return this;\n"); + + if (HasNestedBuilders(descriptor_->containing_type())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" + " return get$capitalized_name$FieldBuilder().getBuilder();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + " if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n" + " return $name$Builder_.getMessageOrBuilder();\n" + " } else {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = $type$.getDefaultInstance();\n" + " }\n" + " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " ($type$) $oneof_name$_,\n" + " getParentForChildren(),\n" + " isClean());\n" + " $oneof_name$_ = null;\n" + " }\n" + " $set_oneof_case_message$;\n" + " return $name$Builder_;\n" + "}\n"); + } +} + +void ImmutableMessageOneofFieldGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n"); + printer->Indent(); + + PrintNestedBuilderCondition(printer, + "result.$oneof_name$_ = $oneof_name$_;\n", + + "result.$oneof_name$_ = $name$Builder_.build();\n"); + + printer->Outdent(); + printer->Print("}\n"); +} + +void ImmutableMessageOneofFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "merge$capitalized_name$(other.get$capitalized_name$());\n"); +} + +void ImmutableMessageOneofFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$type$.Builder subBuilder = null;\n" + "if ($has_oneof_case_message$) {\n" + " subBuilder = (($type$) $oneof_name$_).toBuilder();\n" + "}\n"); + + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n" + " extensionRegistry);\n"); + } else { + printer->Print(variables_, + "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + } + + printer->Print(variables_, + "if (subBuilder != null) {\n" + " subBuilder.mergeFrom(($type$) $oneof_name$_);\n" + " $oneof_name$_ = subBuilder.buildPartial();\n" + "}\n"); + printer->Print(variables_, + "$set_oneof_case_message$;\n"); +} + +void ImmutableMessageOneofFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.write$group_or_message$($number$, ($type$) $oneof_name$_);\n" + "}\n"); +} + +void ImmutableMessageOneofFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$group_or_message$Size($number$, ($type$) $oneof_name$_);\n" + "}\n"); } // =================================================================== -RepeatedMessageFieldGenerator:: -RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, - int builderBitIndex) +RepeatedImmutableMessageFieldGenerator:: +RepeatedImmutableMessageFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) : descriptor_(descriptor), messageBitIndex_(messageBitIndex), - builderBitIndex_(builderBitIndex) { + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, - &variables_); + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); } -RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} +RepeatedImmutableMessageFieldGenerator:: +~RepeatedImmutableMessageFieldGenerator() {} -int RepeatedMessageFieldGenerator::GetNumBitsForMessage() const { +int RepeatedImmutableMessageFieldGenerator::GetNumBitsForMessage() const { return 0; } -int RepeatedMessageFieldGenerator::GetNumBitsForBuilder() const { +int RepeatedImmutableMessageFieldGenerator::GetNumBitsForBuilder() const { return 1; } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { // TODO(jonp): In the future, consider having methods specific to the // interface so that builders can choose dynamically to either return a @@ -499,10 +866,11 @@ GenerateInterfaceMembers(io::Printer* printer) const { } } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private java.util.List<$type$> $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" @@ -533,7 +901,7 @@ GenerateMembers(io::Printer* printer) const { } -void RepeatedMessageFieldGenerator::PrintNestedBuilderCondition( +void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderCondition( io::Printer* printer, const char* regular_case, const char* nested_builder_case) const { @@ -552,7 +920,7 @@ void RepeatedMessageFieldGenerator::PrintNestedBuilderCondition( } } -void RepeatedMessageFieldGenerator::PrintNestedBuilderFunction( +void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderFunction( io::Printer* printer, const char* method_prototype, const char* regular_case, @@ -569,7 +937,7 @@ void RepeatedMessageFieldGenerator::PrintNestedBuilderFunction( printer->Print("}\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { // When using nested-builders, the code initially works just like the // non-nested builder case. It only creates a nested builder lazily on @@ -737,7 +1105,8 @@ GenerateBuilderMembers(io::Printer* printer) const { " java.lang.Iterable<? extends $type$> values)", "ensure$capitalized_name$IsMutable();\n" - "super.addAll(values, $name$_);\n" + "com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" + " values, $name$_);\n" "$on_changed$\n", "$name$Builder_.addAllMessages(values);\n", @@ -836,18 +1205,18 @@ GenerateBuilderMembers(io::Printer* printer) const { } } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateFieldBuilderInitializationCode(io::Printer* printer) const { printer->Print(variables_, "get$capitalized_name$FieldBuilder();\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { PrintNestedBuilderCondition(printer, "$name$_ = java.util.Collections.emptyList();\n" @@ -856,7 +1225,7 @@ GenerateBuilderClearCode(io::Printer* printer) const { "$name$Builder_.clear();\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { // The code below does two optimizations (non-nested builder case): // 1. If the other list is empty, there's nothing to do. This ensures we @@ -890,7 +1259,7 @@ GenerateMergingCode(io::Printer* printer) const { "}\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateBuildingCode(io::Printer* printer) const { // The code below (non-nested builder case) ensures that the result has an // immutable list. If our list is immutable, we can just reuse it. If not, @@ -905,7 +1274,7 @@ GenerateBuildingCode(io::Printer* printer) const { "result.$name$_ = $name$Builder_.build();\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "if (!$get_mutable_bit_parser$) {\n" @@ -923,7 +1292,7 @@ GenerateParsingCode(io::Printer* printer) const { } } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { printer->Print(variables_, "if ($get_mutable_bit_parser$) {\n" @@ -931,7 +1300,7 @@ GenerateParsingDoneCode(io::Printer* printer) const { "}\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" @@ -939,7 +1308,7 @@ GenerateSerializationCode(io::Printer* printer) const { "}\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" @@ -948,14 +1317,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const { "}\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "result = result && get$capitalized_name$List()\n" " .equals(other.get$capitalized_name$List());\n"); } -void RepeatedMessageFieldGenerator:: +void RepeatedImmutableMessageFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "if (get$capitalized_name$Count() > 0) {\n" @@ -964,8 +1333,8 @@ GenerateHashCode(io::Printer* printer) const { "}\n"); } -string RepeatedMessageFieldGenerator::GetBoxedType() const { - return ClassName(descriptor_->message_type()); +string RepeatedImmutableMessageFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); } } // namespace java diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h index 5c8078a1..f7b491e5 100644 --- a/src/google/protobuf/compiler/java/java_message_field.h +++ b/src/google/protobuf/compiler/java/java_message_field.h @@ -41,16 +41,26 @@ namespace google { namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } +} + +namespace protobuf { namespace compiler { namespace java { -class MessageFieldGenerator : public FieldGenerator { +class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator { public: - explicit MessageFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, int builderBitIndex); - ~MessageFieldGenerator(); + explicit ImmutableMessageFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableMessageFieldGenerator(); - // implements FieldGenerator --------------------------------------- + // implements ImmutableFieldGenerator --------------------------------------- int GetNumBitsForMessage() const; int GetNumBitsForBuilder() const; void GenerateInterfaceMembers(io::Printer* printer) const; @@ -70,13 +80,13 @@ class MessageFieldGenerator : public FieldGenerator { string GetBoxedType() const; - private: + protected: const FieldDescriptor* descriptor_; map<string, string> variables_; const int messageBitIndex_; const int builderBitIndex_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); + Context* context_; + ClassNameResolver* name_resolver_; void PrintNestedBuilderCondition(io::Printer* printer, const char* regular_case, const char* nested_builder_case) const; @@ -84,15 +94,39 @@ class MessageFieldGenerator : public FieldGenerator { const char* method_prototype, const char* regular_case, const char* nested_builder_case, const char* trailing_code) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldGenerator); }; -class RepeatedMessageFieldGenerator : public FieldGenerator { +class ImmutableMessageOneofFieldGenerator + : public ImmutableMessageFieldGenerator { public: - explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, int builderBitIndex); - ~RepeatedMessageFieldGenerator(); + ImmutableMessageOneofFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableMessageOneofFieldGenerator(); - // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldGenerator); +}; + +class RepeatedImmutableMessageFieldGenerator : public ImmutableFieldGenerator { + public: + explicit RepeatedImmutableMessageFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableMessageFieldGenerator(); + + // implements ImmutableFieldGenerator --------------------------------------- int GetNumBitsForMessage() const; int GetNumBitsForBuilder() const; void GenerateInterfaceMembers(io::Printer* printer) const; @@ -112,13 +146,13 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { string GetBoxedType() const; - private: + protected: const FieldDescriptor* descriptor_; map<string, string> variables_; const int messageBitIndex_; const int builderBitIndex_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); + Context* context_; + ClassNameResolver* name_resolver_; void PrintNestedBuilderCondition(io::Printer* printer, const char* regular_case, const char* nested_builder_case) const; @@ -126,6 +160,9 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { const char* method_prototype, const char* regular_case, const char* nested_builder_case, const char* trailing_code) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableMessageFieldGenerator); }; } // namespace java diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc new file mode 100644 index 00000000..7f52d234 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_name_resolver.cc @@ -0,0 +1,266 @@ +// 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. + +#include <google/protobuf/compiler/java/java_name_resolver.h> + +#include <map> +#include <string> + +#include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { +// A suffix that will be appended to the file's outer class name if the name +// conflicts with some other types defined in the file. +const char* kOuterClassNameSuffix = "OuterClass"; + +// Strip package name from a descriptor's full name. +// For example: +// Full name : foo.Bar.Baz +// Package name: foo +// After strip : Bar.Baz +string StripPackageName(const string& full_name, + const FileDescriptor* file) { + if (file->package().empty()) { + return full_name; + } else { + // Strip package name + return full_name.substr(file->package().size() + 1); + } +} + +// Get the name of a message's Java class without package name prefix. +string ClassNameWithoutPackage(const Descriptor* descriptor, + bool immutable) { + return StripPackageName(descriptor->full_name(), + descriptor->file()); +} + +// Get the name of an enum's Java class without package name prefix. +string ClassNameWithoutPackage(const EnumDescriptor* descriptor, + bool immutable) { + // Doesn't append "Mutable" for enum type's name. + const Descriptor* message_descriptor = descriptor->containing_type(); + if (message_descriptor == NULL) { + return descriptor->name(); + } else { + return ClassNameWithoutPackage(message_descriptor, immutable) + + "." + descriptor->name(); + } +} + +// Get the name of a service's Java class without package name prefix. +string ClassNameWithoutPackage(const ServiceDescriptor* descriptor, + bool immutable) { + string full_name = StripPackageName(descriptor->full_name(), + descriptor->file()); + // We don't allow nested service definitions. + GOOGLE_CHECK(full_name.find('.') == string::npos); + return full_name; +} + +// Check whether a given message or its nested types has the given class name. +bool MessageHasConflictingClassName(const Descriptor* message, + const string& classname) { + if (message->name() == classname) return true; + for (int i = 0; i < message->nested_type_count(); ++i) { + if (MessageHasConflictingClassName(message->nested_type(i), classname)) { + return true; + } + } + for (int i = 0; i < message->enum_type_count(); ++i) { + if (message->enum_type(i)->name() == classname) { + return true; + } + } + return false; +} + +} // namespace + +ClassNameResolver::ClassNameResolver() { +} + +ClassNameResolver::~ClassNameResolver() { +} + +string ClassNameResolver::GetFileDefaultImmutableClassName( + const FileDescriptor* file) { + 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); + } + return UnderscoresToCamelCase(StripProto(basename), true); +} + +string ClassNameResolver::GetFileImmutableClassName( + const FileDescriptor* file) { + string& class_name = file_immutable_outer_class_names_[file]; + if (class_name.empty()) { + if (file->options().has_java_outer_classname()) { + class_name = file->options().java_outer_classname(); + } else { + class_name = GetFileDefaultImmutableClassName(file); + if (HasConflictingClassName(file, class_name)) { + class_name += kOuterClassNameSuffix; + } + } + } + return class_name; +} + +string ClassNameResolver::GetFileClassName(const FileDescriptor* file, + bool immutable) { + if (immutable) { + return GetFileImmutableClassName(file); + } else { + return "Mutable" + GetFileImmutableClassName(file); + } +} + +// Check whether there is any type defined in the proto file that has +// the given class name. +bool ClassNameResolver::HasConflictingClassName( + const FileDescriptor* file, const string& classname) { + for (int i = 0; i < file->enum_type_count(); i++) { + if (file->enum_type(i)->name() == classname) { + return true; + } + } + for (int i = 0; i < file->service_count(); i++) { + if (file->service(i)->name() == classname) { + return true; + } + } + for (int i = 0; i < file->message_type_count(); i++) { + if (MessageHasConflictingClassName(file->message_type(i), classname)) { + return true; + } + } + return false; +} + +string ClassNameResolver::GetDescriptorClassName( + const FileDescriptor* descriptor) { + return GetFileImmutableClassName(descriptor) + "InternalDescriptors"; +} + +string ClassNameResolver::GetClassName(const FileDescriptor* descriptor, + bool immutable) { + string result = FileJavaPackage(descriptor, immutable); + if (!result.empty()) result += '.'; + result += GetFileClassName(descriptor, immutable); + return result; +} + +// Get the full name of a Java class by prepending the Java package name +// or outer class name. +string ClassNameResolver::GetClassFullName(const string& name_without_package, + const FileDescriptor* file, + bool immutable, + bool multiple_files) { + string result; + if (multiple_files) { + result = FileJavaPackage(file, immutable); + } else { + result = GetClassName(file, immutable); + } + if (!result.empty()) { + result += '.'; + } + result += name_without_package; + return result; +} + +string ClassNameResolver::GetClassName(const Descriptor* descriptor, + bool immutable) { + return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable), + descriptor->file(), immutable, + MultipleJavaFiles(descriptor->file(), immutable)); +} + +string ClassNameResolver::GetClassName(const EnumDescriptor* descriptor, + bool immutable) { + return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable), + descriptor->file(), immutable, + MultipleJavaFiles(descriptor->file(), immutable)); +} + +string ClassNameResolver::GetClassName(const ServiceDescriptor* descriptor, + bool immutable) { + return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable), + descriptor->file(), immutable, + MultipleJavaFiles(descriptor->file(), immutable)); +} + +// Get the Java Class style full name of a message. +string ClassNameResolver::GetJavaClassFullName( + const string& name_without_package, + const FileDescriptor* file, + bool immutable) { + string result; + if (MultipleJavaFiles(file, immutable)) { + result = FileJavaPackage(file, immutable); + if (!result.empty()) result += '.'; + } else { + result = GetClassName(file, immutable); + if (!result.empty()) result += '$'; + } + result += StringReplace(name_without_package, ".", "$", true); + return result; +} + +string ClassNameResolver::GetExtensionIdentifierName( + const FieldDescriptor* descriptor, bool immutable) { + return GetClassName(descriptor->containing_type(), immutable) + "." + + descriptor->name(); +} + + +string ClassNameResolver::GetJavaImmutableClassName( + const Descriptor* descriptor) { + return GetJavaClassFullName( + ClassNameWithoutPackage(descriptor, true), + descriptor->file(), true); +} + + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h new file mode 100644 index 00000000..1d3e185c --- /dev/null +++ b/src/google/protobuf/compiler/java/java_name_resolver.h @@ -0,0 +1,124 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__ + +#include <map> +#include <string> + +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { +class Descriptor; +class EnumDescriptor; +class FieldDescriptor; +class FileDescriptor; +class ServiceDescriptor; + +namespace compiler { +namespace java { + +// Used to get the Java class related names for a given descriptor. It caches +// the results to avoid redundant calculation across multiple name queries. +// Thread-safety note: This class is *not* thread-safe. +class ClassNameResolver { + public: + ClassNameResolver(); + ~ClassNameResolver(); + + // Gets the unqualified outer class name for the file. + string GetFileClassName(const FileDescriptor* file, bool immutable); + // Gets the unqualified immutable outer class name of a file. + string GetFileImmutableClassName(const FileDescriptor* file); + // Gets the unqualified default immutable outer class name of a file + // (converted from the proto file's name). + string GetFileDefaultImmutableClassName(const FileDescriptor* file); + + // Check whether there is any type defined in the proto file that has + // the given class name. + bool HasConflictingClassName(const FileDescriptor* file, + const string& classname); + + // Gets the name of the outer class that holds descriptor information. + // Descriptors are shared between immutable messages and mutable messages. + // Since both of them are generated optionally, the descriptors need to be + // put in another common place. + string GetDescriptorClassName(const FileDescriptor* file); + + // Gets the fully-qualified class name corresponding to the given descriptor. + string GetClassName(const Descriptor* descriptor, bool immutable); + string GetClassName(const EnumDescriptor* descriptor, bool immutable); + string GetClassName(const ServiceDescriptor* descriptor, bool immutable); + string GetClassName(const FileDescriptor* descriptor, bool immutable); + + template<class DescriptorType> + string GetImmutableClassName(const DescriptorType* descriptor) { + return GetClassName(descriptor, true); + } + template<class DescriptorType> + string GetMutableClassName(const DescriptorType* descriptor) { + return GetClassName(descriptor, false); + } + + // Gets the fully qualified name of an extension identifier. + string GetExtensionIdentifierName(const FieldDescriptor* descriptor, + bool immutable); + + // Gets the fully qualified name for generated classes in Java convention. + // Nested classes will be separated using '$' instead of '.' + // For example: + // com.package.OuterClass$OuterMessage$InnerMessage + string GetJavaImmutableClassName(const Descriptor* descriptor); + private: + // Get the full name of a Java class by prepending the Java package name + // or outer class name. + string GetClassFullName(const string& name_without_package, + const FileDescriptor* file, + bool immutable, + bool multiple_files); + // Get the Java Class style full name of a message. + string GetJavaClassFullName( + const string& name_without_package, + const FileDescriptor* file, + bool immutable); + // Caches the result to provide better performance. + map<const FileDescriptor*, string> file_immutable_outer_class_names_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ClassNameResolver); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_NAME_RESOLVER_H__ diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc index ccc94c9d..52577626 100644 --- a/src/google/protobuf/compiler/java/java_plugin_unittest.cc +++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc @@ -34,6 +34,8 @@ // It seemed like parameterizing it would add more complexity than it is // worth. +#include <memory> + #include <google/protobuf/compiler/java/java_generator.h> #include <google/protobuf/compiler/command_line_interface.h> #include <google/protobuf/io/zero_copy_stream.h> @@ -71,7 +73,7 @@ class TestGenerator : public CodeGenerator { void TryInsert(const string& filename, const string& insertion_point, GeneratorContext* context) const { scoped_ptr<io::ZeroCopyOutputStream> output( - context->OpenForInsert(filename, insertion_point)); + context->OpenForInsert(filename, insertion_point)); io::Printer printer(output.get(), '$'); printer.Print("// inserted $name$\n", "name", insertion_point); } @@ -81,16 +83,16 @@ class TestGenerator : public CodeGenerator { // not verify that they are correctly-placed; that would require actually // compiling the output which is a bit more than I care to do for this test. TEST(JavaPluginTest, PluginTest) { - File::WriteStringToFileOrDie( - "syntax = \"proto2\";\n" - "package foo;\n" - "option java_package = \"\";\n" - "option java_outer_classname = \"Test\";\n" - "message Bar {\n" - " message Baz {}\n" - "}\n" - "enum Qux { BLAH = 1; }\n", - TestTempDir() + "/test.proto"); + GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto", + "syntax = \"proto2\";\n" + "package foo;\n" + "option java_package = \"\";\n" + "option java_outer_classname = \"Test\";\n" + "message Bar {\n" + " message Baz {}\n" + "}\n" + "enum Qux { BLAH = 1; }\n", + true)); google::protobuf::compiler::CommandLineInterface cli; cli.SetInputsAreProtoPathRelative(true); diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 0140e23f..031a1293 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -35,10 +35,12 @@ #include <map> #include <string> -#include <google/protobuf/compiler/java/java_primitive_field.h> -#include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/java/java_context.h> +#include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> +#include <google/protobuf/compiler/java/java_primitive_field.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> @@ -73,107 +75,25 @@ const char* PrimitiveTypeName(JavaType type) { return NULL; } -bool IsReferenceType(JavaType type) { - switch (type) { - case JAVATYPE_INT : return false; - case JAVATYPE_LONG : return false; - case JAVATYPE_FLOAT : return false; - case JAVATYPE_DOUBLE : return false; - case JAVATYPE_BOOLEAN: return false; - case JAVATYPE_STRING : return true; - case JAVATYPE_BYTES : return true; - case JAVATYPE_ENUM : return true; - case JAVATYPE_MESSAGE: return true; - - // No default because we want the compiler to complain if any new - // JavaTypes are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return false; -} - -const char* GetCapitalizedType(const FieldDescriptor* field) { - switch (GetType(field)) { - case FieldDescriptor::TYPE_INT32 : return "Int32" ; - case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; - case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; - case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ; - case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; - case FieldDescriptor::TYPE_INT64 : return "Int64" ; - case FieldDescriptor::TYPE_UINT64 : return "UInt64" ; - case FieldDescriptor::TYPE_SINT64 : return "SInt64" ; - case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ; - case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; - case FieldDescriptor::TYPE_FLOAT : return "Float" ; - case FieldDescriptor::TYPE_DOUBLE : return "Double" ; - case FieldDescriptor::TYPE_BOOL : return "Bool" ; - case FieldDescriptor::TYPE_STRING : return "String" ; - case FieldDescriptor::TYPE_BYTES : return "Bytes" ; - case FieldDescriptor::TYPE_ENUM : return "Enum" ; - case FieldDescriptor::TYPE_GROUP : return "Group" ; - case FieldDescriptor::TYPE_MESSAGE : return "Message" ; - - // No default because we want the compiler to complain if any new - // types are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; -} - -// For encodings with fixed sizes, returns that size in bytes. Otherwise -// returns -1. -int FixedSize(FieldDescriptor::Type type) { - switch (type) { - case FieldDescriptor::TYPE_INT32 : return -1; - case FieldDescriptor::TYPE_INT64 : return -1; - case FieldDescriptor::TYPE_UINT32 : return -1; - case FieldDescriptor::TYPE_UINT64 : return -1; - case FieldDescriptor::TYPE_SINT32 : return -1; - case FieldDescriptor::TYPE_SINT64 : return -1; - case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; - case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; - case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; - case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; - case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; - case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; - - case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; - case FieldDescriptor::TYPE_ENUM : return -1; - - case FieldDescriptor::TYPE_STRING : return -1; - case FieldDescriptor::TYPE_BYTES : return -1; - case FieldDescriptor::TYPE_GROUP : return -1; - case FieldDescriptor::TYPE_MESSAGE : return -1; - - // No default because we want the compiler to complain if any new - // types are added. - } - GOOGLE_LOG(FATAL) << "Can't get here."; - return -1; -} - void SetPrimitiveVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, map<string, string>* variables) { - (*variables)["name"] = - UnderscoresToCamelCase(descriptor); - (*variables)["capitalized_name"] = - UnderscoresToCapitalizedCamelCase(descriptor); - (*variables)["constant_name"] = FieldConstantName(descriptor); - (*variables)["number"] = SimpleItoa(descriptor->number()); + SetCommonFieldVariables(descriptor, info, variables); + (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); (*variables)["field_type"] = (*variables)["type"]; (*variables)["field_list_type"] = "java.util.List<" + (*variables)["boxed_type"] + ">"; (*variables)["empty_list"] = "java.util.Collections.emptyList()"; - (*variables)["default"] = DefaultValue(descriptor); + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ? - "" : ("= " + DefaultValue(descriptor)); - (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); + "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver)); + (*variables)["capitalized_type"] = + GetCapitalizedType(descriptor, /* immutable = */ true); (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), GetType(descriptor))); @@ -196,14 +116,33 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["on_changed"] = HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; - // For singular messages and builders, one bit is used for the hasField bit. - (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); - (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex); + if (SupportFieldPresence(descriptor->file())) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); - (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); - (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); - (*variables)["clear_has_field_bit_builder"] = - GenerateClearBit(builderBitIndex); + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["set_has_field_bit_builder"] = + GenerateSetBit(builderBitIndex) + ";"; + (*variables)["clear_has_field_bit_builder"] = + GenerateClearBit(builderBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_builder"] = ""; + (*variables)["clear_has_field_bit_builder"] = ""; + + if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { + (*variables)["is_field_present_message"] = + "!" + (*variables)["name"] + "_.isEmpty()"; + } else { + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + (*variables)["default"]; + } + } // For repated builders, one bit is used for whether the array is immutable. (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); @@ -227,46 +166,53 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // =================================================================== -PrimitiveFieldGenerator:: -PrimitiveFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, - int builderBitIndex) +ImmutablePrimitiveFieldGenerator:: +ImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) : descriptor_(descriptor), messageBitIndex_(messageBitIndex), - builderBitIndex_(builderBitIndex) { + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, - &variables_); + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); } -PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} +ImmutablePrimitiveFieldGenerator::~ImmutablePrimitiveFieldGenerator() {} -int PrimitiveFieldGenerator::GetNumBitsForMessage() const { +int ImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const { return 1; } -int PrimitiveFieldGenerator::GetNumBitsForBuilder() const { +int ImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const { return 1; } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$boolean has$capitalized_name$();\n"); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private $field_type$ $name$_;\n"); - - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public boolean has$capitalized_name$() {\n" - " return $get_has_field_bit_message$;\n" - "}\n"); + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -275,16 +221,18 @@ GenerateMembers(io::Printer* printer) const { "}\n"); } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "private $field_type$ $name$_ $default_init$;\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public boolean has$capitalized_name$() {\n" - " return $get_has_field_bit_builder$;\n" - "}\n"); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_builder$;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -296,7 +244,7 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" "$null_check$" - " $set_has_field_bit_builder$;\n" + " $set_has_field_bit_builder$\n" " $name$_ = value;\n" " $on_changed$\n" " return this;\n" @@ -305,7 +253,7 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" - " $clear_has_field_bit_builder$;\n"); + " $clear_has_field_bit_builder$\n"); JavaType type = GetJavaType(descriptor_); if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { // The default value is not a simple literal so we want to avoid executing @@ -322,70 +270,80 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateFieldBuilderInitializationCode(io::Printer* printer) const { // noop for primitives } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = $default$;\n"); } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = $default$;\n" - "$clear_has_field_bit_builder$;\n"); + "$clear_has_field_bit_builder$\n"); } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } else { + printer->Print(variables_, + "if (other.get$capitalized_name$() != $default$) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateBuildingCode(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "if ($get_has_field_bit_from_local$) {\n" + " $set_has_field_bit_to_local$;\n" + "}\n"); + } printer->Print(variables_, - "if ($get_has_field_bit_from_local$) {\n" - " $set_has_field_bit_to_local$;\n" - "}\n" "result.$name$_ = $name$_;\n"); } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, - "$set_has_field_bit_message$;\n" + "$set_has_field_bit_message$\n" "$name$_ = input.read$capitalized_type$();\n"); } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { // noop for primitives. } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, - "if ($get_has_field_bit_message$) {\n" + "if ($is_field_present_message$) {\n" " output.write$capitalized_type$($number$, $name$_);\n" "}\n"); } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, - "if ($get_has_field_bit_message$) {\n" + "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" " .compute$capitalized_type$Size($number$, $name$_);\n" "}\n"); } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { switch (GetJavaType(descriptor_)) { case JAVATYPE_INT: @@ -398,14 +356,18 @@ GenerateEqualsCode(io::Printer* printer) const { case JAVATYPE_FLOAT: printer->Print(variables_, - "result = result && (Float.floatToIntBits(get$capitalized_name$())" - " == Float.floatToIntBits(other.get$capitalized_name$()));\n"); + "result = result && (\n" + " java.lang.Float.floatToIntBits(get$capitalized_name$())\n" + " == java.lang.Float.floatToIntBits(\n" + " other.get$capitalized_name$()));\n"); break; case JAVATYPE_DOUBLE: printer->Print(variables_, - "result = result && (Double.doubleToLongBits(get$capitalized_name$())" - " == Double.doubleToLongBits(other.get$capitalized_name$()));\n"); + "result = result && (\n" + " java.lang.Double.doubleToLongBits(get$capitalized_name$())\n" + " == java.lang.Double.doubleToLongBits(\n" + " other.get$capitalized_name$()));\n"); break; case JAVATYPE_STRING: @@ -423,7 +385,7 @@ GenerateEqualsCode(io::Printer* printer) const { } } -void PrimitiveFieldGenerator:: +void ImmutablePrimitiveFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "hash = (37 * hash) + $constant_name$;\n"); @@ -435,24 +397,26 @@ GenerateHashCode(io::Printer* printer) const { case JAVATYPE_LONG: printer->Print(variables_, - "hash = (53 * hash) + hashLong(get$capitalized_name$());\n"); + "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n" + " get$capitalized_name$());\n"); break; case JAVATYPE_BOOLEAN: printer->Print(variables_, - "hash = (53 * hash) + hashBoolean(get$capitalized_name$());\n"); + "hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n" + " get$capitalized_name$());\n"); break; case JAVATYPE_FLOAT: printer->Print(variables_, - "hash = (53 * hash) + Float.floatToIntBits(\n" + "hash = (53 * hash) + java.lang.Float.floatToIntBits(\n" " get$capitalized_name$());\n"); break; case JAVATYPE_DOUBLE: printer->Print(variables_, - "hash = (53 * hash) + hashLong(\n" - " Double.doubleToLongBits(get$capitalized_name$()));\n"); + "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n" + " java.lang.Double.doubleToLongBits(get$capitalized_name$()));\n"); break; case JAVATYPE_STRING: @@ -469,33 +433,157 @@ GenerateHashCode(io::Printer* printer) const { } } -string PrimitiveFieldGenerator::GetBoxedType() const { +string ImmutablePrimitiveFieldGenerator::GetBoxedType() const { return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); } // =================================================================== -RepeatedPrimitiveFieldGenerator:: -RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, - int builderBitIndex) +ImmutablePrimitiveOneofFieldGenerator:: +ImmutablePrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutablePrimitiveFieldGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutablePrimitiveOneofFieldGenerator:: +~ImmutablePrimitiveOneofFieldGenerator() {} + +void ImmutablePrimitiveOneofFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($boxed_type$) $oneof_name$_;\n" + " }\n" + " return $default$;\n" + "}\n"); +} + + +void ImmutablePrimitiveOneofFieldGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($boxed_type$) $oneof_name$_;\n" + " }\n" + " return $default$;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + "$null_check$" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " $on_changed$\n" + " }\n" + " return this;\n" + "}\n"); +} + +void ImmutablePrimitiveOneofFieldGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " result.$oneof_name$_ = $oneof_name$_;\n" + "}\n"); +} + +void ImmutablePrimitiveOneofFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "set$capitalized_name$(other.get$capitalized_name$());\n"); +} + +void ImmutablePrimitiveOneofFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$set_oneof_case_message$;\n" + "$oneof_name$_ = input.read$capitalized_type$();\n"); +} + +void ImmutablePrimitiveOneofFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.write$capitalized_type$(\n" + " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n" + "}\n"); +} + +void ImmutablePrimitiveOneofFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$capitalized_type$Size(\n" + " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n" + "}\n"); +} + +// =================================================================== + +RepeatedImmutablePrimitiveFieldGenerator:: +RepeatedImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) : descriptor_(descriptor), messageBitIndex_(messageBitIndex), - builderBitIndex_(builderBitIndex) { + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, - &variables_); + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); } -RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} +RepeatedImmutablePrimitiveFieldGenerator:: +~RepeatedImmutablePrimitiveFieldGenerator() {} -int RepeatedPrimitiveFieldGenerator::GetNumBitsForMessage() const { +int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const { return 0; } -int RepeatedPrimitiveFieldGenerator::GetNumBitsForBuilder() const { +int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const { return 1; } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -509,10 +597,11 @@ GenerateInterfaceMembers(io::Printer* printer) const { } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private $field_list_type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.util.List<$boxed_type$>\n" @@ -537,7 +626,7 @@ GenerateMembers(io::Printer* printer) const { } } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { // One field is the list and the bit field keeps track of whether the // list is immutable. If it's immutable, the invariant is that it must @@ -603,7 +692,8 @@ GenerateBuilderMembers(io::Printer* printer) const { "$deprecation$public Builder addAll$capitalized_name$(\n" " java.lang.Iterable<? extends $boxed_type$> values) {\n" " ensure$capitalized_name$IsMutable();\n" - " super.addAll(values, $name$_);\n" + " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" + " values, $name$_);\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -617,24 +707,24 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateFieldBuilderInitializationCode(io::Printer* printer) const { // noop for primitives } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = $empty_list$;\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = $empty_list$;\n" "$clear_mutable_bit_builder$;\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { // The code below does two optimizations: // 1. If the other list is empty, there's nothing to do. This ensures we @@ -654,7 +744,7 @@ GenerateMergingCode(io::Printer* printer) const { "}\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateBuildingCode(io::Printer* printer) const { // The code below ensures that the result has an immutable list. If our // list is immutable, we can just reuse it. If not, we make it immutable. @@ -666,7 +756,7 @@ GenerateBuildingCode(io::Printer* printer) const { "result.$name$_ = $name$_;\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "if (!$get_mutable_bit_parser$) {\n" @@ -676,7 +766,7 @@ GenerateParsingCode(io::Printer* printer) const { "$name$_.add(input.read$capitalized_type$());\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateParsingCodeFromPacked(io::Printer* printer) const { printer->Print(variables_, "int length = input.readRawVarint32();\n" @@ -691,7 +781,7 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { "input.popLimit(limit);\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { printer->Print(variables_, "if ($get_mutable_bit_parser$) {\n" @@ -699,7 +789,7 @@ GenerateParsingDoneCode(io::Printer* printer) const { "}\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { if (descriptor_->options().packed()) { printer->Print(variables_, @@ -718,7 +808,7 @@ GenerateSerializationCode(io::Printer* printer) const { } } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "{\n" @@ -761,14 +851,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print("}\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "result = result && get$capitalized_name$List()\n" " .equals(other.get$capitalized_name$List());\n"); } -void RepeatedPrimitiveFieldGenerator:: +void RepeatedImmutablePrimitiveFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "if (get$capitalized_name$Count() > 0) {\n" @@ -777,7 +867,7 @@ GenerateHashCode(io::Printer* printer) const { "}\n"); } -string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { +string RepeatedImmutablePrimitiveFieldGenerator::GetBoxedType() const { return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); } diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h index 1b5b6d95..489e1b20 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.h +++ b/src/google/protobuf/compiler/java/java_primitive_field.h @@ -41,16 +41,26 @@ namespace google { namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } +} + +namespace protobuf { namespace compiler { namespace java { -class PrimitiveFieldGenerator : public FieldGenerator { +class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator { public: - explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, int builderBitIndex); - ~PrimitiveFieldGenerator(); + explicit ImmutablePrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutablePrimitiveFieldGenerator(); - // implements FieldGenerator --------------------------------------- + // implements ImmutableFieldGenerator --------------------------------------- int GetNumBitsForMessage() const; int GetNumBitsForBuilder() const; void GenerateInterfaceMembers(io::Printer* printer) const; @@ -70,22 +80,47 @@ class PrimitiveFieldGenerator : public FieldGenerator { string GetBoxedType() const; - private: + protected: const FieldDescriptor* descriptor_; map<string, string> variables_; const int messageBitIndex_; const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldGenerator); +}; + +class ImmutablePrimitiveOneofFieldGenerator + : public ImmutablePrimitiveFieldGenerator { + public: + ImmutablePrimitiveOneofFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutablePrimitiveOneofFieldGenerator(); + + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldGenerator); }; -class RepeatedPrimitiveFieldGenerator : public FieldGenerator { +class RepeatedImmutablePrimitiveFieldGenerator + : public ImmutableFieldGenerator { public: - explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, int builderBitIndex); - ~RepeatedPrimitiveFieldGenerator(); + explicit RepeatedImmutablePrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + virtual ~RepeatedImmutablePrimitiveFieldGenerator(); - // implements FieldGenerator --------------------------------------- + // implements ImmutableFieldGenerator --------------------------------------- int GetNumBitsForMessage() const; int GetNumBitsForBuilder() const; void GenerateInterfaceMembers(io::Printer* printer) const; @@ -111,8 +146,10 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { map<string, string> variables_; const int messageBitIndex_; const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutablePrimitiveFieldGenerator); }; } // namespace java diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc index bcd80359..aa5c5231 100644 --- a/src/google/protobuf/compiler/java/java_service.cc +++ b/src/google/protobuf/compiler/java/java_service.cc @@ -33,8 +33,11 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/java/java_service.h> + +#include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/strutil.h> @@ -49,8 +52,17 @@ ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor) ServiceGenerator::~ServiceGenerator() {} -void ServiceGenerator::Generate(io::Printer* printer) { - bool is_own_file = descriptor_->file()->options().java_multiple_files(); +// =================================================================== +ImmutableServiceGenerator::ImmutableServiceGenerator( + const ServiceDescriptor* descriptor, Context* context) + : ServiceGenerator(descriptor), context_(context), + name_resolver_(context->GetNameResolver()) {} + +ImmutableServiceGenerator::~ImmutableServiceGenerator() {} + +void ImmutableServiceGenerator::Generate(io::Printer* printer) { + bool is_own_file = + MultipleJavaFiles(descriptor_->file(), /* immutable = */ true); WriteServiceDocComment(printer, descriptor_); printer->Print( "public $static$ abstract class $classname$\n" @@ -77,7 +89,7 @@ void ServiceGenerator::Generate(io::Printer* printer) { " getDescriptor() {\n" " return $file$.getDescriptor().getServices().get($index$);\n" "}\n", - "file", ClassName(descriptor_->file()), + "file", name_resolver_->GetImmutableClassName(descriptor_->file()), "index", SimpleItoa(descriptor_->index())); GenerateGetDescriptorForType(printer); @@ -98,7 +110,8 @@ void ServiceGenerator::Generate(io::Printer* printer) { printer->Print("}\n\n"); } -void ServiceGenerator::GenerateGetDescriptorForType(io::Printer* printer) { +void ImmutableServiceGenerator::GenerateGetDescriptorForType( + io::Printer* printer) { printer->Print( "public final com.google.protobuf.Descriptors.ServiceDescriptor\n" " getDescriptorForType() {\n" @@ -106,7 +119,7 @@ void ServiceGenerator::GenerateGetDescriptorForType(io::Printer* printer) { "}\n"); } -void ServiceGenerator::GenerateInterface(io::Printer* printer) { +void ImmutableServiceGenerator::GenerateInterface(io::Printer* printer) { printer->Print("public interface Interface {\n"); printer->Indent(); GenerateAbstractMethods(printer); @@ -114,7 +127,7 @@ void ServiceGenerator::GenerateInterface(io::Printer* printer) { printer->Print("}\n\n"); } -void ServiceGenerator::GenerateNewReflectiveServiceMethod( +void ImmutableServiceGenerator::GenerateNewReflectiveServiceMethod( io::Printer* printer) { printer->Print( "public static com.google.protobuf.Service newReflectiveService(\n" @@ -141,7 +154,7 @@ void ServiceGenerator::GenerateNewReflectiveServiceMethod( printer->Print("}\n\n"); } -void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod( +void ImmutableServiceGenerator::GenerateNewReflectiveBlockingServiceMethod( io::Printer* printer) { printer->Print( "public static com.google.protobuf.BlockingService\n" @@ -162,7 +175,7 @@ void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod( printer->Print("}\n\n"); } -void ServiceGenerator::GenerateAbstractMethods(io::Printer* printer) { +void ImmutableServiceGenerator::GenerateAbstractMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); WriteMethodDocComment(printer, method); @@ -171,7 +184,7 @@ void ServiceGenerator::GenerateAbstractMethods(io::Printer* printer) { } } -void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { +void ImmutableServiceGenerator::GenerateCallMethod(io::Printer* printer) { printer->Print( "\n" "public final void callMethod(\n" @@ -194,8 +207,10 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { map<string, string> vars; vars["index"] = SimpleItoa(i); vars["method"] = UnderscoresToCamelCase(method); - vars["input"] = ClassName(method->input_type()); - vars["output"] = ClassName(method->output_type()); + vars["input"] = name_resolver_->GetImmutableClassName( + method->input_type()); + vars["output"] = name_resolver_->GetImmutableClassName( + method->output_type()); printer->Print(vars, "case $index$:\n" " this.$method$(controller, ($input$)request,\n" @@ -217,7 +232,8 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { "\n"); } -void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) { +void ImmutableServiceGenerator::GenerateCallBlockingMethod( + io::Printer* printer) { printer->Print( "\n" "public final com.google.protobuf.Message callBlockingMethod(\n" @@ -239,8 +255,10 @@ void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) { map<string, string> vars; vars["index"] = SimpleItoa(i); vars["method"] = UnderscoresToCamelCase(method); - vars["input"] = ClassName(method->input_type()); - vars["output"] = ClassName(method->output_type()); + vars["input"] = name_resolver_->GetImmutableClassName( + method->input_type()); + vars["output"] = name_resolver_->GetImmutableClassName( + method->output_type()); printer->Print(vars, "case $index$:\n" " return impl.$method$(controller, ($input$)request);\n"); @@ -259,7 +277,7 @@ void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) { "\n"); } -void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, +void ImmutableServiceGenerator::GenerateGetPrototype(RequestOrResponse which, io::Printer* printer) { /* * TODO(cpovirk): The exception message says "Service.foo" when it may be @@ -283,7 +301,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, const MethodDescriptor* method = descriptor_->method(i); map<string, string> vars; vars["index"] = SimpleItoa(i); - vars["type"] = ClassName( + vars["type"] = name_resolver_->GetImmutableClassName( (which == REQUEST) ? method->input_type() : method->output_type()); printer->Print(vars, "case $index$:\n" @@ -303,7 +321,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, "\n"); } -void ServiceGenerator::GenerateStub(io::Printer* printer) { +void ImmutableServiceGenerator::GenerateStub(io::Printer* printer) { printer->Print( "public static Stub newStub(\n" " com.google.protobuf.RpcChannel channel) {\n" @@ -312,7 +330,7 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) { "\n" "public static final class Stub extends $classname$ implements Interface {" "\n", - "classname", ClassName(descriptor_)); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Indent(); printer->Print( @@ -335,7 +353,8 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) { map<string, string> vars; vars["index"] = SimpleItoa(i); - vars["output"] = ClassName(method->output_type()); + vars["output"] = name_resolver_->GetImmutableClassName( + method->output_type()); printer->Print(vars, "channel.callMethod(\n" " getDescriptor().getMethods().get($index$),\n" @@ -357,7 +376,7 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) { "\n"); } -void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) { +void ImmutableServiceGenerator::GenerateBlockingStub(io::Printer* printer) { printer->Print( "public static BlockingInterface newBlockingStub(\n" " com.google.protobuf.BlockingRpcChannel channel) {\n" @@ -399,7 +418,8 @@ void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) { map<string, string> vars; vars["index"] = SimpleItoa(i); - vars["output"] = ClassName(method->output_type()); + vars["output"] = name_resolver_->GetImmutableClassName( + method->output_type()); printer->Print(vars, "return ($output$) channel.callBlockingMethod(\n" " getDescriptor().getMethods().get($index$),\n" @@ -417,13 +437,13 @@ void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) { printer->Print("}\n"); } -void ServiceGenerator::GenerateMethodSignature(io::Printer* printer, +void ImmutableServiceGenerator::GenerateMethodSignature(io::Printer* printer, const MethodDescriptor* method, IsAbstract is_abstract) { map<string, string> vars; vars["name"] = UnderscoresToCamelCase(method); - vars["input"] = ClassName(method->input_type()); - vars["output"] = ClassName(method->output_type()); + vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); + vars["output"] = name_resolver_->GetImmutableClassName(method->output_type()); vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : ""; printer->Print(vars, "public $abstract$ void $name$(\n" @@ -432,13 +452,13 @@ void ServiceGenerator::GenerateMethodSignature(io::Printer* printer, " com.google.protobuf.RpcCallback<$output$> done)"); } -void ServiceGenerator::GenerateBlockingMethodSignature( +void ImmutableServiceGenerator::GenerateBlockingMethodSignature( io::Printer* printer, const MethodDescriptor* method) { map<string, string> vars; vars["method"] = UnderscoresToCamelCase(method); - vars["input"] = ClassName(method->input_type()); - vars["output"] = ClassName(method->output_type()); + vars["input"] = name_resolver_->GetImmutableClassName(method->input_type()); + vars["output"] = name_resolver_->GetImmutableClassName(method->output_type()); printer->Print(vars, "\n" "public $output$ $method$(\n" diff --git a/src/google/protobuf/compiler/java/java_service.h b/src/google/protobuf/compiler/java/java_service.h index e07eebf7..0d52325e 100644 --- a/src/google/protobuf/compiler/java/java_service.h +++ b/src/google/protobuf/compiler/java/java_service.h @@ -40,8 +40,14 @@ namespace google { namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } namespace io { - class Printer; // printer.h + class Printer; // printer.h } } @@ -52,9 +58,27 @@ namespace java { class ServiceGenerator { public: explicit ServiceGenerator(const ServiceDescriptor* descriptor); - ~ServiceGenerator(); + virtual ~ServiceGenerator(); + + virtual void Generate(io::Printer* printer) = 0; + + enum RequestOrResponse { REQUEST, RESPONSE }; + enum IsAbstract { IS_ABSTRACT, IS_CONCRETE }; + + protected: + const ServiceDescriptor* descriptor_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); +}; - void Generate(io::Printer* printer); +class ImmutableServiceGenerator : public ServiceGenerator { + public: + explicit ImmutableServiceGenerator(const ServiceDescriptor* descriptor, + Context* context); + virtual ~ImmutableServiceGenerator(); + + virtual void Generate(io::Printer* printer); private: @@ -80,7 +104,6 @@ class ServiceGenerator { void GenerateCallBlockingMethod(io::Printer* printer); // Generate the implementations of Service.get{Request,Response}Prototype(). - enum RequestOrResponse { REQUEST, RESPONSE }; void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer); // Generate a stub implementation of the service. @@ -88,7 +111,6 @@ class ServiceGenerator { // Generate a method signature, possibly abstract, without body or trailing // semicolon. - enum IsAbstract { IS_ABSTRACT, IS_CONCRETE }; void GenerateMethodSignature(io::Printer* printer, const MethodDescriptor* method, IsAbstract is_abstract); @@ -100,9 +122,9 @@ class ServiceGenerator { void GenerateBlockingMethodSignature(io::Printer* printer, const MethodDescriptor* method); - const ServiceDescriptor* descriptor_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); + Context* context_; + ClassNameResolver* name_resolver_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableServiceGenerator); }; } // namespace java diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc new file mode 100644 index 00000000..c9f80abf --- /dev/null +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc @@ -0,0 +1,223 @@ +// 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: xiaofeng@google.com (Feng Xiao) + +#include <google/protobuf/compiler/java/java_shared_code_generator.h> + +#include <memory> + +#include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file) + : name_resolver_(new ClassNameResolver), file_(file) { +} + +SharedCodeGenerator::~SharedCodeGenerator() { +} + +void SharedCodeGenerator::Generate(GeneratorContext* context, + vector<string>* file_list) { + string java_package = FileJavaPackage(file_); + string package_dir = JavaPackageToDir(java_package); + + if (HasDescriptorMethods(file_)) { + // Generate descriptors. + string classname = name_resolver_->GetDescriptorClassName(file_); + string filename = package_dir + classname + ".java"; + file_list->push_back(filename); + scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + scoped_ptr<io::Printer> printer(new io::Printer(output.get(), '$')); + + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n", + "filename", file_->name()); + if (!java_package.empty()) { + printer->Print( + "package $package$;\n" + "\n", + "package", java_package); + } + printer->Print( + "public final class $classname$ {\n", + "classname", classname); + printer->Indent(); + GenerateDescriptors(printer.get()); + printer->Outdent(); + printer->Print( + "}\n"); + + printer.reset(); + output.reset(); + } +} + + +void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) { + // Embed the descriptor. We simply serialize the entire FileDescriptorProto + // and embed it as a string literal, which is parsed and built into real + // descriptors at initialization time. We unfortunately have to put it in + // a string literal, not a byte array, because apparently using a literal + // byte array causes the Java compiler to generate *instructions* to + // initialize each and every byte of the array, e.g. as if you typed: + // b[0] = 123; b[1] = 456; b[2] = 789; + // This makes huge bytecode files and can easily hit the compiler's internal + // code size limits (error "code to large"). String literals are apparently + // embedded raw, which is what we want. + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + + + string file_data; + file_proto.SerializeToString(&file_data); + + printer->Print( + "public static com.google.protobuf.Descriptors.FileDescriptor\n" + " descriptor;\n" + "static {\n" + " java.lang.String[] descriptorData = {\n"); + printer->Indent(); + printer->Indent(); + + // Only write 40 bytes per line. + static const int kBytesPerLine = 40; + for (int i = 0; i < file_data.size(); i += kBytesPerLine) { + if (i > 0) { + // Every 400 lines, start a new string literal, in order to avoid the + // 64k length limit. + if (i % 400 == 0) { + printer->Print(",\n"); + } else { + printer->Print(" +\n"); + } + } + printer->Print("\"$data$\"", + "data", CEscape(file_data.substr(i, kBytesPerLine))); + } + + printer->Outdent(); + printer->Print("\n};\n"); + + // ----------------------------------------------------------------- + // Create the InternalDescriptorAssigner. + + printer->Print( + "com.google.protobuf.Descriptors.FileDescriptor." + "InternalDescriptorAssigner assigner =\n" + " new com.google.protobuf.Descriptors.FileDescriptor." + " InternalDescriptorAssigner() {\n" + " public com.google.protobuf.ExtensionRegistry assignDescriptors(\n" + " com.google.protobuf.Descriptors.FileDescriptor root) {\n" + " descriptor = root;\n" + // Custom options will be handled when immutable messages' outer class is + // loaded. Here we just return null and let custom options be unknown + // fields. + " return null;\n" + " }\n" + " };\n"); + + // ----------------------------------------------------------------- + // Find out all dependencies. + vector<pair<string, string> > dependencies; + for (int i = 0; i < file_->dependency_count(); i++) { + if (ShouldIncludeDependency(file_->dependency(i))) { + string filename = file_->dependency(i)->name(); + string classname = FileJavaPackage(file_->dependency(i)) + "." + + name_resolver_->GetDescriptorClassName( + file_->dependency(i)); + dependencies.push_back(make_pair(filename, classname)); + } + } + + // ----------------------------------------------------------------- + // Invoke internalBuildGeneratedFileFrom() to build the file. + printer->Print( + "com.google.protobuf.Descriptors.FileDescriptor\n" + " .internalBuildGeneratedFileFrom(descriptorData,\n"); + + printer->Print( + " $classname$.class,\n" + " new java.lang.String[] {\n", + "classname", name_resolver_->GetDescriptorClassName(file_)); + for (int i = 0; i < dependencies.size(); i++) { + const string& dependency = dependencies[i].second; + printer->Print( + // Here we load the dependency FileDescriptors lazily via Java + // reflection. This is to avoid breaking proto1 targets who have + // genproto dependencies for which we can't generate the descriptor + // class. They will compile fine but when users try to call reflection + // functions upon them it will fail. Users will have to get rid of + // genproto dependencies before they can use proto2 reflection on + // proto1 messages. + " \"$dependency$\",\n", + "dependency", dependency); + } + + printer->Print( + " }, new java.lang.String[] {\n"); + + for (int i = 0; i < dependencies.size(); i++) { + const string& filename = dependencies[i].first; + printer->Print( + " \"$filename$\",\n", + "filename", filename); + } + + printer->Print( + " }, assigner);\n"); + + printer->Outdent(); + printer->Print( + "}\n"); +} + +bool SharedCodeGenerator::ShouldIncludeDependency( + const FileDescriptor* descriptor) { + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h new file mode 100644 index 00000000..c5457bf1 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h @@ -0,0 +1,91 @@ +// 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: xiaofeng@google.com (Feng Xiao) +// +// Generators that generate shared code between immutable API and mutable API. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__ + +#include <memory> +#include <string> +#include <vector> + +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { + class FileDescriptor; // descriptor.h + namespace compiler { + class GeneratorContext; // code_generator.h + namespace java { + class ClassNameResolver; // name_resolver.h + } + } + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +// A generator that generates code that are shared between immutable API +// and mutable API. Currently only descriptors are shared. +class SharedCodeGenerator { + public: + explicit SharedCodeGenerator(const FileDescriptor* file); + ~SharedCodeGenerator(); + + void Generate(GeneratorContext* generator_context, + vector<string>* file_list); + + private: + void GenerateDescriptors(io::Printer* printer); + + // Returns whether the dependency should be included in the output file. + // Always returns true for opensource, but used internally at Google to help + // improve compatibility with version 1 of protocol buffers. + bool ShouldIncludeDependency(const FileDescriptor* descriptor); + + scoped_ptr<ClassNameResolver> name_resolver_; + const FileDescriptor* file_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator); +}; + + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__ diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 4815663b..374e1d4e 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -36,10 +36,12 @@ #include <map> #include <string> -#include <google/protobuf/compiler/java/java_string_field.h> -#include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/java/java_context.h> +#include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> +#include <google/protobuf/compiler/java/java_string_field.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> @@ -57,17 +59,16 @@ namespace { void SetPrimitiveVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, map<string, string>* variables) { - (*variables)["name"] = - UnderscoresToCamelCase(descriptor); - (*variables)["capitalized_name"] = - UnderscoresToCapitalizedCamelCase(descriptor); - (*variables)["constant_name"] = FieldConstantName(descriptor); - (*variables)["number"] = SimpleItoa(descriptor->number()); + SetCommonFieldVariables(descriptor, info, variables); + (*variables)["empty_list"] = "com.google.protobuf.LazyStringArrayList.EMPTY"; - (*variables)["default"] = DefaultValue(descriptor); - (*variables)["default_init"] = ("= " + DefaultValue(descriptor)); + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_init"] = + "= " + ImmutableDefaultValue(descriptor, name_resolver); (*variables)["capitalized_type"] = "String"; (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( @@ -84,16 +85,30 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["on_changed"] = HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; - // For singular messages and builders, one bit is used for the hasField bit. - (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); - (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex); + if (SupportFieldPresence(descriptor->file())) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["set_has_field_bit_builder"] = + GenerateSetBit(builderBitIndex) + ";"; + (*variables)["clear_has_field_bit_builder"] = + GenerateClearBit(builderBitIndex) + ";"; - (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); - (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); - (*variables)["clear_has_field_bit_builder"] = - GenerateClearBit(builderBitIndex); + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_builder"] = ""; + (*variables)["clear_has_field_bit_builder"] = ""; - // For repated builders, one bit is used for whether the array is immutable. + (*variables)["is_field_present_message"] = + "!get" + (*variables)["capitalized_name"] + "Bytes().isEmpty()"; + } + + // For repeated builders, one bit is used for whether the array is immutable. (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); @@ -111,27 +126,34 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, GenerateSetBitToLocal(messageBitIndex); } +bool CheckUtf8(const FieldDescriptor* descriptor) { + return descriptor->file()->options().java_string_check_utf8(); +} + } // namespace // =================================================================== -StringFieldGenerator:: -StringFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, - int builderBitIndex) +ImmutableStringFieldGenerator:: +ImmutableStringFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) : descriptor_(descriptor), messageBitIndex_(messageBitIndex), - builderBitIndex_(builderBitIndex) { + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, - &variables_); + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); } -StringFieldGenerator::~StringFieldGenerator() {} +ImmutableStringFieldGenerator::~ImmutableStringFieldGenerator() {} -int StringFieldGenerator::GetNumBitsForMessage() const { +int ImmutableStringFieldGenerator::GetNumBitsForMessage() const { return 1; } -int StringFieldGenerator::GetNumBitsForBuilder() const { +int ImmutableStringFieldGenerator::GetNumBitsForBuilder() const { return 1; } @@ -167,11 +189,13 @@ int StringFieldGenerator::GetNumBitsForBuilder() const { // For single fields, the logic for this is done inside the generated code. For // repeated fields, the logic is done in LazyStringArrayList and // UnmodifiableLazyStringList. -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$boolean has$capitalized_name$();\n"); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$java.lang.String get$capitalized_name$();\n"); @@ -181,15 +205,19 @@ GenerateInterfaceMembers(io::Printer* printer) const { " get$capitalized_name$Bytes();\n"); } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private java.lang.Object $name$_;\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public boolean has$capitalized_name$() {\n" - " return $get_has_field_bit_message$;\n" - "}\n"); + PrintExtraFieldInfo(variables_, printer); + + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -200,10 +228,17 @@ GenerateMembers(io::Printer* printer) const { " } else {\n" " com.google.protobuf.ByteString bs = \n" " (com.google.protobuf.ByteString) ref;\n" - " java.lang.String s = bs.toStringUtf8();\n" - " if (bs.isValidUtf8()) {\n" - " $name$_ = s;\n" - " }\n" + " java.lang.String s = bs.toStringUtf8();\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " $name$_ = s;\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8()) {\n" + " $name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, " return s;\n" " }\n" "}\n"); @@ -224,24 +259,36 @@ GenerateMembers(io::Printer* printer) const { "}\n"); } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "private java.lang.Object $name$_ $default_init$;\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public boolean has$capitalized_name$() {\n" - " return $get_has_field_bit_builder$;\n" - "}\n"); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_builder$;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$() {\n" " java.lang.Object ref = $name$_;\n" " if (!(ref instanceof java.lang.String)) {\n" - " java.lang.String s = ((com.google.protobuf.ByteString) ref)\n" - " .toStringUtf8();\n" - " $name$_ = s;\n" + " com.google.protobuf.ByteString bs =\n" + " (com.google.protobuf.ByteString) ref;\n" + " java.lang.String s = bs.toStringUtf8();\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " $name$_ = s;\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8()) {\n" + " $name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, " return s;\n" " } else {\n" " return (java.lang.String) ref;\n" @@ -269,7 +316,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "$deprecation$public Builder set$capitalized_name$(\n" " java.lang.String value) {\n" "$null_check$" - " $set_has_field_bit_builder$;\n" + " $set_has_field_bit_builder$\n" " $name$_ = value;\n" " $on_changed$\n" " return this;\n" @@ -277,7 +324,7 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" - " $clear_has_field_bit_builder$;\n"); + " $clear_has_field_bit_builder$\n"); // The default value is not a simple literal so we want to avoid executing // it multiple times. Instead, get the default out of the default instance. printer->Print(variables_, @@ -291,89 +338,113 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public Builder set$capitalized_name$Bytes(\n" " com.google.protobuf.ByteString value) {\n" - "$null_check$" - " $set_has_field_bit_builder$;\n" + "$null_check$"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " $set_has_field_bit_builder$\n" " $name$_ = value;\n" " $on_changed$\n" " return this;\n" "}\n"); } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateFieldBuilderInitializationCode(io::Printer* printer) const { // noop for primitives } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = $default$;\n"); } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = $default$;\n" - "$clear_has_field_bit_builder$;\n"); + "$clear_has_field_bit_builder$\n"); } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - // Allow a slight breach of abstraction here in order to avoid forcing - // all string fields to Strings when copying fields from a Message. - printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " $set_has_field_bit_builder$;\n" - " $name$_ = other.$name$_;\n" - " $on_changed$\n" - "}\n"); + if (SupportFieldPresence(descriptor_->file())) { + // Allow a slight breach of abstraction here in order to avoid forcing + // all string fields to Strings when copying fields from a Message. + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " $set_has_field_bit_builder$\n" + " $name$_ = other.$name$_;\n" + " $on_changed$\n" + "}\n"); + } else { + printer->Print(variables_, + "if (!other.get$capitalized_name$().isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " $on_changed$\n" + "}\n"); + } } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateBuildingCode(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "if ($get_has_field_bit_from_local$) {\n" + " $set_has_field_bit_to_local$;\n" + "}\n"); + } printer->Print(variables_, - "if ($get_has_field_bit_from_local$) {\n" - " $set_has_field_bit_to_local$;\n" - "}\n" "result.$name$_ = $name$_;\n"); } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - printer->Print(variables_, - "$set_has_field_bit_message$;\n" - "$name$_ = input.readBytes();\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "String s = input.readStringRequireUtf8();\n" + "$set_has_field_bit_message$\n" + "$name$_ = s;\n"); + } else { + printer->Print(variables_, + "com.google.protobuf.ByteString bs = input.readBytes();\n" + "$set_has_field_bit_message$\n" + "$name$_ = bs;\n"); + } } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { // noop for strings. } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, - "if ($get_has_field_bit_message$) {\n" + "if ($is_field_present_message$) {\n" " output.writeBytes($number$, get$capitalized_name$Bytes());\n" "}\n"); } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, - "if ($get_has_field_bit_message$) {\n" + "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" "}\n"); } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "result = result && get$capitalized_name$()\n" " .equals(other.get$capitalized_name$());\n"); } -void StringFieldGenerator:: +void ImmutableStringFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "hash = (37 * hash) + $constant_name$;\n"); @@ -381,39 +452,270 @@ GenerateHashCode(io::Printer* printer) const { "hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); } -string StringFieldGenerator::GetBoxedType() const { +string ImmutableStringFieldGenerator::GetBoxedType() const { return "java.lang.String"; } +// =================================================================== + +ImmutableStringOneofFieldGenerator:: +ImmutableStringOneofFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableStringFieldGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableStringOneofFieldGenerator:: +~ImmutableStringOneofFieldGenerator() {} + +void ImmutableStringOneofFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.lang.String get$capitalized_name$() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (ref instanceof java.lang.String) {\n" + " return (java.lang.String) ref;\n" + " } else {\n" + " com.google.protobuf.ByteString bs = \n" + " (com.google.protobuf.ByteString) ref;\n" + " java.lang.String s = bs.toStringUtf8();\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " if ($has_oneof_case_message$) {\n" + " $oneof_name$_ = s;\n" + " }\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n" + " $oneof_name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, + " return s;\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (ref instanceof java.lang.String) {\n" + " com.google.protobuf.ByteString b = \n" + " com.google.protobuf.ByteString.copyFromUtf8(\n" + " (java.lang.String) ref);\n" + " if ($has_oneof_case_message$) {\n" + " $oneof_name$_ = b;\n" + " }\n" + " return b;\n" + " } else {\n" + " return (com.google.protobuf.ByteString) ref;\n" + " }\n" + "}\n"); +} + +void ImmutableStringOneofFieldGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.lang.String get$capitalized_name$() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (!(ref instanceof java.lang.String)) {\n" + " com.google.protobuf.ByteString bs =\n" + " (com.google.protobuf.ByteString) ref;\n" + " java.lang.String s = bs.toStringUtf8();\n" + " if ($has_oneof_case_message$) {\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " $oneof_name$_ = s;\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8()) {\n" + " $oneof_name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, + " }\n" + " return s;\n" + " } else {\n" + " return (java.lang.String) ref;\n" + " }\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (ref instanceof String) {\n" + " com.google.protobuf.ByteString b = \n" + " com.google.protobuf.ByteString.copyFromUtf8(\n" + " (java.lang.String) ref);\n" + " if ($has_oneof_case_message$) {\n" + " $oneof_name$_ = b;\n" + " }\n" + " return b;\n" + " } else {\n" + " return (com.google.protobuf.ByteString) ref;\n" + " }\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " java.lang.String value) {\n" + "$null_check$" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " $on_changed$\n" + " }\n" + " return this;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n" + "$null_check$"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); +} + +void ImmutableStringOneofFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + // Allow a slight breach of abstraction here in order to avoid forcing + // all string fields to Strings when copying fields from a Message. + printer->Print(variables_, + "$set_oneof_case_message$;\n" + "$oneof_name$_ = other.$oneof_name$_;\n" + "$on_changed$\n"); +} + +void ImmutableStringOneofFieldGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " result.$oneof_name$_ = $oneof_name$_;\n" + "}\n"); +} + +void ImmutableStringOneofFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "String s = input.readStringRequireUtf8();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = s;\n}\n"); + } else { + printer->Print(variables_, + "com.google.protobuf.ByteString bs = input.readBytes();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = bs;\n"); + } +} + +void ImmutableStringOneofFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + "}\n"); +} + +void ImmutableStringOneofFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + "}\n"); +} // =================================================================== -RepeatedStringFieldGenerator:: -RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, - int builderBitIndex) +RepeatedImmutableStringFieldGenerator:: +RepeatedImmutableStringFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) : descriptor_(descriptor), messageBitIndex_(messageBitIndex), - builderBitIndex_(builderBitIndex) { + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, - &variables_); + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); } -RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {} +RepeatedImmutableStringFieldGenerator:: +~RepeatedImmutableStringFieldGenerator() {} -int RepeatedStringFieldGenerator::GetNumBitsForMessage() const { +int RepeatedImmutableStringFieldGenerator::GetNumBitsForMessage() const { return 0; } -int RepeatedStringFieldGenerator::GetNumBitsForBuilder() const { +int RepeatedImmutableStringFieldGenerator::GetNumBitsForBuilder() const { return 1; } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$java.util.List<java.lang.String>\n" - "get$capitalized_name$List();\n"); + "$deprecation$com.google.protobuf.ProtocolStringList\n" + " get$capitalized_name$List();\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$int get$capitalized_name$Count();\n"); @@ -427,13 +729,14 @@ GenerateInterfaceMembers(io::Printer* printer) const { } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private com.google.protobuf.LazyStringList $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$public java.util.List<java.lang.String>\n" + "$deprecation$public com.google.protobuf.ProtocolStringList\n" " get$capitalized_name$List() {\n" " return $name$_;\n" // note: unmodifiable list "}\n"); @@ -461,7 +764,7 @@ GenerateMembers(io::Printer* printer) const { } } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { // One field is the list and the bit field keeps track of whether the // list is immutable. If it's immutable, the invariant is that it must @@ -489,9 +792,9 @@ GenerateBuilderMembers(io::Printer* printer) const { // immutable. WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$public java.util.List<java.lang.String>\n" + "$deprecation$public com.google.protobuf.ProtocolStringList\n" " get$capitalized_name$List() {\n" - " return java.util.Collections.unmodifiableList($name$_);\n" + " return $name$_.getUnmodifiableView();\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -534,7 +837,8 @@ GenerateBuilderMembers(io::Printer* printer) const { "$deprecation$public Builder addAll$capitalized_name$(\n" " java.lang.Iterable<java.lang.String> values) {\n" " ensure$capitalized_name$IsMutable();\n" - " super.addAll(values, $name$_);\n" + " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" + " values, $name$_);\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -551,7 +855,12 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public Builder add$capitalized_name$Bytes(\n" " com.google.protobuf.ByteString value) {\n" - "$null_check$" + "$null_check$"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, " ensure$capitalized_name$IsMutable();\n" " $name$_.add(value);\n" " $on_changed$\n" @@ -559,24 +868,24 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateFieldBuilderInitializationCode(io::Printer* printer) const { // noop for primitives } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = $empty_list$;\n"); } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = $empty_list$;\n" "$clear_mutable_bit_builder$;\n"); } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { // The code below does two optimizations: // 1. If the other list is empty, there's nothing to do. This ensures we @@ -596,31 +905,43 @@ GenerateMergingCode(io::Printer* printer) const { "}\n"); } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateBuildingCode(io::Printer* printer) const { // The code below ensures that the result has an immutable list. If our // list is immutable, we can just reuse it. If not, we make it immutable. printer->Print(variables_, "if ($get_mutable_bit_builder$) {\n" - " $name$_ = new com.google.protobuf.UnmodifiableLazyStringList(\n" - " $name$_);\n" + " $name$_ = $name$_.getUnmodifiableView();\n" " $clear_mutable_bit_builder$;\n" "}\n" "result.$name$_ = $name$_;\n"); } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "String s = input.readStringRequireUtf8();\n"); + } else { + printer->Print(variables_, + "com.google.protobuf.ByteString bs = input.readBytes();\n"); + } printer->Print(variables_, "if (!$get_mutable_bit_parser$) {\n" " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" " $set_mutable_bit_parser$;\n" - "}\n" - "$name$_.add(input.readBytes());\n"); + "}\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "$name$_.add(s);\n"); + } else { + printer->Print(variables_, + "$name$_.add(bs);\n"); + } } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateParsingCodeFromPacked(io::Printer* printer) const { printer->Print(variables_, "int length = input.readRawVarint32();\n" @@ -629,21 +950,30 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" " $set_mutable_bit_parser$;\n" "}\n" - "while (input.getBytesUntilLimit() > 0) {\n" - " $name$.add(input.read$capitalized_type$());\n" + "while (input.getBytesUntilLimit() > 0) {\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " String s = input.readStringRequireUtf8();\n"); + } else { + printer->Print(variables_, + " String s = input.readString();\n"); + } + printer->Print(variables_, + " $name$.add(s);\n"); + printer->Print(variables_, "}\n" "input.popLimit(limit);\n"); } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateParsingDoneCode(io::Printer* printer) const { printer->Print(variables_, "if ($get_mutable_bit_parser$) {\n" - " $name$_ = new com.google.protobuf.UnmodifiableLazyStringList($name$_);\n" + " $name$_ = $name$_.getUnmodifiableView();\n" "}\n"); } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { if (descriptor_->options().packed()) { printer->Print(variables_, @@ -662,7 +992,7 @@ GenerateSerializationCode(io::Printer* printer) const { } } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "{\n" @@ -700,14 +1030,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print("}\n"); } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "result = result && get$capitalized_name$List()\n" " .equals(other.get$capitalized_name$List());\n"); } -void RepeatedStringFieldGenerator:: +void RepeatedImmutableStringFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "if (get$capitalized_name$Count() > 0) {\n" @@ -716,7 +1046,7 @@ GenerateHashCode(io::Printer* printer) const { "}\n"); } -string RepeatedStringFieldGenerator::GetBoxedType() const { +string RepeatedImmutableStringFieldGenerator::GetBoxedType() const { return "String"; } diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h index 4f7532f4..348cbcbd 100644 --- a/src/google/protobuf/compiler/java/java_string_field.h +++ b/src/google/protobuf/compiler/java/java_string_field.h @@ -42,16 +42,26 @@ namespace google { namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } +} + +namespace protobuf { namespace compiler { namespace java { -class StringFieldGenerator : public FieldGenerator { +class ImmutableStringFieldGenerator : public ImmutableFieldGenerator { public: - explicit StringFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, int builderBitIndex); - ~StringFieldGenerator(); + explicit ImmutableStringFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableStringFieldGenerator(); - // implements FieldGenerator --------------------------------------- + // implements ImmutableFieldGenerator --------------------------------------- int GetNumBitsForMessage() const; int GetNumBitsForBuilder() const; void GenerateInterfaceMembers(io::Printer* printer) const; @@ -68,24 +78,49 @@ class StringFieldGenerator : public FieldGenerator { void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; void GenerateEqualsCode(io::Printer* printer) const; void GenerateHashCode(io::Printer* printer) const; + string GetBoxedType() const; - private: + protected: const FieldDescriptor* descriptor_; map<string, string> variables_; const int messageBitIndex_; const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldGenerator); }; -class RepeatedStringFieldGenerator : public FieldGenerator { +class ImmutableStringOneofFieldGenerator + : public ImmutableStringFieldGenerator { public: - explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, - int messageBitIndex, int builderBitIndex); - ~RepeatedStringFieldGenerator(); + ImmutableStringOneofFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableStringOneofFieldGenerator(); - // implements FieldGenerator --------------------------------------- + private: + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldGenerator); +}; + +class RepeatedImmutableStringFieldGenerator : public ImmutableFieldGenerator { + public: + explicit RepeatedImmutableStringFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableStringFieldGenerator(); + + // implements ImmutableFieldGenerator --------------------------------------- int GetNumBitsForMessage() const; int GetNumBitsForBuilder() const; void GenerateInterfaceMembers(io::Printer* printer) const; @@ -103,6 +138,7 @@ class RepeatedStringFieldGenerator : public FieldGenerator { void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; void GenerateEqualsCode(io::Printer* printer) const; void GenerateHashCode(io::Printer* printer) const; + string GetBoxedType() const; private: @@ -110,8 +146,10 @@ class RepeatedStringFieldGenerator : public FieldGenerator { map<string, string> variables_; const int messageBitIndex_; const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableStringFieldGenerator); }; } // namespace java |