diff options
author | 2012-09-22 02:40:50 +0000 | |
---|---|---|
committer | 2012-09-22 02:40:50 +0000 | |
commit | b55a20fa2c669b181f47ea9219b8e74d1263da19 (patch) | |
tree | 3936a0e7c22196587a6d8397372de41434fe2129 /src/google/protobuf/compiler/java | |
parent | 9ced30caf94bb4e7e9629c199679ff44e8ca7389 (diff) |
Down-integrate from internal branch
Diffstat (limited to 'src/google/protobuf/compiler/java')
21 files changed, 1296 insertions, 299 deletions
diff --git a/src/google/protobuf/compiler/java/java_doc_comment.cc b/src/google/protobuf/compiler/java/java_doc_comment.cc new file mode 100644 index 00000000..60b4f2ac --- /dev/null +++ b/src/google/protobuf/compiler/java/java_doc_comment.cc @@ -0,0 +1,236 @@ +// 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: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <google/protobuf/compiler/java/java_doc_comment.h> + +#include <vector> + +#include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +string EscapeJavadoc(const string& input) { + string result; + result.reserve(input.size() * 2); + + char prev = '*'; + + for (string::size_type i = 0; i < input.size(); i++) { + char c = input[i]; + switch (c) { + case '*': + // Avoid "/*". + if (prev == '/') { + result.append("*"); + } else { + result.push_back(c); + } + break; + case '/': + // Avoid "*/". + if (prev == '*') { + result.append("/"); + } else { + result.push_back(c); + } + break; + case '@': + // "{@" starts Javadoc markup. + if (prev == '{') { + result.append("@"); + } else { + result.push_back(c); + } + break; + case '<': + // Avoid interpretation as HTML. + result.append("<"); + break; + case '>': + // Avoid interpretation as HTML. + result.append(">"); + break; + case '&': + // Avoid interpretation as HTML. + result.append("&"); + break; + case '\\': + // Java interprets Unicode escape sequences anywhere! + result.append("\"); + break; + default: + result.push_back(c); + break; + } + + prev = c; + } + + return result; +} + +static void WriteDocCommentBodyForLocation( + io::Printer* printer, const SourceLocation& location) { + string comments = location.leading_comments.empty() ? + location.trailing_comments : location.leading_comments; + if (!comments.empty()) { + // TODO(kenton): Ideally we should parse the comment text as Markdown and + // write it back as HTML, but this requires a Markdown parser. For now + // we just use <pre> to get fixed-width text formatting. + + // If the comment itself contains block comment start or end markers, + // HTML-escape them so that they don't accidentally close the doc comment. + comments = EscapeJavadoc(comments); + + vector<string> lines; + SplitStringAllowEmpty(comments, "\n", &lines); + while (!lines.empty() && lines.back().empty()) { + lines.pop_back(); + } + + printer->Print( + " *\n" + " * <pre>\n"); + for (int i = 0; i < lines.size(); i++) { + // Most lines should start with a space. Watch out for lines that start + // with a /, since putting that right after the leading asterisk will + // close the comment. + if (!lines[i].empty() && lines[i][0] == '/') { + printer->Print(" * $line$\n", "line", lines[i]); + } else { + printer->Print(" *$line$\n", "line", lines[i]); + } + } + printer->Print(" * </pre>\n"); + } +} + +template <typename DescriptorType> +static void WriteDocCommentBody( + io::Printer* printer, const DescriptorType* descriptor) { + SourceLocation location; + if (descriptor->GetSourceLocation(&location)) { + WriteDocCommentBodyForLocation(printer, location); + } +} + +static string FirstLineOf(const string& value) { + string result = value; + + string::size_type pos = result.find_first_of('\n'); + if (pos != string::npos) { + result.erase(pos); + } + + // If line ends in an opening brace, make it "{ ... }" so it looks nice. + if (!result.empty() && result[result.size() - 1] == '{') { + result.append(" ... }"); + } + + return result; +} + +void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) { + printer->Print( + "/**\n" + " * Protobuf type {@code $fullname$}\n", + "fullname", EscapeJavadoc(message->full_name())); + WriteDocCommentBody(printer, message); + printer->Print(" */\n"); +} + +void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) { + // In theory we should have slightly different comments for setters, getters, + // etc., but in practice everyone already knows the difference between these + // so it's redundant information. + + // We use the field declaration as the first line of the comment, e.g.: + // optional string foo = 5; + // This communicates a lot of information about the field in a small space. + // If the field is a group, the debug string might end with {. + printer->Print( + "/**\n" + " * <code>$def$</code>\n", + "def", EscapeJavadoc(FirstLineOf(field->DebugString()))); + WriteDocCommentBody(printer, field); + printer->Print(" */\n"); +} + +void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) { + printer->Print( + "/**\n" + " * Protobuf enum {@code $fullname$}\n", + "fullname", EscapeJavadoc(enum_->full_name())); + WriteDocCommentBody(printer, enum_); + printer->Print(" */\n"); +} + +void WriteEnumValueDocComment(io::Printer* printer, + const EnumValueDescriptor* value) { + printer->Print( + "/**\n" + " * <code>$def$</code>\n", + "def", EscapeJavadoc(FirstLineOf(value->DebugString()))); + WriteDocCommentBody(printer, value); + printer->Print(" */\n"); +} + +void WriteServiceDocComment(io::Printer* printer, + const ServiceDescriptor* service) { + printer->Print( + "/**\n" + " * Protobuf service {@code $fullname$}\n", + "fullname", EscapeJavadoc(service->full_name())); + WriteDocCommentBody(printer, service); + printer->Print(" */\n"); +} + +void WriteMethodDocComment(io::Printer* printer, + const MethodDescriptor* method) { + printer->Print( + "/**\n" + " * <code>$def$</code>\n", + "def", EscapeJavadoc(FirstLineOf(method->DebugString()))); + WriteDocCommentBody(printer, method); + printer->Print(" */\n"); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_doc_comment.h b/src/google/protobuf/compiler/java/java_doc_comment.h new file mode 100644 index 00000000..f77720b6 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_doc_comment.h @@ -0,0 +1,69 @@ +// 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: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__ + +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +void WriteMessageDocComment(io::Printer* printer, const Descriptor* message); +void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field); +void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_); +void WriteEnumValueDocComment(io::Printer* printer, + const EnumValueDescriptor* value); +void WriteServiceDocComment(io::Printer* printer, + const ServiceDescriptor* service); +void WriteMethodDocComment(io::Printer* printer, + const MethodDescriptor* method); + +// Exposed for testing only. +string EscapeJavadoc(const string& input); + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__ diff --git a/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc b/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc new file mode 100644 index 00000000..28b6d8b4 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc @@ -0,0 +1,66 @@ +// 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: kenton@google.com (Kenton Varda) + +#include <google/protobuf/compiler/java/java_doc_comment.h> + +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +namespace { + +TEST(JavaDocCommentTest, Escaping) { + EXPECT_EQ("foo /* bar */ baz", EscapeJavadoc("foo /* bar */ baz")); + EXPECT_EQ("foo /*/ baz", EscapeJavadoc("foo /*/ baz")); + EXPECT_EQ("{@foo}", EscapeJavadoc("{@foo}")); + EXPECT_EQ("<i>&</i>", EscapeJavadoc("<i>&</i>")); + EXPECT_EQ("foo\u1234bar", EscapeJavadoc("foo\\u1234bar")); +} + +// TODO(kenton): It's hard to write a robust test of the doc comments -- we +// can only really compare the output against a golden value, which is a +// fairly tedious and fragile testing strategy. If we want to go that route, +// it probably makes sense to bite the bullet and write a test that compares +// the whole generated output for unittest.proto against a golden value, with +// a very simple script that can be run to regenerate it with the latest code. +// This would mean that updates to the golden file would have to be included +// in any change to the code generator, which would actually be fairly useful +// as it allows the reviewer to see clearly how the generated code is +// changing. + +} // namespace +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 9d7bcab6..cfed815f 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -36,6 +36,7 @@ #include <string> #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/io/printer.h> #include <google/protobuf/descriptor.pb.h> @@ -67,6 +68,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) EnumGenerator::~EnumGenerator() {} void EnumGenerator::Generate(io::Printer* printer) { + WriteEnumDocComment(printer, descriptor_); if (HasDescriptorMethods(descriptor_)) { printer->Print( "public enum $classname$\n" @@ -85,6 +87,7 @@ void EnumGenerator::Generate(io::Printer* printer) { vars["name"] = canonical_values_[i]->name(); vars["index"] = SimpleItoa(canonical_values_[i]->index()); vars["number"] = SimpleItoa(canonical_values_[i]->number()); + WriteEnumValueDocComment(printer, canonical_values_[i]); printer->Print(vars, "$name$($index$, $number$),\n"); } @@ -100,6 +103,7 @@ void EnumGenerator::Generate(io::Printer* printer) { vars["classname"] = descriptor_->name(); vars["name"] = aliases_[i].value->name(); vars["canonical_name"] = aliases_[i].canonical_value->name(); + WriteEnumValueDocComment(printer, aliases_[i].value); printer->Print(vars, "public static final $classname$ $name$ = $canonical_name$;\n"); } @@ -108,6 +112,7 @@ void EnumGenerator::Generate(io::Printer* printer) { map<string, string> vars; vars["name"] = descriptor_->value(i)->name(); vars["number"] = SimpleItoa(descriptor_->value(i)->number()); + WriteEnumValueDocComment(printer, descriptor_->value(i)); printer->Print(vars, "public static final int $name$_VALUE = $number$;\n"); } @@ -187,19 +192,30 @@ void EnumGenerator::Generate(io::Printer* printer) { printer->Print( "}\n" "\n" - "private static final $classname$[] VALUES = {\n" - " ", + "private static final $classname$[] VALUES = ", "classname", descriptor_->name()); - for (int i = 0; i < descriptor_->value_count(); i++) { - printer->Print("$name$, ", - "name", descriptor_->value(i)->name()); + if (CanUseEnumValues()) { + // If the constants we are going to output are exactly the ones we + // have declared in the Java enum in the same order, then we can use + // the values() method that the Java compiler automatically generates + // for every enum. + printer->Print("values();\n"); + } else { + printer->Print( + "{\n" + " "); + for (int i = 0; i < descriptor_->value_count(); i++) { + printer->Print("$name$, ", + "name", descriptor_->value(i)->name()); + } + printer->Print( + "\n" + "};\n"); } printer->Print( "\n" - "};\n" - "\n" "public static $classname$ valueOf(\n" " com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n" " if (desc.getType() != getDescriptor()) {\n" @@ -237,6 +253,18 @@ void EnumGenerator::Generate(io::Printer* printer) { printer->Print("}\n\n"); } +bool EnumGenerator::CanUseEnumValues() { + if (canonical_values_.size() != descriptor_->value_count()) { + return false; + } + for (int i = 0; i < descriptor_->value_count(); i++) { + if (descriptor_->value(i)->name() != canonical_values_[i]->name()) { + return false; + } + } + return true; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_enum.h b/src/google/protobuf/compiler/java/java_enum.h index 05ece1f1..9a9e5742 100644 --- a/src/google/protobuf/compiler/java/java_enum.h +++ b/src/google/protobuf/compiler/java/java_enum.h @@ -73,6 +73,8 @@ class EnumGenerator { }; vector<Alias> aliases_; + 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 72caa10b..ec0b067e 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -36,6 +36,7 @@ #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_helpers.h> #include <google/protobuf/io/printer.h> @@ -75,6 +76,7 @@ void SetEnumVariables(const FieldDescriptor* descriptor, // 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); (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); @@ -86,6 +88,13 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); + // 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); + (*variables)["get_has_field_bit_from_local"] = GenerateGetBitFromLocal(builderBitIndex); (*variables)["set_has_field_bit_to_local"] = @@ -117,18 +126,25 @@ int EnumFieldGenerator::GetNumBitsForBuilder() const { void EnumFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$boolean has$capitalized_name$();\n" "$deprecation$$type$ get$capitalized_name$();\n"); } void EnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private $type$ $name$_;\n" + "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" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " return $name$_;\n" "}\n"); @@ -137,13 +153,19 @@ GenerateMembers(io::Printer* printer) const { void EnumFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, - "private $type$ $name$_ = $default$;\n" + "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" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " return $name$_;\n" - "}\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" @@ -152,7 +174,9 @@ GenerateBuilderMembers(io::Printer* printer) const { " $name$_ = value;\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" " $clear_has_field_bit_builder$;\n" " $name$_ = $default$;\n" @@ -210,12 +234,17 @@ GenerateParsingCode(io::Printer* printer) const { "if (value != null) {\n"); } printer->Print(variables_, - " $set_has_field_bit_builder$;\n" + " $set_has_field_bit_message$;\n" " $name$_ = value;\n" "}\n"); } void EnumFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // noop for enums +} + +void EnumFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($get_has_field_bit_message$) {\n" @@ -273,22 +302,33 @@ int RepeatedEnumFieldGenerator::GetNumBitsForBuilder() const { void RepeatedEnumFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n" - "$deprecation$int get$capitalized_name$Count();\n" "$deprecation$$type$ get$capitalized_name$(int index);\n"); } void RepeatedEnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.util.List<$type$> $name$_;\n" + "private java.util.List<$type$> $name$_;\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" " return $name$_;\n" // note: unmodifiable list - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public int get$capitalized_name$Count() {\n" " return $name$_.size();\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" " return $name$_.get(index);\n" "}\n"); @@ -320,21 +360,29 @@ GenerateBuilderMembers(io::Printer* printer) const { " $name$_ = new java.util.ArrayList<$type$>($name$_);\n" " $set_mutable_bit_builder$;\n" " }\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, // Note: We return an unmodifiable list because otherwise the caller // could hold on to the returned list and modify it after the message // 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" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public int get$capitalized_name$Count() {\n" " return $name$_.size();\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" " return $name$_.get(index);\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder set$capitalized_name$(\n" " int index, $type$ value) {\n" " if (value == null) {\n" @@ -344,7 +392,9 @@ GenerateBuilderMembers(io::Printer* printer) const { " $name$_.set(index, value);\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder add$capitalized_name$($type$ value) {\n" " if (value == null) {\n" " throw new NullPointerException();\n" @@ -353,14 +403,18 @@ GenerateBuilderMembers(io::Printer* printer) const { " $name$_.add(value);\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder addAll$capitalized_name$(\n" " java.lang.Iterable<? extends $type$> values) {\n" " ensure$capitalized_name$IsMutable();\n" " super.addAll(values, $name$_);\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" " $name$_ = java.util.Collections.emptyList();\n" " $clear_mutable_bit_builder$;\n" @@ -434,7 +488,11 @@ GenerateParsingCode(io::Printer* printer) const { "if (value != null) {\n"); } printer->Print(variables_, - " add$capitalized_name$(value);\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"); } @@ -457,6 +515,14 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { } void RepeatedEnumFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_mutable_bit_parser$) {\n" + " $name$_ = java.util.Collections.unmodifiableList($name$_);\n" + "}\n"); +} + +void RepeatedEnumFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { if (descriptor_->options().packed()) { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h index 0cad6be0..90fae639 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.h +++ b/src/google/protobuf/compiler/java/java_enum_field.h @@ -61,6 +61,7 @@ class EnumFieldGenerator : public FieldGenerator { 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; @@ -96,6 +97,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingCodeFromPacked(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; diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc index 9b147c77..921fe658 100644 --- a/src/google/protobuf/compiler/java/java_extension.cc +++ b/src/google/protobuf/compiler/java/java_extension.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/java/java_extension.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/io/printer.h> @@ -130,6 +131,7 @@ void ExtensionGenerator::Generate(io::Printer* printer) { printer->Print(vars, "public static final int $constant_name$ = $number$;\n"); + WriteFieldDocComment(printer, descriptor_); if (HasDescriptorMethods(descriptor_->file())) { // Non-lite extensions if (descriptor_->extension_scope() == NULL) { diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index 6097f357..4dd0efd6 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -66,6 +66,7 @@ class FieldGenerator { virtual void GenerateBuildingCode(io::Printer* printer) const = 0; virtual void GenerateParsingCode(io::Printer* printer) const = 0; virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const; + virtual void GenerateParsingDoneCode(io::Printer* printer) const = 0; virtual void GenerateSerializationCode(io::Printer* printer) const = 0; virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer) diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index 8968069f..f43e5500 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -42,6 +42,7 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/dynamic_message.h> #include <google/protobuf/stubs/strutil.h> namespace google { @@ -51,18 +52,24 @@ namespace java { namespace { -// Recursively searches the given message to see if it contains any extensions. -bool UsesExtensions(const Message& message) { + +// Recursively searches the given message to collect extensions. +// Returns true if all the extensions can be recognized. The extensions will be +// appended in to the extensions parameter. +// Returns false when there are unknown fields, in which case the data in the +// extensions output parameter is not reliable and should be discarded. +bool CollectExtensions(const Message& message, + vector<const FieldDescriptor*>* extensions) { const Reflection* reflection = message.GetReflection(); - // We conservatively assume that unknown fields are extensions. - if (reflection->GetUnknownFields(message).field_count() > 0) return true; + // There are unknown fields that could be extensions, thus this call fails. + if (reflection->GetUnknownFields(message).field_count() > 0) return false; vector<const FieldDescriptor*> fields; reflection->ListFields(message, &fields); for (int i = 0; i < fields.size(); i++) { - if (fields[i]->is_extension()) return true; + if (fields[i]->is_extension()) extensions->push_back(fields[i]); if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { if (fields[i]->is_repeated()) { @@ -70,16 +77,56 @@ bool UsesExtensions(const Message& message) { for (int j = 0; j < size; j++) { const Message& sub_message = reflection->GetRepeatedMessage(message, fields[i], j); - if (UsesExtensions(sub_message)) return true; + if (!CollectExtensions(sub_message, extensions)) return false; } } else { const Message& sub_message = reflection->GetMessage(message, fields[i]); - if (UsesExtensions(sub_message)) return true; + if (!CollectExtensions(sub_message, extensions)) return false; } } } - return false; + return true; +} + +// Finds all extensions in the given message and its sub-messages. If the +// message contains unknown fields (which could be extensions), then those +// extensions are defined in alternate_pool. +// The message will be converted to a DynamicMessage backed by alternate_pool +// in order to handle this case. +void CollectExtensions(const FileDescriptorProto& file_proto, + const DescriptorPool& alternate_pool, + vector<const FieldDescriptor*>* extensions, + const string& file_data) { + if (!CollectExtensions(file_proto, extensions)) { + // There are unknown fields in the file_proto, which are probably + // extensions. We need to parse the data into a dynamic message based on the + // builder-pool to find out all extensions. + const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName( + file_proto.GetDescriptor()->full_name()); + GOOGLE_CHECK(file_proto_desc) + << "Find unknown fields in FileDescriptorProto when building " + << file_proto.name() + << ". It's likely that those fields are custom options, however, " + "descriptor.proto is not in the transitive dependencies. " + "This normally should not happen. Please report a bug."; + DynamicMessageFactory factory; + scoped_ptr<Message> dynamic_file_proto( + factory.GetPrototype(file_proto_desc)->New()); + GOOGLE_CHECK(dynamic_file_proto.get() != NULL); + GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data)); + + // Collect the extensions again from the dynamic message. There should be no + // more unknown fields this time, i.e. all the custom options should be + // parsed as extensions now. + extensions->clear(); + GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions)) + << "Find unknown fields in FileDescriptorProto when building " + << file_proto.name() + << ". It's likely that those fields are custom options, however, " + "those options cannot be recognized in the builder pool. " + "This normally should not happen. Please report a bug."; + } } @@ -306,19 +353,32 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { .GenerateNonNestedInitializationCode(printer); } - if (UsesExtensions(file_proto)) { - // Must construct an ExtensionRegistry containing all possible extensions + // Proto compiler builds a DescriptorPool, which holds all the descriptors to + // generate, when processing the ".proto" files. We call this DescriptorPool + // the parsed pool (a.k.a. file_->pool()). + // + // Note that when users try to extend the (.*)DescriptorProto in their + // ".proto" files, it does not affect the pre-built FileDescriptorProto class + // in proto compiler. When we put the descriptor data in the file_proto, those + // extensions become unknown fields. + // + // Now we need to find out all the extension value to the (.*)DescriptorProto + // in the file_proto message, and prepare an ExtensionRegistry to return. + // + // 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 + 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. printer->Print( "com.google.protobuf.ExtensionRegistry registry =\n" - " com.google.protobuf.ExtensionRegistry.newInstance();\n" - "registerAllExtensions(registry);\n"); - for (int i = 0; i < file_->dependency_count(); i++) { - if (ShouldIncludeDependency(file_->dependency(i))) { - printer->Print( - "$dependency$.registerAllExtensions(registry);\n", - "dependency", ClassName(file_->dependency(i))); - } + " com.google.protobuf.ExtensionRegistry.newInstance();\n"); + for (int i = 0; i < extensions.size(); i++) { + ExtensionGenerator(extensions[i]).GenerateRegistrationCode(printer); } printer->Print( "return registry;\n"); @@ -375,7 +435,9 @@ static void GenerateSibling(const string& package_dir, printer.Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "\n"); + "// source: $filename$\n" + "\n", + "filename", descriptor->file()->name()); if (!java_package.empty()) { printer.Print( "package $package$;\n" diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index 1b6f1653..cf241b8a 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -177,6 +177,18 @@ string ToJavaName(const string& full_name, const FileDescriptor* file) { return result; } +string ClassName(const Descriptor* descriptor) { + return ToJavaName(descriptor->full_name(), descriptor->file()); +} + +string ClassName(const EnumDescriptor* descriptor) { + return ToJavaName(descriptor->full_name(), descriptor->file()); +} + +string ClassName(const ServiceDescriptor* descriptor) { + return ToJavaName(descriptor->full_name(), descriptor->file()); +} + string ClassName(const FileDescriptor* descriptor) { string result = FileJavaPackage(descriptor); if (!result.empty()) result += '.'; @@ -326,14 +338,14 @@ string DefaultValue(const FieldDescriptor* field) { } else { // See comments in Internal.java for gory details. return strings::Substitute( - "com.google.protobuf.Internal.stringDefaultValue(\"$0\")", - CEscape(field->default_value_string())); + "com.google.protobuf.Internal.stringDefaultValue(\"$0\")", + CEscape(field->default_value_string())); } } case FieldDescriptor::CPPTYPE_ENUM: return ClassName(field->enum_type()) + "." + - field->default_value_enum()->name(); + field->default_value_enum()->name(); case FieldDescriptor::CPPTYPE_MESSAGE: return ClassName(field->message_type()) + ".getDefaultInstance()"; @@ -427,8 +439,10 @@ string GetBitFieldNameForBit(int bitIndex) { return GetBitFieldName(bitIndex / 32); } -string GenerateGetBit(int bitIndex) { - string varName = GetBitFieldNameForBit(bitIndex); +namespace { + +string GenerateGetBitInternal(const string& prefix, int bitIndex) { + string varName = prefix + GetBitFieldNameForBit(bitIndex); int bitInVarIndex = bitIndex % 32; string mask = bit_masks[bitInVarIndex]; @@ -436,8 +450,8 @@ string GenerateGetBit(int bitIndex) { return result; } -string GenerateSetBit(int bitIndex) { - string varName = GetBitFieldNameForBit(bitIndex); +string GenerateSetBitInternal(const string& prefix, int bitIndex) { + string varName = prefix + GetBitFieldNameForBit(bitIndex); int bitInVarIndex = bitIndex % 32; string mask = bit_masks[bitInVarIndex]; @@ -445,6 +459,16 @@ string GenerateSetBit(int bitIndex) { return result; } +} // namespace + +string GenerateGetBit(int bitIndex) { + return GenerateGetBitInternal("", bitIndex); +} + +string GenerateSetBit(int bitIndex) { + return GenerateSetBitInternal("", bitIndex); +} + string GenerateClearBit(int bitIndex) { string varName = GetBitFieldNameForBit(bitIndex); int bitInVarIndex = bitIndex % 32; @@ -455,21 +479,19 @@ string GenerateClearBit(int bitIndex) { } string GenerateGetBitFromLocal(int bitIndex) { - string varName = "from_" + GetBitFieldNameForBit(bitIndex); - int bitInVarIndex = bitIndex % 32; - - string mask = bit_masks[bitInVarIndex]; - string result = "((" + varName + " & " + mask + ") == " + mask + ")"; - return result; + return GenerateGetBitInternal("from_", bitIndex); } string GenerateSetBitToLocal(int bitIndex) { - string varName = "to_" + GetBitFieldNameForBit(bitIndex); - int bitInVarIndex = bitIndex % 32; + return GenerateSetBitInternal("to_", bitIndex); +} - string mask = bit_masks[bitInVarIndex]; - string result = varName + " |= " + mask; - return result; +string GenerateGetBitMutableLocal(int bitIndex) { + return GenerateGetBitInternal("mutable_", bitIndex); +} + +string GenerateSetBitMutableLocal(int bitIndex) { + return GenerateSetBitInternal("mutable_", bitIndex); } } // namespace java diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 4ae07f15..3937f069 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -78,19 +78,14 @@ string ToJavaName(const string& full_name, const FileDescriptor* file); // These return the fully-qualified class name corresponding to the given // descriptor. -inline string ClassName(const Descriptor* descriptor) { - return ToJavaName(descriptor->full_name(), descriptor->file()); -} -inline string ClassName(const EnumDescriptor* descriptor) { - return ToJavaName(descriptor->full_name(), descriptor->file()); -} -inline string ClassName(const ServiceDescriptor* descriptor) { - return ToJavaName(descriptor->full_name(), descriptor->file()); -} +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()); } -string ClassName(const FileDescriptor* descriptor); // Get the unqualified name that should be used for a field's field // number constant. @@ -205,6 +200,18 @@ string GenerateGetBitFromLocal(int bitIndex); // Example: "to_bitField1_ = (to_bitField1_ | 0x04)" string GenerateSetBitToLocal(int bitIndex); +// Does the same as GenerateGetBit but operates on the bit field on a local +// variable. This is used by the parsing constructor to record if a repeated +// field is mutable. +// Example: "((mutable_bitField1_ & 0x04) == 0x04)" +string GenerateGetBitMutableLocal(int bitIndex); + +// Does the same as GenerateSetBit but operates on the bit field on a local +// variable. This is used by the parsing constructor to record if a repeated +// field is mutable. +// Example: "mutable_bitField1_ = (mutable_bitField1_ | 0x04)" +string GenerateSetBitMutableLocal(int bitIndex); + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 4c087db5..9322e242 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -32,17 +32,23 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <google/protobuf/compiler/java/java_message.h> + #include <algorithm> #include <google/protobuf/stubs/hash.h> -#include <google/protobuf/compiler/java/java_message.h> +#include <map> +#include <vector> + +#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_helpers.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/io/printer.h> #include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/wire_format.h> +#include <google/protobuf/io/printer.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> namespace google { namespace protobuf { @@ -233,10 +239,8 @@ void MessageGenerator::GenerateStaticVariableInitializers( "field_name", UnderscoresToCapitalizedCamelCase(descriptor_->field(i))); } - printer->Print("},\n" - " $classname$.class,\n" - " $classname$.Builder.class);\n", - "classname", ClassName(descriptor_)); + printer->Print( + "});\n"); } // Generate static member initializers for all nested types. @@ -250,7 +254,6 @@ void MessageGenerator::GenerateStaticVariableInitializers( // =================================================================== void MessageGenerator::GenerateInterface(io::Printer* printer) { - if (descriptor_->extension_range_count() > 0) { if (HasDescriptorMethods(descriptor_)) { printer->Print( @@ -298,6 +301,10 @@ void MessageGenerator::Generate(io::Printer* printer) { descriptor_->containing_type() == NULL && descriptor_->file()->options().java_multiple_files(); + 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( @@ -306,6 +313,9 @@ void MessageGenerator::Generate(io::Printer* printer) { " $classname$> implements $classname$OrBuilder {\n", "static", is_own_file ? "" : "static", "classname", descriptor_->name()); + builder_type = strings::Substitute( + "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>", + ClassName(descriptor_)); } else { printer->Print( "public $static$ final class $classname$ extends\n" @@ -313,6 +323,9 @@ void MessageGenerator::Generate(io::Printer* printer) { " $classname$> implements $classname$OrBuilder {\n", "static", is_own_file ? "" : "static", "classname", descriptor_->name()); + builder_type = strings::Substitute( + "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>", + ClassName(descriptor_)); } } else { if (HasDescriptorMethods(descriptor_)) { @@ -322,6 +335,7 @@ void MessageGenerator::Generate(io::Printer* printer) { " implements $classname$OrBuilder {\n", "static", is_own_file ? "" : "static", "classname", descriptor_->name()); + builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>"; } else { printer->Print( "public $static$ final class $classname$ extends\n" @@ -329,17 +343,28 @@ void MessageGenerator::Generate(io::Printer* printer) { " implements $classname$OrBuilder {\n", "static", is_own_file ? "" : "static", "classname", descriptor_->name()); + builder_type = "com.google.protobuf.GeneratedMessageLite.Builder"; } } printer->Indent(); + // Using builder_type, instead of Builder, prevents the Builder class from + // being loaded into PermGen space when the default instance is created. + // This optimizes the PermGen space usage for clients that do not modify + // messages. printer->Print( "// Use $classname$.newBuilder() to construct.\n" - "private $classname$(Builder builder) {\n" + "private $classname$($buildertype$ builder) {\n" " super(builder);\n" - "}\n" + "$set_unknown_fields$\n" + "}\n", + "classname", descriptor_->name(), + "buildertype", builder_type, + "set_unknown_fields", HasUnknownFields(descriptor_) + ? " 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. - "private $classname$(boolean noInit) {}\n" + "private $classname$(boolean noInit) {$set_default_unknown_fields$}\n" "\n" "private static final $classname$ defaultInstance;\n" "public static $classname$ getDefaultInstance() {\n" @@ -350,9 +375,28 @@ void MessageGenerator::Generate(io::Printer* printer) { " return defaultInstance;\n" "}\n" "\n", - "classname", descriptor_->name()); + "classname", descriptor_->name(), + "set_default_unknown_fields", HasUnknownFields(descriptor_) + ? " this.unknownFields =" + " com.google.protobuf.UnknownFieldSet.getDefaultInstance(); " : ""); + + if (HasUnknownFields(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"); + } + + if (HasGeneratedMethods(descriptor_)) { + GenerateParsingConstructor(printer); + } GenerateDescriptorMethods(printer); + GenerateParser(printer); // Nested types for (int i = 0; i < descriptor_->enum_type_count(); i++) { @@ -567,68 +611,54 @@ GenerateParseFromMethods(io::Printer* printer) { "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return newBuilder().mergeFrom(data).buildParsed();\n" + " return PARSER.parseFrom(data);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return newBuilder().mergeFrom(data, extensionRegistry)\n" - " .buildParsed();\n" + " return PARSER.parseFrom(data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(byte[] data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return newBuilder().mergeFrom(data).buildParsed();\n" + " return PARSER.parseFrom(data);\n" "}\n" "public static $classname$ parseFrom(\n" " byte[] data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return newBuilder().mergeFrom(data, extensionRegistry)\n" - " .buildParsed();\n" + " return PARSER.parseFrom(data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeFrom(input).buildParsed();\n" + " return PARSER.parseFrom(input);\n" "}\n" "public static $classname$ parseFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeFrom(input, extensionRegistry)\n" - " .buildParsed();\n" + " return PARSER.parseFrom(input, extensionRegistry);\n" "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " Builder builder = newBuilder();\n" - " if (builder.mergeDelimitedFrom(input)) {\n" - " return builder.buildParsed();\n" - " } else {\n" - " return null;\n" - " }\n" + " return PARSER.parseDelimitedFrom(input);\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " Builder builder = newBuilder();\n" - " if (builder.mergeDelimitedFrom(input, extensionRegistry)) {\n" - " return builder.buildParsed();\n" - " } else {\n" - " return null;\n" - " }\n" + " return PARSER.parseDelimitedFrom(input, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeFrom(input).buildParsed();\n" + " return PARSER.parseFrom(input);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeFrom(input, extensionRegistry)\n" - " .buildParsed();\n" + " return PARSER.parseFrom(input, extensionRegistry);\n" "}\n" "\n", "classname", ClassName(descriptor_)); @@ -669,6 +699,8 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) { "}\n"); } + WriteMessageDocComment(printer, descriptor_); + if (descriptor_->extension_range_count() > 0) { if (HasDescriptorMethods(descriptor_)) { printer->Print( @@ -739,17 +771,25 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) { void MessageGenerator::GenerateDescriptorMethods(io::Printer* printer) { if (HasDescriptorMethods(descriptor_)) { + if (!descriptor_->options().no_standard_descriptor_accessor()) { + printer->Print( + "public static final com.google.protobuf.Descriptors.Descriptor\n" + " getDescriptor() {\n" + " return $fileclass$.internal_$identifier$_descriptor;\n" + "}\n" + "\n", + "fileclass", ClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_)); + } printer->Print( - "public static final com.google.protobuf.Descriptors.Descriptor\n" - " getDescriptor() {\n" - " return $fileclass$.internal_$identifier$_descriptor;\n" - "}\n" - "\n" "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" " internalGetFieldAccessorTable() {\n" - " return $fileclass$.internal_$identifier$_fieldAccessorTable;\n" + " return $fileclass$.internal_$identifier$_fieldAccessorTable\n" + " .ensureFieldAccessorsInitialized(\n" + " $classname$.class, $classname$.Builder.class);\n" "}\n" "\n", + "classname", ClassName(descriptor_), "fileclass", ClassName(descriptor_->file()), "identifier", UniqueFileScopeIdentifier(descriptor_)); } @@ -768,7 +808,8 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { if (HasDescriptorMethods(descriptor_)) { printer->Print( - "private Builder(BuilderParent parent) {\n" + "private Builder(\n" + " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n" " super(parent);\n" " maybeForceBuilderInitialization();\n" "}\n", @@ -830,10 +871,11 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { printer->Print( "public com.google.protobuf.Descriptors.Descriptor\n" " getDescriptorForType() {\n" - " return $classname$.getDescriptor();\n" + " return $fileclass$.internal_$identifier$_descriptor;\n" "}\n" "\n", - "classname", ClassName(descriptor_)); + "fileclass", ClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_)); } printer->Print( "public $classname$ getDefaultInstanceForType() {\n" @@ -853,16 +895,6 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { " return result;\n" "}\n" "\n" - "private $classname$ buildParsed()\n" - " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " $classname$ result = buildPartial();\n" - " if (!result.isInitialized()) {\n" - " throw newUninitializedMessageException(\n" - " result).asInvalidProtocolBufferException();\n" - " }\n" - " return result;\n" - "}\n" - "\n" "public $classname$ buildPartial() {\n" " $classname$ result = new $classname$(this);\n", "classname", ClassName(descriptor_)); @@ -969,108 +1001,25 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { // =================================================================== void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { - scoped_array<const FieldDescriptor*> sorted_fields( - SortFieldsByNumber(descriptor_)); - printer->Print( "public Builder mergeFrom(\n" " com.google.protobuf.CodedInputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" - " throws java.io.IOException {\n"); - printer->Indent(); - - if (HasUnknownFields(descriptor_)) { - printer->Print( - "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n" - " com.google.protobuf.UnknownFieldSet.newBuilder(\n" - " this.getUnknownFields());\n"); - } - - printer->Print( - "while (true) {\n"); - printer->Indent(); - - printer->Print( - "int tag = input.readTag();\n" - "switch (tag) {\n"); - printer->Indent(); - - if (HasUnknownFields(descriptor_)) { - printer->Print( - "case 0:\n" // zero signals EOF / limit reached - " this.setUnknownFields(unknownFields.build());\n" - " $on_changed$\n" - " return this;\n" - "default: {\n" - " if (!parseUnknownField(input, unknownFields,\n" - " extensionRegistry, tag)) {\n" - " this.setUnknownFields(unknownFields.build());\n" - " $on_changed$\n" - " return this;\n" // it's an endgroup tag - " }\n" - " break;\n" - "}\n", - "on_changed", HasDescriptorMethods(descriptor_) ? "onChanged();" : ""); - } else { - printer->Print( - "case 0:\n" // zero signals EOF / limit reached - " $on_changed$\n" - " return this;\n" - "default: {\n" - " if (!parseUnknownField(input, extensionRegistry, tag)) {\n" - " $on_changed$\n" - " return this;\n" // it's an endgroup tag - " }\n" - " break;\n" - "}\n", - "on_changed", HasDescriptorMethods(descriptor_) ? "onChanged();" : ""); - } - - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = sorted_fields[i]; - uint32 tag = WireFormatLite::MakeTag(field->number(), - WireFormat::WireTypeForFieldType(field->type())); - - printer->Print( - "case $tag$: {\n", - "tag", SimpleItoa(tag)); - printer->Indent(); - - field_generators_.get(field).GenerateParsingCode(printer); - - printer->Outdent(); - printer->Print( - " break;\n" - "}\n"); - - if (field->is_packable()) { - // To make packed = true wire compatible, we generate parsing code from a - // packed version of this field regardless of field->options().packed(). - uint32 packed_tag = WireFormatLite::MakeTag(field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED); - printer->Print( - "case $tag$: {\n", - "tag", SimpleItoa(packed_tag)); - printer->Indent(); - - field_generators_.get(field).GenerateParsingCodeFromPacked(printer); - - printer->Outdent(); - printer->Print( - " break;\n" - "}\n"); - } - } - - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); - printer->Print( - " }\n" // switch (tag) - " }\n" // while (true) - "}\n" - - "\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", ClassName(descriptor_)); } // =================================================================== @@ -1232,10 +1181,19 @@ 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(); printer->Print( + "if (memoizedHashCode != 0) {\n"); + printer->Indent(); + printer->Print( + "return memoizedHashCode;\n"); + printer->Outdent(); + printer->Print( + "}\n" "int hash = 41;\n" "hash = (19 * hash) + getDescriptorForType().hashCode();\n"); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -1260,6 +1218,7 @@ void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) { } printer->Print( "hash = (29 * hash) + getUnknownFields().hashCode();\n" + "memoizedHashCode = hash;\n" "return hash;\n"); printer->Outdent(); printer->Print( @@ -1281,6 +1240,195 @@ void MessageGenerator::GenerateExtensionRegistrationCode(io::Printer* printer) { } } +// =================================================================== +void MessageGenerator::GenerateParsingConstructor(io::Printer* printer) { + scoped_array<const FieldDescriptor*> sorted_fields( + SortFieldsByNumber(descriptor_)); + + printer->Print( + "private $classname$(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n", + "classname", descriptor_->name()); + printer->Indent(); + + // Initialize all fields to default. + printer->Print( + "initFields();\n"); + + // 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)); + totalBuilderBits += field.GetNumBitsForBuilder(); + } + int totalBuilderInts = (totalBuilderBits + 31) / 32; + for (int i = 0; i < totalBuilderInts; i++) { + printer->Print("int mutable_$bit_field_name$ = 0;\n", + "bit_field_name", GetBitFieldName(i)); + } + + if (HasUnknownFields(descriptor_)) { + printer->Print( + "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n" + " com.google.protobuf.UnknownFieldSet.newBuilder();\n"); + } + + printer->Print( + "try {\n"); + printer->Indent(); + + printer->Print( + "boolean done = false;\n" + "while (!done) {\n"); + printer->Indent(); + + printer->Print( + "int tag = input.readTag();\n" + "switch (tag) {\n"); + printer->Indent(); + + 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", HasUnknownFields(descriptor_) + ? " unknownFields," : ""); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + uint32 tag = WireFormatLite::MakeTag(field->number(), + WireFormat::WireTypeForFieldType(field->type())); + + printer->Print( + "case $tag$: {\n", + "tag", SimpleItoa(tag)); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCode(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + + if (field->is_packable()) { + // To make packed = true wire compatible, we generate parsing code from a + // packed version of this field regardless of field->options().packed(). + uint32 packed_tag = WireFormatLite::MakeTag(field->number(), + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + printer->Print( + "case $tag$: {\n", + "tag", SimpleItoa(packed_tag)); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCodeFromPacked(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + } + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // switch (tag) + "}\n"); // while (!done) + + printer->Outdent(); + printer->Print( + "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " throw e.setUnfinishedMessage(this);\n" + "} catch (java.io.IOException e) {\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " e.getMessage()).setUnfinishedMessage(this);\n" + "} finally {\n"); + printer->Indent(); + + // Make repeated field list immutable. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + field_generators_.get(field).GenerateParsingDoneCode(printer); + } + + // Make unknown fields immutable. + if (HasUnknownFields(descriptor_)) { + printer->Print( + "this.unknownFields = unknownFields.build();\n"); + } + + // Make extensions immutable. + printer->Print( + "makeExtensionsImmutable();\n"); + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // finally + "}\n"); +} + +// =================================================================== +void MessageGenerator::GenerateParser(io::Printer* printer) { + printer->Print( + "public static com.google.protobuf.Parser<$classname$> PARSER =\n" + " new com.google.protobuf.AbstractParser<$classname$>() {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Print( + "public $classname$ parsePartialFrom(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n", + "classname", descriptor_->name()); + if (HasGeneratedMethods(descriptor_)) { + printer->Print( + " return new $classname$(input, extensionRegistry);\n", + "classname", descriptor_->name()); + } else { + // When parsing constructor isn't generated, use builder to parse messages. + // Note, will fallback to use reflection based mergeFieldFrom() in + // AbstractMessage.Builder. + printer->Indent(); + printer->Print( + "Builder builder = newBuilder();\n" + "try {\n" + " builder.mergeFrom(input, extensionRegistry);\n" + "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " throw e.setUnfinishedMessage(builder.buildPartial());\n" + "} catch (java.io.IOException e) {\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " e.getMessage()).setUnfinishedMessage(builder.buildPartial());\n" + "}\n" + "return builder.buildPartial();\n"); + printer->Outdent(); + } + printer->Print( + "}\n"); + printer->Outdent(); + printer->Print( + "};\n" + "\n"); + + printer->Print( + "@java.lang.Override\n" + "public com.google.protobuf.Parser<$classname$> getParserForType() {\n" + " return PARSER;\n" + "}\n" + "\n", + "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 4c6fbbe5..a30f0202 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -95,6 +95,9 @@ class MessageGenerator { UseMemoization useMemoization); void GenerateEqualsAndHashCode(io::Printer* printer); + void GenerateParser(io::Printer* printer); + void GenerateParsingConstructor(io::Printer* printer); + const Descriptor* descriptor_; FieldGeneratorMap field_generators_; diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index 251945af..b0b284f7 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -36,6 +36,7 @@ #include <string> #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/io/printer.h> #include <google/protobuf/wire_format.h> @@ -73,6 +74,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // 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); (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); @@ -84,6 +86,13 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); + // 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); + (*variables)["get_has_field_bit_from_local"] = GenerateGetBitFromLocal(builderBitIndex); (*variables)["set_has_field_bit_to_local"] = @@ -120,11 +129,15 @@ GenerateInterfaceMembers(io::Printer* printer) const { // 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"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$boolean has$capitalized_name$();\n" "$deprecation$$type$ get$capitalized_name$();\n"); if (HasNestedBuilders(descriptor_->containing_type())) { + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n"); } @@ -133,15 +146,20 @@ GenerateInterfaceMembers(io::Printer* printer) const { void MessageFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private $type$ $name$_;\n" + "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" + "}\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" @@ -208,12 +226,14 @@ GenerateBuilderMembers(io::Printer* printer) const { // 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"); // Field getField() + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public $type$ get$capitalized_name$()", @@ -224,6 +244,7 @@ GenerateBuilderMembers(io::Printer* printer) const { NULL); // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public Builder set$capitalized_name$($type$ value)", @@ -239,6 +260,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public Builder set$capitalized_name$(\n" " $type$.Builder builderForValue)", @@ -252,6 +274,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public Builder merge$capitalized_name$($type$ value)", @@ -270,6 +293,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public Builder clear$capitalized_name$()", @@ -282,19 +306,24 @@ GenerateBuilderMembers(io::Printer* printer) const { "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" + "}\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" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "private com.google.protobuf.SingleFieldBuilder<\n" " $type$, $type$.Builder, $type$OrBuilder> \n" " get$capitalized_name$FieldBuilder() {\n" @@ -357,21 +386,32 @@ GenerateBuildingCode(io::Printer* printer) const { void MessageFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, - "$type$.Builder subBuilder = $type$.newBuilder();\n" - "if (has$capitalized_name$()) {\n" - " subBuilder.mergeFrom(get$capitalized_name$());\n" + "$type$.Builder subBuilder = null;\n" + "if ($get_has_field_bit_message$) {\n" + " subBuilder = $name$_.toBuilder();\n" "}\n"); if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "input.readGroup($number$, subBuilder, extensionRegistry);\n"); + "$name$_ = input.readGroup($number$, $type$.PARSER,\n" + " extensionRegistry);\n"); } else { printer->Print(variables_, - "input.readMessage(subBuilder, extensionRegistry);\n"); + "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); } printer->Print(variables_, - "set$capitalized_name$(subBuilder.buildPartial());\n"); + "if (subBuilder != null) {\n" + " subBuilder.mergeFrom($name$_);\n" + " $name$_ = subBuilder.buildPartial();\n" + "}\n"); + printer->Print(variables_, + "$set_has_field_bit_message$;\n"); +} + +void MessageFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // noop for messages. } void MessageFieldGenerator:: @@ -437,15 +477,23 @@ GenerateInterfaceMembers(io::Printer* printer) const { // 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$java.util.List<$type$> \n" - " get$capitalized_name$List();\n" - "$deprecation$$type$ get$capitalized_name$(int index);\n" + " get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$int get$capitalized_name$Count();\n"); if (HasNestedBuilders(descriptor_->containing_type())) { + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$java.util.List<? extends $type$OrBuilder> \n" - " get$capitalized_name$OrBuilderList();\n" + " get$capitalized_name$OrBuilderList();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n" " int index);\n"); } @@ -454,20 +502,30 @@ GenerateInterfaceMembers(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.util.List<$type$> $name$_;\n" + "private java.util.List<$type$> $name$_;\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" " return $name$_;\n" // note: unmodifiable list - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public java.util.List<? extends $type$OrBuilder> \n" " get$capitalized_name$OrBuilderList() {\n" " return $name$_;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public int get$capitalized_name$Count() {\n" " return $name$_.size();\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" " return $name$_.get(index);\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" " int index) {\n" " return $name$_.get(index);\n" @@ -552,6 +610,7 @@ GenerateBuilderMembers(io::Printer* printer) const { // 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()", @@ -561,6 +620,7 @@ GenerateBuilderMembers(io::Printer* printer) const { NULL); // int getRepeatedFieldCount() + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public int get$capitalized_name$Count()", @@ -570,6 +630,7 @@ GenerateBuilderMembers(io::Printer* printer) const { NULL); // Field getRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public $type$ get$capitalized_name$(int index)", @@ -580,6 +641,7 @@ GenerateBuilderMembers(io::Printer* printer) const { NULL); // Builder setRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public Builder set$capitalized_name$(\n" " int index, $type$ value)", @@ -593,6 +655,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "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)", @@ -606,6 +669,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); // Builder addRepeatedField(Field value) + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public Builder add$capitalized_name$($type$ value)", @@ -622,6 +686,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "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)", @@ -638,6 +703,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); // Builder addRepeatedField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public Builder add$capitalized_name$(\n" " $type$.Builder builderForValue)", @@ -651,6 +717,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "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)", @@ -664,6 +731,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "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)", @@ -677,6 +745,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); // Builder clearAllRepeatedField() + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public Builder clear$capitalized_name$()", @@ -689,6 +758,7 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); // Builder removeRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public Builder remove$capitalized_name$(int index)", @@ -701,12 +771,15 @@ GenerateBuilderMembers(io::Printer* printer) const { "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" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" " int index) {\n" " if ($name$Builder_ == null) {\n" @@ -714,8 +787,10 @@ GenerateBuilderMembers(io::Printer* printer) const { " } else {\n" " return $name$Builder_.getMessageOrBuilder(index);\n" " }\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" @@ -723,17 +798,23 @@ GenerateBuilderMembers(io::Printer* printer) const { " } else {\n" " return java.util.Collections.unmodifiableList($name$_);\n" " }\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" + "}\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" + "}\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" @@ -827,18 +908,27 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, - "$type$.Builder subBuilder = $type$.newBuilder();\n"); + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new java.util.ArrayList<$type$>();\n" + " $set_mutable_bit_parser$;\n" + "}\n"); if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "input.readGroup($number$, subBuilder, extensionRegistry);\n"); + "$name$_.add(input.readGroup($number$, $type$.PARSER,\n" + " extensionRegistry));\n"); } else { printer->Print(variables_, - "input.readMessage(subBuilder, extensionRegistry);\n"); + "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n"); } +} +void RepeatedMessageFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { printer->Print(variables_, - "add$capitalized_name$(subBuilder.buildPartial());\n"); + "if ($get_mutable_bit_parser$) {\n" + " $name$_ = java.util.Collections.unmodifiableList($name$_);\n" + "}\n"); } void RepeatedMessageFieldGenerator:: diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h index 2efbcd97..5c8078a1 100644 --- a/src/google/protobuf/compiler/java/java_message_field.h +++ b/src/google/protobuf/compiler/java/java_message_field.h @@ -61,6 +61,7 @@ class MessageFieldGenerator : public FieldGenerator { 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; @@ -102,6 +103,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { 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; diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 712e047a..0140e23f 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -36,6 +36,7 @@ #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_helpers.h> #include <google/protobuf/io/printer.h> @@ -197,6 +198,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // 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); (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); @@ -208,6 +210,13 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); + // 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); + (*variables)["get_has_field_bit_from_local"] = GenerateGetBitFromLocal(builderBitIndex); (*variables)["set_has_field_bit_to_local"] = @@ -240,19 +249,26 @@ int PrimitiveFieldGenerator::GetNumBitsForBuilder() const { void PrimitiveFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$boolean has$capitalized_name$();\n" "$deprecation$$type$ get$capitalized_name$();\n"); } void PrimitiveFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private $field_type$ $name$_;\n" + "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"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " return $name$_;\n" @@ -262,16 +278,21 @@ GenerateMembers(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, - "private $field_type$ $name$_ $default_init$;\n" + "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"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " return $name$_;\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" "$null_check$" @@ -279,7 +300,10 @@ GenerateBuilderMembers(io::Printer* printer) const { " $name$_ = value;\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" " $clear_has_field_bit_builder$;\n"); JavaType type = GetJavaType(descriptor_); @@ -335,11 +359,16 @@ GenerateBuildingCode(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, - "$set_has_field_bit_builder$;\n" + "$set_has_field_bit_message$;\n" "$name$_ = input.read$capitalized_type$();\n"); } void PrimitiveFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // noop for primitives. +} + +void PrimitiveFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($get_has_field_bit_message$) {\n" @@ -468,9 +497,14 @@ int RepeatedPrimitiveFieldGenerator::GetNumBitsForBuilder() const { void RepeatedPrimitiveFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n" - "$deprecation$int get$capitalized_name$Count();\n" "$deprecation$$type$ get$capitalized_name$(int index);\n"); } @@ -478,14 +512,20 @@ GenerateInterfaceMembers(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private $field_list_type$ $name$_;\n" + "private $field_list_type$ $name$_;\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public java.util.List<$boxed_type$>\n" " get$capitalized_name$List() {\n" " return $name$_;\n" // note: unmodifiable list - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public int get$capitalized_name$Count() {\n" " return $name$_.size();\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" " return $name$_.get(index);\n" "}\n"); @@ -523,17 +563,24 @@ GenerateBuilderMembers(io::Printer* printer) const { // could hold on to the returned list and modify it after the message // has been built, thus mutating the message which is supposed to be // immutable. + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.util.List<$boxed_type$>\n" " get$capitalized_name$List() {\n" " return java.util.Collections.unmodifiableList($name$_);\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public int get$capitalized_name$Count() {\n" " return $name$_.size();\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" " return $name$_.get(index);\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder set$capitalized_name$(\n" " int index, $type$ value) {\n" "$null_check$" @@ -541,21 +588,27 @@ GenerateBuilderMembers(io::Printer* printer) const { " $name$_.set(index, value);\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder add$capitalized_name$($type$ value) {\n" "$null_check$" " ensure$capitalized_name$IsMutable();\n" " $name$_.add(value);\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$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" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" " $name$_ = $empty_list$;\n" " $clear_mutable_bit_builder$;\n" @@ -616,7 +669,10 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, - "ensure$capitalized_name$IsMutable();\n" + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new java.util.ArrayList<$boxed_type$>();\n" + " $set_mutable_bit_parser$;\n" + "}\n" "$name$_.add(input.read$capitalized_type$());\n"); } @@ -625,13 +681,25 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { printer->Print(variables_, "int length = input.readRawVarint32();\n" "int limit = input.pushLimit(length);\n" + "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n" + " $name$_ = new java.util.ArrayList<$boxed_type$>();\n" + " $set_mutable_bit_parser$;\n" + "}\n" "while (input.getBytesUntilLimit() > 0) {\n" - " add$capitalized_name$(input.read$capitalized_type$());\n" + " $name$_.add(input.read$capitalized_type$());\n" "}\n" "input.popLimit(limit);\n"); } void RepeatedPrimitiveFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_mutable_bit_parser$) {\n" + " $name$_ = java.util.Collections.unmodifiableList($name$_);\n" + "}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { if (descriptor_->options().packed()) { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h index 7900fac5..1b5b6d95 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.h +++ b/src/google/protobuf/compiler/java/java_primitive_field.h @@ -61,6 +61,7 @@ class PrimitiveFieldGenerator : public FieldGenerator { 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; @@ -96,6 +97,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingCodeFromPacked(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; diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc index 1ae4f461..bbd24806 100644 --- a/src/google/protobuf/compiler/java/java_service.cc +++ b/src/google/protobuf/compiler/java/java_service.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/java/java_service.h> +#include <google/protobuf/compiler/java/java_doc_comment.h> #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> @@ -50,6 +51,7 @@ ServiceGenerator::~ServiceGenerator() {} void ServiceGenerator::Generate(io::Printer* printer) { bool is_own_file = descriptor_->file()->options().java_multiple_files(); + WriteServiceDocComment(printer, descriptor_); printer->Print( "public $static$ abstract class $classname$\n" " implements com.google.protobuf.Service {\n", @@ -157,6 +159,7 @@ void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod( void ServiceGenerator::GenerateAbstractMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); + WriteMethodDocComment(printer, method); GenerateMethodSignature(printer, method, IS_ABSTRACT); printer->Print(";\n\n"); } diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 222285bd..4815663b 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -37,6 +37,7 @@ #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_helpers.h> #include <google/protobuf/io/printer.h> @@ -85,6 +86,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // 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); (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); @@ -96,6 +98,13 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); + // 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); + (*variables)["get_has_field_bit_from_local"] = GenerateGetBitFromLocal(builderBitIndex); (*variables)["set_has_field_bit_to_local"] = @@ -160,19 +169,29 @@ int StringFieldGenerator::GetNumBitsForBuilder() const { // UnmodifiableLazyStringList. void StringFieldGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$boolean has$capitalized_name$();\n" "$deprecation$java.lang.String get$capitalized_name$();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes();\n"); } void StringFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.lang.Object $name$_;\n" + "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"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$() {\n" " java.lang.Object ref = $name$_;\n" @@ -182,13 +201,16 @@ GenerateMembers(io::Printer* printer) const { " com.google.protobuf.ByteString bs = \n" " (com.google.protobuf.ByteString) ref;\n" " java.lang.String s = bs.toStringUtf8();\n" - " if (com.google.protobuf.Internal.isValidUtf8(bs)) {\n" + " if (bs.isValidUtf8()) {\n" " $name$_ = s;\n" " }\n" " return s;\n" " }\n" - "}\n" - "private com.google.protobuf.ByteString get$capitalized_name$Bytes() {\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes() {\n" " java.lang.Object ref = $name$_;\n" " if (ref instanceof java.lang.String) {\n" " com.google.protobuf.ByteString b = \n" @@ -205,11 +227,14 @@ GenerateMembers(io::Printer* printer) const { void StringFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.lang.Object $name$_ $default_init$;\n" + "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"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$() {\n" " java.lang.Object ref = $name$_;\n" @@ -223,6 +248,23 @@ GenerateBuilderMembers(io::Printer* printer) const { " }\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes() {\n" + " java.lang.Object ref = $name$_;\n" + " if (ref instanceof String) {\n" + " com.google.protobuf.ByteString b = \n" + " com.google.protobuf.ByteString.copyFromUtf8(\n" + " (java.lang.String) ref);\n" + " $name$_ = b;\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" @@ -231,7 +273,9 @@ GenerateBuilderMembers(io::Printer* printer) const { " $name$_ = value;\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" " $clear_has_field_bit_builder$;\n"); // The default value is not a simple literal so we want to avoid executing @@ -243,11 +287,15 @@ GenerateBuilderMembers(io::Printer* printer) const { " return this;\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "void set$capitalized_name$(com.google.protobuf.ByteString value) {\n" + "$deprecation$public Builder set$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n" + "$null_check$" " $set_has_field_bit_builder$;\n" " $name$_ = value;\n" " $on_changed$\n" + " return this;\n" "}\n"); } @@ -270,9 +318,13 @@ GenerateBuilderClearCode(io::Printer* printer) const { void StringFieldGenerator:: 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$capitalized_name$(other.get$capitalized_name$());\n" + " $set_has_field_bit_builder$;\n" + " $name$_ = other.$name$_;\n" + " $on_changed$\n" "}\n"); } @@ -288,11 +340,16 @@ GenerateBuildingCode(io::Printer* printer) const { void StringFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, - "$set_has_field_bit_builder$;\n" + "$set_has_field_bit_message$;\n" "$name$_ = input.readBytes();\n"); } void StringFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // noop for strings. +} + +void StringFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($get_has_field_bit_message$) {\n" @@ -353,28 +410,49 @@ int RepeatedStringFieldGenerator::GetNumBitsForBuilder() const { void RepeatedStringFieldGenerator:: 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$int get$capitalized_name$Count();\n" + "get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$java.lang.String get$capitalized_name$(int index);\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes(int index);\n"); } void RepeatedStringFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private com.google.protobuf.LazyStringList $name$_;\n" + "private com.google.protobuf.LazyStringList $name$_;\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public java.util.List<java.lang.String>\n" " get$capitalized_name$List() {\n" " return $name$_;\n" // note: unmodifiable list - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public int get$capitalized_name$Count() {\n" " return $name$_.size();\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n" " return $name$_.get(index);\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes(int index) {\n" + " return $name$_.getByteString(index);\n" + "}\n"); if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->containing_type())) { @@ -409,17 +487,30 @@ GenerateBuilderMembers(io::Printer* printer) const { // could hold on to the returned list and modify it after the message // has been built, thus mutating the message which is supposed to be // immutable. + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.util.List<java.lang.String>\n" " get$capitalized_name$List() {\n" " return java.util.Collections.unmodifiableList($name$_);\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public int get$capitalized_name$Count() {\n" " return $name$_.size();\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n" " return $name$_.get(index);\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes(int index) {\n" + " return $name$_.getByteString(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder set$capitalized_name$(\n" " int index, java.lang.String value) {\n" "$null_check$" @@ -427,7 +518,9 @@ GenerateBuilderMembers(io::Printer* printer) const { " $name$_.set(index, value);\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder add$capitalized_name$(\n" " java.lang.String value) {\n" "$null_check$" @@ -435,14 +528,18 @@ GenerateBuilderMembers(io::Printer* printer) const { " $name$_.add(value);\n" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$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" " $on_changed$\n" " return this;\n" - "}\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" " $name$_ = $empty_list$;\n" " $clear_mutable_bit_builder$;\n" @@ -450,11 +547,15 @@ GenerateBuilderMembers(io::Printer* printer) const { " return this;\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "void add$capitalized_name$(com.google.protobuf.ByteString value) {\n" + "$deprecation$public Builder add$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n" + "$null_check$" " ensure$capitalized_name$IsMutable();\n" " $name$_.add(value);\n" " $on_changed$\n" + " return this;\n" "}\n"); } @@ -512,7 +613,10 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, - "ensure$capitalized_name$IsMutable();\n" + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + " $set_mutable_bit_parser$;\n" + "}\n" "$name$_.add(input.readBytes());\n"); } @@ -521,13 +625,25 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { printer->Print(variables_, "int length = input.readRawVarint32();\n" "int limit = input.pushLimit(length);\n" + "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n" + " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + " $set_mutable_bit_parser$;\n" + "}\n" "while (input.getBytesUntilLimit() > 0) {\n" - " add$capitalized_name$(input.read$capitalized_type$());\n" + " $name$.add(input.read$capitalized_type$());\n" "}\n" "input.popLimit(limit);\n"); } void RepeatedStringFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_mutable_bit_parser$) {\n" + " $name$_ = new com.google.protobuf.UnmodifiableLazyStringList($name$_);\n" + "}\n"); +} + +void RepeatedStringFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { if (descriptor_->options().packed()) { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h index 8cb41469..4f7532f4 100644 --- a/src/google/protobuf/compiler/java/java_string_field.h +++ b/src/google/protobuf/compiler/java/java_string_field.h @@ -62,6 +62,7 @@ class StringFieldGenerator : public FieldGenerator { 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; @@ -96,6 +97,7 @@ class RepeatedStringFieldGenerator : public FieldGenerator { void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingCodeFromPacked(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; |