diff options
Diffstat (limited to 'src/google/protobuf/compiler/java')
21 files changed, 1159 insertions, 387 deletions
diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h index 57914450..7f1ce1f9 100644 --- a/src/google/protobuf/compiler/java/java_context.h +++ b/src/google/protobuf/compiler/java/java_context.h @@ -33,6 +33,9 @@ #include <map> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <vector> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 668377a3..0353b607 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -111,6 +111,10 @@ void EnumGenerator::Generate(io::Printer* printer) { "$name$($index$, $number$),\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print("UNRECOGNIZED(-1, -1),\n"); + } + printer->Print( ";\n" "\n"); @@ -141,7 +145,17 @@ void EnumGenerator::Generate(io::Printer* printer) { printer->Print( "\n" - "public final int getNumber() { return value; }\n" + "public final int getNumber() {\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + " if (index == -1) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } + printer->Print( + " return value;\n" + "}\n" "\n" "public static $classname$ valueOf(int value) {\n" " switch (value) {\n", @@ -231,11 +245,12 @@ void EnumGenerator::Generate(io::Printer* printer) { "index", SimpleItoa(descriptor_->index())); } printer->Print( - "return $immutable_package$.$descriptor_class$.getDescriptor()\n" + "return $immutable_package$.$descriptor_class$.$descriptor$\n" " .getEnumTypes().get($index$);\n", "immutable_package", FileJavaPackage(descriptor_->file(), true), "descriptor_class", name_resolver_->GetDescriptorClassName(descriptor_->file()), + "descriptor", "getDescriptor()", "index", SimpleItoa(descriptor_->index())); printer->Outdent(); } @@ -283,11 +298,18 @@ void EnumGenerator::Generate(io::Printer* printer) { " if (desc.getType() != getDescriptor()) {\n" " throw new java.lang.IllegalArgumentException(\n" " \"EnumValueDescriptor is not for this type.\");\n" - " }\n" + " }\n", + "classname", descriptor_->name()); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + " if (desc.getIndex() == -1) {\n" + " return UNRECOGNIZED;\n" + " }\n"); + } + printer->Print( " return VALUES[desc.getIndex()];\n" "}\n" - "\n", - "classname", descriptor_->name()); + "\n"); // index is only used for reflection; lite implementation does not need it printer->Print("private final int index;\n"); diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 1f0c4af0..71a2ba4b 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -65,6 +65,8 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["mutable_type"] = name_resolver->GetMutableClassName(descriptor->enum_type()); (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_number"] = SimpleItoa( + descriptor->default_value_enum()->number()); (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); @@ -95,7 +97,8 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["clear_has_field_bit_builder"] = ""; (*variables)["is_field_present_message"] = - (*variables)["name"] + "_ != " + (*variables)["default"]; + (*variables)["name"] + "_ != " + + (*variables)["default"] + ".getNumber()"; } // For repated builders, one bit is used for whether the array is immutable. @@ -114,6 +117,12 @@ void SetEnumVariables(const FieldDescriptor* descriptor, GenerateGetBitFromLocal(builderBitIndex); (*variables)["set_has_field_bit_to_local"] = GenerateSetBitToLocal(messageBitIndex); + + if (SupportUnknownEnumValue(descriptor->file())) { + (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED"; + } else { + (*variables)["unknown"] = (*variables)["default"]; + } } } // namespace @@ -150,6 +159,11 @@ GenerateInterfaceMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$boolean has$capitalized_name$();\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value();\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); @@ -158,7 +172,7 @@ GenerateInterfaceMembers(io::Printer* printer) const { void ImmutableEnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private $type$ $name$_;\n"); + "private int $name$_;\n"); PrintExtraFieldInfo(variables_, printer); if (SupportFieldPresence(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); @@ -167,17 +181,25 @@ GenerateMembers(io::Printer* printer) const { " return $get_has_field_bit_message$;\n" "}\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " return $name$_;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " return $name$_;\n" + " $type$ result = $type$.valueOf($name$_);\n" + " return result == null ? $unknown$ : result;\n" "}\n"); } void ImmutableEnumFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, - "private $type$ $name$_ = $default$;\n"); + "private int $name$_ = $default_number$;\n"); if (SupportFieldPresence(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -185,10 +207,25 @@ GenerateBuilderMembers(io::Printer* printer) const { " return $get_has_field_bit_builder$;\n" "}\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " return $name$_;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Value(int value) {\n" + " $name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " return $name$_;\n" + " $type$ result = $type$.valueOf($name$_);\n" + " return result == null ? $unknown$ : result;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -197,7 +234,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " $set_has_field_bit_builder$\n" - " $name$_ = value;\n" + " $name$_ = value.getNumber();\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -205,7 +242,7 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" " $clear_has_field_bit_builder$\n" - " $name$_ = $default$;\n" + " $name$_ = $default_number$;\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -218,13 +255,13 @@ GenerateFieldBuilderInitializationCode(io::Printer* printer) const { void ImmutableEnumFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = $default$;\n"); + printer->Print(variables_, "$name$_ = $default_number$;\n"); } void ImmutableEnumFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { printer->Print(variables_, - "$name$_ = $default$;\n" + "$name$_ = $default_number$;\n" "$clear_has_field_bit_builder$\n"); } @@ -235,11 +272,13 @@ GenerateMergingCode(io::Printer* printer) const { "if (other.has$capitalized_name$()) {\n" " set$capitalized_name$(other.get$capitalized_name$());\n" "}\n"); - } else { + } else if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - "if (other.get$capitalized_name$() != $default$) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" + "if (other.$name$_ != $default_number$) {\n" + " set$capitalized_name$Value(other.get$capitalized_name$Value());\n" "}\n"); + } else { + GOOGLE_LOG(FATAL) << "Can't reach here."; } } @@ -257,23 +296,26 @@ GenerateBuildingCode(io::Printer* printer) const { void ImmutableEnumFieldGenerator:: 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())) { + if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - " unknownFields.mergeVarintField($number$, rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$set_has_field_bit_message$\n" + "$name$_ = rawValue;\n"); } else { printer->Print(variables_, - " unknownFieldsCodedOutput.writeRawVarint32(tag);\n" - " unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (PreserveUnknownFields(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " $set_has_field_bit_message$\n" + " $name$_ = rawValue;\n" + "}\n"); } - printer->Print(variables_, - "} else {\n" - " $set_has_field_bit_message$\n" - " $name$_ = value;\n" - "}\n"); } void ImmutableEnumFieldGenerator:: @@ -285,7 +327,7 @@ void ImmutableEnumFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.writeEnum($number$, $name$_.getNumber());\n" + " output.writeEnum($number$, $name$_);\n" "}\n"); } @@ -294,23 +336,21 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeEnumSize($number$, $name$_.getNumber());\n" + " .computeEnumSize($number$, $name$_);\n" "}\n"); } void ImmutableEnumFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, - "result = result &&\n" - " (get$capitalized_name$() == other.get$capitalized_name$());\n"); + "result = result && $name$_ == other.$name$_;\n"); } void ImmutableEnumFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "hash = (37 * hash) + $constant_name$;\n" - "hash = (53 * hash) + com.google.protobuf.Internal.hashEnum(\n" - " get$capitalized_name$());\n"); + "hash = (53 * hash) + $name$_;\n"); } string ImmutableEnumFieldGenerator::GetBoxedType() const { @@ -344,11 +384,22 @@ GenerateMembers(io::Printer* printer) const { " return $has_oneof_case_message$;\n" "}\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " if ($has_oneof_case_message$) {\n" + " return (java.lang.Integer) $oneof_name$_;\n" + " }\n" + " return $default_number$;\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" + " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" "}\n"); @@ -363,11 +414,30 @@ GenerateBuilderMembers(io::Printer* printer) const { " return $has_oneof_case_message$;\n" "}\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " if ($has_oneof_case_message$) {\n" + " return ((java.lang.Integer) $oneof_name$_).intValue();\n" + " }\n" + " return $default_number$;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Value(int value) {\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 $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " return ($type$) $oneof_name$_;\n" + " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" "}\n"); @@ -378,7 +448,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " $set_oneof_case_message$;\n" - " $oneof_name$_ = value;\n" + " $oneof_name$_ = value.getNumber();\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -404,36 +474,44 @@ GenerateBuildingCode(io::Printer* printer) const { void ImmutableEnumOneofFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, - "set$capitalized_name$(other.get$capitalized_name$());\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "set$capitalized_name$Value(other.get$capitalized_name$Value());\n"); + } else { + 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())) { + if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - " unknownFields.mergeVarintField($number$, rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = rawValue;\n"); } else { printer->Print(variables_, - " unknownFieldsCodedOutput.writeRawVarint32(tag);\n" - " unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (PreserveUnknownFields(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = rawValue;\n" + "}\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" + " output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n" "}\n"); } @@ -442,10 +520,36 @@ 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" + " .computeEnumSize($number$, ((java.lang.Integer) $oneof_name$_));\n" "}\n"); } +void ImmutableEnumOneofFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "result = result && get$capitalized_name$Value()\n" + " == other.get$capitalized_name$Value();\n"); + } else { + printer->Print(variables_, + "result = result && get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$());\n"); + } +} + +void ImmutableEnumOneofFieldGenerator:: +GenerateHashCode(io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$Value();\n"); + } else { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$().getNumber();\n"); + } +} + // =================================================================== RepeatedImmutableEnumFieldGenerator:: @@ -482,17 +586,36 @@ GenerateInterfaceMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$(int index);\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<java.lang.Integer>\n" + "get$capitalized_name$ValueList();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value(int index);\n"); + } } void RepeatedImmutableEnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.util.List<$type$> $name$_;\n"); + "private java.util.List<java.lang.Integer> $name$_;\n" + "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$> $name$_converter_ =\n" + " new com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$>() {\n" + " public $type$ convert(java.lang.Integer from) {\n" + " $type$ result = $type$.valueOf(from);\n" + " return result == null ? $unknown$ : result;\n" + " }\n" + " };\n"); PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" - " return $name$_;\n" // note: unmodifiable list + " return new com.google.protobuf.Internal.ListAdapter<\n" + " java.lang.Integer, $type$>($name$_, $name$_converter_);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -502,8 +625,21 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" - " return $name$_.get(index);\n" + " return $name$_converter_.convert($name$_.get(index));\n" "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<java.lang.Integer>\n" + "get$capitalized_name$ValueList() {\n" + " return $name$_;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + } if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->containing_type())) { @@ -524,12 +660,12 @@ GenerateBuilderMembers(io::Printer* printer) const { // memory allocations. Note, immutable is a strong guarantee here -- not // just that the list cannot be modified via the reference but that the // list can never be modified. - "private java.util.List<$type$> $name$_ =\n" + "private java.util.List<java.lang.Integer> $name$_ =\n" " java.util.Collections.emptyList();\n" "private void ensure$capitalized_name$IsMutable() {\n" " if (!$get_mutable_bit_builder$) {\n" - " $name$_ = new java.util.ArrayList<$type$>($name$_);\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>($name$_);\n" " $set_mutable_bit_builder$;\n" " }\n" "}\n"); @@ -541,7 +677,8 @@ GenerateBuilderMembers(io::Printer* printer) const { // has been built, thus mutating the message which is supposed to be // immutable. "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" - " return java.util.Collections.unmodifiableList($name$_);\n" + " return new com.google.protobuf.Internal.ListAdapter<\n" + " java.lang.Integer, $type$>($name$_, $name$_converter_);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -551,7 +688,7 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" - " return $name$_.get(index);\n" + " return $name$_converter_.convert($name$_.get(index));\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -561,7 +698,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " ensure$capitalized_name$IsMutable();\n" - " $name$_.set(index, value);\n" + " $name$_.set(index, value.getNumber());\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -572,7 +709,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " ensure$capitalized_name$IsMutable();\n" - " $name$_.add(value);\n" + " $name$_.add(value.getNumber());\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -581,8 +718,9 @@ GenerateBuilderMembers(io::Printer* printer) const { "$deprecation$public Builder addAll$capitalized_name$(\n" " java.lang.Iterable<? extends $type$> values) {\n" " ensure$capitalized_name$IsMutable();\n" - " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" - " values, $name$_);\n" + " for ($type$ value : values) {\n" + " $name$_.add(value.getNumber());\n" + " }\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -594,6 +732,48 @@ GenerateBuilderMembers(io::Printer* printer) const { " $on_changed$\n" " return this;\n" "}\n"); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<java.lang.Integer>\n" + "get$capitalized_name$ValueList() {\n" + " return java.util.Collections.unmodifiableList($name$_);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Value(\n" + " int index, int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$Value(int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder addAll$capitalized_name$Value(\n" + " java.lang.Iterable<java.lang.Integer> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " for (int value : values) {\n" + " $name$_.add(value);\n" + " }\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + } } void RepeatedImmutableEnumFieldGenerator:: @@ -648,26 +828,32 @@ GenerateBuildingCode(io::Printer* printer) const { 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 (value == null) {\n"); - if (UseUnknownFieldSet(descriptor_->containing_type())) { + if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - " unknownFields.mergeVarintField($number$, rawValue);\n"); + "int rawValue = input.readEnum();\n" + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n" + " $set_mutable_bit_parser$;\n" + "}\n" + "$name$_.add(rawValue);\n"); } else { printer->Print(variables_, - " unknownFieldsCodedOutput.writeRawVarint32(tag);\n" - " unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (PreserveUnknownFields(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n" + " $set_mutable_bit_parser$;\n" + " }\n" + " $name$_.add(rawValue);\n" + "}\n"); } - printer->Print(variables_, - " } else {\n" - " if (!$get_mutable_bit_parser$) {\n" - " $name$_ = new java.util.ArrayList<$type$>();\n" - " $set_mutable_bit_parser$;\n" - " }\n" - " $name$_.add(value);\n" - "}\n"); } void RepeatedImmutableEnumFieldGenerator:: @@ -705,12 +891,12 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeEnumNoTag($name$_.get(i).getNumber());\n" + " output.writeEnumNoTag($name$_.get(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeEnum($number$, $name$_.get(i).getNumber());\n" + " output.writeEnum($number$, $name$_.get(i));\n" "}\n"); } } @@ -725,7 +911,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" - " .computeEnumSizeNoTag($name$_.get(i).getNumber());\n" + " .computeEnumSizeNoTag($name$_.get(i));\n" "}\n"); printer->Print( "size += dataSize;\n"); @@ -754,8 +940,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { void RepeatedImmutableEnumFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, - "result = result && get$capitalized_name$List()\n" - " .equals(other.get$capitalized_name$List());\n"); + "result = result && $name$_.equals(other.$name$_);\n"); } void RepeatedImmutableEnumFieldGenerator:: @@ -763,8 +948,7 @@ GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "if (get$capitalized_name$Count() > 0) {\n" " hash = (37 * hash) + $constant_name$;\n" - " hash = (53 * hash) + com.google.protobuf.Internal.hashEnumList(\n" - " get$capitalized_name$List());\n" + " hash = (53 * hash) + $name$_.hashCode();\n" "}\n"); } diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h index 6a9535aa..b8ff7343 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.h +++ b/src/google/protobuf/compiler/java/java_enum_field.h @@ -106,6 +106,8 @@ class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator { void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldGenerator); diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index d7b0f3fc..49635bb4 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -35,12 +35,16 @@ #include <google/protobuf/compiler/java/java_field.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #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_map_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> @@ -48,6 +52,7 @@ #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> + namespace google { namespace protobuf { namespace compiler { @@ -61,12 +66,17 @@ ImmutableFieldGenerator* MakeImmutableGenerator( if (field->is_repeated()) { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { - return new RepeatedImmutableLazyMessageFieldGenerator( + if (IsMapEntry(field->message_type())) { + return new ImmutableMapFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { - return new RepeatedImmutableMessageFieldGenerator( - field, messageBitIndex, builderBitIndex, context); + if (IsLazy(field)) { + return new RepeatedImmutableLazyMessageFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } else { + return new RepeatedImmutableMessageFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } } case JAVATYPE_ENUM: return new RepeatedImmutableEnumFieldGenerator( diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index db339d5b..5bc5634e 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -37,6 +37,9 @@ #include <map> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index 231b1445..1ac945cd 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -35,6 +35,9 @@ #include <google/protobuf/compiler/java/java_file.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum.h> @@ -180,29 +183,6 @@ 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; } @@ -323,6 +303,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( SharedCodeGenerator shared_code_generator(file_); shared_code_generator.GenerateDescriptors(printer); + for (int i = 0; i < file_->message_type_count(); i++) { message_generators_[i]->GenerateStaticVariableInitializers(printer); } diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h index c805b9a6..0b2230a0 100644 --- a/src/google/protobuf/compiler/java/java_file.h +++ b/src/google/protobuf/compiler/java/java_file.h @@ -36,6 +36,9 @@ #define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> #include <vector> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc index c3a47e3e..a743ce22 100644 --- a/src/google/protobuf/compiler/java/java_generator.cc +++ b/src/google/protobuf/compiler/java/java_generator.cc @@ -35,6 +35,9 @@ #include <google/protobuf/compiler/java/java_generator.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/java/java_file.h> #include <google/protobuf/compiler/java/java_generator_factory.h> @@ -99,10 +102,14 @@ bool JavaGenerator::Generate(const FileDescriptor* file, vector<string> all_files; + 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) { diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index 3efd7edb..23685385 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -306,6 +306,26 @@ JavaType GetJavaType(const FieldDescriptor* field) { return JAVATYPE_INT; } +const char* PrimitiveTypeName(JavaType type) { + switch (type) { + case JAVATYPE_INT : return "int"; + case JAVATYPE_LONG : return "long"; + case JAVATYPE_FLOAT : return "float"; + case JAVATYPE_DOUBLE : return "double"; + case JAVATYPE_BOOLEAN: return "boolean"; + case JAVATYPE_STRING : return "java.lang.String"; + case JAVATYPE_BYTES : return "com.google.protobuf.ByteString"; + case JAVATYPE_ENUM : return NULL; + case JAVATYPE_MESSAGE: return NULL; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + const char* BoxedPrimitiveTypeName(JavaType type) { switch (type) { case JAVATYPE_INT : return "java.lang.Integer"; diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 93f23a93..2707fa0a 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -149,6 +149,8 @@ enum JavaType { JavaType GetJavaType(const FieldDescriptor* field); +const char* PrimitiveTypeName(JavaType type); + // Get the fully-qualified class name for a boxed primitive type, e.g. // "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message // types. @@ -168,13 +170,6 @@ inline string ImmutableDefaultValue(const FieldDescriptor* field, } bool IsDefaultValueJavaDefault(const FieldDescriptor* field); -// 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; -} - // Does this message class have generated parsing, serialization, and other // standard methods for which reflection-based fallback implementations exist? inline bool HasGeneratedMethods(const Descriptor* descriptor) { @@ -308,12 +303,27 @@ 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; + return descriptor->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + +// Whether unknown enum values are kept (i.e., not stored in UnknownFieldSet +// but in the message and can be queried using additional getters that return +// ints. +inline bool SupportUnknownEnumValue(const FileDescriptor* descriptor) { + return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3; } // Check whether a mesasge has repeated fields. bool HasRepeatedFields(const Descriptor* descriptor); +inline bool IsMapEntry(const Descriptor* descriptor) { + return descriptor->options().map_entry(); +} + +inline bool PreserveUnknownFields(const Descriptor* descriptor) { + return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc new file mode 100644 index 00000000..2986f51f --- /dev/null +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -0,0 +1,455 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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_map_field.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> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("key"); +} + +const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("value"); +} + +string TypeName(const FieldDescriptor* field, + ClassNameResolver* name_resolver, + bool boxed) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { + return name_resolver->GetImmutableClassName(field->message_type()); + } else if (GetJavaType(field) == JAVATYPE_ENUM) { + return name_resolver->GetImmutableClassName(field->enum_type()); + } else { + return boxed ? BoxedPrimitiveTypeName(GetJavaType(field)) + : PrimitiveTypeName(GetJavaType(field)); + } +} + +string WireType(const FieldDescriptor* field) { + return "com.google.protobuf.WireFormat.FieldType." + + string(FieldTypeName(field->type())); +} + +void SetMessageVariables(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + map<string, string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->message_type()); + const FieldDescriptor* key = KeyField(descriptor); + const FieldDescriptor* value = ValueField(descriptor); + (*variables)["key_type"] = TypeName(key, name_resolver, false); + (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true); + (*variables)["key_wire_type"] = WireType(key); + (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver); + if (GetJavaType(value) == JAVATYPE_ENUM) { + // We store enums as Integers internally. + (*variables)["value_type"] = "int"; + (*variables)["boxed_value_type"] = "java.lang.Integer"; + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver) + ".getNumber()"; + + (*variables)["value_enum_type"] = TypeName(value, name_resolver, false); + + if (SupportUnknownEnumValue(descriptor->file())) { + // Map unknown values to a special UNRECOGNIZED value if supported. + (*variables)["unrecognized_value"] = + (*variables)["value_enum_type"] + ".UNRECOGNIZED"; + } else { + // Map unknown values to the default value if we don't have UNRECOGNIZED. + (*variables)["unrecognized_value"] = + DefaultValue(value, true, name_resolver); + } + } else { + (*variables)["value_type"] = TypeName(value, name_resolver, false); + (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true); + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver); + } + (*variables)["type_parameters"] = + (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"]; + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = descriptor->options().deprecated() + ? "@java.lang.Deprecated " : ""; + (*variables)["on_changed"] = + HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + + // For repeated fields, one bit is used for whether the array is immutable + // in the parsing constructor. + (*variables)["get_mutable_bit_parser"] = + GenerateGetBitMutableLocal(builderBitIndex); + (*variables)["set_mutable_bit_parser"] = + GenerateSetBitMutableLocal(builderBitIndex); + + if (HasDescriptorMethods(descriptor->file())) { + (*variables)["lite"] = ""; + (*variables)["map_field_parameter"] = (*variables)["name"] + "DefaultEntry"; + (*variables)["descriptor"] = + name_resolver->GetImmutableClassName(descriptor->file()) + + ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) + + "_descriptor, "; + } else { + (*variables)["lite"] = "Lite"; + (*variables)["map_field_parameter"] = ""; + (*variables)["descriptor"] = ""; + } +} + +} // namespace + +ImmutableMapFieldGenerator:: +ImmutableMapFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableMapFieldGenerator:: +~ImmutableMapFieldGenerator() {} + +int ImmutableMapFieldGenerator::GetNumBitsForMessage() const { + return 0; +} + +int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const { + return 1; +} + +void ImmutableMapFieldGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "get$capitalized_name$();\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "get$capitalized_name$Value();\n"); + } + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "get$capitalized_name$();\n"); + } +} + +void ImmutableMapFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print( + variables_, + "private static final com.google.protobuf.MapEntry$lite$<\n" + " $type_parameters$> $name$DefaultEntry =\n" + " com.google.protobuf.MapEntry$lite$\n" + " .<$type_parameters$>newDefaultInstance(\n" + " $descriptor$\n" + " $key_wire_type$,\n" + " $key_default_value$,\n" + " $value_wire_type$,\n" + " $value_default_value$);\n"); + printer->Print( + variables_, + "private com.google.protobuf.MapField$lite$<\n" + " $type_parameters$> $name$_ =\n" + " com.google.protobuf.MapField$lite$.emptyMapField(\n" + " $map_field_parameter$);\n" + "\n"); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "private static final\n" + "com.google.protobuf.Internal.MapAdapter.Converter<\n" + " java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n" + " com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n" + " $value_enum_type$.internalGetValueMap(),\n" + " $unrecognized_value$);\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "get$capitalized_name$Value() {\n" + " return $name$_.getMap();\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "get$capitalized_name$() {\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " $name$_.getMap(), $name$ValueConverter);\n" + "}\n"); + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n" + " return $name$_.getMap();\n" + "}\n"); + } +} + +void ImmutableMapFieldGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + printer->Print( + variables_, + "private com.google.protobuf.MapField$lite$<\n" + " $type_parameters$> $name$_ =\n" + " com.google.protobuf.MapField$lite$.newMapField(\n" + " $map_field_parameter$);\n" + "\n"); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "get$capitalized_name$() {\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " $name$_.getMap(), $name$ValueConverter);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "getMutable$capitalized_name$() {\n" + " $on_changed$\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " $name$_.getMutableMap(), $name$ValueConverter);\n" + "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "get$capitalized_name$Value() {\n" + " return $name$_.getMap();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "getMutable$capitalized_name$Value() {\n" + " $on_changed$\n" + " return $name$_.getMutableMap();\n" + "}\n"); + } + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n" + " return $name$_.getMap();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "public java.util.Map<$type_parameters$>\n" + "getMutable$capitalized_name$() {\n" + " $on_changed$\n" + " return $name$_.getMutableMap();\n" + "}\n"); + } +} + +void ImmutableMapFieldGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // Nothing to initialize. +} + +void ImmutableMapFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Nothing to initialize. +} + +void ImmutableMapFieldGenerator:: +GenerateBuilderClearCode(io::Printer* printer) const { + printer->Print( + variables_, + "$name$_.clear();\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print( + variables_, + "$name$_.mergeFrom(other.$name$_);\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + printer->Print( + variables_, + // We do a copy of the map field to ensure that the built result is + // immutable. Implementation of this copy() method can do copy-on-write + // to defer this copy until further modifications are made on the field. + "result.$name$_ = $name$_.copy();\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print( + variables_, + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n" + " $map_field_parameter$);\n" + " $set_mutable_bit_parser$;\n" + "}\n"); + if (!SupportUnknownEnumValue(descriptor_->file()) && + GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "com.google.protobuf.ByteString bytes = input.readBytes();\n" + "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + "$name$ = $name$DefaultEntry.getParserForType().parseFrom(bytes);\n"); + printer->Print( + variables_, + "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n" + " unknownFields.mergeLengthDelimitedField($number$, bytes);\n" + "} else {\n" + " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n" + "}\n"); + } else { + printer->Print( + variables_, + "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + "$name$ = input.readMessage(\n" + " $name$DefaultEntry.getParserForType(), extensionRegistry);\n" + "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"); + } +} + +void ImmutableMapFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // Nothing to do here. +} + +void ImmutableMapFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print( + variables_, + "for (java.util.Map.Entry<$type_parameters$> entry\n" + " : $name$_.getMap().entrySet()) {\n" + " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + " $name$ = $name$DefaultEntry.newBuilderForType()\n" + " .setKey(entry.getKey())\n" + " .setValue(entry.getValue())\n" + " .build();\n" + " output.writeMessage($number$, $name$);\n" + "}\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print( + variables_, + "for (java.util.Map.Entry<$type_parameters$> entry\n" + " : $name$_.getMap().entrySet()) {\n" + " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + " $name$ = $name$DefaultEntry.newBuilderForType()\n" + " .setKey(entry.getKey())\n" + " .setValue(entry.getValue())\n" + " .build();\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeMessageSize($number$, $name$);\n" + "}\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print( + variables_, + "result = result && $name$_.equals(other.$name$_);\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print( + variables_, + "if (!$name$_.getMap().isEmpty()) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + $name$_.hashCode();\n" + "}\n"); +} + +string ImmutableMapFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h new file mode 100644 index 00000000..80a94f45 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_map_field.h @@ -0,0 +1,82 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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_MAP_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__ + +#include <google/protobuf/compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMapFieldGenerator : public ImmutableFieldGenerator { + public: + explicit ImmutableMapFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableMapFieldGenerator(); + + // implements ImmutableFieldGenerator --------------------------------------- + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + 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 GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__ diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 8aa89ac7..dd1ad6a6 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -38,6 +38,9 @@ #include <google/protobuf/stubs/hash.h> #include <map> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <vector> #include <google/protobuf/compiler/java/java_context.h> @@ -264,60 +267,36 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { descriptor_->containing_type() == NULL && MultipleJavaFiles(descriptor_->file(), /* immutable = */ true); + map<string, string> variables; + variables["static"] = is_own_file ? " " : " static "; + variables["classname"] = descriptor_->name(); + variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_); + variables["lite"] = HasDescriptorMethods(descriptor_) ? "" : "Lite"; + WriteMessageDocComment(printer, descriptor_); // The builder_type stores the super type name of the nested Builder class. string builder_type; if (descriptor_->extension_range_count() > 0) { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public$static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessage.ExtendableMessage<\n" - " $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, ?>", - name_resolver_->GetImmutableClassName(descriptor_)); - } else { - printer->Print( - "public$static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n" - " $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, ?>", - name_resolver_->GetImmutableClassName(descriptor_)); - } + printer->Print(variables, + "public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessage$lite$.ExtendableMessage<\n" + " $classname$> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + builder_type = strings::Substitute( + "com.google.protobuf.GeneratedMessage$1.ExtendableBuilder<$0, ?>", + name_resolver_->GetImmutableClassName(descriptor_), + variables["lite"]); } else { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "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 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"; - } + printer->Print(variables, + "public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessage$lite$ implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + builder_type = strings::Substitute( + "com.google.protobuf.GeneratedMessage$0.Builder", + variables["lite"]); } printer->Indent(); // Using builder_type, instead of Builder, prevents the Builder class from @@ -328,16 +307,22 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "// Use $classname$.newBuilder() to construct.\n" "private $classname$($buildertype$ builder) {\n" " super(builder);\n" - "$set_unknown_fields$\n" "}\n", "classname", descriptor_->name(), - "buildertype", builder_type, - "set_unknown_fields", - " this.unknownFields = builder.getUnknownFields();"); + "buildertype", builder_type); printer->Print( - // Used when constructing the default instance, which cannot be initialized - // immediately because it may cyclically refer to other default instances. - "private $classname$(boolean noInit) {$set_default_unknown_fields$}\n" + "private $classname$() {\n", + "classname", descriptor_->name()); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } + } + printer->Outdent(); + printer->Print( + "}\n" "\n" "private static final $classname$ defaultInstance;\n" "public static $classname$ getDefaultInstance() {\n" @@ -349,23 +334,22 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "}\n" "\n", "classname", descriptor_->name(), - "set_default_unknown_fields", UseUnknownFieldSet(descriptor_) - ? " this.unknownFields =" - " com.google.protobuf.UnknownFieldSet.getDefaultInstance(); " - : " this.unknownFields = com.google.protobuf.ByteString.EMPTY;"); + "lite", variables["lite"]); - if (UseUnknownFieldSet(descriptor_)) { + if (HasDescriptorMethods(descriptor_)) { printer->Print( - "private final com.google.protobuf.UnknownFieldSet unknownFields;\n" - "" - "@java.lang.Override\n" - "public final com.google.protobuf.UnknownFieldSet\n" - " getUnknownFields() {\n" - " return this.unknownFields;\n" - "}\n"); - } else { + "@java.lang.Override\n" + "public final com.google.protobuf.UnknownFieldSet\n" + "getUnknownFields() {\n"); + if (PreserveUnknownFields(descriptor_)) { + printer->Print( + " return this.unknownFields;\n"); + } else { + printer->Print( + " return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n"); + } printer->Print( - "private final com.google.protobuf.ByteString unknownFields;\n"); + "}\n"); } if (HasGeneratedMethods(descriptor_)) { @@ -382,6 +366,8 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { } for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // Don't generate Java classes for map entry messages. + if (IsMapEntry(descriptor_->nested_type(i))) continue; ImmutableMessageGenerator messageGenerator( descriptor_->nested_type(i), context_); messageGenerator.GenerateInterface(printer); @@ -480,20 +466,6 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print("\n"); } - // Called by the constructor, except in the case of the default instance, - // in which case this is called by static init code later on. - printer->Print("private void initFields() {\n"); - printer->Indent(); - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->containing_oneof()) { - field_generators_.get(descriptor_->field(i)) - .GenerateInitializationCode(printer); - } - } - - printer->Outdent(); - printer->Print("}\n"); - if (HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer, MEMOIZE); GenerateMessageSerializationMethods(printer); @@ -512,8 +484,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print( "\n" "static {\n" - " defaultInstance = new $classname$(true);\n" - " defaultInstance.initFields();\n" + " defaultInstance = new $classname$();\n" "}\n" "\n" "// @@protoc_insertion_point(class_scope:$full_name$)\n", @@ -593,17 +564,15 @@ GenerateMessageSerializationMethods(io::Printer* printer) { } } - if (UseUnknownFieldSet(descriptor_)) { - if (descriptor_->options().message_set_wire_format()) { + if (PreserveUnknownFields(descriptor_)) { + if (descriptor_->options().message_set_wire_format() + && HasDescriptorMethods(descriptor_)) { printer->Print( - "getUnknownFields().writeAsMessageSetTo(output);\n"); + "unknownFields.writeAsMessageSetTo(output);\n"); } else { printer->Print( - "getUnknownFields().writeTo(output);\n"); + "unknownFields.writeTo(output);\n"); } - } else { - printer->Print( - "output.writeRawBytes(unknownFields);\n"); } printer->Outdent(); @@ -632,17 +601,15 @@ GenerateMessageSerializationMethods(io::Printer* printer) { } } - if (UseUnknownFieldSet(descriptor_)) { - if (descriptor_->options().message_set_wire_format()) { + if (PreserveUnknownFields(descriptor_)) { + if (descriptor_->options().message_set_wire_format() + && HasDescriptorMethods(descriptor_)) { printer->Print( - "size += getUnknownFields().getSerializedSizeAsMessageSet();\n"); + "size += unknownFields.getSerializedSizeAsMessageSet();\n"); } else { printer->Print( - "size += getUnknownFields().getSerializedSize();\n"); + "size += unknownFields.getSerializedSize();\n"); } - } else { - printer->Print( - "size += unknownFields.size();\n"); } printer->Outdent(); @@ -653,13 +620,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { "\n"); printer->Print( - "private static final long serialVersionUID = 0L;\n" - "@java.lang.Override\n" - "protected java.lang.Object writeReplace()\n" - " throws java.io.ObjectStreamException {\n" - " return super.writeReplace();\n" - "}\n" - "\n"); + "private static final long serialVersionUID = 0L;\n"); } void ImmutableMessageGenerator:: @@ -740,7 +701,7 @@ void ImmutableMessageGenerator::GenerateSerializeOneExtensionRange( void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { printer->Print( - "public static Builder newBuilder() { return Builder.create(); }\n" + "public static Builder newBuilder() { return new Builder(); }\n" "public Builder newBuilderForType() { return newBuilder(); }\n" "public static Builder newBuilder($classname$ prototype) {\n" " return newBuilder().mergeFrom(prototype);\n" @@ -809,7 +770,6 @@ void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { if (HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer, DONT_MEMOIZE); - GenerateBuilderParsingMethods(printer); } // oneof @@ -864,6 +824,20 @@ void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { .GenerateBuilderMembers(printer); } + if (!PreserveUnknownFields(descriptor_)) { + printer->Print( + "public final Builder setUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return this;\n" + "}\n" + "\n" + "public final Builder mergeUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return this;\n" + "}\n" + "\n"); + } + printer->Print( "\n" "// @@protoc_insertion_point(builder_scope:$full_name$)\n", @@ -886,6 +860,41 @@ GenerateDescriptorMethods(io::Printer* printer) { "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), "identifier", UniqueFileScopeIdentifier(descriptor_)); } + vector<const FieldDescriptor*> map_fields; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + IsMapEntry(field->message_type())) { + map_fields.push_back(field); + } + } + if (!map_fields.empty()) { + printer->Print( + "@SuppressWarnings({\"rawtypes\"})\n" + "protected com.google.protobuf.MapField internalGetMapField(\n" + " int number) {\n" + " switch (number) {\n"); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < map_fields.size(); ++i) { + const FieldDescriptor* field = map_fields[i]; + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + printer->Print( + "case $number$:\n" + " return $name$_;\n", + "number", SimpleItoa(field->number()), + "name", info->name); + } + printer->Print( + "default:\n" + " throw new RuntimeException(\n" + " \"Invalid map field number: \" + number);\n"); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" + "}\n"); + } printer->Print( "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" " internalGetFieldAccessorTable() {\n" @@ -949,13 +958,8 @@ GenerateCommonBuilderMethods(io::Printer* printer) { } printer->Print( - "private static Builder create() {\n" - " return new Builder();\n" - "}\n" - "\n" "public Builder clear() {\n" - " super.clear();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + " super.clear();\n"); printer->Indent(); @@ -979,12 +983,8 @@ GenerateCommonBuilderMethods(io::Printer* printer) { printer->Print( " return this;\n" "}\n" - "\n" - "public Builder clone() {\n" - " return create().mergeFrom(buildPartial());\n" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + "\n"); + if (HasDescriptorMethods(descriptor_)) { printer->Print( "public com.google.protobuf.Descriptors.Descriptor\n" @@ -1153,13 +1153,13 @@ GenerateCommonBuilderMethods(io::Printer* printer) { " this.mergeExtensionFields(other);\n"); } - if (UseUnknownFieldSet(descriptor_)) { + if (PreserveUnknownFields(descriptor_)) { printer->Print( - " this.mergeUnknownFields(other.getUnknownFields());\n"); - } else { - printer->Print( - " setUnknownFields(\n" - " getUnknownFields().concat(other.unknownFields));\n"); + " this.mergeUnknownFields(other.unknownFields);\n"); + } + + if (HasDescriptorMethods(descriptor_)) { + printer->Print(" onChanged();\n"); } printer->Print( @@ -1171,31 +1171,6 @@ GenerateCommonBuilderMethods(io::Printer* printer) { // =================================================================== -void ImmutableMessageGenerator:: -GenerateBuilderParsingMethods(io::Printer* printer) { - printer->Print( - "public Builder mergeFrom(\n" - " com.google.protobuf.CodedInputStream input,\n" - " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" - " throws java.io.IOException {\n" - " $classname$ parsedMessage = null;\n" - " try {\n" - " parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n" - " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" - " parsedMessage = ($classname$) e.getUnfinishedMessage();\n" - " throw e;\n" - " } finally {\n" - " if (parsedMessage != null) {\n" - " mergeFrom(parsedMessage);\n" - " }\n" - " }\n" - " return this;\n" - "}\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); -} - -// =================================================================== - void ImmutableMessageGenerator::GenerateIsInitialized( io::Printer* printer, UseMemoization useMemoization) { bool memoization = useMemoization == MEMOIZE; @@ -1256,15 +1231,26 @@ void ImmutableMessageGenerator::GenerateIsInitialized( "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); break; case FieldDescriptor::LABEL_OPTIONAL: + if (!SupportFieldPresence(descriptor_->file()) && + field->containing_oneof() != NULL) { + const OneofDescriptor* oneof = field->containing_oneof(); + const OneofGeneratorInfo* oneof_info = + context_->GetOneofGeneratorInfo(oneof); + printer->Print( + "if ($oneof_name$Case_ == $field_number$) {\n", + "oneof_name", oneof_info->name, + "field_number", SimpleItoa(field->number())); + } else { + printer->Print( + "if (has$name$()) {\n", + "name", info->capitalized_name); + } printer->Print( - "if (has$name$()) {\n" " if (!get$name$().isInitialized()) {\n" " $memoize$\n" " return false;\n" " }\n" "}\n", - "type", name_resolver_->GetImmutableClassName( - field->message_type()), "name", info->capitalized_name, "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); break; @@ -1358,10 +1344,14 @@ GenerateEqualsAndHashCode(io::Printer* printer) { "}\n"); } } - if (HasDescriptorMethods(descriptor_)) { + if (PreserveUnknownFields(descriptor_)) { + // Always consider unknown fields for equality. This will sometimes return + // false for non-canonical ordering when running in LITE_RUNTIME but it's + // the best we can do. printer->Print( - "result = result &&\n" - " getUnknownFields().equals(other.getUnknownFields());\n"); + "result = result && unknownFields.equals(other.unknownFields);\n"); + } + if (HasDescriptorMethods(descriptor_)) { if (descriptor_->extension_range_count() > 0) { printer->Print( "result = result &&\n" @@ -1421,13 +1411,8 @@ GenerateEqualsAndHashCode(io::Printer* printer) { } } - 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) + unknownFields.hashCode();\n"); printer->Print( "memoizedHashCode = hash;\n" "return hash;\n"); @@ -1468,7 +1453,7 @@ GenerateParsingConstructor(io::Printer* printer) { // Initialize all fields to default. printer->Print( - "initFields();\n"); + "this();\n"); // Use builder bits to track mutable repeated fields. int totalBuilderBits = 0; @@ -1483,17 +1468,16 @@ GenerateParsingConstructor(io::Printer* printer) { "bit_field_name", GetBitFieldName(i)); } - 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"); + if (PreserveUnknownFields(descriptor_)) { + if (HasDescriptorMethods(descriptor_)) { + printer->Print( + "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n" + " com.google.protobuf.UnknownFieldSet.newBuilder();\n"); + } else { + printer->Print( + "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n" + " com.google.protobuf.UnknownFieldSetLite.newBuilder();\n"); + } } printer->Print( @@ -1513,16 +1497,41 @@ GenerateParsingConstructor(io::Printer* printer) { printer->Print( "case 0:\n" // zero signals EOF / limit reached " done = true;\n" - " break;\n" - "default: {\n" - " if (!parseUnknownField(input,$unknown_fields$\n" - " extensionRegistry, tag)) {\n" - " done = true;\n" // it's an endgroup tag - " }\n" - " break;\n" - "}\n", - "unknown_fields", UseUnknownFieldSet(descriptor_) - ? " unknownFields," : " unknownFieldsCodedOutput,"); + " break;\n"); + + if (PreserveUnknownFields(descriptor_)) { + if (!HasDescriptorMethods(descriptor_) + && descriptor_->extension_range_count() > 0) { + // Lite runtime directly invokes parseUnknownField to reduce method + // counts. + printer->Print( + "default: {\n" + " if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n" + " input, unknownFields,\n" + " extensionRegistry, tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } else { + printer->Print( + "default: {\n" + " if (!parseUnknownField(input, unknownFields,\n" + " extensionRegistry, tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } + } else { + printer->Print( + "default: {\n" + " if (!input.skipField(tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = sorted_fields[i]; @@ -1582,19 +1591,9 @@ GenerateParsingConstructor(io::Printer* printer) { field_generators_.get(field).GenerateParsingDoneCode(printer); } - // Make unknown fields immutable. - 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"); + if (PreserveUnknownFields(descriptor_)) { + // Make unknown fields immutable. + printer->Print("this.unknownFields = unknownFields.build();\n"); } // Make extensions immutable. @@ -1611,7 +1610,7 @@ GenerateParsingConstructor(io::Printer* printer) { // =================================================================== void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { printer->Print( - "public static com.google.protobuf.Parser<$classname$> PARSER =\n" + "public static final com.google.protobuf.Parser<$classname$> PARSER =\n" " new com.google.protobuf.AbstractParser<$classname$>() {\n", "classname", descriptor_->name()); printer->Indent(); diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index fece1c21..2703016e 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -118,7 +118,6 @@ class ImmutableMessageGenerator : public MessageGenerator { void GenerateBuilder(io::Printer* printer); void GenerateCommonBuilderMethods(io::Printer* printer); void GenerateDescriptorMethods(io::Printer* printer); - void GenerateBuilderParsingMethods(io::Printer* printer); void GenerateIsInitialized(io::Printer* printer, UseMemoization useMemoization); void GenerateEqualsAndHashCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index e681314e..538f1248 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -179,7 +179,7 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " return $name$_;\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" "}\n"); if (HasNestedBuilders(descriptor_->containing_type())) { @@ -187,7 +187,7 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$OrBuilder " "get$capitalized_name$OrBuilder() {\n" - " return $name$_;\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" "}\n"); } } else { @@ -257,14 +257,8 @@ GenerateBuilderMembers(io::Printer* printer) const { 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"); - } + printer->Print(variables_, + "private $type$ $name$_ = null;\n"); if (HasNestedBuilders(descriptor_->containing_type())) { printer->Print(variables_, @@ -296,13 +290,8 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public $type$ get$capitalized_name$()", - - support_field_presence - ? "return $name$_;\n" - : "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n", - + "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n", "return $name$Builder_.getMessage();\n", - NULL); // Field.Builder setField(Field value) @@ -342,6 +331,7 @@ GenerateBuilderMembers(io::Printer* printer) const { support_field_presence ? "if ($get_has_field_bit_builder$ &&\n" + " $name$_ != null &&\n" " $name$_ != $type$.getDefaultInstance()) {\n" " $name$_ =\n" " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" @@ -367,11 +357,8 @@ GenerateBuilderMembers(io::Printer* printer) const { PrintNestedBuilderFunction(printer, "$deprecation$public Builder clear$capitalized_name$()", - support_field_presence - ? "$name$_ = $type$.getDefaultInstance();\n" - "$on_changed$\n" - : "$name$_ = null;\n" - "$on_changed$\n", + "$name$_ = null;\n" + "$on_changed$\n", support_field_presence ? "$name$Builder_.clear();\n" @@ -394,16 +381,9 @@ 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"); - 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_, + " } else {\n" + " return $name$_ == null ?\n" + " $type$.getDefaultInstance() : $name$_;\n" " }\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -434,17 +414,13 @@ GenerateFieldBuilderInitializationCode(io::Printer* printer) const { void ImmutableMessageFieldGenerator:: -GenerateInitializationCode(io::Printer* printer) const { - if (SupportFieldPresence(descriptor_->file())) { - printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n"); - } -} +GenerateInitializationCode(io::Printer* printer) const {} void ImmutableMessageFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { PrintNestedBuilderCondition(printer, - "$name$_ = $type$.getDefaultInstance();\n", + "$name$_ = null;\n", "$name$Builder_.clear();\n"); printer->Print(variables_, "$clear_has_field_bit_builder$\n"); @@ -514,7 +490,7 @@ void ImmutableMessageFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.write$group_or_message$($number$, $name$_);\n" + " output.write$group_or_message$($number$, get$capitalized_name$());\n" "}\n"); } @@ -523,7 +499,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .compute$group_or_message$Size($number$, $name$_);\n" + " .compute$group_or_message$Size($number$, get$capitalized_name$());\n" "}\n"); } diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc index c4d6995d..45aa8ffe 100644 --- a/src/google/protobuf/compiler/java/java_plugin_unittest.cc +++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc @@ -35,6 +35,9 @@ // worth. #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/java/java_generator.h> #include <google/protobuf/compiler/command_line_interface.h> diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 6713d29a..e331d7a4 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -55,26 +55,6 @@ using internal::WireFormatLite; namespace { -const char* PrimitiveTypeName(JavaType type) { - switch (type) { - case JAVATYPE_INT : return "int"; - case JAVATYPE_LONG : return "long"; - case JAVATYPE_FLOAT : return "float"; - case JAVATYPE_DOUBLE : return "double"; - case JAVATYPE_BOOLEAN: return "boolean"; - case JAVATYPE_STRING : return "java.lang.String"; - case JAVATYPE_BYTES : return "com.google.protobuf.ByteString"; - case JAVATYPE_ENUM : return NULL; - case JAVATYPE_MESSAGE: return NULL; - - // No default because we want the compiler to complain if any new - // JavaTypes are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; -} - void SetPrimitiveVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc index ea77f792..f8723f2a 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc @@ -33,6 +33,9 @@ #include <google/protobuf/compiler/java/java_shared_code_generator.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/compiler/java/java_name_resolver.h> @@ -176,7 +179,8 @@ void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) { // Invoke internalBuildGeneratedFileFrom() to build the file. printer->Print( "com.google.protobuf.Descriptors.FileDescriptor\n" - " .internalBuildGeneratedFileFrom(descriptorData,\n" + " .internalBuildGeneratedFileFrom(descriptorData,\n"); + printer->Print( " new com.google.protobuf.Descriptors.FileDescriptor[] {\n"); for (int i = 0; i < dependencies.size(); i++) { diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h index 1bb2f3dc..fdbe2ce8 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.h +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h @@ -36,6 +36,9 @@ #define GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__ #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> #include <vector> @@ -68,6 +71,7 @@ class SharedCodeGenerator { void Generate(GeneratorContext* generator_context, vector<string>* file_list); + void GenerateDescriptors(io::Printer* printer); private: diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 8889a744..1c9302af 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -407,6 +407,15 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); + } else if (!HasDescriptorMethods(descriptor_->file())) { + // Lite runtime should attempt to reduce allocations by attempting to + // construct the string directly from the input stream buffer. This avoids + // spurious intermediary ByteString allocations, cutting overall allocations + // in half. + printer->Print(variables_, + "String s = input.readString();\n" + "$set_has_field_bit_message$\n" + "$name$_ = s;\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n" @@ -659,6 +668,15 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n}\n"); + } else if (!HasDescriptorMethods(descriptor_->file())) { + // Lite runtime should attempt to reduce allocations by attempting to + // construct the string directly from the input stream buffer. This avoids + // spurious intermediary ByteString allocations, cutting overall allocations + // in half. + printer->Print(variables_, + "String s = input.readString();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = s;\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n" @@ -923,6 +941,13 @@ GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, "String s = input.readStringRequireUtf8();\n"); + } else if (!HasDescriptorMethods(descriptor_->file())) { + // Lite runtime should attempt to reduce allocations by attempting to + // construct the string directly from the input stream buffer. This avoids + // spurious intermediary ByteString allocations, cutting overall allocations + // in half. + printer->Print(variables_, + "String s = input.readString();\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n"); @@ -932,7 +957,7 @@ GenerateParsingCode(io::Printer* printer) const { " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" " $set_mutable_bit_parser$;\n" "}\n"); - if (CheckUtf8(descriptor_)) { + if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { printer->Print(variables_, "$name$_.add(s);\n"); } else { |