Integrate internal changes

pull/2145/head
Bo Yang 8 years ago
parent b5bbdb0967
commit 98835fb8f8
  1. 16
      conformance/Makefile.am
  2. 8
      conformance/conformance_python.py
  3. 586
      conformance/conformance_test.cc
  4. 52
      conformance/conformance_test.h
  5. 12
      conformance/conformance_test_runner.cc
  6. 83
      conformance/failure_list_cpp.txt
  7. 88
      conformance/failure_list_java.txt
  8. 61
      conformance/failure_list_python.txt
  9. 93
      conformance/failure_list_python_cpp.txt
  10. 14
      java/core/src/main/java/com/google/protobuf/ByteString.java
  11. 3593
      java/core/src/main/java/com/google/protobuf/CodedInputStream.java
  12. 400
      java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
  13. 31
      java/core/src/main/java/com/google/protobuf/Descriptors.java
  14. 481
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  15. 10
      java/core/src/main/java/com/google/protobuf/Internal.java
  16. 16
      java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
  17. 9
      java/core/src/main/java/com/google/protobuf/MapEntry.java
  18. 9
      java/core/src/main/java/com/google/protobuf/NioByteString.java
  19. 1
      java/core/src/main/java/com/google/protobuf/RopeByteString.java
  20. 22
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  21. 3
      java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
  22. 31
      java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
  23. 119
      java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
  24. 4
      java/core/src/main/java/com/google/protobuf/WireFormat.java
  25. 4
      java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
  26. 3
      java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
  27. 3
      java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
  28. 4
      java/core/src/test/java/com/google/protobuf/ByteStringTest.java
  29. 802
      java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
  30. 55
      java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
  31. 4
      java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
  32. 15
      java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
  33. 3
      java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
  34. 4
      java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
  35. 47
      java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
  36. 3
      java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
  37. 4
      java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  38. 3
      java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
  39. 4
      java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
  40. 4
      java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
  41. 4
      java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
  42. 3
      java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
  43. 4
      java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
  44. 9
      java/core/src/test/java/com/google/protobuf/LiteTest.java
  45. 3
      java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
  46. 3
      java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
  47. 4
      java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
  48. 10
      java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
  49. 170
      java/core/src/test/java/com/google/protobuf/MapTest.java
  50. 4
      java/core/src/test/java/com/google/protobuf/MessageTest.java
  51. 4
      java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
  52. 3
      java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
  53. 8
      java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
  54. 4
      java/core/src/test/java/com/google/protobuf/ParserTest.java
  55. 3
      java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
  56. 4
      java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
  57. 8
      java/core/src/test/java/com/google/protobuf/ServiceTest.java
  58. 3
      java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
  59. 11
      java/core/src/test/java/com/google/protobuf/TestUtil.java
  60. 29
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  61. 4
      java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
  62. 4
      java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
  63. 3
      java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
  64. 4
      java/core/src/test/java/com/google/protobuf/WireFormatTest.java
  65. 1
      java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
  66. 37
      java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
  67. 37
      java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
  68. 39
      java/core/src/test/proto/com/google/protobuf/map_test.proto
  69. 1
      java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
  70. 646
      java/src/main/java/com/google/protobuf/AbstractMessage.java
  71. 384
      java/src/main/java/com/google/protobuf/AbstractMessageLite.java
  72. 258
      java/src/main/java/com/google/protobuf/AbstractParser.java
  73. 180
      java/src/main/java/com/google/protobuf/AbstractProtobufList.java
  74. 51
      java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
  75. 64
      java/src/main/java/com/google/protobuf/BlockingService.java
  76. 182
      java/util/src/main/java/com/google/protobuf/util/Durations.java
  77. 15
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  78. 207
      java/util/src/main/java/com/google/protobuf/util/Timestamps.java
  79. 110
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  80. 7
      java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
  81. 1
      java/util/src/test/proto/com/google/protobuf/util/json_test.proto
  82. 2
      js/binary/proto_test.js
  83. 3
      js/debug.js
  84. 2
      js/debug_test.js
  85. 22
      js/map.js
  86. 359
      js/maps_test.js
  87. 154
      js/message.js
  88. 55
      js/message_test.js
  89. 2
      js/proto3_test.js
  90. 6
      objectivec/google/protobuf/Duration.pbobjc.h
  91. 6
      objectivec/google/protobuf/FieldMask.pbobjc.h
  92. 8
      objectivec/google/protobuf/Timestamp.pbobjc.h
  93. 1385
      php/tests/test.pb.php
  94. 36
      php/tests/test_include.pb.php
  95. 49
      python/google/protobuf/descriptor.py
  96. 138
      python/google/protobuf/descriptor_pool.py
  97. 14
      python/google/protobuf/internal/any_test.proto
  98. 21
      python/google/protobuf/internal/containers.py
  99. 5
      python/google/protobuf/internal/descriptor_pool_test.py
  100. 19
      python/google/protobuf/internal/descriptor_test.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -251,31 +251,31 @@ conformance-csharp: $(other_language_protoc_outputs)
# Targets for actually running tests.
test_cpp: protoc_middleman conformance-test-runner conformance-cpp
./conformance-test-runner --failure_list failure_list_cpp.txt ./conformance-cpp
./conformance-test-runner --enforce_recommended --failure_list failure_list_cpp.txt ./conformance-cpp
test_java: protoc_middleman conformance-test-runner conformance-java
./conformance-test-runner --failure_list failure_list_java.txt ./conformance-java
./conformance-test-runner --enforce_recommended --failure_list failure_list_java.txt ./conformance-java
test_java_lite: protoc_middleman conformance-test-runner conformance-java-lite
./conformance-test-runner ./conformance-java-lite
./conformance-test-runner --enforce_recommended ./conformance-java-lite
test_csharp: protoc_middleman conformance-test-runner conformance-csharp
./conformance-test-runner --failure_list failure_list_csharp.txt ./conformance-csharp
./conformance-test-runner --enforce_recommended --failure_list failure_list_csharp.txt ./conformance-csharp
test_ruby: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
RUBYLIB=../ruby/lib:. ./conformance-test-runner --failure_list failure_list_ruby.txt ./conformance_ruby.rb
RUBYLIB=../ruby/lib:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_ruby.txt ./conformance_ruby.rb
# These depend on library paths being properly set up. The easiest way to
# run them is to just use "tox" from the python dir.
test_python: protoc_middleman conformance-test-runner
./conformance-test-runner --failure_list failure_list_python.txt ./conformance_python.py
./conformance-test-runner --enforce_recommended --failure_list failure_list_python.txt ./conformance_python.py
test_python_cpp: protoc_middleman conformance-test-runner
./conformance-test-runner --failure_list failure_list_python_cpp.txt ./conformance_python.py
./conformance-test-runner --enforce_recommended --failure_list failure_list_python_cpp.txt ./conformance_python.py
if OBJC_CONFORMANCE_TEST
test_objc: protoc_middleman conformance-test-runner conformance-objc
./conformance-test-runner --failure_list failure_list_objc.txt ./conformance-objc
./conformance-test-runner --enforce_recomemnded --failure_list failure_list_objc.txt ./conformance-objc
endif

@ -67,7 +67,7 @@ def do_test(request):
elif request.WhichOneof('payload') == 'json_payload':
try:
json_format.Parse(request.json_payload, test_message)
except json_format.ParseError as e:
except Exception as e:
response.parse_error = str(e)
return response
@ -81,7 +81,11 @@ def do_test(request):
response.protobuf_payload = test_message.SerializeToString()
elif request.requested_output_format == conformance_pb2.JSON:
response.json_payload = json_format.MessageToJson(test_message)
try:
response.json_payload = json_format.MessageToJson(test_message)
except Exception as e:
response.serialize_error = str(e)
return response
except Exception as e:
response.runtime_error = str(e)

File diff suppressed because it is too large Load Diff

@ -91,7 +91,7 @@ class ConformanceTestRunner {
//
class ConformanceTestSuite {
public:
ConformanceTestSuite() : verbose_(false) {}
ConformanceTestSuite() : verbose_(false), enforce_recommended_(false) {}
void SetVerbose(bool verbose) { verbose_ = verbose; }
@ -104,6 +104,18 @@ class ConformanceTestSuite {
void SetFailureList(const std::string& filename,
const std::vector<std::string>& failure_list);
// Whether to require the testee to pass RECOMMENDED tests. By default failing
// a RECOMMENDED test case will not fail the entire suite but will only
// generated a warning. If this flag is set to true, RECOMMENDED tests will
// be treated the same way as REQUIRED tests and failing a RECOMMENDED test
// case will cause the entire test suite to fail as well. An implementation
// can enable this if it wants to be strictly conforming to protobuf spec.
// See the comments about ConformanceLevel below to learn more about the
// difference between REQUIRED and RECOMMENDED test cases.
void SetEnforceRecommended(bool value) {
enforce_recommended_ = value;
}
// Run all the conformance tests against the given test runner.
// Test output will be stored in "output".
//
@ -113,8 +125,27 @@ class ConformanceTestSuite {
bool RunSuite(ConformanceTestRunner* runner, std::string* output);
private:
// Test cases are classified into a few categories:
// REQUIRED: the test case must be passed for an implementation to be
// interoperable with other implementations. For example, a
// parser implementaiton must accept both packed and unpacked
// form of repeated primitive fields.
// RECOMMENDED: the test case is not required for the implementation to
// be interoperable with other implementations, but is
// recommended for best performance and compatibility. For
// example, a proto3 serializer should serialize repeated
// primitive fields in packed form, but an implementation
// failing to do so will still be able to communicate with
// other implementations.
enum ConformanceLevel {
REQUIRED = 0,
RECOMMENDED = 1,
};
string ConformanceLevelToString(ConformanceLevel level);
void ReportSuccess(const std::string& test_name);
void ReportFailure(const string& test_name,
ConformanceLevel level,
const conformance::ConformanceRequest& request,
const conformance::ConformanceResponse& response,
const char* fmt, ...);
@ -124,13 +155,18 @@ class ConformanceTestSuite {
void RunTest(const std::string& test_name,
const conformance::ConformanceRequest& request,
conformance::ConformanceResponse* response);
void RunValidInputTest(const string& test_name, const string& input,
void RunValidInputTest(const string& test_name,
ConformanceLevel level,
const string& input,
conformance::WireFormat input_format,
const string& equivalent_text_format,
conformance::WireFormat requested_output);
void RunValidJsonTest(const string& test_name, const string& input_json,
void RunValidJsonTest(const string& test_name,
ConformanceLevel level,
const string& input_json,
const string& equivalent_text_format);
void RunValidJsonTestWithProtobufInput(const string& test_name,
ConformanceLevel level,
const conformance::TestAllTypes& input,
const string& equivalent_text_format);
void RunValidProtobufTest(const string& test_name,
@ -139,16 +175,21 @@ class ConformanceTestSuite {
typedef std::function<bool(const Json::Value&)> Validator;
void RunValidJsonTestWithValidator(const string& test_name,
ConformanceLevel level,
const string& input_json,
const Validator& validator);
void ExpectParseFailureForJson(const string& test_name,
ConformanceLevel level,
const string& input_json);
void ExpectSerializeFailureForJson(const string& test_name,
ConformanceLevel level,
const string& text_format);
void ExpectParseFailureForProto(const std::string& proto,
const std::string& test_name);
const std::string& test_name,
ConformanceLevel level);
void ExpectHardParseFailureForProto(const std::string& proto,
const std::string& test_name);
const std::string& test_name,
ConformanceLevel level);
void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type);
bool CheckSetEmpty(const set<string>& set_to_check,
const std::string& write_to_file, const std::string& msg);
@ -156,6 +197,7 @@ class ConformanceTestSuite {
int successes_;
int expected_failures_;
bool verbose_;
bool enforce_recommended_;
std::string output_;
std::string failure_list_filename_;

@ -251,6 +251,16 @@ void UsageError() {
" should contain one test name per\n");
fprintf(stderr,
" line. Use '#' for comments.\n");
fprintf(stderr,
" --enforce_recommended Enforce that recommended test\n");
fprintf(stderr,
" cases are also passing. Specify\n");
fprintf(stderr,
" this flag if you want to be\n");
fprintf(stderr,
" strictly conforming to protobuf\n");
fprintf(stderr,
" spec.\n");
exit(1);
}
@ -290,6 +300,8 @@ int main(int argc, char *argv[]) {
ParseFailureList(argv[arg], &failure_list);
} else if (strcmp(argv[arg], "--verbose") == 0) {
suite.SetVerbose(true);
} else if (strcmp(argv[arg], "--enforce_recommended") == 0) {
suite.SetEnforceRecommended(true);
} else if (argv[arg][0] == '-') {
fprintf(stderr, "Unknown option: %s\n", argv[arg]);
UsageError();

@ -7,48 +7,41 @@
# TODO(haberman): insert links to corresponding bugs tracking the issue.
# Should we use GitHub issues or the Google-internal bug tracker?
FieldMaskNumbersDontRoundTrip.JsonOutput
FieldMaskPathsDontRoundTrip.JsonOutput
FieldMaskTooManyUnderscore.JsonOutput
JsonInput.AnyUnorderedTypeTag.JsonOutput
JsonInput.AnyUnorderedTypeTag.ProtobufOutput
JsonInput.BoolFieldDoubleQuotedFalse
JsonInput.BoolFieldDoubleQuotedTrue
JsonInput.BytesFieldNoPadding
JsonInput.DoubleFieldTooSmall
JsonInput.DurationHasZeroFractionalDigit.Validator
JsonInput.EnumFieldUnknownValue.Validator
JsonInput.FieldMaskInvalidCharacter
JsonInput.FieldNameDuplicate
JsonInput.FieldNameDuplicateDifferentCasing1
JsonInput.FieldNameDuplicateDifferentCasing2
JsonInput.FieldNameNotQuoted
JsonInput.MapFieldValueIsNull
JsonInput.RepeatedFieldMessageElementIsNull
JsonInput.RepeatedFieldPrimitiveElementIsNull
JsonInput.RepeatedFieldTrailingComma
JsonInput.RepeatedFieldTrailingCommaWithNewlines
JsonInput.RepeatedFieldTrailingCommaWithSpace
JsonInput.RepeatedFieldTrailingCommaWithSpaceCommaSpace
JsonInput.StringFieldSingleQuoteBoth
JsonInput.StringFieldSingleQuoteKey
JsonInput.StringFieldSingleQuoteValue
JsonInput.StringFieldUppercaseEscapeLetter
JsonInput.TrailingCommaInAnObject
JsonInput.TrailingCommaInAnObjectWithNewlines
JsonInput.TrailingCommaInAnObjectWithSpace
JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
JsonInput.WrapperTypesWithNullValue.JsonOutput
JsonInput.WrapperTypesWithNullValue.ProtobufOutput
ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
ProtobufInput.PrematureEofInPackedField.BOOL
ProtobufInput.PrematureEofInPackedField.ENUM
ProtobufInput.PrematureEofInPackedField.INT32
ProtobufInput.PrematureEofInPackedField.INT64
ProtobufInput.PrematureEofInPackedField.SINT32
ProtobufInput.PrematureEofInPackedField.SINT64
ProtobufInput.PrematureEofInPackedField.UINT32
ProtobufInput.PrematureEofInPackedField.UINT64
ProtobufInput.PrematureEofInsideKnownRepeatedValue.MESSAGE
Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
Recommended.FieldMaskTooManyUnderscore.JsonOutput
Recommended.JsonInput.BoolFieldDoubleQuotedFalse
Recommended.JsonInput.BoolFieldDoubleQuotedTrue
Recommended.JsonInput.FieldMaskInvalidCharacter
Recommended.JsonInput.FieldNameDuplicate
Recommended.JsonInput.FieldNameDuplicateDifferentCasing1
Recommended.JsonInput.FieldNameDuplicateDifferentCasing2
Recommended.JsonInput.FieldNameNotQuoted
Recommended.JsonInput.MapFieldValueIsNull
Recommended.JsonInput.RepeatedFieldMessageElementIsNull
Recommended.JsonInput.RepeatedFieldPrimitiveElementIsNull
Recommended.JsonInput.RepeatedFieldTrailingComma
Recommended.JsonInput.RepeatedFieldTrailingCommaWithNewlines
Recommended.JsonInput.RepeatedFieldTrailingCommaWithSpace
Recommended.JsonInput.RepeatedFieldTrailingCommaWithSpaceCommaSpace
Recommended.JsonInput.StringFieldSingleQuoteBoth
Recommended.JsonInput.StringFieldSingleQuoteKey
Recommended.JsonInput.StringFieldSingleQuoteValue
Recommended.JsonInput.StringFieldUppercaseEscapeLetter
Recommended.JsonInput.TrailingCommaInAnObject
Recommended.JsonInput.TrailingCommaInAnObjectWithNewlines
Recommended.JsonInput.TrailingCommaInAnObjectWithSpace
Recommended.JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
Required.JsonInput.DoubleFieldTooSmall
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInPackedField.BOOL
Required.ProtobufInput.PrematureEofInPackedField.ENUM
Required.ProtobufInput.PrematureEofInPackedField.INT32
Required.ProtobufInput.PrematureEofInPackedField.INT64
Required.ProtobufInput.PrematureEofInPackedField.SINT32
Required.ProtobufInput.PrematureEofInPackedField.SINT64
Required.ProtobufInput.PrematureEofInPackedField.UINT32
Required.ProtobufInput.PrematureEofInPackedField.UINT64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.MESSAGE

@ -4,48 +4,46 @@
# By listing them here we can keep tabs on which ones are failing and be sure
# that we don't introduce regressions in other tests.
FieldMaskNumbersDontRoundTrip.JsonOutput
FieldMaskPathsDontRoundTrip.JsonOutput
FieldMaskTooManyUnderscore.JsonOutput
JsonInput.BoolFieldAllCapitalFalse
JsonInput.BoolFieldAllCapitalTrue
JsonInput.BoolFieldCamelCaseFalse
JsonInput.BoolFieldCamelCaseTrue
JsonInput.BoolFieldDoubleQuotedFalse
JsonInput.BoolFieldDoubleQuotedTrue
JsonInput.BoolMapFieldKeyNotQuoted
JsonInput.DoubleFieldInfinityNotQuoted
JsonInput.DoubleFieldNanNotQuoted
JsonInput.DoubleFieldNegativeInfinityNotQuoted
JsonInput.EnumFieldNotQuoted
JsonInput.FieldMaskInvalidCharacter
JsonInput.FieldNameDuplicate
JsonInput.FieldNameInLowerCamelCase.Validator
JsonInput.FieldNameInSnakeCase.JsonOutput
JsonInput.FieldNameInSnakeCase.ProtobufOutput
JsonInput.FieldNameNotQuoted
JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
JsonInput.FieldNameWithDoubleUnderscores.Validator
JsonInput.FloatFieldInfinityNotQuoted
JsonInput.FloatFieldNanNotQuoted
JsonInput.FloatFieldNegativeInfinityNotQuoted
JsonInput.Int32FieldLeadingZero
JsonInput.Int32FieldNegativeWithLeadingZero
JsonInput.Int32FieldPlusSign
JsonInput.Int32MapFieldKeyNotQuoted
JsonInput.Int64MapFieldKeyNotQuoted
JsonInput.JsonWithComments
JsonInput.OriginalProtoFieldName.JsonOutput
JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
JsonInput.StringFieldNotAString
JsonInput.StringFieldSingleQuoteBoth
JsonInput.StringFieldSingleQuoteKey
JsonInput.StringFieldSingleQuoteValue
JsonInput.StringFieldSurrogateInWrongOrder
JsonInput.StringFieldUnpairedHighSurrogate
JsonInput.StringFieldUnpairedLowSurrogate
JsonInput.StringFieldUppercaseEscapeLetter
JsonInput.Uint32MapFieldKeyNotQuoted
JsonInput.Uint64MapFieldKeyNotQuoted
Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
Recommended.FieldMaskTooManyUnderscore.JsonOutput
Recommended.JsonInput.BoolFieldAllCapitalFalse
Recommended.JsonInput.BoolFieldAllCapitalTrue
Recommended.JsonInput.BoolFieldCamelCaseFalse
Recommended.JsonInput.BoolFieldCamelCaseTrue
Recommended.JsonInput.BoolFieldDoubleQuotedFalse
Recommended.JsonInput.BoolFieldDoubleQuotedTrue
Recommended.JsonInput.BoolMapFieldKeyNotQuoted
Recommended.JsonInput.DoubleFieldInfinityNotQuoted
Recommended.JsonInput.DoubleFieldNanNotQuoted
Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted
Recommended.JsonInput.FieldMaskInvalidCharacter
Recommended.JsonInput.FieldNameDuplicate
Recommended.JsonInput.FieldNameInLowerCamelCase.Validator
Recommended.JsonInput.FieldNameInSnakeCase.ProtobufOutput
Recommended.JsonInput.FieldNameNotQuoted
Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
Recommended.JsonInput.FloatFieldInfinityNotQuoted
Recommended.JsonInput.FloatFieldNanNotQuoted
Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
Recommended.JsonInput.Int32MapFieldKeyNotQuoted
Recommended.JsonInput.Int64MapFieldKeyNotQuoted
Recommended.JsonInput.JsonWithComments
Recommended.JsonInput.StringFieldSingleQuoteBoth
Recommended.JsonInput.StringFieldSingleQuoteKey
Recommended.JsonInput.StringFieldSingleQuoteValue
Recommended.JsonInput.StringFieldSurrogateInWrongOrder
Recommended.JsonInput.StringFieldUnpairedHighSurrogate
Recommended.JsonInput.StringFieldUnpairedLowSurrogate
Recommended.JsonInput.StringFieldUppercaseEscapeLetter
Recommended.JsonInput.Uint32MapFieldKeyNotQuoted
Recommended.JsonInput.Uint64MapFieldKeyNotQuoted
Required.JsonInput.EnumFieldNotQuoted
Required.JsonInput.Int32FieldLeadingZero
Required.JsonInput.Int32FieldNegativeWithLeadingZero
Required.JsonInput.Int32FieldPlusSign
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
Required.JsonInput.StringFieldNotAString

@ -1,46 +1,15 @@
DurationProtoInputTooLarge.JsonOutput
DurationProtoInputTooSmall.JsonOutput
FieldMaskNumbersDontRoundTrip.JsonOutput
FieldMaskPathsDontRoundTrip.JsonOutput
FieldMaskTooManyUnderscore.JsonOutput
JsonInput.AnyWithFieldMask.ProtobufOutput
JsonInput.BytesFieldInvalidBase64Characters
JsonInput.DoubleFieldInfinityNotQuoted
JsonInput.DoubleFieldNanNotQuoted
JsonInput.DoubleFieldNegativeInfinityNotQuoted
JsonInput.DoubleFieldTooSmall
JsonInput.DurationJsonInputTooLarge
JsonInput.DurationJsonInputTooSmall
JsonInput.DurationMissingS
JsonInput.EnumFieldNumericValueNonZero.JsonOutput
JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
JsonInput.EnumFieldNumericValueZero.JsonOutput
JsonInput.EnumFieldNumericValueZero.ProtobufOutput
JsonInput.EnumFieldUnknownValue.Validator
JsonInput.FieldMask.ProtobufOutput
JsonInput.FieldMaskInvalidCharacter
JsonInput.FloatFieldInfinityNotQuoted
JsonInput.FloatFieldNanNotQuoted
JsonInput.FloatFieldNegativeInfinityNotQuoted
JsonInput.FloatFieldTooLarge
JsonInput.FloatFieldTooSmall
JsonInput.Int32FieldExponentialFormat.JsonOutput
JsonInput.Int32FieldExponentialFormat.ProtobufOutput
JsonInput.Int32FieldFloatTrailingZero.JsonOutput
JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
JsonInput.Int32FieldMaxFloatValue.JsonOutput
JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
JsonInput.Int32FieldMinFloatValue.JsonOutput
JsonInput.Int32FieldMinFloatValue.ProtobufOutput
JsonInput.OneofZeroMessage.JsonOutput
JsonInput.OneofZeroMessage.ProtobufOutput
JsonInput.OriginalProtoFieldName.JsonOutput
JsonInput.OriginalProtoFieldName.ProtobufOutput
JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
JsonInput.TimestampJsonInputLowercaseT
JsonInput.Uint32FieldMaxFloatValue.JsonOutput
JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
JsonInput.ValueAcceptNull.JsonOutput
JsonInput.ValueAcceptNull.ProtobufOutput
TimestampProtoInputTooLarge.JsonOutput
TimestampProtoInputTooSmall.JsonOutput
Recommended.JsonInput.DoubleFieldInfinityNotQuoted
Recommended.JsonInput.DoubleFieldNanNotQuoted
Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted
Recommended.JsonInput.FloatFieldInfinityNotQuoted
Recommended.JsonInput.FloatFieldNanNotQuoted
Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
Recommended.JsonInput.OneofZeroMessage.JsonOutput
Recommended.JsonInput.OneofZeroMessage.ProtobufOutput
Required.JsonInput.BytesFieldInvalidBase64Characters
Required.JsonInput.DoubleFieldTooSmall
Required.JsonInput.EnumFieldUnknownValue.Validator
Required.JsonInput.FloatFieldTooLarge
Required.JsonInput.FloatFieldTooSmall
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
Required.JsonInput.TimestampJsonInputLowercaseT

@ -7,65 +7,34 @@
# TODO(haberman): insert links to corresponding bugs tracking the issue.
# Should we use GitHub issues or the Google-internal bug tracker?
DurationProtoInputTooLarge.JsonOutput
DurationProtoInputTooSmall.JsonOutput
FieldMaskNumbersDontRoundTrip.JsonOutput
FieldMaskPathsDontRoundTrip.JsonOutput
FieldMaskTooManyUnderscore.JsonOutput
JsonInput.AnyWithFieldMask.ProtobufOutput
JsonInput.BytesFieldInvalidBase64Characters
JsonInput.DoubleFieldInfinityNotQuoted
JsonInput.DoubleFieldNanNotQuoted
JsonInput.DoubleFieldNegativeInfinityNotQuoted
JsonInput.DoubleFieldTooSmall
JsonInput.DurationJsonInputTooLarge
JsonInput.DurationJsonInputTooSmall
JsonInput.DurationMissingS
JsonInput.EnumFieldNumericValueNonZero.JsonOutput
JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
JsonInput.EnumFieldNumericValueZero.JsonOutput
JsonInput.EnumFieldNumericValueZero.ProtobufOutput
JsonInput.EnumFieldUnknownValue.Validator
JsonInput.FieldMask.ProtobufOutput
JsonInput.FieldMaskInvalidCharacter
JsonInput.FloatFieldInfinityNotQuoted
JsonInput.FloatFieldNanNotQuoted
JsonInput.FloatFieldNegativeInfinityNotQuoted
JsonInput.FloatFieldTooLarge
JsonInput.FloatFieldTooSmall
JsonInput.Int32FieldExponentialFormat.JsonOutput
JsonInput.Int32FieldExponentialFormat.ProtobufOutput
JsonInput.Int32FieldFloatTrailingZero.JsonOutput
JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
JsonInput.Int32FieldMaxFloatValue.JsonOutput
JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
JsonInput.Int32FieldMinFloatValue.JsonOutput
JsonInput.Int32FieldMinFloatValue.ProtobufOutput
JsonInput.OneofZeroMessage.JsonOutput
JsonInput.OneofZeroMessage.ProtobufOutput
JsonInput.OriginalProtoFieldName.JsonOutput
JsonInput.OriginalProtoFieldName.ProtobufOutput
JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
JsonInput.TimestampJsonInputLowercaseT
JsonInput.Uint32FieldMaxFloatValue.JsonOutput
JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
JsonInput.ValueAcceptNull.JsonOutput
JsonInput.ValueAcceptNull.ProtobufOutput
ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
ProtobufInput.PrematureEofInPackedField.BOOL
ProtobufInput.PrematureEofInPackedField.DOUBLE
ProtobufInput.PrematureEofInPackedField.ENUM
ProtobufInput.PrematureEofInPackedField.FIXED32
ProtobufInput.PrematureEofInPackedField.FIXED64
ProtobufInput.PrematureEofInPackedField.FLOAT
ProtobufInput.PrematureEofInPackedField.INT32
ProtobufInput.PrematureEofInPackedField.INT64
ProtobufInput.PrematureEofInPackedField.SFIXED32
ProtobufInput.PrematureEofInPackedField.SFIXED64
ProtobufInput.PrematureEofInPackedField.SINT32
ProtobufInput.PrematureEofInPackedField.SINT64
ProtobufInput.PrematureEofInPackedField.UINT32
ProtobufInput.PrematureEofInPackedField.UINT64
TimestampProtoInputTooLarge.JsonOutput
TimestampProtoInputTooSmall.JsonOutput
Recommended.JsonInput.DoubleFieldInfinityNotQuoted
Recommended.JsonInput.DoubleFieldNanNotQuoted
Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted
Recommended.JsonInput.FloatFieldInfinityNotQuoted
Recommended.JsonInput.FloatFieldNanNotQuoted
Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
Recommended.JsonInput.OneofZeroMessage.JsonOutput
Recommended.JsonInput.OneofZeroMessage.ProtobufOutput
Required.JsonInput.BytesFieldInvalidBase64Characters
Required.JsonInput.DoubleFieldTooSmall
Required.JsonInput.EnumFieldUnknownValue.Validator
Required.JsonInput.FloatFieldTooLarge
Required.JsonInput.FloatFieldTooSmall
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
Required.JsonInput.TimestampJsonInputLowercaseT
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInPackedField.BOOL
Required.ProtobufInput.PrematureEofInPackedField.DOUBLE
Required.ProtobufInput.PrematureEofInPackedField.ENUM
Required.ProtobufInput.PrematureEofInPackedField.FIXED32
Required.ProtobufInput.PrematureEofInPackedField.FIXED64
Required.ProtobufInput.PrematureEofInPackedField.FLOAT
Required.ProtobufInput.PrematureEofInPackedField.INT32
Required.ProtobufInput.PrematureEofInPackedField.INT64
Required.ProtobufInput.PrematureEofInPackedField.SFIXED32
Required.ProtobufInput.PrematureEofInPackedField.SFIXED64
Required.ProtobufInput.PrematureEofInPackedField.SINT32
Required.ProtobufInput.PrematureEofInPackedField.SINT64
Required.ProtobufInput.PrematureEofInPackedField.UINT32
Required.ProtobufInput.PrematureEofInPackedField.UINT64

@ -310,6 +310,18 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
return copyFrom(bytes, 0, bytes.length);
}
/**
* Wraps the given bytes into a {@code ByteString}. Intended for internal only usage.
*/
static ByteString wrap(ByteBuffer buffer) {
if (buffer.hasArray()) {
final int offset = buffer.arrayOffset();
return ByteString.wrap(buffer.array(), offset + buffer.position(), buffer.remaining());
} else {
return new NioByteString(buffer);
}
}
/**
* Wraps the given bytes into a {@code ByteString}. Intended for internal only
* usage to force a classload of ByteString before LiteralByteString.
@ -679,6 +691,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
*/
abstract void writeTo(ByteOutput byteOutput) throws IOException;
/**
* Constructs a read-only {@code java.nio.ByteBuffer} whose content
* is equal to the contents of this byte string.
@ -820,6 +833,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
return true;
}
/**
* Check equality of the substring of given length of this object starting at
* zero with another {@code ByteString} substring starting at offset.

@ -30,10 +30,12 @@
package com.google.protobuf;
import static com.google.protobuf.WireFormat.FIXED_32_SIZE;
import static com.google.protobuf.WireFormat.FIXED_64_SIZE;
import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
import static java.lang.Math.max;
import com.google.protobuf.Utf8.UnpairedSurrogateException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
@ -59,10 +61,6 @@ public abstract class CodedOutputStream extends ByteOutput {
private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations();
private static final long ARRAY_BASE_OFFSET = UnsafeUtil.getArrayBaseOffset();
private static final int FIXED_32_SIZE = 4;
private static final int FIXED_64_SIZE = 8;
private static final int MAX_VARINT_SIZE = 10;
/**
* @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
*/
@ -134,14 +132,27 @@ public abstract class CodedOutputStream extends ByteOutput {
return new ArrayEncoder(flatArray, offset, length);
}
/**
* Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
*/
public static CodedOutputStream newInstance(ByteBuffer byteBuffer) {
if (byteBuffer.hasArray()) {
return new NioHeapEncoder(byteBuffer);
/** Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}. */
public static CodedOutputStream newInstance(ByteBuffer buffer) {
if (buffer.hasArray()) {
return new HeapNioEncoder(buffer);
}
return new NioEncoder(byteBuffer);
if (buffer.isDirect() && !buffer.isReadOnly()) {
return UnsafeDirectNioEncoder.isSupported()
? newUnsafeInstance(buffer)
: newSafeInstance(buffer);
}
throw new IllegalArgumentException("ByteBuffer is read-only");
}
/** For testing purposes only. */
static CodedOutputStream newUnsafeInstance(ByteBuffer buffer) {
return new UnsafeDirectNioEncoder(buffer);
}
/** For testing purposes only. */
static CodedOutputStream newSafeInstance(ByteBuffer buffer) {
return new SafeDirectNioEncoder(buffer);
}
/**
@ -979,6 +990,10 @@ public abstract class CodedOutputStream extends ByteOutput {
super(MESSAGE);
}
OutOfSpaceException(String explanationMessage) {
super(MESSAGE + ": " + explanationMessage);
}
OutOfSpaceException(Throwable cause) {
super(MESSAGE, cause);
}
@ -1486,11 +1501,11 @@ public abstract class CodedOutputStream extends ByteOutput {
* A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are
* done directly to the underlying array. The buffer position is only updated after a flush.
*/
private static final class NioHeapEncoder extends ArrayEncoder {
private static final class HeapNioEncoder extends ArrayEncoder {
private final ByteBuffer byteBuffer;
private int initialPosition;
NioHeapEncoder(ByteBuffer byteBuffer) {
HeapNioEncoder(ByteBuffer byteBuffer) {
super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(),
byteBuffer.remaining());
this.byteBuffer = byteBuffer;
@ -1505,14 +1520,15 @@ public abstract class CodedOutputStream extends ByteOutput {
}
/**
* A {@link CodedOutputStream} that writes directly to a {@link ByteBuffer}.
* A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuffer}, using only
* safe operations..
*/
private static final class NioEncoder extends CodedOutputStream {
private static final class SafeDirectNioEncoder extends CodedOutputStream {
private final ByteBuffer originalBuffer;
private final ByteBuffer buffer;
private final int initialPosition;
NioEncoder(ByteBuffer buffer) {
SafeDirectNioEncoder(ByteBuffer buffer) {
this.originalBuffer = buffer;
this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
initialPosition = buffer.position();
@ -1814,6 +1830,356 @@ public abstract class CodedOutputStream extends ByteOutput {
}
}
/**
* A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuffer} using {@code
* sun.misc.Unsafe}.
*/
private static final class UnsafeDirectNioEncoder extends CodedOutputStream {
private final ByteBuffer originalBuffer;
private final ByteBuffer buffer;
private final long address;
private final long initialPosition;
private final long limit;
private final long oneVarintLimit;
private long position;
UnsafeDirectNioEncoder(ByteBuffer buffer) {
this.originalBuffer = buffer;
this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
address = UnsafeUtil.addressOffset(buffer);
initialPosition = address + buffer.position();
limit = address + buffer.limit();
oneVarintLimit = limit - MAX_VARINT_SIZE;
position = initialPosition;
}
static boolean isSupported() {
return UnsafeUtil.hasUnsafeByteBufferOperations();
}
@Override
public void writeTag(int fieldNumber, int wireType) throws IOException {
writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
}
@Override
public void writeInt32(int fieldNumber, int value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeInt32NoTag(value);
}
@Override
public void writeUInt32(int fieldNumber, int value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeUInt32NoTag(value);
}
@Override
public void writeFixed32(int fieldNumber, int value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
writeFixed32NoTag(value);
}
@Override
public void writeUInt64(int fieldNumber, long value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeUInt64NoTag(value);
}
@Override
public void writeFixed64(int fieldNumber, long value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
writeFixed64NoTag(value);
}
@Override
public void writeBool(int fieldNumber, boolean value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
write((byte) (value ? 1 : 0));
}
@Override
public void writeString(int fieldNumber, String value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
writeStringNoTag(value);
}
@Override
public void writeBytes(int fieldNumber, ByteString value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
writeBytesNoTag(value);
}
@Override
public void writeByteArray(int fieldNumber, byte[] value) throws IOException {
writeByteArray(fieldNumber, value, 0, value.length);
}
@Override
public void writeByteArray(int fieldNumber, byte[] value, int offset, int length)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
writeByteArrayNoTag(value, offset, length);
}
@Override
public void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
writeUInt32NoTag(value.capacity());
writeRawBytes(value);
}
@Override
public void writeMessage(int fieldNumber, MessageLite value) throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
writeMessageNoTag(value);
}
@Override
public void writeMessageSetExtension(int fieldNumber, MessageLite value) throws IOException {
writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
}
@Override
public void writeRawMessageSetExtension(int fieldNumber, ByteString value) throws IOException {
writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
}
@Override
public void writeMessageNoTag(MessageLite value) throws IOException {
writeUInt32NoTag(value.getSerializedSize());
value.writeTo(this);
}
@Override
public void write(byte value) throws IOException {
if (position >= limit) {
throw new OutOfSpaceException(
String.format("Pos: %d, limit: %d, len: %d", position, limit, 1));
}
UnsafeUtil.putByte(position++, value);
}
@Override
public void writeBytesNoTag(ByteString value) throws IOException {
writeUInt32NoTag(value.size());
value.writeTo(this);
}
@Override
public void writeByteArrayNoTag(byte[] value, int offset, int length) throws IOException {
writeUInt32NoTag(length);
write(value, offset, length);
}
@Override
public void writeRawBytes(ByteBuffer value) throws IOException {
if (value.hasArray()) {
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
duplicated.clear();
write(duplicated);
}
}
@Override
public void writeInt32NoTag(int value) throws IOException {
if (value >= 0) {
writeUInt32NoTag(value);
} else {
// Must sign-extend.
writeUInt64NoTag(value);
}
}
@Override
public void writeUInt32NoTag(int value) throws IOException {
if (position <= oneVarintLimit) {
// Optimization to avoid bounds checks on each iteration.
while (true) {
if ((value & ~0x7F) == 0) {
UnsafeUtil.putByte(position++, (byte) value);
return;
} else {
UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80));
value >>>= 7;
}
}
} else {
while (position < limit) {
if ((value & ~0x7F) == 0) {
UnsafeUtil.putByte(position++, (byte) value);
return;
} else {
UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80));
value >>>= 7;
}
}
throw new OutOfSpaceException(
String.format("Pos: %d, limit: %d, len: %d", position, limit, 1));
}
}
@Override
public void writeFixed32NoTag(int value) throws IOException {
buffer.putInt(bufferPos(position), value);
position += FIXED_32_SIZE;
}
@Override
public void writeUInt64NoTag(long value) throws IOException {
if (position <= oneVarintLimit) {
// Optimization to avoid bounds checks on each iteration.
while (true) {
if ((value & ~0x7FL) == 0) {
UnsafeUtil.putByte(position++, (byte) value);
return;
} else {
UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80));
value >>>= 7;
}
}
} else {
while (position < limit) {
if ((value & ~0x7FL) == 0) {
UnsafeUtil.putByte(position++, (byte) value);
return;
} else {
UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80));
value >>>= 7;
}
}
throw new OutOfSpaceException(
String.format("Pos: %d, limit: %d, len: %d", position, limit, 1));
}
}
@Override
public void writeFixed64NoTag(long value) throws IOException {
buffer.putLong(bufferPos(position), value);
position += FIXED_64_SIZE;
}
@Override
public void write(byte[] value, int offset, int length) throws IOException {
if (value == null
|| offset < 0
|| length < 0
|| (value.length - length) < offset
|| (limit - length) < position) {
if (value == null) {
throw new NullPointerException("value");
}
throw new OutOfSpaceException(
String.format("Pos: %d, limit: %d, len: %d", position, limit, length));
}
UnsafeUtil.copyMemory(
value, UnsafeUtil.getArrayBaseOffset() + offset, null, position, length);
position += length;
}
@Override
public void writeLazy(byte[] value, int offset, int length) throws IOException {
write(value, offset, length);
}
@Override
public void write(ByteBuffer value) throws IOException {
try {
int length = value.remaining();
repositionBuffer(position);
buffer.put(value);
position += length;
} catch (BufferOverflowException e) {
throw new OutOfSpaceException(e);
}
}
@Override
public void writeLazy(ByteBuffer value) throws IOException {
write(value);
}
@Override
public void writeStringNoTag(String value) throws IOException {
long prevPos = position;
try {
// UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
// and at most 3 times of it. We take advantage of this in both branches below.
int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR;
int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize);
int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
if (minLengthVarIntSize == maxLengthVarIntSize) {
// Save the current position and increment past the length field. We'll come back
// and write the length field after the encoding is complete.
int stringStart = bufferPos(position) + minLengthVarIntSize;
buffer.position(stringStart);
// Encode the string.
Utf8.encodeUtf8(value, buffer);
// Write the length and advance the position.
int length = buffer.position() - stringStart;
writeUInt32NoTag(length);
position += length;
} else {
// Calculate and write the encoded length.
int length = Utf8.encodedLength(value);
writeUInt32NoTag(length);
// Write the string and advance the position.
repositionBuffer(position);
Utf8.encodeUtf8(value, buffer);
position += length;
}
} catch (UnpairedSurrogateException e) {
// Roll back the change and convert to an IOException.
position = prevPos;
repositionBuffer(position);
// TODO(nathanmittler): We should throw an IOException here instead.
inefficientWriteStringNoTag(value, e);
} catch (IllegalArgumentException e) {
// Thrown by buffer.position() if out of range.
throw new OutOfSpaceException(e);
} catch (IndexOutOfBoundsException e) {
throw new OutOfSpaceException(e);
}
}
@Override
public void flush() {
// Update the position of the original buffer.
originalBuffer.position(bufferPos(position));
}
@Override
public int spaceLeft() {
return (int) (limit - position);
}
@Override
public int getTotalBytesWritten() {
return (int) (position - initialPosition);
}
private void repositionBuffer(long pos) {
buffer.position(bufferPos(pos));
}
private int bufferPos(long pos) {
return (int) (pos - address);
}
}
/**
* Abstract base class for buffered encoders.
*/

@ -1212,33 +1212,20 @@ public final class Descriptors {
private final Object defaultDefault;
}
// TODO(xiaofeng): Implement it consistently across different languages. See b/24751348.
private static String fieldNameToLowerCamelCase(String name) {
// This method should match exactly with the ToJsonName() function in C++
// descriptor.cc.
private static String fieldNameToJsonName(String name) {
StringBuilder result = new StringBuilder(name.length());
boolean isNextUpperCase = false;
for (int i = 0; i < name.length(); i++) {
Character ch = name.charAt(i);
if (Character.isLowerCase(ch)) {
if (isNextUpperCase) {
result.append(Character.toUpperCase(ch));
} else {
result.append(ch);
}
isNextUpperCase = false;
} else if (Character.isUpperCase(ch)) {
if (i == 0) {
// Force first letter to lower-case.
result.append(Character.toLowerCase(ch));
} else {
// Capital letters after the first are left as-is.
result.append(ch);
}
isNextUpperCase = false;
} else if (Character.isDigit(ch)) {
result.append(ch);
if (ch == '_') {
isNextUpperCase = true;
} else if (isNextUpperCase) {
result.append(Character.toUpperCase(ch));
isNextUpperCase = false;
} else {
isNextUpperCase = true;
result.append(ch);
}
}
return result.toString();
@ -1257,7 +1244,7 @@ public final class Descriptors {
if (proto.hasJsonName()) {
jsonName = proto.getJsonName();
} else {
jsonName = fieldNameToLowerCamelCase(proto.getName());
jsonName = fieldNameToJsonName(proto.getName());
}
if (proto.hasType()) {

@ -36,7 +36,6 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.GeneratedMessage.GeneratedExtension;
import java.io.IOException;
import java.io.InputStream;
@ -45,6 +44,7 @@ import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@ -1609,6 +1609,43 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
FieldDescriptor getDescriptor();
}
/** For use by generated code only. */
public static <ContainingType extends Message, Type>
GeneratedExtension<ContainingType, Type>
newMessageScopedGeneratedExtension(final Message scope,
final int descriptorIndex,
final Class singularType,
final Message defaultInstance) {
// For extensions scoped within a Message, we use the Message to resolve
// the outer class's descriptor, from which the extension descriptor is
// obtained.
return new GeneratedExtension<ContainingType, Type>(
new CachedDescriptorRetriever() {
@Override
public FieldDescriptor loadDescriptor() {
return scope.getDescriptorForType().getExtensions().get(descriptorIndex);
}
},
singularType,
defaultInstance,
Extension.ExtensionType.IMMUTABLE);
}
/** For use by generated code only. */
public static <ContainingType extends Message, Type>
GeneratedExtension<ContainingType, Type>
newFileScopedGeneratedExtension(final Class singularType,
final Message defaultInstance) {
// For extensions scoped within a file, we rely on the outer class's
// static initializer to call internalInit() on the extension when the
// descriptor is available.
return new GeneratedExtension<ContainingType, Type>(
null, // ExtensionDescriptorRetriever is initialized in internalInit();
singularType,
defaultInstance,
Extension.ExtensionType.IMMUTABLE);
}
private abstract static class CachedDescriptorRetriever
implements ExtensionDescriptorRetriever {
private volatile FieldDescriptor descriptor;
@ -1627,6 +1664,301 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
}
}
/**
* Used in proto1 generated code only.
*
* After enabling bridge, we can define proto2 extensions (the extended type
* is a proto2 mutable message) in a proto1 .proto file. For these extensions
* we should generate proto2 GeneratedExtensions.
*/
public static <ContainingType extends Message, Type>
GeneratedExtension<ContainingType, Type>
newMessageScopedGeneratedExtension(
final Message scope, final String name,
final Class singularType, final Message defaultInstance) {
// For extensions scoped within a Message, we use the Message to resolve
// the outer class's descriptor, from which the extension descriptor is
// obtained.
return new GeneratedExtension<ContainingType, Type>(
new CachedDescriptorRetriever() {
@Override
protected FieldDescriptor loadDescriptor() {
return scope.getDescriptorForType().findFieldByName(name);
}
},
singularType,
defaultInstance,
Extension.ExtensionType.MUTABLE);
}
/**
* Used in proto1 generated code only.
*
* After enabling bridge, we can define proto2 extensions (the extended type
* is a proto2 mutable message) in a proto1 .proto file. For these extensions
* we should generate proto2 GeneratedExtensions.
*/
public static <ContainingType extends Message, Type>
GeneratedExtension<ContainingType, Type>
newFileScopedGeneratedExtension(
final Class singularType, final Message defaultInstance,
final String descriptorOuterClass, final String extensionName) {
// For extensions scoped within a file, we load the descriptor outer
// class and rely on it to get the FileDescriptor which then can be
// used to obtain the extension's FieldDescriptor.
return new GeneratedExtension<ContainingType, Type>(
new CachedDescriptorRetriever() {
@Override
protected FieldDescriptor loadDescriptor() {
try {
Class clazz = singularType.getClassLoader().loadClass(descriptorOuterClass);
FileDescriptor file = (FileDescriptor) clazz.getField("descriptor").get(null);
return file.findExtensionByName(extensionName);
} catch (Exception e) {
throw new RuntimeException(
"Cannot load descriptors: "
+ descriptorOuterClass
+ " is not a valid descriptor class name",
e);
}
}
},
singularType,
defaultInstance,
Extension.ExtensionType.MUTABLE);
}
/**
* Type used to represent generated extensions. The protocol compiler
* generates a static singleton instance of this class for each extension.
*
* <p>For example, imagine you have the {@code .proto} file:
*
* <pre>
* option java_class = "MyProto";
*
* message Foo {
* extensions 1000 to max;
* }
*
* extend Foo {
* optional int32 bar;
* }
* </pre>
*
* <p>Then, {@code MyProto.Foo.bar} has type
* {@code GeneratedExtension<MyProto.Foo, Integer>}.
*
* <p>In general, users should ignore the details of this type, and simply use
* these static singletons as parameters to the extension accessors defined
* in {@link ExtendableMessage} and {@link ExtendableBuilder}.
*/
public static class GeneratedExtension<
ContainingType extends Message, Type> extends
Extension<ContainingType, Type> {
// TODO(kenton): Find ways to avoid using Java reflection within this
// class. Also try to avoid suppressing unchecked warnings.
// We can't always initialize the descriptor of a GeneratedExtension when
// we first construct it due to initialization order difficulties (namely,
// the descriptor may not have been constructed yet, since it is often
// constructed by the initializer of a separate module).
//
// In the case of nested extensions, we initialize the
// ExtensionDescriptorRetriever with an instance that uses the scoping
// Message's default instance to retrieve the extension's descriptor.
//
// In the case of non-nested extensions, we initialize the
// ExtensionDescriptorRetriever to null and rely on the outer class's static
// initializer to call internalInit() after the descriptor has been parsed.
GeneratedExtension(ExtensionDescriptorRetriever descriptorRetriever,
Class singularType,
Message messageDefaultInstance,
ExtensionType extensionType) {
if (Message.class.isAssignableFrom(singularType) &&
!singularType.isInstance(messageDefaultInstance)) {
throw new IllegalArgumentException(
"Bad messageDefaultInstance for " + singularType.getName());
}
this.descriptorRetriever = descriptorRetriever;
this.singularType = singularType;
this.messageDefaultInstance = messageDefaultInstance;
if (ProtocolMessageEnum.class.isAssignableFrom(singularType)) {
this.enumValueOf = getMethodOrDie(singularType, "valueOf",
EnumValueDescriptor.class);
this.enumGetValueDescriptor =
getMethodOrDie(singularType, "getValueDescriptor");
} else {
this.enumValueOf = null;
this.enumGetValueDescriptor = null;
}
this.extensionType = extensionType;
}
/** For use by generated code only. */
public void internalInit(final FieldDescriptor descriptor) {
if (descriptorRetriever != null) {
throw new IllegalStateException("Already initialized.");
}
descriptorRetriever =
new ExtensionDescriptorRetriever() {
@Override
public FieldDescriptor getDescriptor() {
return descriptor;
}
};
}
private ExtensionDescriptorRetriever descriptorRetriever;
private final Class singularType;
private final Message messageDefaultInstance;
private final Method enumValueOf;
private final Method enumGetValueDescriptor;
private final ExtensionType extensionType;
@Override
public FieldDescriptor getDescriptor() {
if (descriptorRetriever == null) {
throw new IllegalStateException(
"getDescriptor() called before internalInit()");
}
return descriptorRetriever.getDescriptor();
}
/**
* If the extension is an embedded message or group, returns the default
* instance of the message.
*/
@Override
public Message getMessageDefaultInstance() {
return messageDefaultInstance;
}
@Override
protected ExtensionType getExtensionType() {
return extensionType;
}
/**
* Convert from the type used by the reflection accessors to the type used
* by native accessors. E.g., for enums, the reflection accessors use
* EnumValueDescriptors but the native accessors use the generated enum
* type.
*/
@Override
@SuppressWarnings("unchecked")
protected Object fromReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
if (descriptor.isRepeated()) {
if (descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE ||
descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
// Must convert the whole list.
final List result = new ArrayList();
for (final Object element : (List) value) {
result.add(singularFromReflectionType(element));
}
return result;
} else {
return value;
}
} else {
return singularFromReflectionType(value);
}
}
/**
* Like {@link #fromReflectionType(Object)}, but if the type is a repeated
* type, this converts a single element.
*/
@Override
protected Object singularFromReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
switch (descriptor.getJavaType()) {
case MESSAGE:
if (singularType.isInstance(value)) {
return value;
} else {
return messageDefaultInstance.newBuilderForType()
.mergeFrom((Message) value).build();
}
case ENUM:
return invokeOrDie(enumValueOf, null, (EnumValueDescriptor) value);
default:
return value;
}
}
/**
* Convert from the type used by the native accessors to the type used
* by reflection accessors. E.g., for enums, the reflection accessors use
* EnumValueDescriptors but the native accessors use the generated enum
* type.
*/
@Override
@SuppressWarnings("unchecked")
protected Object toReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
if (descriptor.isRepeated()) {
if (descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
// Must convert the whole list.
final List result = new ArrayList();
for (final Object element : (List) value) {
result.add(singularToReflectionType(element));
}
return result;
} else {
return value;
}
} else {
return singularToReflectionType(value);
}
}
/**
* Like {@link #toReflectionType(Object)}, but if the type is a repeated
* type, this converts a single element.
*/
@Override
protected Object singularToReflectionType(final Object value) {
FieldDescriptor descriptor = getDescriptor();
switch (descriptor.getJavaType()) {
case ENUM:
return invokeOrDie(enumGetValueDescriptor, value);
default:
return value;
}
}
@Override
public int getNumber() {
return getDescriptor().getNumber();
}
@Override
public WireFormat.FieldType getLiteType() {
return getDescriptor().getLiteType();
}
@Override
public boolean isRepeated() {
return getDescriptor().isRepeated();
}
@Override
@SuppressWarnings("unchecked")
public Type getDefaultValue() {
if (isRepeated()) {
return (Type) Collections.emptyList();
}
if (getDescriptor().getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
return (Type) messageDefaultInstance;
}
return (Type) singularFromReflectionType(
getDescriptor().getDefaultValue());
}
}
// =================================================================
/** Calls Class.getMethod and throws a RuntimeException if it fails. */
@ -2223,6 +2555,20 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
field.getNumber());
}
private Message coerceType(Message value) {
if (value == null) {
return null;
}
if (mapEntryMessageDefaultInstance.getClass().isInstance(value)) {
return value;
}
// The value is not the exact right message type. However, if it
// is an alternative implementation of the same type -- e.g. a
// DynamicMessage -- we should accept it. In this case we can make
// a copy of the message.
return mapEntryMessageDefaultInstance.toBuilder().mergeFrom(value).build();
}
@Override
public Object get(GeneratedMessageV3 message) {
List result = new ArrayList();
@ -2278,15 +2624,15 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
public Object getRepeatedRaw(Builder builder, int index) {
return getRepeated(builder, index);
}
@Override
public void setRepeated(Builder builder, int index, Object value) {
getMutableMapField(builder).getMutableList().set(index, (Message) value);
getMutableMapField(builder).getMutableList().set(index, coerceType((Message) value));
}
@Override
public void addRepeated(Builder builder, Object value) {
getMutableMapField(builder).getMutableList().add((Message) value);
getMutableMapField(builder).getMutableList().add(coerceType((Message) value));
}
@Override
@ -2713,4 +3059,131 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
output.writeBytesNoTag((ByteString) value);
}
}
protected static <V> void serializeIntegerMapTo(
CodedOutputStream out,
MapField<Integer, V> field,
MapEntry<Integer, V> defaultEntry,
int fieldNumber) throws IOException {
Map<Integer, V> m = field.getMap();
if (!out.isSerializationDeterministic()) {
serializeMapTo(out, m, defaultEntry, fieldNumber);
return;
}
// Sorting the unboxed keys and then look up the values during serialziation is 2x faster
// than sorting map entries with a custom comparator directly.
int[] keys = new int[m.size()];
int index = 0;
for (int k : m.keySet()) {
keys[index++] = k;
}
Arrays.sort(keys);
for (int key : keys) {
out.writeMessage(fieldNumber,
defaultEntry.newBuilderForType()
.setKey(key)
.setValue(m.get(key))
.build());
}
}
protected static <V> void serializeLongMapTo(
CodedOutputStream out,
MapField<Long, V> field,
MapEntry<Long, V> defaultEntry,
int fieldNumber)
throws IOException {
Map<Long, V> m = field.getMap();
if (!out.isSerializationDeterministic()) {
serializeMapTo(out, m, defaultEntry, fieldNumber);
return;
}
long[] keys = new long[m.size()];
int index = 0;
for (long k : m.keySet()) {
keys[index++] = k;
}
Arrays.sort(keys);
for (long key : keys) {
out.writeMessage(fieldNumber,
defaultEntry.newBuilderForType()
.setKey(key)
.setValue(m.get(key))
.build());
}
}
protected static <V> void serializeStringMapTo(
CodedOutputStream out,
MapField<String, V> field,
MapEntry<String, V> defaultEntry,
int fieldNumber)
throws IOException {
Map<String, V> m = field.getMap();
if (!out.isSerializationDeterministic()) {
serializeMapTo(out, m, defaultEntry, fieldNumber);
return;
}
// Sorting the String keys and then look up the values during serialziation is 25% faster than
// sorting map entries with a custom comparator directly.
String[] keys = new String[m.size()];
keys = m.keySet().toArray(keys);
Arrays.sort(keys);
for (String key : keys) {
out.writeMessage(fieldNumber,
defaultEntry.newBuilderForType()
.setKey(key)
.setValue(m.get(key))
.build());
}
}
protected static <V> void serializeBooleanMapTo(
CodedOutputStream out,
MapField<Boolean, V> field,
MapEntry<Boolean, V> defaultEntry,
int fieldNumber)
throws IOException {
Map<Boolean, V> m = field.getMap();
if (!out.isSerializationDeterministic()) {
serializeMapTo(out, m, defaultEntry, fieldNumber);
return;
}
maybeSerializeBooleanEntryTo(out, m, defaultEntry, fieldNumber, false);
maybeSerializeBooleanEntryTo(out, m, defaultEntry, fieldNumber, true);
}
private static <V> void maybeSerializeBooleanEntryTo(
CodedOutputStream out,
Map<Boolean, V> m,
MapEntry<Boolean, V> defaultEntry,
int fieldNumber,
boolean key)
throws IOException {
if (m.containsKey(key)) {
out.writeMessage(fieldNumber,
defaultEntry.newBuilderForType()
.setKey(key)
.setValue(m.get(key))
.build());
}
}
/** Serialize the map using the iteration order. */
private static <K, V> void serializeMapTo(
CodedOutputStream out,
Map<K, V> m,
MapEntry<K, V> defaultEntry,
int fieldNumber)
throws IOException {
for (Map.Entry<K, V> entry : m.entrySet()) {
out.writeMessage(fieldNumber,
defaultEntry.newBuilderForType()
.setKey(entry.getKey())
.setValue(entry.getValue())
.build());
}
}
}

@ -59,6 +59,16 @@ public final class Internal {
static final Charset UTF_8 = Charset.forName("UTF-8");
static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
/**
* Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
*/
static <T> T checkNotNull(T obj, String message) {
if (obj == null) {
throw new NullPointerException(message);
}
return obj;
}
/**
* Helper called by generated code to construct default values for string
* fields.

@ -107,11 +107,23 @@ public class InvalidProtocolBufferException extends IOException {
"Protocol message end-group tag did not match expected tag.");
}
static InvalidProtocolBufferException invalidWireType() {
return new InvalidProtocolBufferException(
static InvalidWireTypeException invalidWireType() {
return new InvalidWireTypeException(
"Protocol message tag had invalid wire type.");
}
/**
* Exception indicating that and unexpected wire type was encountered for a field.
*/
@ExperimentalApi
public static class InvalidWireTypeException extends InvalidProtocolBufferException {
private static final long serialVersionUID = 3283890091615336259L;
public InvalidWireTypeException(String description) {
super(description);
}
}
static InvalidProtocolBufferException recursionLimitExceeded() {
return new InvalidProtocolBufferException(
"Protocol message had too many levels of nesting. May be malicious. " +

@ -334,6 +334,15 @@ public final class MapEntry<K, V> extends AbstractMessage {
} else {
if (field.getType() == FieldDescriptor.Type.ENUM) {
value = ((EnumValueDescriptor) value).getNumber();
} else if (field.getType() == FieldDescriptor.Type.MESSAGE) {
if (value != null && !metadata.defaultValue.getClass().isInstance(value)) {
// The value is not the exact right message type. However, if it
// is an alternative implementation of the same type -- e.g. a
// DynamicMessage -- we should accept it. In this case we can make
// a copy of the message.
value =
((Message) metadata.defaultValue).toBuilder().mergeFrom((Message) value).build();
}
}
setValue((V) value);
}

@ -30,6 +30,8 @@
package com.google.protobuf;
import static com.google.protobuf.Internal.checkNotNull;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
@ -49,10 +51,9 @@ final class NioByteString extends ByteString.LeafByteString {
private final ByteBuffer buffer;
NioByteString(ByteBuffer buffer) {
if (buffer == null) {
throw new NullPointerException("buffer");
}
checkNotNull(buffer, "buffer");
// Use native byte order for fast fixed32/64 operations.
this.buffer = buffer.slice().order(ByteOrder.nativeOrder());
}
@ -266,7 +267,7 @@ final class NioByteString extends ByteString.LeafByteString {
@Override
public CodedInputStream newCodedInput() {
return CodedInputStream.newInstance(buffer);
return CodedInputStream.newInstance(buffer, true);
}
/**

@ -406,6 +406,7 @@ final class RopeByteString extends ByteString {
right.writeTo(output);
}
@Override
protected String toStringInternal(Charset charset) {
return new String(toByteArray(), charset);

@ -1576,14 +1576,22 @@ public final class TextFormat {
// Support specifying repeated field values as a comma-separated list.
// Ex."foo: [1, 2, 3]"
if (field.isRepeated() && tokenizer.tryConsume("[")) {
while (true) {
consumeFieldValue(tokenizer, extensionRegistry, target, field, extension,
parseTreeBuilder, unknownFields);
if (tokenizer.tryConsume("]")) {
// End of list.
break;
if (!tokenizer.tryConsume("]")) { // Allow "foo: []" to be treated as empty.
while (true) {
consumeFieldValue(
tokenizer,
extensionRegistry,
target,
field,
extension,
parseTreeBuilder,
unknownFields);
if (tokenizer.tryConsume("]")) {
// End of list.
break;
}
tokenizer.consume(",");
}
tokenizer.consume(",");
}
} else {
consumeFieldValue(tokenizer, extensionRegistry, target, field,

@ -45,7 +45,8 @@ import java.util.Map.Entry;
*
* <p>The locations of primary fields values are retrieved by {@code getLocation} or
* {@code getLocations}. The locations of sub message values are within nested
* {@code TextFormatParseInfoTree}s and are retrieve by {@code getNestedTree} or {@code getNestedTrees}.
* {@code TextFormatParseInfoTree}s and are retrieve by {@code getNestedTree} or
* {@code getNestedTrees}.
*
* <p>The {@code TextFormatParseInfoTree} is created by a Builder.
*/

@ -64,6 +64,29 @@ import java.nio.ByteBuffer;
public final class UnsafeByteOperations {
private UnsafeByteOperations() {}
/**
* An unsafe operation that returns a {@link ByteString} that is backed by the provided buffer.
*
* @param buffer the buffer to be wrapped
* @return a {@link ByteString} backed by the provided buffer
*/
public static ByteString unsafeWrap(byte[] buffer) {
return ByteString.wrap(buffer);
}
/**
* An unsafe operation that returns a {@link ByteString} that is backed by a subregion of the
* provided buffer.
*
* @param buffer the buffer to be wrapped
* @param offset the offset of the wrapped region
* @param length the number of bytes of the wrapped region
* @return a {@link ByteString} backed by the provided buffer
*/
public static ByteString unsafeWrap(byte[] buffer, int offset, int length) {
return ByteString.wrap(buffer, offset, length);
}
/**
* An unsafe operation that returns a {@link ByteString} that is backed by the provided buffer.
*
@ -71,12 +94,7 @@ public final class UnsafeByteOperations {
* @return a {@link ByteString} backed by the provided buffer
*/
public static ByteString unsafeWrap(ByteBuffer buffer) {
if (buffer.hasArray()) {
final int offset = buffer.arrayOffset();
return ByteString.wrap(buffer.array(), offset + buffer.position(), buffer.remaining());
} else {
return new NioByteString(buffer);
}
return ByteString.wrap(buffer);
}
/**
@ -98,4 +116,5 @@ public final class UnsafeByteOperations {
public static void unsafeWriteTo(ByteString bytes, ByteOutput output) throws IOException {
bytes.writeTo(output);
}
}

@ -30,17 +30,14 @@
package com.google.protobuf;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import sun.misc.Unsafe;
/**
* Utility class for working with unsafe operations.
*/
/** Utility class for working with unsafe operations. */
// TODO(nathanmittler): Add support for Android Memory/MemoryBlock
final class UnsafeUtil {
private static final sun.misc.Unsafe UNSAFE = getUnsafe();
@ -50,8 +47,7 @@ final class UnsafeUtil {
private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(field(Buffer.class, "address"));
private UnsafeUtil() {
}
private UnsafeUtil() {}
static boolean hasUnsafeArrayOperations() {
return HAS_UNSAFE_ARRAY_OPERATIONS;
@ -61,27 +57,83 @@ final class UnsafeUtil {
return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
}
static Object allocateInstance(Class<?> clazz) {
try {
return UNSAFE.allocateInstance(clazz);
} catch (InstantiationException e) {
throw new RuntimeException(e);
}
}
static long objectFieldOffset(Field field) {
return UNSAFE.objectFieldOffset(field);
}
static long getArrayBaseOffset() {
return ARRAY_BASE_OFFSET;
}
static byte getByte(byte[] target, long offset) {
static byte getByte(Object target, long offset) {
return UNSAFE.getByte(target, offset);
}
static void putByte(byte[] target, long offset, byte value) {
static void putByte(Object target, long offset, byte value) {
UNSAFE.putByte(target, offset, value);
}
static void copyMemory(
byte[] src, long srcOffset, byte[] target, long targetOffset, long length) {
UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length);
static int getInt(Object target, long offset) {
return UNSAFE.getInt(target, offset);
}
static long getLong(byte[] target, long offset) {
static void putInt(Object target, long offset, int value) {
UNSAFE.putInt(target, offset, value);
}
static long getLong(Object target, long offset) {
return UNSAFE.getLong(target, offset);
}
static void putLong(Object target, long offset, long value) {
UNSAFE.putLong(target, offset, value);
}
static boolean getBoolean(Object target, long offset) {
return UNSAFE.getBoolean(target, offset);
}
static void putBoolean(Object target, long offset, boolean value) {
UNSAFE.putBoolean(target, offset, value);
}
static float getFloat(Object target, long offset) {
return UNSAFE.getFloat(target, offset);
}
static void putFloat(Object target, long offset, float value) {
UNSAFE.putFloat(target, offset, value);
}
static double getDouble(Object target, long offset) {
return UNSAFE.getDouble(target, offset);
}
static void putDouble(Object target, long offset, double value) {
UNSAFE.putDouble(target, offset, value);
}
static Object getObject(Object target, long offset) {
return UNSAFE.getObject(target, offset);
}
static void putObject(Object target, long offset, Object value) {
UNSAFE.putObject(target, offset, value);
}
static void copyMemory(
Object src, long srcOffset, Object target, long targetOffset, long length) {
UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length);
}
static byte getByte(long address) {
return UNSAFE.getByte(address);
}
@ -90,14 +142,30 @@ final class UnsafeUtil {
UNSAFE.putByte(address, value);
}
static int getInt(long address) {
return UNSAFE.getInt(address);
}
static void putInt(long address, int value) {
UNSAFE.putInt(address, value);
}
static long getLong(long address) {
return UNSAFE.getLong(address);
}
static void putLong(long address, long value) {
UNSAFE.putLong(address, value);
}
static void copyMemory(long srcAddress, long targetAddress, long length) {
UNSAFE.copyMemory(srcAddress, targetAddress, length);
}
static void setMemory(long address, long numBytes, byte value) {
UNSAFE.setMemory(address, numBytes, value);
}
/**
* Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
*/
@ -136,18 +204,29 @@ final class UnsafeUtil {
return unsafe;
}
/**
* Indicates whether or not unsafe array operations are supported on this platform.
*/
/** Indicates whether or not unsafe array operations are supported on this platform. */
private static boolean supportsUnsafeArrayOperations() {
boolean supported = false;
if (UNSAFE != null) {
try {
Class<?> clazz = UNSAFE.getClass();
clazz.getMethod("objectFieldOffset", Field.class);
clazz.getMethod("allocateInstance", Class.class);
clazz.getMethod("arrayBaseOffset", Class.class);
clazz.getMethod("getByte", Object.class, long.class);
clazz.getMethod("putByte", Object.class, long.class, byte.class);
clazz.getMethod("getBoolean", Object.class, long.class);
clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
clazz.getMethod("getInt", Object.class, long.class);
clazz.getMethod("putInt", Object.class, long.class, int.class);
clazz.getMethod("getLong", Object.class, long.class);
clazz.getMethod("putLong", Object.class, long.class, long.class);
clazz.getMethod("getFloat", Object.class, long.class);
clazz.getMethod("putFloat", Object.class, long.class, float.class);
clazz.getMethod("getDouble", Object.class, long.class);
clazz.getMethod("putDouble", Object.class, long.class, double.class);
clazz.getMethod("getObject", Object.class, long.class);
clazz.getMethod("putObject", Object.class, long.class, Object.class);
clazz.getMethod(
"copyMemory", Object.class, long.class, Object.class, long.class, long.class);
supported = true;
@ -163,11 +242,17 @@ final class UnsafeUtil {
if (UNSAFE != null) {
try {
Class<?> clazz = UNSAFE.getClass();
// Methods for getting direct buffer address.
clazz.getMethod("objectFieldOffset", Field.class);
clazz.getMethod("getByte", long.class);
clazz.getMethod("getLong", Object.class, long.class);
clazz.getMethod("getByte", long.class);
clazz.getMethod("putByte", long.class, byte.class);
clazz.getMethod("getInt", long.class);
clazz.getMethod("putInt", long.class, int.class);
clazz.getMethod("getLong", long.class);
clazz.getMethod("putLong", long.class, long.class);
clazz.getMethod("setMemory", long.class, long.class, byte.class);
clazz.getMethod("copyMemory", long.class, long.class, long.class);
supported = true;
} catch (Throwable e) {

@ -47,6 +47,10 @@ public final class WireFormat {
// Do not allow instantiation.
private WireFormat() {}
static final int FIXED_32_SIZE = 4;
static final int FIXED_64_SIZE = 8;
static final int MAX_VARINT_SIZE = 10;
public static final int WIRETYPE_VARINT = 0;
public static final int WIRETYPE_FIXED64 = 1;
public static final int WIRETYPE_LENGTH_DELIMITED = 2;

@ -40,9 +40,8 @@ import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestRequiredForeign;
import protobuf_unittest.UnittestProto.TestUnpackedTypes;
import junit.framework.TestCase;
import java.util.Map;
import junit.framework.TestCase;
/**
* Unit test for {@link AbstractMessage}.
@ -492,7 +491,6 @@ public class AbstractMessageTest extends TestCase {
checkEqualsIsConsistent(eUnknownFields, eUnknownFields2);
}
/**
* Asserts that the given proto has symmetric equals and hashCode methods.
*/

@ -32,11 +32,10 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import junit.framework.TestCase;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import junit.framework.TestCase;
/**
* Tests for {@link BooleanArrayList}.

@ -30,13 +30,12 @@
package com.google.protobuf;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;
import junit.framework.TestCase;
/**
* Tests for {@link ByteBufferWriter}.

@ -31,9 +31,6 @@
package com.google.protobuf;
import com.google.protobuf.ByteString.Output;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -48,6 +45,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import junit.framework.TestCase;
/**
* Test methods with implementations in {@link ByteString}, plus do some top-level "integration"

@ -35,15 +35,13 @@ import protobuf_unittest.UnittestProto.SparseEnumMessage;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestSparseEnum;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.TestCase;
/**
* Unit test for {@link CodedOutputStream}.
@ -151,16 +149,21 @@ public class CodedOutputStreamTest extends TestCase {
private final int initialPosition;
private final CodedOutputStream stream;
private final ByteBuffer buffer;
private final boolean unsafe;
NioDirectCoder(int size) {
this(size, 0);
NioDirectCoder(int size, boolean unsafe) {
this(size, 0, unsafe);
}
NioDirectCoder(int size, int initialPosition) {
NioDirectCoder(int size, int initialPosition, boolean unsafe) {
this.unsafe = unsafe;
this.initialPosition = initialPosition;
buffer = ByteBuffer.allocateDirect(size);
buffer.position(initialPosition);
stream = CodedOutputStream.newInstance(buffer);
stream =
unsafe
? CodedOutputStream.newUnsafeInstance(buffer)
: CodedOutputStream.newSafeInstance(buffer);
}
@Override
@ -181,7 +184,7 @@ public class CodedOutputStreamTest extends TestCase {
@Override
public OutputType getOutputType() {
return OutputType.NIO_DIRECT;
return unsafe ? OutputType.NIO_DIRECT_SAFE : OutputType.NIO_DIRECT_UNSAFE;
}
}
@ -198,10 +201,16 @@ public class CodedOutputStreamTest extends TestCase {
return new NioHeapCoder(size);
}
},
NIO_DIRECT() {
NIO_DIRECT_SAFE() {
@Override
Coder newCoder(int size) {
return new NioDirectCoder(size);
return new NioDirectCoder(size, false);
}
},
NIO_DIRECT_UNSAFE() {
@Override
Coder newCoder(int size) {
return new NioDirectCoder(size, true);
}
},
STREAM() {
@ -389,6 +398,7 @@ public class CodedOutputStreamTest extends TestCase {
!= CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
coder.stream().writeStringNoTag(string);
coder.stream().flush();
int stringSize = CodedOutputStream.computeStringSizeNoTag(string);
// Verify that the total bytes written is correct
@ -478,11 +488,12 @@ public class CodedOutputStreamTest extends TestCase {
public void testWriteByteArrayWithOffsets() throws Exception {
byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
byte[] destination = new byte[4];
CodedOutputStream codedStream = CodedOutputStream.newInstance(destination);
codedStream.writeByteArrayNoTag(fullArray, 2, 2);
assertEqualBytes(OutputType.ARRAY, bytes(0x02, 0x33, 0x44, 0x00), destination);
assertEquals(3, codedStream.getTotalBytesWritten());
for (OutputType type : new OutputType[] {OutputType.ARRAY}) {
Coder coder = type.newCoder(4);
coder.stream().writeByteArrayNoTag(fullArray, 2, 2);
assertEqualBytes(type, bytes(0x02, 0x33, 0x44), coder.toByteArray());
assertEquals(3, coder.stream().getTotalBytesWritten());
}
}
public void testSerializeUtf8_MultipleSmallWrites() throws Exception {
@ -561,7 +572,12 @@ public class CodedOutputStreamTest extends TestCase {
// Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes.
// An array of size 1 will cause a failure when trying to write the varint.
for (OutputType outputType :
new OutputType[] {OutputType.ARRAY, OutputType.NIO_HEAP, OutputType.NIO_DIRECT}) {
new OutputType[] {
OutputType.ARRAY,
OutputType.NIO_HEAP,
OutputType.NIO_DIRECT_SAFE,
OutputType.NIO_DIRECT_UNSAFE
}) {
for (int i = 0; i < 11; i++) {
Coder coder = outputType.newCoder(i);
try {
@ -599,10 +615,13 @@ public class CodedOutputStreamTest extends TestCase {
public void testNioEncodersWithInitialOffsets() throws Exception {
String value = "abc";
for (Coder coder : new Coder[] {new NioHeapCoder(10, 2), new NioDirectCoder(10, 2)}) {
for (Coder coder :
new Coder[] {
new NioHeapCoder(10, 2), new NioDirectCoder(10, 2, false), new NioDirectCoder(10, 2, true)
}) {
coder.stream().writeStringNoTag(value);
coder.stream().flush();
assertEqualBytes(coder.getOutputType(), new byte[]{3, 'a', 'b', 'c'}, coder.toByteArray());
assertEqualBytes(coder.getOutputType(), new byte[] {3, 'a', 'b', 'c'}, coder.toByteArray());
}
}

@ -31,11 +31,9 @@
package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestDeprecatedFields;
import junit.framework.TestCase;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import junit.framework.TestCase;
/**
* Test field deprecation

@ -55,15 +55,15 @@ import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
import protobuf_unittest.UnittestProto.TestJsonName;
import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestReservedFields;
import protobuf_unittest.UnittestProto.TestService;
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
/**
* Unit test for {@link Descriptors}.
@ -805,4 +805,15 @@ public class DescriptorsTest extends TestCase {
Descriptors.FileDescriptor.buildFrom(
fileDescriptorProto, new FileDescriptor[0]);
}
public void testFieldJsonName() throws Exception {
Descriptor d = TestJsonName.getDescriptor();
assertEquals(6, d.getFields().size());
assertEquals("fieldName1", d.getFields().get(0).getJsonName());
assertEquals("fieldName2", d.getFields().get(1).getJsonName());
assertEquals("FieldName3", d.getFields().get(2).getJsonName());
assertEquals("FieldName4", d.getFields().get(3).getJsonName());
assertEquals("FIELDNAME5", d.getFields().get(4).getJsonName());
assertEquals("@type", d.getFields().get(5).getJsonName());
}
}

@ -32,11 +32,10 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import junit.framework.TestCase;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import junit.framework.TestCase;
/**
* Tests for {@link DoubleArrayList}.

@ -37,10 +37,8 @@ import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import junit.framework.TestCase;
import java.util.Arrays;
import junit.framework.TestCase;
/**
* Unit test for {@link DynamicMessage}. See also {@link MessageTest}, which

@ -32,26 +32,24 @@ package com.google.protobuf;
import protobuf_unittest.NonNestedExtension;
import protobuf_unittest.NonNestedExtensionLite;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Tests for {@link ExtensionRegistryFactory} and the {@link ExtensionRegistry} instances it
* creates.
*
*
* <p>This test simulates the runtime behaviour of the ExtensionRegistryFactory by delegating test
* definitions to two inner classes {@link InnerTest} and {@link InnerLiteTest}, the latter of
* which is executed using a custom ClassLoader, simulating the ProtoLite environment.
*
*
* <p>The test mechanism employed here is based on the pattern in
* {@code com.google.common.util.concurrent.AbstractFutureFallbackAtomicHelperTest}
*/
@ -68,6 +66,7 @@ public class ExtensionRegistryFactoryTest extends TestCase {
void testEmpty();
void testIsFullRegistry();
void testAdd();
void testAdd_immutable();
}
/**
@ -125,6 +124,29 @@ public class ExtensionRegistryFactoryTest extends TestCase {
assertNotNull("Extension is registered in masqueraded full registry",
fullRegistry2.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"));
}
@Override
public void testAdd_immutable() {
ExtensionRegistryLite registry1 = ExtensionRegistryLite.newInstance().getUnmodifiable();
try {
NonNestedExtensionLite.registerAllExtensions(registry1);
fail();
} catch (UnsupportedOperationException expected) {}
try {
registry1.add(NonNestedExtensionLite.nonNestedExtensionLite);
fail();
} catch (UnsupportedOperationException expected) {}
ExtensionRegistryLite registry2 = ExtensionRegistryLite.newInstance().getUnmodifiable();
try {
NonNestedExtension.registerAllExtensions((ExtensionRegistry) registry2);
fail();
} catch (IllegalArgumentException expected) {}
try {
registry2.add(NonNestedExtension.nonNestedExtension);
fail();
} catch (IllegalArgumentException expected) {}
}
}
/**
@ -162,12 +184,21 @@ public class ExtensionRegistryFactoryTest extends TestCase {
NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
assertNotNull("Extension is registered in Lite registry", extension);
}
@Override
public void testAdd_immutable() {
ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance().getUnmodifiable();
try {
NonNestedExtensionLite.registerAllExtensions(registry);
fail();
} catch (UnsupportedOperationException expected) {}
}
}
/**
* Defines a suite of tests which the JUnit3 runner retrieves by reflection.
*/
public static Test suite() {
public static Test suite() {
TestSuite suite = new TestSuite();
for (Method method : RegistryTests.class.getMethods()) {
suite.addTest(TestSuite.createTest(ExtensionRegistryFactoryTest.class, method.getName()));

@ -32,11 +32,10 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import junit.framework.TestCase;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import junit.framework.TestCase;
/**
* Tests for {@link FloatArrayList}.

@ -65,9 +65,6 @@ import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestUnpackedTypes;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
@ -76,6 +73,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
/**
* Unit test for generated messages and generated code. See also

@ -32,11 +32,10 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import junit.framework.TestCase;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import junit.framework.TestCase;
/**
* Tests for {@link IntArrayList}.

@ -35,10 +35,8 @@ import static protobuf_unittest.UnittestProto.optionalInt64Extension;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import junit.framework.TestCase;
import java.io.IOException;
import junit.framework.TestCase;
/**
* Unit test for {@link LazyFieldLite}.

@ -32,10 +32,8 @@ package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import junit.framework.TestCase;
import java.io.IOException;
import junit.framework.TestCase;
/**
* Unit test for {@link LazyField}.

@ -34,10 +34,8 @@ import protobuf_unittest.LazyFieldsLite.LazyExtension;
import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite;
import protobuf_unittest.LazyFieldsLite.LazyMessageLite;
import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite;
import junit.framework.TestCase;
import java.util.ArrayList;
import junit.framework.TestCase;
/**
* Unit test for messages with lazy fields.

@ -32,13 +32,12 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
/**
* Tests for {@link LazyStringArrayList}.

@ -32,10 +32,8 @@ package com.google.protobuf;
import protobuf_unittest.UnittestProto;
import junit.framework.TestCase;
import java.io.IOException;
import junit.framework.TestCase;
/**
* Tests to make sure the lazy conversion of UTF8-encoded byte arrays to

@ -35,7 +35,6 @@ import static java.util.Collections.singletonList;
import com.google.protobuf.UnittestImportLite.ImportEnumLite;
import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
import com.google.protobuf.UnittestLite;
import com.google.protobuf.UnittestLite.ForeignEnumLite;
import com.google.protobuf.UnittestLite.ForeignMessageLite;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
@ -52,15 +51,8 @@ import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* Test lite runtime.
*
@ -139,7 +131,6 @@ public class LiteTest extends TestCase {
UnittestLite.optionalNestedMessageExtensionLite).getBb());
}
public void testClone() {
TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder()
.setOptionalInt32(123);

@ -30,8 +30,6 @@
package com.google.protobuf;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
@ -45,6 +43,7 @@ import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import junit.framework.TestCase;
/**
* Test {@code LiteralByteString} by setting up a reference string in {@link #setUp()}.

@ -32,11 +32,10 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import junit.framework.TestCase;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import junit.framework.TestCase;
/**
* Tests for {@link LongArrayList}.

@ -35,15 +35,13 @@ import map_lite_test.MapForProto2TestProto.TestMap;
import map_lite_test.MapForProto2TestProto.TestMap.MessageValue;
import map_lite_test.MapForProto2TestProto.TestMapOrBuilder;
import map_lite_test.MapForProto2TestProto.TestUnknownEnumValue;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import junit.framework.TestCase;
/**
* Unit tests for map fields.

@ -32,14 +32,14 @@ package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor;
import map_test.MapForProto2TestProto.BizarroTestMap;
import map_test.MapForProto2TestProto.ReservedAsMapField;
import map_test.MapForProto2TestProto.ReservedAsMapFieldWithEnumValue;
import map_test.MapForProto2TestProto.TestMap;
import map_test.MapForProto2TestProto.TestMap.MessageValue;
import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields;
import map_test.MapForProto2TestProto.TestMapOrBuilder;
import map_test.MapForProto2TestProto.TestRecursiveMap;
import map_test.MapForProto2TestProto.TestUnknownEnumValue;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@ -47,6 +47,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
/**
* Unit tests for map fields in proto2 protos.
@ -1143,6 +1144,11 @@ public class MapForProto2Test extends TestCase {
assertEquals(2, mapEntry.getAllFields().size());
}
public void testReservedWordsFieldNames() {
ReservedAsMapField.newBuilder().build();
ReservedAsMapFieldWithEnumValue.newBuilder().build();
}
private static <K, V> Map<K, V> newMap(K key1, V value1) {
Map<K, V> map = new HashMap<K, V>();
map.put(key1, value1);

@ -36,12 +36,12 @@ import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import map_test.MapTestProto.BizarroTestMap;
import map_test.MapTestProto.ReservedAsMapField;
import map_test.MapTestProto.ReservedAsMapFieldWithEnumValue;
import map_test.MapTestProto.TestMap;
import map_test.MapTestProto.TestMap.MessageValue;
import map_test.MapTestProto.TestMapOrBuilder;
import map_test.MapTestProto.TestOnChangeEventPropagation;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@ -49,6 +49,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
/**
* Unit tests for map fields.
@ -1307,6 +1308,171 @@ public class MapTest extends TestCase {
}
}
public void testReservedWordsFieldNames() {
ReservedAsMapField.newBuilder().build();
ReservedAsMapFieldWithEnumValue.newBuilder().build();
}
public void testDeterministicSerialziation() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
// int32->int32
builder.putInt32ToInt32Field(5, 1);
builder.putInt32ToInt32Field(1, 1);
builder.putInt32ToInt32Field(4, 1);
builder.putInt32ToInt32Field(-2, 1);
builder.putInt32ToInt32Field(0, 1);
// uint32->int32
builder.putUint32ToInt32Field(5, 1);
builder.putUint32ToInt32Field(1, 1);
builder.putUint32ToInt32Field(4, 1);
builder.putUint32ToInt32Field(-2, 1);
builder.putUint32ToInt32Field(0, 1);
// int64->int32
builder.putInt64ToInt32Field(5L, 1);
builder.putInt64ToInt32Field(1L, 1);
builder.putInt64ToInt32Field(4L, 1);
builder.putInt64ToInt32Field(-2L, 1);
builder.putInt64ToInt32Field(0L, 1);
// string->int32
builder.putStringToInt32Field("baz", 1);
builder.putStringToInt32Field("foo", 1);
builder.putStringToInt32Field("bar", 1);
builder.putStringToInt32Field("", 1);
builder.putStringToInt32Field("hello", 1);
builder.putStringToInt32Field("world", 1);
TestMap message = builder.build();
byte[] serialized = new byte[message.getSerializedSize()];
CodedOutputStream output = CodedOutputStream.newInstance(serialized);
output.useDeterministicSerialization();
message.writeTo(output);
output.flush();
CodedInputStream input = CodedInputStream.newInstance(serialized);
List<Integer> int32Keys = new ArrayList<Integer>();
List<Integer> uint32Keys = new ArrayList<Integer>();
List<Long> int64Keys = new ArrayList<Long>();
List<String> stringKeys = new ArrayList<String>();
int tag;
while (true) {
tag = input.readTag();
if (tag == 0) {
break;
}
int length = input.readRawVarint32();
int oldLimit = input.pushLimit(length);
switch (WireFormat.getTagFieldNumber(tag)) {
case TestMap.STRING_TO_INT32_FIELD_FIELD_NUMBER:
stringKeys.add(readMapStringKey(input));
break;
case TestMap.INT32_TO_INT32_FIELD_FIELD_NUMBER:
int32Keys.add(readMapIntegerKey(input));
break;
case TestMap.UINT32_TO_INT32_FIELD_FIELD_NUMBER:
uint32Keys.add(readMapIntegerKey(input));
break;
case TestMap.INT64_TO_INT32_FIELD_FIELD_NUMBER:
int64Keys.add(readMapLongKey(input));
break;
default:
fail("Unexpected fields.");
}
input.popLimit(oldLimit);
}
assertEquals(
Arrays.asList(-2, 0, 1, 4, 5),
int32Keys);
assertEquals(
Arrays.asList(-2, 0, 1, 4, 5),
uint32Keys);
assertEquals(
Arrays.asList(-2L, 0L, 1L, 4L, 5L),
int64Keys);
assertEquals(
Arrays.asList("", "bar", "baz", "foo", "hello", "world"),
stringKeys);
}
public void testInitFromPartialDynamicMessage() {
FieldDescriptor fieldDescriptor =
TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER);
Descriptor mapEntryType = fieldDescriptor.getMessageType();
FieldDescriptor keyField = mapEntryType.findFieldByNumber(1);
FieldDescriptor valueField = mapEntryType.findFieldByNumber(2);
DynamicMessage dynamicMessage =
DynamicMessage.newBuilder(TestMap.getDescriptor())
.addRepeatedField(
fieldDescriptor,
DynamicMessage.newBuilder(mapEntryType)
.setField(keyField, 10)
.setField(valueField, TestMap.MessageValue.newBuilder().setValue(10).build())
.build())
.build();
TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build();
assertEquals(
TestMap.MessageValue.newBuilder().setValue(10).build(),
message.getInt32ToMessageFieldMap().get(10));
}
public void testInitFromFullyDynamicMessage() {
FieldDescriptor fieldDescriptor =
TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER);
Descriptor mapEntryType = fieldDescriptor.getMessageType();
FieldDescriptor keyField = mapEntryType.findFieldByNumber(1);
FieldDescriptor valueField = mapEntryType.findFieldByNumber(2);
DynamicMessage dynamicMessage =
DynamicMessage.newBuilder(TestMap.getDescriptor())
.addRepeatedField(
fieldDescriptor,
DynamicMessage.newBuilder(mapEntryType)
.setField(keyField, 10)
.setField(
valueField,
DynamicMessage.newBuilder(TestMap.MessageValue.getDescriptor())
.setField(
TestMap.MessageValue.getDescriptor().findFieldByName("value"), 10)
.build())
.build())
.build();
TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build();
assertEquals(
TestMap.MessageValue.newBuilder().setValue(10).build(),
message.getInt32ToMessageFieldMap().get(10));
}
private int readMapIntegerKey(CodedInputStream input) throws IOException {
int tag = input.readTag();
assertEquals(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT), tag);
int ret = input.readInt32();
// skip the value field.
input.skipField(input.readTag());
assertTrue(input.isAtEnd());
return ret;
}
private long readMapLongKey(CodedInputStream input) throws IOException {
int tag = input.readTag();
assertEquals(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT), tag);
long ret = input.readInt64();
// skip the value field.
input.skipField(input.readTag());
assertTrue(input.isAtEnd());
return ret;
}
private String readMapStringKey(CodedInputStream input) throws IOException {
int tag = input.readTag();
assertEquals(WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED), tag);
String ret = input.readString();
// skip the value field.
input.skipField(input.readTag());
assertTrue(input.isAtEnd());
return ret;
}
private static <K, V> Map<K, V> newMap(K key1, V value1) {
Map<K, V> map = new HashMap<K, V>();
map.put(key1, value1);

@ -35,10 +35,8 @@ import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestRequiredForeign;
import junit.framework.TestCase;
import java.util.List;
import junit.framework.TestCase;
/**
* Misc. unit tests for message operations that apply to both generated

@ -32,11 +32,9 @@ package com.google.protobuf;
import protobuf_unittest.Vehicle;
import protobuf_unittest.Wheel;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
/**
* Test cases that exercise end-to-end use cases involving

@ -32,8 +32,6 @@ package com.google.protobuf;
import static com.google.protobuf.Internal.UTF_8;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
@ -48,6 +46,7 @@ import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import junit.framework.TestCase;
/**
* Tests for {@link NioByteString}.

@ -36,16 +36,14 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Tests the exceptions thrown when parsing from a stream. The methods on the {@link Parser}

@ -42,13 +42,11 @@ import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestParsingMerge;
import protobuf_unittest.UnittestProto.TestRequired;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import junit.framework.TestCase;
/**
* Unit test for {@link Parser}.

@ -32,12 +32,11 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import junit.framework.TestCase;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
/**
* Tests for {@link ProtobufArrayList}.

@ -32,11 +32,9 @@ package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
import junit.framework.TestCase;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
/**
* Tests for {@link RepeatedFieldBuilderV3}. This tests basic functionality.

@ -42,15 +42,13 @@ import protobuf_unittest.UnittestProto.FooResponse;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestService;
import java.util.HashSet;
import java.util.Set;
import junit.framework.TestCase;
import org.easymock.classextension.EasyMock;
import org.easymock.IArgumentMatcher;
import org.easymock.classextension.IMocksControl;
import java.util.HashSet;
import java.util.Set;
/**
* Tests services and stubs.
*
@ -271,6 +269,8 @@ public class ServiceTest extends TestCase {
file.getServices().get(0).getMethods().get(0).getName());
}
// =================================================================
/**

@ -30,8 +30,6 @@
package com.google.protobuf;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -40,6 +38,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import junit.framework.TestCase;
/**
* @author darick@google.com Darick Tong

@ -232,12 +232,10 @@ import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestUnpackedTypes;
import junit.framework.Assert;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import junit.framework.Assert;
/**
* Contains methods for setting all fields of {@code TestAllTypes} to
@ -259,6 +257,13 @@ public final class TestUtil {
return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
}
/**
* Dirties the message by resetting the momoized serialized size.
*/
public static void resetMemoizedSize(AbstractMessage message) {
message.memoizedSize = -1;
}
/**
* Get a {@code TestAllTypes} with all fields set as they would be by
* {@link #setAllFields(TestAllTypes.Builder)}.

@ -42,11 +42,9 @@ import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestOneof2;
import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
import junit.framework.TestCase;
import java.io.StringReader;
import java.util.List;
import junit.framework.TestCase;
/**
* Test case for {@link TextFormat}.
@ -992,10 +990,35 @@ public class TextFormatTest extends TestCase {
assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n");
}
public void testParseShortRepeatedFormOfEmptyRepeatedFields() throws Exception {
assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: []");
assertParseSuccessWithOverwriteForbidden("repeated_int32: []\n");
assertParseSuccessWithOverwriteForbidden("RepeatedGroup []\n");
assertParseSuccessWithOverwriteForbidden("repeated_nested_message []\n");
}
public void testParseShortRepeatedFormWithTrailingComma() throws Exception {
assertParseErrorWithOverwriteForbidden(
"1:38: Expected identifier. Found \']\'",
"repeated_foreign_enum: [FOREIGN_FOO, ]\n");
assertParseErrorWithOverwriteForbidden(
"1:22: Couldn't parse integer: For input string: \"]\"",
"repeated_int32: [ 1, ]\n");
assertParseErrorWithOverwriteForbidden(
"1:25: Expected \"{\".",
"RepeatedGroup [{ a: 1 },]\n");
assertParseErrorWithOverwriteForbidden(
"1:37: Expected \"{\".",
"repeated_nested_message [{ bb: 1 }, ]\n");
}
public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
assertParseErrorWithOverwriteForbidden(
"1:17: Couldn't parse integer: For input string: \"[\"",
"optional_int32: [1]\n");
assertParseErrorWithOverwriteForbidden(
"1:17: Couldn't parse integer: For input string: \"[\"",
"optional_int32: []\n");
}
// =======================================================================

@ -35,11 +35,9 @@ import com.google.protobuf.UnittestLite.TestAllTypesLite;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import junit.framework.TestCase;
/**
* Tests for {@link UnknownFieldSetLite}.

@ -38,11 +38,9 @@ import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.Map;
import junit.framework.TestCase;
/**
* Tests related to unknown field handling.

@ -30,11 +30,10 @@
package com.google.protobuf;
import junit.framework.TestCase;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import junit.framework.TestCase;
/**
* Tests for {@link UnmodifiableLazyStringList}.

@ -44,12 +44,10 @@ import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;
import junit.framework.TestCase;
/**
* Tests related to parsing and serialization.

@ -36,7 +36,6 @@ import "google/protobuf/unittest.proto";
option java_package = "com.google.protobuf";
option java_outer_classname = "FieldPresenceTestProto";
option java_generate_equals_and_hash = true;
message TestAllTypes {
enum NestedEnum {

@ -32,7 +32,6 @@ syntax = "proto2";
option java_outer_classname = "MapForProto2TestProto";
option java_generate_equals_and_hash = true;
message TestMap {
message MessageValue {
@ -81,6 +80,42 @@ message BizarroTestMap {
map<string, bytes> int32_to_message_field = 5; // different key and value types
map<string, bytes> string_to_int32_field = 6; // same key type, different value
}
// Used to test that java reserved words can be used as protobuf field names
// Not all reserved words are tested (to avoid bloat) but instead an arbitrary
// subset of them chosen to cover various keyword categories like
// type, modifier, declaration, etc.
message ReservedAsMapField {
map<string, uint32> if = 1;
map<string, uint32> const = 2;
map<string, uint32> private = 3;
map<string, uint32> class = 4;
map<string, uint32> int = 5;
map<string, uint32> void = 6;
map<string, uint32> string = 7; // These are also proto keywords
map<string, uint32> package = 8;
map<string, uint32> enum = 9; // Most recent Java reserved word
map<string, uint32> null = 10;
// null is not a 'reserved word' per se but as a literal needs similar care
}
message ReservedAsMapFieldWithEnumValue {
enum SampleEnum {
A = 0;
B = 1;
}
map<string, SampleEnum> if = 1;
map<string, SampleEnum> const = 2;
map<string, SampleEnum> private = 3;
map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6;
map<string, SampleEnum> string = 7; // These are also proto keywords
map<string, SampleEnum> package = 8;
map<string, SampleEnum> enum = 9; // Most recent Java reserved word
map<string, SampleEnum> null = 10;
// null is not a 'reserved word' per se but as a literal needs similar care
}
package map_for_proto2_lite_test;
option java_package = "map_lite_test";
option optimize_for = LITE_RUNTIME;

@ -34,7 +34,6 @@ package map_for_proto2_test;
option java_package = "map_test";
option java_outer_classname = "MapForProto2TestProto";
option java_generate_equals_and_hash = true;
message TestMap {
message MessageValue {
@ -83,3 +82,39 @@ message BizarroTestMap {
map<string, bytes> int32_to_message_field = 5; // different key and value types
map<string, bytes> string_to_int32_field = 6; // same key type, different value
}
// Used to test that java reserved words can be used as protobuf field names
// Not all reserved words are tested (to avoid bloat) but instead an arbitrary
// subset of them chosen to cover various keyword categories like
// type, modifier, declaration, etc.
message ReservedAsMapField {
map<string, uint32> if = 1;
map<string, uint32> const = 2;
map<string, uint32> private = 3;
map<string, uint32> class = 4;
map<string, uint32> int = 5;
map<string, uint32> void = 6;
map<string, uint32> string = 7; // These are also proto keywords
map<string, uint32> package = 8;
map<string, uint32> enum = 9; // Most recent Java reserved word
map<string, uint32> null = 10;
// null is not a 'reserved word' per se but as a literal needs similar care
}
message ReservedAsMapFieldWithEnumValue {
enum SampleEnum {
A = 0;
B = 1;
}
map<string, SampleEnum> if = 1;
map<string, SampleEnum> const = 2;
map<string, SampleEnum> private = 3;
map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6;
map<string, SampleEnum> string = 7; // These are also proto keywords
map<string, SampleEnum> package = 8;
map<string, SampleEnum> enum = 9; // Most recent Java reserved word
map<string, SampleEnum> null = 10;
// null is not a 'reserved word' per se but as a literal needs similar care
}

@ -34,7 +34,6 @@ package map_test;
option java_package = "map_test";
option java_outer_classname = "MapTestProto";
option java_generate_equals_and_hash = true;
message TestMap {
message MessageValue {
@ -53,6 +52,8 @@ message TestMap {
map<int32, EnumValue> int32_to_enum_field = 4;
map<int32, MessageValue> int32_to_message_field = 5;
map<string, int32> string_to_int32_field = 6;
map<uint32, int32> uint32_to_int32_field = 7;
map<int64, int32> int64_to_int32_field = 8;
}
// Used to test that a nested builder containing map fields will properly
@ -71,3 +72,39 @@ message BizarroTestMap {
map<string, bytes> int32_to_message_field = 5; // different key and value types
map<string, bytes> string_to_int32_field = 6; // same key type, different value
}
// Used to test that java reserved words can be used as protobuf field names
// Not all reserved words are tested (to avoid bloat) but instead an arbitrary
// subset of them chosen to cover various keyword categories like
// type, modifier, declaration, etc.
message ReservedAsMapField {
map<string, uint32> if = 1;
map<string, uint32> const = 2;
map<string, uint32> private = 3;
map<string, uint32> class = 4;
map<string, uint32> int = 5;
map<string, uint32> void = 6;
map<string, uint32> string = 7; // These are also proto keywords
map<string, uint32> package = 8;
map<string, uint32> enum = 9; // Most recent Java reserved word
map<string, uint32> null = 10;
// null is not a 'reserved word' per se but as a literal needs similar care
}
message ReservedAsMapFieldWithEnumValue {
enum SampleEnum {
A = 0;
B = 1;
}
map<string, SampleEnum> if = 1;
map<string, SampleEnum> const = 2;
map<string, SampleEnum> private = 3;
map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6;
map<string, SampleEnum> string = 7; // These are also proto keywords
map<string, SampleEnum> package = 8;
map<string, SampleEnum> enum = 9; // Most recent Java reserved word
map<string, SampleEnum> null = 10;
// null is not a 'reserved word' per se but as a literal needs similar care
}

@ -43,7 +43,6 @@ package io_protocol_tests;
option java_package = "com.google.protobuf";
option java_outer_classname = "TestBadIdentifiersProto";
option java_generate_equals_and_hash = true;
message TestMessage {
optional string cached_size = 1;

@ -0,0 +1,646 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.Internal.EnumLite;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* A partial implementation of the {@link Message} interface which implements
* as many methods of that interface as possible in terms of other methods.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class AbstractMessage
// TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType.
extends AbstractMessageLite
implements Message {
@Override
public boolean isInitialized() {
return MessageReflection.isInitialized(this);
}
/**
* Interface for the parent of a Builder that allows the builder to
* communicate invalidations back to the parent for use when using nested
* builders.
*/
protected interface BuilderParent {
/**
* A builder becomes dirty whenever a field is modified -- including fields
* in nested builders -- and becomes clean when build() is called. Thus,
* when a builder becomes dirty, all its parents become dirty as well, and
* when it becomes clean, all its children become clean. The dirtiness
* state is used to invalidate certain cached values.
* <br>
* To this end, a builder calls markDirty() on its parent whenever it
* transitions from clean to dirty. The parent must propagate this call to
* its own parent, unless it was already dirty, in which case the
* grandparent must necessarily already be dirty as well. The parent can
* only transition back to "clean" after calling build() on all children.
*/
void markDirty();
}
/** Create a nested builder. */
protected Message.Builder newBuilderForType(BuilderParent parent) {
throw new UnsupportedOperationException("Nested builder is not supported for this type.");
}
@Override
public List<String> findInitializationErrors() {
return MessageReflection.findMissingFields(this);
}
@Override
public String getInitializationErrorString() {
return MessageReflection.delimitWithCommas(findInitializationErrors());
}
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
@Override
public boolean hasOneof(OneofDescriptor oneof) {
throw new UnsupportedOperationException("hasOneof() is not implemented.");
}
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
@Override
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
throw new UnsupportedOperationException(
"getOneofFieldDescriptor() is not implemented.");
}
@Override
public final String toString() {
return TextFormat.printToString(this);
}
@Override
public void writeTo(final CodedOutputStream output) throws IOException {
MessageReflection.writeMessageTo(this, getAllFields(), output, false);
}
protected int memoizedSize = -1;
@Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) {
return size;
}
memoizedSize = MessageReflection.getSerializedSize(this, getAllFields());
return memoizedSize;
}
@Override
public boolean equals(final Object other) {
if (other == this) {
return true;
}
if (!(other instanceof Message)) {
return false;
}
final Message otherMessage = (Message) other;
if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
return false;
}
return compareFields(getAllFields(), otherMessage.getAllFields()) &&
getUnknownFields().equals(otherMessage.getUnknownFields());
}
@Override
public int hashCode() {
int hash = memoizedHashCode;
if (hash == 0) {
hash = 41;
hash = (19 * hash) + getDescriptorForType().hashCode();
hash = hashFields(hash, getAllFields());
hash = (29 * hash) + getUnknownFields().hashCode();
memoizedHashCode = hash;
}
return hash;
}
private static ByteString toByteString(Object value) {
if (value instanceof byte[]) {
return ByteString.copyFrom((byte[]) value);
} else {
return (ByteString) value;
}
}
/**
* Compares two bytes fields. The parameters must be either a byte array or a
* ByteString object. They can be of different type though.
*/
private static boolean compareBytes(Object a, Object b) {
if (a instanceof byte[] && b instanceof byte[]) {
return Arrays.equals((byte[])a, (byte[])b);
}
return toByteString(a).equals(toByteString(b));
}
/**
* Converts a list of MapEntry messages into a Map used for equals() and
* hashCode().
*/
@SuppressWarnings({"rawtypes", "unchecked"})
private static Map convertMapEntryListToMap(List list) {
if (list.isEmpty()) {
return Collections.emptyMap();
}
Map result = new HashMap();
Iterator iterator = list.iterator();
Message entry = (Message) iterator.next();
Descriptors.Descriptor descriptor = entry.getDescriptorForType();
Descriptors.FieldDescriptor key = descriptor.findFieldByName("key");
Descriptors.FieldDescriptor value = descriptor.findFieldByName("value");
Object fieldValue = entry.getField(value);
if (fieldValue instanceof EnumValueDescriptor) {
fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
}
result.put(entry.getField(key), fieldValue);
while (iterator.hasNext()) {
entry = (Message) iterator.next();
fieldValue = entry.getField(value);
if (fieldValue instanceof EnumValueDescriptor) {
fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
}
result.put(entry.getField(key), fieldValue);
}
return result;
}
/**
* Compares two map fields. The parameters must be a list of MapEntry
* messages.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
private static boolean compareMapField(Object a, Object b) {
Map ma = convertMapEntryListToMap((List) a);
Map mb = convertMapEntryListToMap((List) b);
return MapFieldLite.equals(ma, mb);
}
/**
* Compares two set of fields.
* This method is used to implement {@link AbstractMessage#equals(Object)}
* and {@link AbstractMutableMessage#equals(Object)}. It takes special care
* of bytes fields because immutable messages and mutable messages use
* different Java type to reprensent a bytes field and this method should be
* able to compare immutable messages, mutable messages and also an immutable
* message to a mutable message.
*/
static boolean compareFields(Map<FieldDescriptor, Object> a,
Map<FieldDescriptor, Object> b) {
if (a.size() != b.size()) {
return false;
}
for (FieldDescriptor descriptor : a.keySet()) {
if (!b.containsKey(descriptor)) {
return false;
}
Object value1 = a.get(descriptor);
Object value2 = b.get(descriptor);
if (descriptor.getType() == FieldDescriptor.Type.BYTES) {
if (descriptor.isRepeated()) {
List list1 = (List) value1;
List list2 = (List) value2;
if (list1.size() != list2.size()) {
return false;
}
for (int i = 0; i < list1.size(); i++) {
if (!compareBytes(list1.get(i), list2.get(i))) {
return false;
}
}
} else {
// Compares a singular bytes field.
if (!compareBytes(value1, value2)) {
return false;
}
}
} else if (descriptor.isMapField()) {
if (!compareMapField(value1, value2)) {
return false;
}
} else {
// Compare non-bytes fields.
if (!value1.equals(value2)) {
return false;
}
}
}
return true;
}
/**
* Calculates the hash code of a map field. {@code value} must be a list of
* MapEntry messages.
*/
@SuppressWarnings("unchecked")
private static int hashMapField(Object value) {
return MapFieldLite.calculateHashCodeForMap(convertMapEntryListToMap((List) value));
}
/** Get a hash code for given fields and values, using the given seed. */
@SuppressWarnings("unchecked")
protected static int hashFields(int hash, Map<FieldDescriptor, Object> map) {
for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
FieldDescriptor field = entry.getKey();
Object value = entry.getValue();
hash = (37 * hash) + field.getNumber();
if (field.isMapField()) {
hash = (53 * hash) + hashMapField(value);
} else if (field.getType() != FieldDescriptor.Type.ENUM){
hash = (53 * hash) + value.hashCode();
} else if (field.isRepeated()) {
List<? extends EnumLite> list = (List<? extends EnumLite>) value;
hash = (53 * hash) + Internal.hashEnumList(list);
} else {
hash = (53 * hash) + Internal.hashEnum((EnumLite) value);
}
}
return hash;
}
/**
* Package private helper method for AbstractParser to create
* UninitializedMessageException with missing field information.
*/
@Override
UninitializedMessageException newUninitializedMessageException() {
return Builder.newUninitializedMessageException(this);
}
// =================================================================
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
* other methods.
*/
@SuppressWarnings("unchecked")
public static abstract class Builder<BuilderType extends Builder<BuilderType>>
extends AbstractMessageLite.Builder
implements Message.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
public abstract BuilderType clone();
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
@Override
public boolean hasOneof(OneofDescriptor oneof) {
throw new UnsupportedOperationException("hasOneof() is not implemented.");
}
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
@Override
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
throw new UnsupportedOperationException(
"getOneofFieldDescriptor() is not implemented.");
}
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
@Override
public BuilderType clearOneof(OneofDescriptor oneof) {
throw new UnsupportedOperationException("clearOneof() is not implemented.");
}
@Override
public BuilderType clear() {
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
clearField(entry.getKey());
}
return (BuilderType) this;
}
@Override
public List<String> findInitializationErrors() {
return MessageReflection.findMissingFields(this);
}
@Override
public String getInitializationErrorString() {
return MessageReflection.delimitWithCommas(findInitializationErrors());
}
@Override
protected BuilderType internalMergeFrom(AbstractMessageLite other) {
return mergeFrom((Message) other);
}
@Override
public BuilderType mergeFrom(final Message other) {
if (other.getDescriptorForType() != getDescriptorForType()) {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
}
// Note: We don't attempt to verify that other's fields have valid
// types. Doing so would be a losing battle. We'd have to verify
// all sub-messages as well, and we'd have to make copies of all of
// them to insure that they don't change after verification (since
// the Message interface itself cannot enforce immutability of
// implementations).
// TODO(kenton): Provide a function somewhere called makeDeepCopy()
// which allows people to make secure deep copies of messages.
for (final Map.Entry<FieldDescriptor, Object> entry :
other.getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
if (field.isRepeated()) {
for (final Object element : (List)entry.getValue()) {
addRepeatedField(field, element);
}
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
final Message existingValue = (Message)getField(field);
if (existingValue == existingValue.getDefaultInstanceForType()) {
setField(field, entry.getValue());
} else {
setField(field,
existingValue.newBuilderForType()
.mergeFrom(existingValue)
.mergeFrom((Message)entry.getValue())
.build());
}
} else {
setField(field, entry.getValue());
}
}
mergeUnknownFields(other.getUnknownFields());
return (BuilderType) this;
}
@Override
public BuilderType mergeFrom(final CodedInputStream input)
throws IOException {
return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
}
@Override
public BuilderType mergeFrom(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final UnknownFieldSet.Builder unknownFields =
UnknownFieldSet.newBuilder(getUnknownFields());
while (true) {
final int tag = input.readTag();
if (tag == 0) {
break;
}
MessageReflection.BuilderAdapter builderAdapter =
new MessageReflection.BuilderAdapter(this);
if (!MessageReflection.mergeFieldFrom(input, unknownFields,
extensionRegistry,
getDescriptorForType(),
builderAdapter,
tag)) {
// end group tag
break;
}
}
setUnknownFields(unknownFields.build());
return (BuilderType) this;
}
@Override
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
setUnknownFields(
UnknownFieldSet.newBuilder(getUnknownFields())
.mergeFrom(unknownFields)
.build());
return (BuilderType) this;
}
@Override
public Message.Builder getFieldBuilder(final FieldDescriptor field) {
throw new UnsupportedOperationException(
"getFieldBuilder() called on an unsupported message type.");
}
@Override
public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
throw new UnsupportedOperationException(
"getRepeatedFieldBuilder() called on an unsupported message type.");
}
@Override
public String toString() {
return TextFormat.printToString(this);
}
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
*/
protected static UninitializedMessageException
newUninitializedMessageException(Message message) {
return new UninitializedMessageException(
MessageReflection.findMissingFields(message));
}
/**
* Used to support nested builders and called to mark this builder as clean.
* Clean builders will propagate the {@link BuilderParent#markDirty()} event
* to their parent builders, while dirty builders will not, as their parents
* should be dirty already.
*
* NOTE: Implementations that don't support nested builders don't need to
* override this method.
*/
void markClean() {
throw new IllegalStateException("Should be overridden by subclasses.");
}
/**
* Used to support nested builders and called when this nested builder is
* no longer used by its parent builder and should release the reference
* to its parent builder.
*
* NOTE: Implementations that don't support nested builders don't need to
* override this method.
*/
void dispose() {
throw new IllegalStateException("Should be overridden by subclasses.");
}
// ===============================================================
// The following definitions seem to be required in order to make javac
// not produce weird errors like:
//
// java/com/google/protobuf/DynamicMessage.java:203: types
// com.google.protobuf.AbstractMessage.Builder<
// com.google.protobuf.DynamicMessage.Builder> and
// com.google.protobuf.AbstractMessage.Builder<
// com.google.protobuf.DynamicMessage.Builder> are incompatible; both
// define mergeFrom(com.google.protobuf.ByteString), but with unrelated
// return types.
//
// Strangely, these lines are only needed if javac is invoked separately
// on AbstractMessage.java and AbstractMessageLite.java. If javac is
// invoked on both simultaneously, it works. (Or maybe the important
// point is whether or not DynamicMessage.java is compiled together with
// AbstractMessageLite.java -- not sure.) I suspect this is a compiler
// bug.
@Override
public BuilderType mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
return (BuilderType) super.mergeFrom(data);
}
@Override
public BuilderType mergeFrom(
final ByteString data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return (BuilderType) super.mergeFrom(data, extensionRegistry);
}
@Override
public BuilderType mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
return (BuilderType) super.mergeFrom(data);
}
@Override
public BuilderType mergeFrom(
final byte[] data, final int off, final int len)
throws InvalidProtocolBufferException {
return (BuilderType) super.mergeFrom(data, off, len);
}
@Override
public BuilderType mergeFrom(
final byte[] data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return (BuilderType) super.mergeFrom(data, extensionRegistry);
}
@Override
public BuilderType mergeFrom(
final byte[] data, final int off, final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry);
}
@Override
public BuilderType mergeFrom(final InputStream input)
throws IOException {
return (BuilderType) super.mergeFrom(input);
}
@Override
public BuilderType mergeFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
return (BuilderType) super.mergeFrom(input, extensionRegistry);
}
@Override
public boolean mergeDelimitedFrom(final InputStream input)
throws IOException {
return super.mergeDelimitedFrom(input);
}
@Override
public boolean mergeDelimitedFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
return super.mergeDelimitedFrom(input, extensionRegistry);
}
}
/**
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
* generated code.
*/
@Deprecated
protected static int hashLong(long n) {
return (int) (n ^ (n >>> 32));
}
//
/**
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
* generated code.
*/
@Deprecated
protected static int hashBoolean(boolean b) {
return b ? 1231 : 1237;
}
//
/**
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
* generated code.
*/
@Deprecated
protected static int hashEnum(EnumLite e) {
return e.getNumber();
}
//
/**
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
* generated code.
*/
@Deprecated
protected static int hashEnumList(List<? extends EnumLite> list) {
int hash = 1;
for (EnumLite e : list) {
hash = 31 * hash + hashEnum(e);
}
return hash;
}
}

@ -0,0 +1,384 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
/**
* A partial implementation of the {@link MessageLite} interface which
* implements as many methods of that interface as possible in terms of other
* methods.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class AbstractMessageLite<
MessageType extends AbstractMessageLite<MessageType, BuilderType>,
BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
implements MessageLite {
protected int memoizedHashCode = 0;
@Override
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
ByteString.newCodedBuilder(getSerializedSize());
writeTo(out.getCodedOutput());
return out.build();
} catch (IOException e) {
throw new RuntimeException(getSerializingExceptionMessage("ByteString"), e);
}
}
@Override
public byte[] toByteArray() {
try {
final byte[] result = new byte[getSerializedSize()];
final CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(output);
output.checkNoSpaceLeft();
return result;
} catch (IOException e) {
throw new RuntimeException(getSerializingExceptionMessage("byte array"), e);
}
}
@Override
public void writeTo(final OutputStream output) throws IOException {
final int bufferSize =
CodedOutputStream.computePreferredBufferSize(getSerializedSize());
final CodedOutputStream codedOutput =
CodedOutputStream.newInstance(output, bufferSize);
writeTo(codedOutput);
codedOutput.flush();
}
@Override
public void writeDelimitedTo(final OutputStream output) throws IOException {
final int serialized = getSerializedSize();
final int bufferSize = CodedOutputStream.computePreferredBufferSize(
CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
final CodedOutputStream codedOutput =
CodedOutputStream.newInstance(output, bufferSize);
codedOutput.writeRawVarint32(serialized);
writeTo(codedOutput);
codedOutput.flush();
}
/**
* Package private helper method for AbstractParser to create
* UninitializedMessageException.
*/
UninitializedMessageException newUninitializedMessageException() {
return new UninitializedMessageException(this);
}
private String getSerializingExceptionMessage(String target) {
return "Serializing " + getClass().getName() + " to a " + target
+ " threw an IOException (should never happen).";
}
protected static void checkByteStringIsUtf8(ByteString byteString)
throws IllegalArgumentException {
if (!byteString.isValidUtf8()) {
throw new IllegalArgumentException("Byte string is not UTF-8.");
}
}
protected static <T> void addAll(final Iterable<T> values,
final Collection<? super T> list) {
Builder.addAll(values, list);
}
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
* other methods.
*/
@SuppressWarnings("unchecked")
public abstract static class Builder<
MessageType extends AbstractMessageLite<MessageType, BuilderType>,
BuilderType extends Builder<MessageType, BuilderType>>
implements MessageLite.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
public abstract BuilderType clone();
@Override
public BuilderType mergeFrom(final CodedInputStream input) throws IOException {
return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
}
// Re-defined here for return type covariance.
@Override
public abstract BuilderType mergeFrom(
final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)
throws IOException;
@Override
public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
}
}
@Override
public BuilderType mergeFrom(
final ByteString data, final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
}
}
@Override
public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length);
}
@Override
public BuilderType mergeFrom(final byte[] data, final int off, final int len)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
}
}
@Override
public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length, extensionRegistry);
}
@Override
public BuilderType mergeFrom(
final byte[] data,
final int off,
final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
}
}
@Override
public BuilderType mergeFrom(final InputStream input) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
}
@Override
public BuilderType mergeFrom(
final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput, extensionRegistry);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
}
/**
* An InputStream implementations which reads from some other InputStream
* but is limited to a particular number of bytes. Used by
* mergeDelimitedFrom(). This is intentionally package-private so that
* UnknownFieldSet can share it.
*/
static final class LimitedInputStream extends FilterInputStream {
private int limit;
LimitedInputStream(InputStream in, int limit) {
super(in);
this.limit = limit;
}
@Override
public int available() throws IOException {
return Math.min(super.available(), limit);
}
@Override
public int read() throws IOException {
if (limit <= 0) {
return -1;
}
final int result = super.read();
if (result >= 0) {
--limit;
}
return result;
}
@Override
public int read(final byte[] b, final int off, int len)
throws IOException {
if (limit <= 0) {
return -1;
}
len = Math.min(len, limit);
final int result = super.read(b, off, len);
if (result >= 0) {
limit -= result;
}
return result;
}
@Override
public long skip(final long n) throws IOException {
final long result = super.skip(Math.min(n, limit));
if (result >= 0) {
limit -= result;
}
return result;
}
}
@Override
public boolean mergeDelimitedFrom(
final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
return false;
}
final int size = CodedInputStream.readRawVarint32(firstByte, input);
final InputStream limitedInput = new LimitedInputStream(input, size);
mergeFrom(limitedInput, extensionRegistry);
return true;
}
@Override
public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
return mergeDelimitedFrom(input,
ExtensionRegistryLite.getEmptyRegistry());
}
@Override
@SuppressWarnings("unchecked") // isInstance takes care of this
public BuilderType mergeFrom(final MessageLite other) {
if (!getDefaultInstanceForType().getClass().isInstance(other)) {
throw new IllegalArgumentException(
"mergeFrom(MessageLite) can only merge messages of the same type.");
}
return internalMergeFrom((MessageType) other);
}
protected abstract BuilderType internalMergeFrom(MessageType message);
private String getReadingExceptionMessage(String target) {
return "Reading " + getClass().getName() + " from a " + target
+ " threw an IOException (should never happen).";
}
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
*/
protected static UninitializedMessageException
newUninitializedMessageException(MessageLite message) {
return new UninitializedMessageException(message);
}
/**
* Adds the {@code values} to the {@code list}. This is a helper method
* used by generated code. Users should ignore it.
*
* @throws NullPointerException if {@code values} or any of the elements of
* {@code values} is null. When that happens, some elements of
* {@code values} may have already been added to the result {@code list}.
*/
protected static <T> void addAll(final Iterable<T> values,
final Collection<? super T> list) {
if (values == null) {
throw new NullPointerException();
}
if (values instanceof LazyStringList) {
// For StringOrByteStringLists, check the underlying elements to avoid
// forcing conversions of ByteStrings to Strings.
checkForNullValues(((LazyStringList) values).getUnderlyingElements());
list.addAll((Collection<T>) values);
} else if (values instanceof Collection) {
checkForNullValues(values);
list.addAll((Collection<T>) values);
} else {
for (final T value : values) {
if (value == null) {
throw new NullPointerException();
}
list.add(value);
}
}
}
private static void checkForNullValues(final Iterable<?> values) {
for (final Object value : values) {
if (value == null) {
throw new NullPointerException();
}
}
}
}
}

@ -0,0 +1,258 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* A partial implementation of the {@link Parser} interface which implements
* as many methods of that interface as possible in terms of other methods.
*
* Note: This class implements all the convenience methods in the
* {@link Parser} interface. See {@link Parser} for related javadocs.
* Subclasses need to implement
* {@link Parser#parsePartialFrom(CodedInputStream, ExtensionRegistryLite)}
*
* @author liujisi@google.com (Pherl Liu)
*/
public abstract class AbstractParser<MessageType extends MessageLite>
implements Parser<MessageType> {
/**
* Creates an UninitializedMessageException for MessageType.
*/
private UninitializedMessageException
newUninitializedMessageException(MessageType message) {
if (message instanceof AbstractMessageLite) {
return ((AbstractMessageLite) message).newUninitializedMessageException();
}
return new UninitializedMessageException(message);
}
/**
* Helper method to check if message is initialized.
*
* @throws InvalidProtocolBufferException if it is not initialized.
* @return The message to check.
*/
private MessageType checkMessageInitialized(MessageType message)
throws InvalidProtocolBufferException {
if (message != null && !message.isInitialized()) {
throw newUninitializedMessageException(message)
.asInvalidProtocolBufferException()
.setUnfinishedMessage(message);
}
return message;
}
private static final ExtensionRegistryLite EMPTY_REGISTRY
= ExtensionRegistryLite.getEmptyRegistry();
@Override
public MessageType parsePartialFrom(CodedInputStream input)
throws InvalidProtocolBufferException {
return parsePartialFrom(input, EMPTY_REGISTRY);
}
@Override
public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(input, extensionRegistry));
}
@Override
public MessageType parseFrom(CodedInputStream input) throws InvalidProtocolBufferException {
return parseFrom(input, EMPTY_REGISTRY);
}
@Override
public MessageType parsePartialFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
MessageType message;
try {
CodedInputStream input = data.newCodedInput();
message = parsePartialFrom(input, extensionRegistry);
try {
input.checkLastTagWas(0);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(message);
}
return message;
} catch (InvalidProtocolBufferException e) {
throw e;
}
}
@Override
public MessageType parsePartialFrom(ByteString data) throws InvalidProtocolBufferException {
return parsePartialFrom(data, EMPTY_REGISTRY);
}
@Override
public MessageType parseFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(parsePartialFrom(data, extensionRegistry));
}
@Override
public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException {
return parseFrom(data, EMPTY_REGISTRY);
}
@Override
public MessageType parsePartialFrom(
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
CodedInputStream input = CodedInputStream.newInstance(data, off, len);
MessageType message = parsePartialFrom(input, extensionRegistry);
try {
input.checkLastTagWas(0);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(message);
}
return message;
} catch (InvalidProtocolBufferException e) {
throw e;
}
}
@Override
public MessageType parsePartialFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
return parsePartialFrom(data, off, len, EMPTY_REGISTRY);
}
@Override
public MessageType parsePartialFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return parsePartialFrom(data, 0, data.length, extensionRegistry);
}
@Override
public MessageType parsePartialFrom(byte[] data) throws InvalidProtocolBufferException {
return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY);
}
@Override
public MessageType parseFrom(
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(data, off, len, extensionRegistry));
}
@Override
public MessageType parseFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
return parseFrom(data, off, len, EMPTY_REGISTRY);
}
@Override
public MessageType parseFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return parseFrom(data, 0, data.length, extensionRegistry);
}
@Override
public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException {
return parseFrom(data, EMPTY_REGISTRY);
}
@Override
public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
CodedInputStream codedInput = CodedInputStream.newInstance(input);
MessageType message = parsePartialFrom(codedInput, extensionRegistry);
try {
codedInput.checkLastTagWas(0);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(message);
}
return message;
}
@Override
public MessageType parsePartialFrom(InputStream input) throws InvalidProtocolBufferException {
return parsePartialFrom(input, EMPTY_REGISTRY);
}
@Override
public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(input, extensionRegistry));
}
@Override
public MessageType parseFrom(InputStream input) throws InvalidProtocolBufferException {
return parseFrom(input, EMPTY_REGISTRY);
}
@Override
public MessageType parsePartialDelimitedFrom(
InputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
int size;
try {
int firstByte = input.read();
if (firstByte == -1) {
return null;
}
size = CodedInputStream.readRawVarint32(firstByte, input);
} catch (IOException e) {
throw new InvalidProtocolBufferException(e.getMessage());
}
InputStream limitedInput = new LimitedInputStream(input, size);
return parsePartialFrom(limitedInput, extensionRegistry);
}
@Override
public MessageType parsePartialDelimitedFrom(InputStream input)
throws InvalidProtocolBufferException {
return parsePartialDelimitedFrom(input, EMPTY_REGISTRY);
}
@Override
public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialDelimitedFrom(input, extensionRegistry));
}
@Override
public MessageType parseDelimitedFrom(InputStream input) throws InvalidProtocolBufferException {
return parseDelimitedFrom(input, EMPTY_REGISTRY);
}
}

@ -0,0 +1,180 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Internal.ProtobufList;
import java.util.AbstractList;
import java.util.Collection;
import java.util.List;
import java.util.RandomAccess;
/**
* An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate
* methods must check if the list is mutable before proceeding. Subclasses must invoke
* {@link #ensureIsMutable()} manually when overriding those methods.
* <p>
* This implementation assumes all subclasses are array based, supporting random access.
*/
abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> {
protected static final int DEFAULT_CAPACITY = 10;
/**
* Whether or not this list is modifiable.
*/
private boolean isMutable;
/**
* Constructs a mutable list by default.
*/
AbstractProtobufList() {
isMutable = true;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof List)) {
return false;
}
// Handle lists that do not support RandomAccess as efficiently as possible by using an iterator
// based approach in our super class. Otherwise our index based approach will avoid those
// allocations.
if (!(o instanceof RandomAccess)) {
return super.equals(o);
}
List<?> other = (List<?>) o;
final int size = size();
if (size != other.size()) {
return false;
}
for (int i = 0; i < size; i++) {
if (!get(i).equals(other.get(i))) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
final int size = size();
int hashCode = 1;
for (int i = 0; i < size; i++) {
hashCode = (31 * hashCode) + get(i).hashCode();
}
return hashCode;
}
@Override
public boolean add(E e) {
ensureIsMutable();
return super.add(e);
}
@Override
public void add(int index, E element) {
ensureIsMutable();
super.add(index, element);
}
@Override
public boolean addAll(Collection<? extends E> c) {
ensureIsMutable();
return super.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
ensureIsMutable();
return super.addAll(index, c);
}
@Override
public void clear() {
ensureIsMutable();
super.clear();
}
@Override
public boolean isModifiable() {
return isMutable;
}
@Override
public final void makeImmutable() {
isMutable = false;
}
@Override
public E remove(int index) {
ensureIsMutable();
return super.remove(index);
}
@Override
public boolean remove(Object o) {
ensureIsMutable();
return super.remove(o);
}
@Override
public boolean removeAll(Collection<?> c) {
ensureIsMutable();
return super.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
ensureIsMutable();
return super.retainAll(c);
}
@Override
public E set(int index, E element) {
ensureIsMutable();
return super.set(index, element);
}
/**
* Throws an {@link UnsupportedOperationException} if the list is immutable. Subclasses are
* responsible for invoking this method on mutate operations.
*/
protected void ensureIsMutable() {
if (!isMutable) {
throw new UnsupportedOperationException();
}
}
}

@ -0,0 +1,51 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* <p>Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel}
* is the blocking equivalent to {@link RpcChannel}.
*
* @author kenton@google.com Kenton Varda
* @author cpovirk@google.com Chris Povirk
*/
public interface BlockingRpcChannel {
/**
* Call the given method of the remote service and blocks until it returns.
* {@code callBlockingMethod()} is the blocking equivalent to
* {@link RpcChannel#callMethod}.
*/
Message callBlockingMethod(
Descriptors.MethodDescriptor method,
RpcController controller,
Message request,
Message responsePrototype) throws ServiceException;
}

@ -0,0 +1,64 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Blocking equivalent to {@link Service}.
*
* @author kenton@google.com Kenton Varda
* @author cpovirk@google.com Chris Povirk
*/
public interface BlockingService {
/**
* Equivalent to {@link Service#getDescriptorForType}.
*/
Descriptors.ServiceDescriptor getDescriptorForType();
/**
* Equivalent to {@link Service#callMethod}, except that
* {@code callBlockingMethod()} returns the result of the RPC or throws a
* {@link ServiceException} if there is a failure, rather than passing the
* information to a callback.
*/
Message callBlockingMethod(Descriptors.MethodDescriptor method,
RpcController controller,
Message request) throws ServiceException;
/**
* Equivalent to {@link Service#getRequestPrototype}.
*/
Message getRequestPrototype(Descriptors.MethodDescriptor method);
/**
* Equivalent to {@link Service#getResponsePrototype}.
*/
Message getResponsePrototype(Descriptors.MethodDescriptor method);
}

@ -30,50 +30,86 @@
package com.google.protobuf.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.math.IntMath.checkedAdd;
import static com.google.common.math.IntMath.checkedSubtract;
import static com.google.common.math.LongMath.checkedAdd;
import static com.google.common.math.LongMath.checkedMultiply;
import static com.google.common.math.LongMath.checkedSubtract;
import static com.google.protobuf.util.Timestamps.MICROS_PER_SECOND;
import static com.google.protobuf.util.Timestamps.MILLIS_PER_SECOND;
import static com.google.protobuf.util.Timestamps.NANOS_PER_MICROSECOND;
import static com.google.protobuf.util.Timestamps.NANOS_PER_MILLISECOND;
import static com.google.protobuf.util.Timestamps.NANOS_PER_SECOND;
import com.google.common.collect.ComparisonChain;
import com.google.protobuf.Duration;
import java.text.ParseException;
import java.util.Comparator;
/**
* Utilities to help create/manipulate {@code protobuf/duration.proto}.
* Utilities to help create/manipulate {@code protobuf/duration.proto}. All operations throw an
* {@link IllegalArgumentException} if the input(s) are not {@linkplain #isValid(Duration) valid}.
*/
public final class Durations {
static final long DURATION_SECONDS_MIN = -315576000000L;
static final long DURATION_SECONDS_MAX = 315576000000L;
// TODO(kak): Do we want to expose Duration constants for MAX/MIN?
/** A constant holding the minimum valid {@link Duration}, approximately {@code -10,000} years. */
public static final Duration MIN_VALUE =
Duration.newBuilder().setSeconds(DURATION_SECONDS_MIN).setNanos(-999999999).build();
/** A constant holding the maximum valid {@link Duration}, approximately {@code +10,000} years. */
public static final Duration MAX_VALUE =
Duration.newBuilder().setSeconds(DURATION_SECONDS_MAX).setNanos(999999999).build();
private Durations() {}
private static final Comparator<Duration> COMPARATOR =
new Comparator<Duration>() {
@Override
public int compare(Duration d1, Duration d2) {
checkValid(d1);
checkValid(d2);
return ComparisonChain.start()
.compare(d1.getSeconds(), d2.getSeconds())
.compare(d1.getNanos(), d2.getNanos())
.result();
}
};
/**
* Returns a {@link Comparator} for {@link Duration}s which sorts in increasing chronological
* order. Nulls and invalid {@link Duration}s are not allowed (see {@link #isValid}).
*/
public static Comparator<Duration> comparator() {
return COMPARATOR;
}
/**
* Returns true if the given {@link Duration} is valid. The {@code seconds} value must be in the
* range [-315,576,000,000, +315,576,000,000]. The {@code nanos} value must be in the range
* [-999,999,999, +999,999,999].
*
* <p>Note: Durations less than one second are represented with a 0 {@code seconds} field and a
* positive or negative {@code nanos} field. For durations of one second or more, a non-zero value
* for the {@code nanos} field must be of the same sign as the {@code seconds} field.
* <p><b>Note:</b> Durations less than one second are represented with a 0 {@code seconds} field
* and a positive or negative {@code nanos} field. For durations of one second or more, a non-zero
* value for the {@code nanos} field must be of the same sign as the {@code seconds} field.
*/
public static boolean isValid(Duration duration) {
return isValid(duration.getSeconds(), duration.getNanos());
}
/**
* Returns true if the given number of seconds and nanos is a valid {@link Duration}. The
* {@code seconds} value must be in the range [-315,576,000,000, +315,576,000,000]. The
* {@code nanos} value must be in the range [-999,999,999, +999,999,999].
* Returns true if the given number of seconds and nanos is a valid {@link Duration}. The {@code
* seconds} value must be in the range [-315,576,000,000, +315,576,000,000]. The {@code nanos}
* value must be in the range [-999,999,999, +999,999,999].
*
* <p>Note: Durations less than one second are represented with a 0 {@code seconds} field and a
* positive or negative {@code nanos} field. For durations of one second or more, a non-zero value
* for the {@code nanos} field must be of the same sign as the {@code seconds} field.
* <p><b>Note:</b> Durations less than one second are represented with a 0 {@code seconds} field
* and a positive or negative {@code nanos} field. For durations of one second or more, a non-zero
* value for the {@code nanos} field must be of the same sign as the {@code seconds} field.
*/
public static boolean isValid(long seconds, long nanos) {
public static boolean isValid(long seconds, int nanos) {
if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) {
return false;
}
@ -88,35 +124,35 @@ public final class Durations {
return true;
}
/**
* Throws an {@link IllegalArgumentException} if the given seconds/nanos are not
* a valid {@link Duration}.
*/
private static void checkValid(long seconds, int nanos) {
if (!isValid(seconds, nanos)) {
throw new IllegalArgumentException(String.format(
"Duration is not valid. See proto definition for valid values. "
+ "Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]."
+ "Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
+ "Nanos must have the same sign as seconds", seconds, nanos));
}
/** Throws an {@link IllegalArgumentException} if the given {@link Duration} is not valid. */
public static Duration checkValid(Duration duration) {
long seconds = duration.getSeconds();
int nanos = duration.getNanos();
checkArgument(
isValid(seconds, nanos),
"Duration is not valid. See proto definition for valid values. "
+ "Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]. "
+ "Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
+ "Nanos must have the same sign as seconds",
seconds,
nanos);
return duration;
}
/**
* Convert Duration to string format. The string format will contains 3, 6,
* or 9 fractional digits depending on the precision required to represent
* the exact Duration value. For example: "1s", "1.010s", "1.000000100s",
* "-3.100s" The range that can be represented by Duration is from
* Convert Duration to string format. The string format will contains 3, 6, or 9 fractional digits
* depending on the precision required to represent the exact Duration value. For example: "1s",
* "1.010s", "1.000000100s", "-3.100s" The range that can be represented by Duration is from
* -315,576,000,000 to +315,576,000,000 inclusive (in seconds).
*
* @return The string representation of the given duration.
* @throws IllegalArgumentException if the given duration is not in the valid
* range.
* @throws IllegalArgumentException if the given duration is not in the valid range.
*/
public static String toString(Duration duration) {
checkValid(duration);
long seconds = duration.getSeconds();
int nanos = duration.getNanos();
checkValid(seconds, nanos);
StringBuilder result = new StringBuilder();
if (seconds < 0 || nanos < 0) {
@ -172,9 +208,20 @@ public final class Durations {
}
}
/** Create a Duration from the number of seconds. */
public static Duration fromSeconds(long seconds) {
return normalizedDuration(seconds, 0);
}
/**
* Create a Duration from the number of milliseconds.
* Convert a Duration to the number of seconds. The result will be rounded towards 0 to the
* nearest second. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
*/
public static long toSeconds(Duration duration) {
return checkValid(duration).getSeconds();
}
/** Create a Duration from the number of milliseconds. */
public static Duration fromMillis(long milliseconds) {
return normalizedDuration(
milliseconds / MILLIS_PER_SECOND,
@ -182,17 +229,17 @@ public final class Durations {
}
/**
* Convert a Duration to the number of milliseconds.The result will be
* rounded towards 0 to the nearest millisecond. E.g., if the duration
* represents -1 nanosecond, it will be rounded to 0.
* Convert a Duration to the number of milliseconds. The result will be rounded towards 0 to the
* nearest millisecond. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
*/
public static long toMillis(Duration duration) {
return duration.getSeconds() * MILLIS_PER_SECOND + duration.getNanos() / NANOS_PER_MILLISECOND;
checkValid(duration);
return checkedAdd(
checkedMultiply(duration.getSeconds(), MILLIS_PER_SECOND),
duration.getNanos() / NANOS_PER_MILLISECOND);
}
/**
* Create a Duration from the number of microseconds.
*/
/** Create a Duration from the number of microseconds. */
public static Duration fromMicros(long microseconds) {
return normalizedDuration(
microseconds / MICROS_PER_SECOND,
@ -200,57 +247,60 @@ public final class Durations {
}
/**
* Convert a Duration to the number of microseconds.The result will be
* rounded towards 0 to the nearest microseconds. E.g., if the duration
* represents -1 nanosecond, it will be rounded to 0.
* Convert a Duration to the number of microseconds. The result will be rounded towards 0 to the
* nearest microseconds. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
*/
public static long toMicros(Duration duration) {
return duration.getSeconds() * MICROS_PER_SECOND + duration.getNanos() / NANOS_PER_MICROSECOND;
checkValid(duration);
return checkedAdd(
checkedMultiply(duration.getSeconds(), MICROS_PER_SECOND),
duration.getNanos() / NANOS_PER_MICROSECOND);
}
/**
* Create a Duration from the number of nanoseconds.
*/
/** Create a Duration from the number of nanoseconds. */
public static Duration fromNanos(long nanoseconds) {
return normalizedDuration(
nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
}
/**
* Convert a Duration to the number of nanoseconds.
*/
/** Convert a Duration to the number of nanoseconds. */
public static long toNanos(Duration duration) {
return duration.getSeconds() * NANOS_PER_SECOND + duration.getNanos();
checkValid(duration);
return checkedAdd(
checkedMultiply(duration.getSeconds(), NANOS_PER_SECOND), duration.getNanos());
}
/**
* Add two durations.
*/
/** Add two durations. */
public static Duration add(Duration d1, Duration d2) {
return normalizedDuration(d1.getSeconds() + d2.getSeconds(), d1.getNanos() + d2.getNanos());
checkValid(d1);
checkValid(d2);
return normalizedDuration(
checkedAdd(d1.getSeconds(), d2.getSeconds()), checkedAdd(d1.getNanos(), d2.getNanos()));
}
/**
* Subtract a duration from another.
*/
/** Subtract a duration from another. */
public static Duration subtract(Duration d1, Duration d2) {
return normalizedDuration(d1.getSeconds() - d2.getSeconds(), d1.getNanos() - d2.getNanos());
checkValid(d1);
checkValid(d2);
return normalizedDuration(
checkedSubtract(d1.getSeconds(), d2.getSeconds()),
checkedSubtract(d1.getNanos(), d2.getNanos()));
}
static Duration normalizedDuration(long seconds, int nanos) {
if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
seconds += nanos / NANOS_PER_SECOND;
seconds = checkedAdd(seconds, nanos / NANOS_PER_SECOND);
nanos %= NANOS_PER_SECOND;
}
if (seconds > 0 && nanos < 0) {
nanos += NANOS_PER_SECOND;
seconds -= 1;
nanos += NANOS_PER_SECOND; // no overflow since nanos is negative (and we're adding)
seconds--; // no overflow since seconds is positive (and we're decrementing)
}
if (seconds < 0 && nanos > 0) {
nanos -= NANOS_PER_SECOND;
seconds += 1;
nanos -= NANOS_PER_SECOND; // no overflow since nanos is positive (and we're subtracting)
seconds++; // no overflow since seconds is negative (and we're incrementing)
}
checkValid(seconds, nanos);
return Duration.newBuilder().setSeconds(seconds).setNanos(nanos).build();
Duration duration = Duration.newBuilder().setSeconds(seconds).setNanos(nanos).build();
return checkValid(duration);
}
}

@ -640,6 +640,10 @@ public class JsonFormat {
/** Prints google.protobuf.Any */
private void printAny(MessageOrBuilder message) throws IOException {
if (Any.getDefaultInstance().equals(message)) {
generator.print("{}");
return;
}
Descriptor descriptor = message.getDescriptorForType();
FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
FieldDescriptor valueField = descriptor.findFieldByName("value");
@ -1235,6 +1239,9 @@ public class JsonFormat {
throw new InvalidProtocolBufferException("Expect message object but got: " + json);
}
JsonObject object = (JsonObject) json;
if (object.entrySet().isEmpty()) {
return; // builder never modified, so it will end up building the default instance of Any
}
JsonElement typeUrlElement = object.get("@type");
if (typeUrlElement == null) {
throw new InvalidProtocolBufferException("Missing type url when parsing: " + json);
@ -1327,6 +1334,9 @@ public class JsonFormat {
Message.Builder listBuilder = builder.newBuilderForField(field);
merge(json, listBuilder);
builder.setField(field, listBuilder.build());
} else if (json instanceof JsonNull) {
builder.setField(
type.findFieldByName("null_value"), NullValue.NULL_VALUE.getValueDescriptor());
} else {
throw new IllegalStateException("Unexpected json data: " + json);
}
@ -1620,11 +1630,6 @@ public class JsonFormat {
}
private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferException {
String encoded = json.getAsString();
if (encoded.length() % 4 != 0) {
throw new InvalidProtocolBufferException(
"Bytes field is not encoded in standard BASE64 with paddings: " + encoded);
}
return ByteString.copyFrom(BaseEncoding.base64().decode(json.getAsString()));
}

@ -30,19 +30,29 @@
package com.google.protobuf.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.math.IntMath.checkedAdd;
import static com.google.common.math.IntMath.checkedSubtract;
import static com.google.common.math.LongMath.checkedAdd;
import static com.google.common.math.LongMath.checkedMultiply;
import static com.google.common.math.LongMath.checkedSubtract;
import com.google.common.collect.ComparisonChain;
import com.google.protobuf.Duration;
import com.google.protobuf.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
/**
* Utilities to help create/manipulate {@code protobuf/timestamp.proto}.
* Utilities to help create/manipulate {@code protobuf/timestamp.proto}. All operations throw an
* {@link IllegalArgumentException} if the input(s) are not {@linkplain #isValid(Timestamp) valid}.
*/
public final class Timestamps {
// Timestamp for "0001-01-01T00:00:00Z"
static final long TIMESTAMP_SECONDS_MIN = -62135596800L;
@ -55,10 +65,19 @@ public final class Timestamps {
static final long MILLIS_PER_SECOND = 1000;
static final long MICROS_PER_SECOND = 1000000;
// TODO(kak): Do we want to expose Timestamp constants for MAX/MIN?
/** A constant holding the minimum valid {@link Timestamp}, {@code 0001-01-01T00:00:00Z}. */
public static final Timestamp MIN_VALUE =
Timestamp.newBuilder().setSeconds(TIMESTAMP_SECONDS_MIN).setNanos(0).build();
/**
* A constant holding the maximum valid {@link Timestamp}, {@code 9999-12-31T23:59:59.999999999Z}.
*/
public static final Timestamp MAX_VALUE =
Timestamp.newBuilder().setSeconds(TIMESTAMP_SECONDS_MAX).setNanos(999999999).build();
private static final ThreadLocal<SimpleDateFormat> timestampFormat =
new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return createTimestampFormat();
}
@ -76,28 +95,50 @@ public final class Timestamps {
private Timestamps() {}
private static final Comparator<Timestamp> COMPARATOR =
new Comparator<Timestamp>() {
@Override
public int compare(Timestamp t1, Timestamp t2) {
checkValid(t1);
checkValid(t2);
return ComparisonChain.start()
.compare(t1.getSeconds(), t2.getSeconds())
.compare(t1.getNanos(), t2.getNanos())
.result();
}
};
/**
* Returns a {@link Comparator} for {@link Timestamp}s which sorts in increasing chronological
* order. Nulls and invalid {@link Timestamp}s are not allowed (see {@link #isValid}).
*/
public static Comparator<Timestamp> comparator() {
return COMPARATOR;
}
/**
* Returns true if the given {@link Timestamp} is valid. The {@code seconds} value must be in the
* range [-62,135,596,800, +253,402,300,799] (i.e., between 0001-01-01T00:00:00Z and
* 9999-12-31T23:59:59Z). The {@code nanos} value must be in the range [0, +999,999,999].
*
* <p>Note: Negative second values with fractions must still have non-negative nanos value that
* counts forward in time.
* <p><b>Note:</b> Negative second values with fractional seconds must still have non-negative
* nanos values that count forward in time.
*/
public static boolean isValid(Timestamp timestamp) {
return isValid(timestamp.getSeconds(), timestamp.getNanos());
}
/**
* Returns true if the given number of seconds and nanos is a valid {@link Timestamp}. The
* {@code seconds} value must be in the range [-62,135,596,800, +253,402,300,799] (i.e., between
* Returns true if the given number of seconds and nanos is a valid {@link Timestamp}. The {@code
* seconds} value must be in the range [-62,135,596,800, +253,402,300,799] (i.e., between
* 0001-01-01T00:00:00Z and 9999-12-31T23:59:59Z). The {@code nanos} value must be in the range
* [0, +999,999,999].
*
* <p>Note: Negative second values with fractions must still have non-negative nanos value that
* counts forward in time.
* <p><b>Note:</b> Negative second values with fractional seconds must still have non-negative
* nanos values that count forward in time.
*/
public static boolean isValid(long seconds, long nanos) {
public static boolean isValid(long seconds, int nanos) {
if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
return false;
}
@ -107,37 +148,37 @@ public final class Timestamps {
return true;
}
/**
* Throws an {@link IllegalArgumentException} if the given seconds/nanos are not
* a valid {@link Timestamp}.
*/
private static void checkValid(long seconds, int nanos) {
if (!isValid(seconds, nanos)) {
throw new IllegalArgumentException(String.format(
"Timestamp is not valid. See proto definition for valid values. "
+ "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]."
+ "Nanos (%s) must be in range [0, +999,999,999].",
seconds, nanos));
}
/** Throws an {@link IllegalArgumentException} if the given {@link Timestamp} is not valid. */
public static Timestamp checkValid(Timestamp timestamp) {
long seconds = timestamp.getSeconds();
int nanos = timestamp.getNanos();
checkArgument(
isValid(seconds, nanos),
"Timestamp is not valid. See proto definition for valid values. "
+ "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]. "
+ "Nanos (%s) must be in range [0, +999,999,999].",
seconds,
nanos);
return timestamp;
}
/**
* Convert Timestamp to RFC 3339 date string format. The output will always
* be Z-normalized and uses 3, 6 or 9 fractional digits as required to
* represent the exact value. Note that Timestamp can only represent time
* from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. See
* Convert Timestamp to RFC 3339 date string format. The output will always be Z-normalized and
* uses 3, 6 or 9 fractional digits as required to represent the exact value. Note that Timestamp
* can only represent time from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. See
* https://www.ietf.org/rfc/rfc3339.txt
*
* <p>Example of generated format: "1972-01-01T10:00:20.021Z"
*
* @return The string representation of the given timestamp.
* @throws IllegalArgumentException if the given timestamp is not in the
* valid range.
* @throws IllegalArgumentException if the given timestamp is not in the valid range.
*/
public static String toString(Timestamp timestamp) {
checkValid(timestamp);
long seconds = timestamp.getSeconds();
int nanos = timestamp.getNanos();
checkValid(seconds, nanos);
StringBuilder result = new StringBuilder();
// Format the seconds part.
Date date = new Date(seconds * MILLIS_PER_SECOND);
@ -152,10 +193,9 @@ public final class Timestamps {
}
/**
* Parse from RFC 3339 date string to Timestamp. This method accepts all
* outputs of {@link #toString(Timestamp)} and it also accepts any fractional
* digits (or none) and any offset as long as they fit into nano-seconds
* precision.
* Parse from RFC 3339 date string to Timestamp. This method accepts all outputs of {@link
* #toString(Timestamp)} and it also accepts any fractional digits (or none) and any offset as
* long as they fit into nano-seconds precision.
*
* <p>Example of accepted format: "1972-01-01T10:00:20.021-05:00"
*
@ -210,13 +250,26 @@ public final class Timestamps {
try {
return normalizedTimestamp(seconds, nanos);
} catch (IllegalArgumentException e) {
throw new ParseException("Failed to parse timestmap: timestamp is out of range.", 0);
throw new ParseException("Failed to parse timestamp: timestamp is out of range.", 0);
}
}
/** Create a Timestamp from the number of seconds elapsed from the epoch. */
public static Timestamp fromSeconds(long seconds) {
return normalizedTimestamp(seconds, 0);
}
/**
* Create a Timestamp from the number of milliseconds elapsed from the epoch.
* Convert a Timestamp to the number of seconds elapsed from the epoch.
*
* <p>The result will be rounded down to the nearest second. E.g., if the timestamp represents
* "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 second.
*/
public static long toSeconds(Timestamp timestamp) {
return checkValid(timestamp).getSeconds();
}
/** Create a Timestamp from the number of milliseconds elapsed from the epoch. */
public static Timestamp fromMillis(long milliseconds) {
return normalizedTimestamp(
milliseconds / MILLIS_PER_SECOND,
@ -226,18 +279,17 @@ public final class Timestamps {
/**
* Convert a Timestamp to the number of milliseconds elapsed from the epoch.
*
* <p>The result will be rounded down to the nearest millisecond. E.g., if the
* timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
* to -1 millisecond.
* <p>The result will be rounded down to the nearest millisecond. E.g., if the timestamp
* represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 millisecond.
*/
public static long toMillis(Timestamp timestamp) {
return timestamp.getSeconds() * MILLIS_PER_SECOND
+ timestamp.getNanos() / NANOS_PER_MILLISECOND;
checkValid(timestamp);
return checkedAdd(
checkedMultiply(timestamp.getSeconds(), MILLIS_PER_SECOND),
timestamp.getNanos() / NANOS_PER_MILLISECOND);
}
/**
* Create a Timestamp from the number of microseconds elapsed from the epoch.
*/
/** Create a Timestamp from the number of microseconds elapsed from the epoch. */
public static Timestamp fromMicros(long microseconds) {
return normalizedTimestamp(
microseconds / MICROS_PER_SECOND,
@ -247,65 +299,67 @@ public final class Timestamps {
/**
* Convert a Timestamp to the number of microseconds elapsed from the epoch.
*
* <p>The result will be rounded down to the nearest microsecond. E.g., if the
* timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
* to -1 millisecond.
* <p>The result will be rounded down to the nearest microsecond. E.g., if the timestamp
* represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 millisecond.
*/
public static long toMicros(Timestamp timestamp) {
return timestamp.getSeconds() * MICROS_PER_SECOND
+ timestamp.getNanos() / NANOS_PER_MICROSECOND;
checkValid(timestamp);
return checkedAdd(
checkedMultiply(timestamp.getSeconds(), MICROS_PER_SECOND),
timestamp.getNanos() / NANOS_PER_MICROSECOND);
}
/**
* Create a Timestamp from the number of nanoseconds elapsed from the epoch.
*/
/** Create a Timestamp from the number of nanoseconds elapsed from the epoch. */
public static Timestamp fromNanos(long nanoseconds) {
return normalizedTimestamp(
nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
}
/**
* Convert a Timestamp to the number of nanoseconds elapsed from the epoch.
*/
/** Convert a Timestamp to the number of nanoseconds elapsed from the epoch. */
public static long toNanos(Timestamp timestamp) {
return timestamp.getSeconds() * NANOS_PER_SECOND + timestamp.getNanos();
checkValid(timestamp);
return checkedAdd(
checkedMultiply(timestamp.getSeconds(), NANOS_PER_SECOND), timestamp.getNanos());
}
/**
* Calculate the difference between two timestamps.
*/
/** Calculate the difference between two timestamps. */
public static Duration between(Timestamp from, Timestamp to) {
checkValid(from);
checkValid(to);
return Durations.normalizedDuration(
to.getSeconds() - from.getSeconds(), to.getNanos() - from.getNanos());
checkedSubtract(to.getSeconds(), from.getSeconds()),
checkedSubtract(to.getNanos(), from.getNanos()));
}
/**
* Add a duration to a timestamp.
*/
/** Add a duration to a timestamp. */
public static Timestamp add(Timestamp start, Duration length) {
checkValid(start);
Durations.checkValid(length);
return normalizedTimestamp(
start.getSeconds() + length.getSeconds(), start.getNanos() + length.getNanos());
checkedAdd(start.getSeconds(), length.getSeconds()),
checkedAdd(start.getNanos(), length.getNanos()));
}
/**
* Subtract a duration from a timestamp.
*/
/** Subtract a duration from a timestamp. */
public static Timestamp subtract(Timestamp start, Duration length) {
checkValid(start);
Durations.checkValid(length);
return normalizedTimestamp(
start.getSeconds() - length.getSeconds(), start.getNanos() - length.getNanos());
checkedSubtract(start.getSeconds(), length.getSeconds()),
checkedSubtract(start.getNanos(), length.getNanos()));
}
private static Timestamp normalizedTimestamp(long seconds, int nanos) {
static Timestamp normalizedTimestamp(long seconds, int nanos) {
if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
seconds += nanos / NANOS_PER_SECOND;
seconds = checkedAdd(seconds, nanos / NANOS_PER_SECOND);
nanos %= NANOS_PER_SECOND;
}
if (nanos < 0) {
nanos += NANOS_PER_SECOND;
seconds -= 1;
nanos += NANOS_PER_SECOND; // no overflow since nanos is negative (and we're adding)
seconds = checkedSubtract(seconds, 1);
}
checkValid(seconds, nanos);
return Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
Timestamp timestamp = Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
return checkValid(timestamp);
}
private static long parseTimezoneOffset(String value) throws ParseException {
@ -324,7 +378,7 @@ public final class Timestamps {
result = result * 10;
if (i < value.length()) {
if (value.charAt(i) < '0' || value.charAt(i) > '9') {
throw new ParseException("Invalid nanosecnds.", 0);
throw new ParseException("Invalid nanoseconds.", 0);
}
result += value.charAt(i) - '0';
}
@ -332,11 +386,8 @@ public final class Timestamps {
return result;
}
/**
* Format the nano part of a timestamp or a duration.
*/
/** Format the nano part of a timestamp or a duration. */
static String formatNanos(int nanos) {
assert nanos >= 1 && nanos <= 999999999;
// Determine whether to use 3, 6, or 9 digits for the nano part.
if (nanos % NANOS_PER_MILLISECOND == 0) {
return String.format("%1$03d", nanos / NANOS_PER_MILLISECOND);

@ -60,12 +60,10 @@ import com.google.protobuf.util.JsonTestProto.TestOneof;
import com.google.protobuf.util.JsonTestProto.TestStruct;
import com.google.protobuf.util.JsonTestProto.TestTimestamp;
import com.google.protobuf.util.JsonTestProto.TestWrappers;
import junit.framework.TestCase;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import junit.framework.TestCase;
public class JsonFormatTest extends TestCase {
private void setAllFields(TestAllTypes.Builder builder) {
@ -819,6 +817,15 @@ public class JsonFormatTest extends TestCase {
printer.print(message));
assertRoundTripEquals(message, registry);
TestAny messageWithDefaultAnyValue =
TestAny.newBuilder().setAnyValue(Any.getDefaultInstance()).build();
assertEquals(
"{\n"
+ " \"anyValue\": {}\n"
+ "}",
printer.print(messageWithDefaultAnyValue));
assertRoundTripEquals(messageWithDefaultAnyValue, registry);
// Well-known types have a special formatting when embedded in Any.
//
// 1. Any in Any.
@ -952,6 +959,8 @@ public class JsonFormatTest extends TestCase {
+ "}",
printer.print(anyMessage));
assertRoundTripEquals(anyMessage, registry);
// 7. Value (number type) in Any
Value.Builder valueBuilder = Value.newBuilder();
valueBuilder.setNumberValue(1);
anyMessage = Any.pack(valueBuilder.build());
@ -962,6 +971,95 @@ public class JsonFormatTest extends TestCase {
+ "}",
printer.print(anyMessage));
assertRoundTripEquals(anyMessage, registry);
// 8. Value (null type) in Any
anyMessage = Any.pack(Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build());
assertEquals(
"{\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+ " \"value\": null\n"
+ "}",
printer.print(anyMessage));
assertRoundTripEquals(anyMessage, registry);
}
public void testAnyInMaps() throws Exception {
JsonFormat.TypeRegistry registry =
JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build();
JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
TestAny.Builder testAny = TestAny.newBuilder();
testAny.putAnyMap("int32_wrapper", Any.pack(Int32Value.newBuilder().setValue(123).build()));
testAny.putAnyMap("int64_wrapper", Any.pack(Int64Value.newBuilder().setValue(456).build()));
testAny.putAnyMap("timestamp", Any.pack(Timestamps.parse("1969-12-31T23:59:59Z")));
testAny.putAnyMap("duration", Any.pack(Durations.parse("12345.1s")));
testAny.putAnyMap("field_mask", Any.pack(FieldMaskUtil.fromString("foo.bar,baz")));
Value numberValue = Value.newBuilder().setNumberValue(1.125).build();
Struct.Builder struct = Struct.newBuilder();
struct.putFields("number", numberValue);
testAny.putAnyMap("struct", Any.pack(struct.build()));
Value nullValue = Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build();
testAny.putAnyMap(
"list_value",
Any.pack(ListValue.newBuilder().addValues(numberValue).addValues(nullValue).build()));
testAny.putAnyMap("number_value", Any.pack(numberValue));
testAny.putAnyMap("any_value_number", Any.pack(Any.pack(numberValue)));
testAny.putAnyMap("any_value_default", Any.pack(Any.getDefaultInstance()));
testAny.putAnyMap("default", Any.getDefaultInstance());
assertEquals(
"{\n"
+ " \"anyMap\": {\n"
+ " \"int32_wrapper\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
+ " \"value\": 123\n"
+ " },\n"
+ " \"int64_wrapper\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
+ " \"value\": \"456\"\n"
+ " },\n"
+ " \"timestamp\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
+ " \"value\": \"1969-12-31T23:59:59Z\"\n"
+ " },\n"
+ " \"duration\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
+ " \"value\": \"12345.100s\"\n"
+ " },\n"
+ " \"field_mask\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
+ " \"value\": \"foo.bar,baz\"\n"
+ " },\n"
+ " \"struct\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
+ " \"value\": {\n"
+ " \"number\": 1.125\n"
+ " }\n"
+ " },\n"
+ " \"list_value\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.ListValue\",\n"
+ " \"value\": [1.125, null]\n"
+ " },\n"
+ " \"number_value\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+ " \"value\": 1.125\n"
+ " },\n"
+ " \"any_value_number\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+ " \"value\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+ " \"value\": 1.125\n"
+ " }\n"
+ " },\n"
+ " \"any_value_default\": {\n"
+ " \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+ " \"value\": {}\n"
+ " },\n"
+ " \"default\": {}\n"
+ " }\n"
+ "}",
printer.print(testAny.build()));
assertRoundTripEquals(testAny.build(), registry);
}
public void testParserMissingTypeUrl() throws Exception {
@ -1016,8 +1114,10 @@ public class JsonFormatTest extends TestCase {
public void testParserRejectInvalidBase64() throws Exception {
assertRejects("optionalBytes", "!@#$");
// We use standard BASE64 with paddings.
assertRejects("optionalBytes", "AQI");
}
public void testParserAcceptBase64Variants() throws Exception {
assertAccepts("optionalBytes", "AQI");
}
public void testParserRejectInvalidEnumValue() throws Exception {

@ -32,14 +32,11 @@ package com.google.protobuf.util;
import com.google.protobuf.Duration;
import com.google.protobuf.Timestamp;
import junit.framework.TestCase;
import org.junit.Assert;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.junit.Assert;
/** Unit tests for {@link TimeUtil}. */
public class TimeUtilTest extends TestCase {

@ -195,6 +195,7 @@ message TestStruct {
message TestAny {
google.protobuf.Any any_value = 1;
map<string, google.protobuf.Any> any_map = 2;
}
message TestCustomJsonName {

@ -496,7 +496,7 @@ describe('protoBinaryTest', function() {
msg.setRepeatedBytesList([BYTES_B64, BYTES_B64]);
assertGetters();
msg.setRepeatedBytesList(null);
msg.setRepeatedBytesList([]);
assertEquals(0, msg.getRepeatedBytesList().length);
assertEquals(0, msg.getRepeatedBytesList_asB64().length);
assertEquals(0, msg.getRepeatedBytesList_asU8().length);

@ -95,8 +95,7 @@ jspb.debug.dump_ = function(thing) {
if (match && name != 'getExtension' &&
name != 'getJsPbMessageId') {
var has = 'has' + match[1];
if (!thing[has] || thing[has]())
{
if (!thing[has] || thing[has]()) {
var val = thing[name]();
object[jspb.debug.formatFieldName_(match[1])] = jspb.debug.dump_(val);
}

@ -65,7 +65,7 @@ describe('debugTest', function() {
'aBoolean': true
}, jspb.debug.dump(message));
message.setAString(undefined);
message.clearAString();
assertObjectEquals({
$name: 'proto.jspb.test.Simple1',

@ -103,7 +103,10 @@ jspb.Map.prototype.toArray = function() {
var m = this.map_;
for (var p in m) {
if (Object.prototype.hasOwnProperty.call(m, p)) {
m[p].valueWrapper.toArray();
var valueWrapper = /** @type {?jspb.Message} */ (m[p].valueWrapper);
if (valueWrapper) {
valueWrapper.toArray();
}
}
}
}
@ -343,13 +346,13 @@ jspb.Map.prototype.has = function(key) {
* number.
* @param {number} fieldNumber
* @param {!jspb.BinaryWriter} writer
* @param {function(this:jspb.BinaryWriter,number,K)=} keyWriterFn
* @param {!function(this:jspb.BinaryWriter,number,K)} keyWriterFn
* The method on BinaryWriter that writes type K to the stream.
* @param {function(this:jspb.BinaryWriter,number,V)|
* function(this:jspb.BinaryReader,V,?)=} valueWriterFn
* @param {!function(this:jspb.BinaryWriter,number,V)|
* function(this:jspb.BinaryReader,V,?)} valueWriterFn
* The method on BinaryWriter that writes type V to the stream. May be
* writeMessage, in which case the second callback arg form is used.
* @param {?function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback
* @param {function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback
* The BinaryWriter serialization callback for type V, if V is a message
* type.
*/
@ -376,14 +379,15 @@ jspb.Map.prototype.serializeBinary = function(
* Read one key/value message from the given BinaryReader. Compatible as the
* `reader` callback parameter to jspb.BinaryReader.readMessage, to be called
* when a key/value pair submessage is encountered.
* @template K, V
* @param {!jspb.Map} map
* @param {!jspb.BinaryReader} reader
* @param {function(this:jspb.BinaryReader):K=} keyReaderFn
* @param {!function(this:jspb.BinaryReader):K} keyReaderFn
* The method on BinaryReader that reads type K from the stream.
*
* @param {function(this:jspb.BinaryReader):V|
* function(this:jspb.BinaryReader,V,
* function(V,!jspb.BinaryReader))=} valueReaderFn
* @param {!function(this:jspb.BinaryReader):V|
* function(this:jspb.BinaryReader,V,
* function(V,!jspb.BinaryReader))} valueReaderFn
* The method on BinaryReader that reads type V from the stream. May be
* readMessage, in which case the second callback arg form is used.
*

@ -0,0 +1,359 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
goog.require('goog.testing.asserts');
goog.require('goog.userAgent');
goog.require('proto.jspb.test.MapValueEnum');
goog.require('proto.jspb.test.MapValueMessage');
goog.require('proto.jspb.test.MapValueMessageNoBinary');
goog.require('proto.jspb.test.TestMapFields');
goog.require('proto.jspb.test.TestMapFieldsNoBinary');
/**
* Helper: check that the given map has exactly this set of (sorted) entries.
* @param {!jspb.Map} map
* @param {!Array<!Array<?>>} entries
*/
function checkMapEquals(map, entries) {
var arr = map.toArray();
assertEquals(arr.length, entries.length);
for (var i = 0; i < arr.length; i++) {
assertElementsEquals(arr[i], entries[i]);
}
}
/**
* Converts an ES6 iterator to an array.
* @template T
* @param {!Iterator<T>} iter an iterator
* @return {!Array<T>}
*/
function toArray(iter) {
var arr = [];
while (true) {
var val = iter.next();
if (val.done) {
break;
}
arr.push(val.value);
}
return arr;
}
/**
* Helper: generate test methods for this TestMapFields class.
* @param {?} msgInfo
* @param {?} submessageCtor
* @param {!string} suffix
*/
function makeTests(msgInfo, submessageCtor, suffix) {
/**
* Helper: fill all maps on a TestMapFields.
* @param {?} msg
*/
var fillMapFields = function(msg) {
msg.getMapStringStringMap().set('asdf', 'jkl;').set('key 2', 'hello world');
msg.getMapStringInt32Map().set('a', 1).set('b', -2);
msg.getMapStringInt64Map().set('c', 0x100000000).set('d', 0x200000000);
msg.getMapStringBoolMap().set('e', true).set('f', false);
msg.getMapStringDoubleMap().set('g', 3.14159).set('h', 2.71828);
msg.getMapStringEnumMap()
.set('i', proto.jspb.test.MapValueEnum.MAP_VALUE_BAR)
.set('j', proto.jspb.test.MapValueEnum.MAP_VALUE_BAZ);
msg.getMapStringMsgMap()
.set('k', new submessageCtor())
.set('l', new submessageCtor());
msg.getMapStringMsgMap().get('k').setFoo(42);
msg.getMapStringMsgMap().get('l').setFoo(84);
msg.getMapInt32StringMap().set(-1, 'a').set(42, 'b');
msg.getMapInt64StringMap().set(0x123456789abc, 'c').set(0xcba987654321, 'd');
msg.getMapBoolStringMap().set(false, 'e').set(true, 'f');
};
/**
* Helper: check all maps on a TestMapFields.
* @param {?} msg
*/
var checkMapFields = function(msg) {
checkMapEquals(msg.getMapStringStringMap(), [
['asdf', 'jkl;'],
['key 2', 'hello world']
]);
checkMapEquals(msg.getMapStringInt32Map(), [
['a', 1],
['b', -2]
]);
checkMapEquals(msg.getMapStringInt64Map(), [
['c', 0x100000000],
['d', 0x200000000]
]);
checkMapEquals(msg.getMapStringBoolMap(), [
['e', true],
['f', false]
]);
checkMapEquals(msg.getMapStringDoubleMap(), [
['g', 3.14159],
['h', 2.71828]
]);
checkMapEquals(msg.getMapStringEnumMap(), [
['i', proto.jspb.test.MapValueEnum.MAP_VALUE_BAR],
['j', proto.jspb.test.MapValueEnum.MAP_VALUE_BAZ]
]);
checkMapEquals(msg.getMapInt32StringMap(), [
[-1, 'a'],
[42, 'b']
]);
checkMapEquals(msg.getMapInt64StringMap(), [
[0x123456789abc, 'c'],
[0xcba987654321, 'd']
]);
checkMapEquals(msg.getMapBoolStringMap(), [
[false, 'e'],
[true, 'f']
]);
assertEquals(msg.getMapStringMsgMap().getLength(), 2);
assertEquals(msg.getMapStringMsgMap().get('k').getFoo(), 42);
assertEquals(msg.getMapStringMsgMap().get('l').getFoo(), 84);
var entries = toArray(msg.getMapStringMsgMap().entries());
assertEquals(entries.length, 2);
entries.forEach(function(entry) {
var key = entry[0];
var val = entry[1];
assert(val === msg.getMapStringMsgMap().get(key));
});
msg.getMapStringMsgMap().forEach(function(val, key) {
assert(val === msg.getMapStringMsgMap().get(key));
});
};
it('testMapStringStringField' + suffix, function() {
var msg = new msgInfo.constructor();
assertEquals(msg.getMapStringStringMap().getLength(), 0);
assertEquals(msg.getMapStringInt32Map().getLength(), 0);
assertEquals(msg.getMapStringInt64Map().getLength(), 0);
assertEquals(msg.getMapStringBoolMap().getLength(), 0);
assertEquals(msg.getMapStringDoubleMap().getLength(), 0);
assertEquals(msg.getMapStringEnumMap().getLength(), 0);
assertEquals(msg.getMapStringMsgMap().getLength(), 0);
// Re-create to clear out any internally-cached wrappers, etc.
msg = new msgInfo.constructor();
var m = msg.getMapStringStringMap();
assertEquals(m.has('asdf'), false);
assertEquals(m.get('asdf'), undefined);
m.set('asdf', 'hello world');
assertEquals(m.has('asdf'), true);
assertEquals(m.get('asdf'), 'hello world');
m.set('jkl;', 'key 2');
assertEquals(m.has('jkl;'), true);
assertEquals(m.get('jkl;'), 'key 2');
assertEquals(m.getLength(), 2);
var it = m.entries();
assertElementsEquals(it.next().value, ['asdf', 'hello world']);
assertElementsEquals(it.next().value, ['jkl;', 'key 2']);
assertEquals(it.next().done, true);
checkMapEquals(m, [
['asdf', 'hello world'],
['jkl;', 'key 2']
]);
m.del('jkl;');
assertEquals(m.has('jkl;'), false);
assertEquals(m.get('jkl;'), undefined);
assertEquals(m.getLength(), 1);
it = m.keys();
assertEquals(it.next().value, 'asdf');
assertEquals(it.next().done, true);
it = m.values();
assertEquals(it.next().value, 'hello world');
assertEquals(it.next().done, true);
var count = 0;
m.forEach(function(value, key, map) {
assertEquals(map, m);
assertEquals(key, 'asdf');
assertEquals(value, 'hello world');
count++;
});
assertEquals(count, 1);
m.clear();
assertEquals(m.getLength(), 0);
});
/**
* Tests operations on maps with all key and value types.
*/
it('testAllMapTypes' + suffix, function() {
var msg = new msgInfo.constructor();
fillMapFields(msg);
checkMapFields(msg);
});
if (msgInfo.deserializeBinary) {
/**
* Tests serialization and deserialization in binary format.
*/
it('testBinaryFormat' + suffix, function() {
if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) {
// IE8/9 currently doesn't support binary format because they lack
// TypedArray.
return;
}
// Check that the format is correct.
var msg = new msgInfo.constructor();
msg.getMapStringStringMap().set('A', 'a');
var serialized = msg.serializeBinary();
var expectedSerialized = [
0x0a, 0x6, // field 1 (map_string_string), delimited, length 6
0x0a, 0x1, // field 1 in submessage (key), delimited, length 1
0x41, // ASCII 'A'
0x12, 0x1, // field 2 in submessage (value), delimited, length 1
0x61 // ASCII 'a'
];
assertEquals(serialized.length, expectedSerialized.length);
for (var i = 0; i < serialized.length; i++) {
assertEquals(serialized[i], expectedSerialized[i]);
}
// Check that all map fields successfully round-trip.
msg = new msgInfo.constructor();
fillMapFields(msg);
serialized = msg.serializeBinary();
var decoded = msgInfo.deserializeBinary(serialized);
checkMapFields(decoded);
});
}
/**
* Tests serialization and deserialization in JSPB format.
*/
it('testJSPBFormat' + suffix, function() {
var msg = new msgInfo.constructor();
fillMapFields(msg);
var serialized = msg.serialize();
var decoded = msgInfo.deserialize(serialized);
checkMapFields(decoded);
});
/**
* Tests serialization and deserialization in JSPB format, when there is
* a submessage that also contains map entries. This tests recursive
* sync.
*/
it('testJSPBFormatNested' + suffix, function() {
var submsg = new msgInfo.constructor();
var mapValue = new msgInfo.constructor();
var msg = new msgInfo.constructor();
msg.getMapStringTestmapfieldsMap().set('test', mapValue);
msg.setTestMapFields(submsg);
fillMapFields(submsg);
fillMapFields(msg);
fillMapFields(mapValue);
var serialized = msg.serialize();
var decoded = msgInfo.deserialize(serialized);
checkMapFields(decoded);
var decodedSubmsg = decoded.getTestMapFields();
assertNotNull(decodedSubmsg);
checkMapFields(decodedSubmsg);
var decodedMapValue = decoded.getMapStringTestmapfieldsMap().get('test');
assertNotNull(decodedMapValue);
checkMapFields(decodedMapValue);
});
/**
* Tests toObject()/fromObject().
*/
it('testToFromObject' + suffix, function() {
var msg = new msgInfo.constructor();
fillMapFields(msg);
var obj = msg.toObject();
var decoded = msgInfo.fromObject(obj);
checkMapFields(decoded);
obj = msgInfo.deserialize(msg.serialize()).toObject();
decoded = msgInfo.fromObject(obj);
checkMapFields(decoded);
});
/**
* Exercises the lazy map<->underlying array sync.
*/
it('testLazyMapSync' + suffix, function() {
// Start with a JSPB array containing a few map entries.
var entries = [
['a', 'entry 1'],
['c', 'entry 2'],
['b', 'entry 3']
];
var msg = new msgInfo.constructor([entries]);
assertEquals(entries.length, 3);
assertEquals(entries[0][0], 'a');
assertEquals(entries[1][0], 'c');
assertEquals(entries[2][0], 'b');
msg.getMapStringStringMap().del('a');
assertEquals(entries.length, 3); // not yet sync'd
msg.toArray(); // force a sync
assertEquals(entries.length, 2);
assertEquals(entries[0][0], 'b'); // now in sorted order
assertEquals(entries[1][0], 'c');
var a = msg.toArray();
assertEquals(a[0], entries); // retains original reference
});
}
describe('mapsTest', function() {
makeTests({
constructor: proto.jspb.test.TestMapFields,
fromObject: proto.jspb.test.TestMapFields.fromObject,
deserialize: proto.jspb.test.TestMapFields.deserialize,
deserializeBinary: proto.jspb.test.TestMapFields.deserializeBinary
}, proto.jspb.test.MapValueMessage, "_Binary");
makeTests({
constructor: proto.jspb.test.TestMapFieldsNoBinary,
fromObject: proto.jspb.test.TestMapFieldsNoBinary.fromObject,
deserialize: proto.jspb.test.TestMapFieldsNoBinary.deserialize,
deserializeBinary: null
}, proto.jspb.test.MapValueMessageNoBinary, "_NoBinary");
});

@ -106,17 +106,17 @@ jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn,
/**
* Stores binary-related information for a single extension field.
* @param {!jspb.ExtensionFieldInfo<T>} fieldInfo
* @param {?function(number,?)=} binaryReaderFn
* @param {?function(number,?)|function(number,?,?,?,?,?)=} binaryWriterFn
* @param {?function(?,?)=} opt_binaryMessageSerializeFn
* @param {?function(?,?)=} opt_binaryMessageDeserializeFn
* @param {?boolean=} opt_isPacked
* @param {!function(number,?)} binaryReaderFn
* @param {!function(number,?)|function(number,?,?,?,?,?)} binaryWriterFn
* @param {function(?,?)=} opt_binaryMessageSerializeFn
* @param {function(?,?)=} opt_binaryMessageDeserializeFn
* @param {boolean=} opt_isPacked
* @constructor
* @struct
* @template T
*/
jspb.ExtensionFieldBinaryInfo = function(fieldInfo, binaryReaderFn, binaryWriterFn,
binaryMessageSerializeFn, binaryMessageDeserializeFn, isPacked) {
opt_binaryMessageSerializeFn, opt_binaryMessageDeserializeFn, opt_isPacked) {
/** @const */
this.fieldInfo = fieldInfo;
/** @const */
@ -124,11 +124,11 @@ jspb.ExtensionFieldBinaryInfo = function(fieldInfo, binaryReaderFn, binaryWriter
/** @const */
this.binaryWriterFn = binaryWriterFn;
/** @const */
this.binaryMessageSerializeFn = binaryMessageSerializeFn;
this.binaryMessageSerializeFn = opt_binaryMessageSerializeFn;
/** @const */
this.binaryMessageDeserializeFn = binaryMessageDeserializeFn;
this.binaryMessageDeserializeFn = opt_binaryMessageDeserializeFn;
/** @const */
this.isPacked = isPacked;
this.isPacked = opt_isPacked;
};
/**
@ -744,7 +744,7 @@ jspb.Message.assertConsistentTypes_ = function(array) {
* @return {T} The field's value.
* @protected
*/
jspb.Message.getFieldProto3 = function(msg, fieldNumber, defaultValue) {
jspb.Message.getFieldWithDefault = function(msg, fieldNumber, defaultValue) {
var value = jspb.Message.getField(msg, fieldNumber);
if (value == null) {
return defaultValue;
@ -810,6 +810,24 @@ jspb.Message.setField = function(msg, fieldNumber, value) {
};
/**
* Adds a value to a repeated, primitive field.
* @param {!jspb.Message} msg A jspb proto.
* @param {number} fieldNumber The field number.
* @param {string|number|boolean|!Uint8Array} value New value
* @param {number=} opt_index Index where to put new value.
* @protected
*/
jspb.Message.addToRepeatedField = function(msg, fieldNumber, value, opt_index) {
var arr = jspb.Message.getField(msg, fieldNumber);
if (opt_index != undefined) {
arr.splice(opt_index, 0, value);
} else {
arr.push(value);
}
};
/**
* Sets the value of a field in a oneof union and clears all other fields in
* the union.
@ -907,6 +925,24 @@ jspb.Message.getWrapperField = function(msg, ctor, fieldNumber, opt_required) {
* @protected
*/
jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {
jspb.Message.wrapRepeatedField_(msg, ctor, fieldNumber);
var val = msg.wrappers_[fieldNumber];
if (val == jspb.Message.EMPTY_LIST_SENTINEL_) {
val = msg.wrappers_[fieldNumber] = [];
}
return /** @type {!Array<!jspb.Message>} */ (val);
};
/**
* Wraps underlying array into proto message representation if it wasn't done
* before.
* @param {!jspb.Message} msg A jspb proto.
* @param {function(new:jspb.Message, ?Array)} ctor Constructor for the field.
* @param {number} fieldNumber The field number.
* @private
*/
jspb.Message.wrapRepeatedField_ = function(msg, ctor, fieldNumber) {
if (!msg.wrappers_) {
msg.wrappers_ = {};
}
@ -917,11 +953,6 @@ jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {
}
msg.wrappers_[fieldNumber] = wrappers;
}
var val = msg.wrappers_[fieldNumber];
if (val == jspb.Message.EMPTY_LIST_SENTINEL_) {
val = msg.wrappers_[fieldNumber] = [];
}
return /** @type {Array<!jspb.Message>} */ (val);
};
@ -980,6 +1011,48 @@ jspb.Message.setRepeatedWrapperField = function(msg, fieldNumber, value) {
};
/**
* Add a message to a repeated proto field.
* @param {!jspb.Message} msg A jspb proto.
* @param {number} fieldNumber The field number.
* @param {T_CHILD|undefined} value Proto that will be added to the
* repeated field.
* @param {function(new:T_CHILD, ?Array=)} ctor The constructor of the
* message type.
* @param {number|undefined} index Index at which to insert the value.
* @return {T_CHILD_NOT_UNDEFINED} proto that was inserted to the repeated field
* @template MessageType
* Use go/closure-ttl to declare a non-undefined version of T_CHILD. Replace the
* undefined in blah|undefined with none. This is necessary because the compiler
* will infer T_CHILD to be |undefined.
* @template T_CHILD
* @template T_CHILD_NOT_UNDEFINED :=
* cond(isUnknown(T_CHILD), unknown(),
* mapunion(T_CHILD, (X) =>
* cond(eq(X, 'undefined'), none(), X)))
* =:
* @protected
*/
jspb.Message.addToRepeatedWrapperField = function(
msg, fieldNumber, value, ctor, index) {
jspb.Message.wrapRepeatedField_(msg, ctor, fieldNumber);
var wrapperArray = msg.wrappers_[fieldNumber];
if (!wrapperArray) {
wrapperArray = msg.wrappers_[fieldNumber] = [];
}
var insertedValue = value ? value : new ctor();
var array = jspb.Message.getField(msg, fieldNumber);
if (index != undefined) {
wrapperArray.splice(index, 0, insertedValue);
array.splice(index, 0, insertedValue.toArray());
} else {
wrapperArray.push(insertedValue);
array.push(insertedValue.toArray());
}
return insertedValue;
};
/**
* Converts a JsPb repeated message field into a map. The map will contain
* protos unless an optional toObject function is given, in which case it will
@ -1114,32 +1187,39 @@ jspb.Message.prototype.getExtension = function(fieldInfo) {
* @param {jspb.ExtensionFieldInfo} fieldInfo Specifies the field to set.
* @param {jspb.Message|string|Uint8Array|number|boolean|Array?} value The value
* to set.
* @return {THIS} For chaining
* @this {THIS}
* @template THIS
*/
jspb.Message.prototype.setExtension = function(fieldInfo, value) {
if (!this.wrappers_) {
this.wrappers_ = {};
// Cast self, since the inferred THIS is unknown inside the function body.
// https://github.com/google/closure-compiler/issues/1411#issuecomment-232442220
var self = /** @type {!jspb.Message} */ (this);
if (!self.wrappers_) {
self.wrappers_ = {};
}
jspb.Message.maybeInitEmptyExtensionObject_(this);
jspb.Message.maybeInitEmptyExtensionObject_(self);
var fieldNumber = fieldInfo.fieldIndex;
if (fieldInfo.isRepeated) {
value = value || [];
if (fieldInfo.isMessageType()) {
this.wrappers_[fieldNumber] = value;
this.extensionObject_[fieldNumber] = goog.array.map(
self.wrappers_[fieldNumber] = value;
self.extensionObject_[fieldNumber] = goog.array.map(
/** @type {Array<jspb.Message>} */ (value), function(msg) {
return msg.toArray();
});
} else {
this.extensionObject_[fieldNumber] = value;
self.extensionObject_[fieldNumber] = value;
}
} else {
if (fieldInfo.isMessageType()) {
this.wrappers_[fieldNumber] = value;
this.extensionObject_[fieldNumber] = value ? value.toArray() : value;
self.wrappers_[fieldNumber] = value;
self.extensionObject_[fieldNumber] = value ? value.toArray() : value;
} else {
this.extensionObject_[fieldNumber] = value;
self.extensionObject_[fieldNumber] = value;
}
}
return self;
};
@ -1308,7 +1388,30 @@ jspb.Message.compareFields = function(field1, field2) {
/**
* Static clone function. NOTE: A type-safe method called "cloneMessage" exists
* Templated, type-safe cloneMessage definition.
* @return {THIS}
* @this {THIS}
* @template THIS
*/
jspb.Message.prototype.cloneMessage = function() {
return jspb.Message.cloneMessage(/** @type {!jspb.Message} */ (this));
};
/**
* Alias clone to cloneMessage. goog.object.unsafeClone uses clone to
* efficiently copy objects. Without this alias, copying jspb messages comes
* with a large performance penalty.
* @return {THIS}
* @this {THIS}
* @template THIS
*/
jspb.Message.prototype.clone = function() {
return jspb.Message.cloneMessage(/** @type {!jspb.Message} */ (this));
};
/**
* Static clone function. NOTE: A type-safe method called "cloneMessage"
* exists
* on each generated JsPb class. Do not call this function directly.
* @param {!jspb.Message} msg A message to clone.
* @return {!jspb.Message} A deep clone of the given message.
@ -1429,3 +1532,4 @@ jspb.Message.registry_ = {};
* @type {!Object.<number, jspb.ExtensionFieldInfo>}
*/
jspb.Message.messageSetExtensions = {};
jspb.Message.messageSetExtensionsBinary = {};

@ -269,7 +269,7 @@ describe('Message test suite', function() {
assertFalse(response.hasEnumField());
});
it('testMessageRegistration', function() {
it('testMessageRegistration', /** @suppress {visibility} */ function() {
// goog.require(SomeResponse) will include its library, which will in
// turn add SomeResponse to the message registry.
assertEquals(jspb.Message.registry_['res'], proto.jspb.test.SomeResponse);
@ -297,47 +297,9 @@ describe('Message test suite', function() {
var expected = [,,, [], []];
expected[0] = expected[1] = expected[2] = undefined;
assertObjectEquals(expected, foo.toArray());
// Test set(null). We could deprecated this in favor of clear(), but
// it's also convenient to have.
data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
foo = new proto.jspb.test.OptionalFields(data);
foo.setAString(null);
foo.setABool(null);
foo.setANestedMessage(null);
foo.setARepeatedMessageList(null);
foo.setARepeatedStringList(null);
assertEquals('', foo.getAString());
assertEquals(false, foo.getABool());
assertNull(foo.getANestedMessage());
assertFalse(foo.hasAString());
assertFalse(foo.hasABool());
assertObjectEquals([], foo.getARepeatedMessageList());
assertObjectEquals([], foo.getARepeatedStringList());
assertObjectEquals([null, null, null, [], []], foo.toArray());
// Test set(undefined). Again, not something we really need, and not
// supported directly by our typing, but it should 'do the right thing'.
data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
foo = new proto.jspb.test.OptionalFields(data);
foo.setAString(undefined);
foo.setABool(undefined);
foo.setANestedMessage(undefined);
foo.setARepeatedMessageList(undefined);
foo.setARepeatedStringList(undefined);
assertEquals('', foo.getAString());
assertEquals(false, foo.getABool());
assertUndefined(foo.getANestedMessage());
assertFalse(foo.hasAString());
assertFalse(foo.hasABool());
assertObjectEquals([], foo.getARepeatedMessageList());
assertObjectEquals([], foo.getARepeatedStringList());
expected = [,,, [], []];
expected[0] = expected[1] = expected[2] = undefined;
assertObjectEquals(expected, foo.toArray());
});
it('testDifferenceRawObject', function() {
it('testDifferenceRawObject', /** @suppress {visibility} */ function() {
var p1 = new proto.jspb.test.HasExtensions(['hi', 'diff', {}]);
var p2 = new proto.jspb.test.HasExtensions(['hi', 'what',
{1000: 'unique'}]);
@ -477,7 +439,7 @@ describe('Message test suite', function() {
var extension = new proto.jspb.test.CloneExtension();
extension.setExt('e1');
original.setExtension(proto.jspb.test.IsExtension.extField, extension);
var clone = original.cloneMessage();
var clone = original.clone();
assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
[['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1,, { 100: [, 'e1'] }],
clone.toArray());
@ -712,11 +674,12 @@ describe('Message test suite', function() {
assertArrayEquals([1, 2, 3, {1: 'hi'}], msg.toArray());
});
it('testExtendedMessageEnsureObject', function() {
var data = new proto.jspb.test.HasExtensions(['str1',
{'a_key': 'an_object'}]);
assertEquals('an_object', data.extensionObject_['a_key']);
});
it('testExtendedMessageEnsureObject',
/** @suppress {visibility} */ function() {
var data =
new proto.jspb.test.HasExtensions(['str1', {'a_key': 'an_object'}]);
assertEquals('an_object', data.extensionObject_['a_key']);
});
it('testToObject_hasExtensionField', function() {
var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1']}]);

@ -294,7 +294,7 @@ describe('proto3Test', function() {
msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR);
msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_FOO);
msg.setOneofUint32(32);
msg.setOneofUint32(null);
msg.clearOneofUint32();
var serialized = msg.serializeBinary();

@ -92,6 +92,12 @@ typedef GPB_ENUM(GPBDuration_FieldNumber) {
* end.seconds += 1;
* end.nanos -= 1000000000;
* }
*
* Example 3: Compute Duration from datetime.timedelta in Python.
*
* td = datetime.timedelta(days=3, minutes=10)
* duration = Duration()
* duration.FromTimedelta(td)
**/
@interface GPBDuration : GPBMessage

@ -94,7 +94,7 @@ typedef GPB_ENUM(GPBFieldMask_FieldNumber) {
* }
*
* A repeated field is not allowed except at the last position of a
* field mask.
* paths string.
*
* If a FieldMask object is not present in a get operation, the
* operation applies to all fields (as if a FieldMask of all fields
@ -121,8 +121,8 @@ typedef GPB_ENUM(GPBFieldMask_FieldNumber) {
*
* If a repeated field is specified for an update operation, the existing
* repeated values in the target resource will be overwritten by the new values.
* Note that a repeated field is only allowed in the last position of a field
* mask.
* Note that a repeated field is only allowed in the last position of a `paths`
* string.
*
* If a sub-message is specified in the last position of the field mask for an
* update operation, then the existing sub-message in the target resource is

@ -101,16 +101,14 @@ typedef GPB_ENUM(GPBTimestamp_FieldNumber) {
*
* Example 5: Compute Timestamp from current time in Python.
*
* now = time.time()
* seconds = int(now)
* nanos = int((now - seconds) * 10**9)
* timestamp = Timestamp(seconds=seconds, nanos=nanos)
* timestamp = Timestamp()
* timestamp.GetCurrentTime()
**/
@interface GPBTimestamp : GPBMessage
/**
* Represents seconds of UTC time since Unix epoch
* 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
* 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
* 9999-12-31T23:59:59Z inclusive.
**/
@property(nonatomic, readwrite) int64_t seconds;

File diff suppressed because it is too large Load Diff

@ -0,0 +1,36 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: test_include.proto
namespace Bar;
use Google\Protobuf\Internal\DescriptorPool;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
class TestInclude extends \Google\Protobuf\Internal\Message
{
private $a = 0;
public function getA()
{
return $this->a;
}
public function setA($var)
{
GPBUtil::checkInt32($var);
$this->a = $var;
}
}
$pool = DescriptorPool::getGeneratedPool();
$pool->internalAddGeneratedFile(hex2bin(
"0a3b0a12746573745f696e636c7564652e70726f746f120362617222180a" .
"0b54657374496e636c75646512090a0161180120012805620670726f746f" .
"33"
));

@ -171,13 +171,6 @@ class _NestedDescriptorBase(DescriptorBase):
self._serialized_start = serialized_start
self._serialized_end = serialized_end
def GetTopLevelContainingType(self):
"""Returns the root if this is a nested type, or itself if its the root."""
desc = self
while desc.containing_type is not None:
desc = desc.containing_type
return desc
def CopyToProto(self, proto):
"""Copies this to the matching proto in descriptor_pb2.
@ -497,7 +490,7 @@ class FieldDescriptor(DescriptorBase):
def __new__(cls, name, full_name, index, number, type, cpp_type, label,
default_value, message_type, enum_type, containing_type,
is_extension, extension_scope, options=None,
has_default_value=True, containing_oneof=None):
has_default_value=True, containing_oneof=None, json_name=None):
_message.Message._CheckCalledFromGeneratedFile()
if is_extension:
return _message.default_pool.FindExtensionByName(full_name)
@ -507,7 +500,7 @@ class FieldDescriptor(DescriptorBase):
def __init__(self, name, full_name, index, number, type, cpp_type, label,
default_value, message_type, enum_type, containing_type,
is_extension, extension_scope, options=None,
has_default_value=True, containing_oneof=None):
has_default_value=True, containing_oneof=None, json_name=None):
"""The arguments are as described in the description of FieldDescriptor
attributes above.
@ -519,6 +512,10 @@ class FieldDescriptor(DescriptorBase):
self.name = name
self.full_name = full_name
self._camelcase_name = None
if json_name is None:
self.json_name = _ToJsonName(name)
else:
self.json_name = json_name
self.index = index
self.number = number
self.type = type
@ -894,6 +891,31 @@ def _ToCamelCase(name):
return ''.join(result)
def _OptionsOrNone(descriptor_proto):
"""Returns the value of the field `options`, or None if it is not set."""
if descriptor_proto.HasField('options'):
return descriptor_proto.options
else:
return None
def _ToJsonName(name):
"""Converts name to Json name and returns it."""
capitalize_next = False
result = []
for c in name:
if c == '_':
capitalize_next = True
elif capitalize_next:
result.append(c.upper())
capitalize_next = False
else:
result += c
return ''.join(result)
def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
syntax=None):
"""Make a protobuf Descriptor given a DescriptorProto protobuf.
@ -970,6 +992,10 @@ def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
full_name = '.'.join(full_message_name + [field_proto.name])
enum_desc = None
nested_desc = None
if field_proto.json_name:
json_name = field_proto.json_name
else:
json_name = None
if field_proto.HasField('type_name'):
type_name = field_proto.type_name
full_type_name = '.'.join(full_message_name +
@ -984,10 +1010,11 @@ def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
field_proto.number, field_proto.type,
FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type),
field_proto.label, None, nested_desc, enum_desc, None, False, None,
options=field_proto.options, has_default_value=False)
options=_OptionsOrNone(field_proto), has_default_value=False,
json_name=json_name)
fields.append(field)
desc_name = '.'.join(full_message_name)
return Descriptor(desc_proto.name, desc_name, None, None, fields,
list(nested_types.values()), list(enum_types.values()), [],
options=desc_proto.options)
options=_OptionsOrNone(desc_proto))

@ -62,7 +62,7 @@ from google.protobuf import descriptor_database
from google.protobuf import text_encoding
_USE_C_DESCRIPTORS = descriptor._USE_C_DESCRIPTORS
_USE_C_DESCRIPTORS = descriptor._USE_C_DESCRIPTORS # pylint: disable=protected-access
def _NormalizeFullyQualifiedName(name):
@ -80,6 +80,14 @@ def _NormalizeFullyQualifiedName(name):
return name.lstrip('.')
def _OptionsOrNone(descriptor_proto):
"""Returns the value of the field `options`, or None if it is not set."""
if descriptor_proto.HasField('options'):
return descriptor_proto.options
else:
return None
class DescriptorPool(object):
"""A collection of protobufs dynamically constructed by descriptor protos."""
@ -326,78 +334,61 @@ class DescriptorPool(object):
name=file_proto.name,
package=file_proto.package,
syntax=file_proto.syntax,
options=file_proto.options,
options=_OptionsOrNone(file_proto),
serialized_pb=file_proto.SerializeToString(),
dependencies=direct_deps,
public_dependencies=public_deps)
if _USE_C_DESCRIPTORS:
# When using C++ descriptors, all objects defined in the file were added
# to the C++ database when the FileDescriptor was built above.
# Just add them to this descriptor pool.
def _AddMessageDescriptor(message_desc):
self._descriptors[message_desc.full_name] = message_desc
for nested in message_desc.nested_types:
_AddMessageDescriptor(nested)
for enum_type in message_desc.enum_types:
_AddEnumDescriptor(enum_type)
def _AddEnumDescriptor(enum_desc):
self._enum_descriptors[enum_desc.full_name] = enum_desc
for message_type in file_descriptor.message_types_by_name.values():
_AddMessageDescriptor(message_type)
for enum_type in file_descriptor.enum_types_by_name.values():
_AddEnumDescriptor(enum_type)
scope = {}
# This loop extracts all the message and enum types from all the
# dependencies of the file_proto. This is necessary to create the
# scope of available message types when defining the passed in
# file proto.
for dependency in built_deps:
scope.update(self._ExtractSymbols(
dependency.message_types_by_name.values()))
scope.update((_PrefixWithDot(enum.full_name), enum)
for enum in dependency.enum_types_by_name.values())
for message_type in file_proto.message_type:
message_desc = self._ConvertMessageDescriptor(
message_type, file_proto.package, file_descriptor, scope,
file_proto.syntax)
file_descriptor.message_types_by_name[message_desc.name] = (
message_desc)
for enum_type in file_proto.enum_type:
file_descriptor.enum_types_by_name[enum_type.name] = (
self._ConvertEnumDescriptor(enum_type, file_proto.package,
file_descriptor, None, scope))
for index, extension_proto in enumerate(file_proto.extension):
extension_desc = self._MakeFieldDescriptor(
extension_proto, file_proto.package, index, is_extension=True)
extension_desc.containing_type = self._GetTypeFromScope(
file_descriptor.package, extension_proto.extendee, scope)
self._SetFieldType(extension_proto, extension_desc,
file_descriptor.package, scope)
file_descriptor.extensions_by_name[extension_desc.name] = (
extension_desc)
for desc_proto in file_proto.message_type:
self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
if file_proto.package:
desc_proto_prefix = _PrefixWithDot(file_proto.package)
else:
scope = {}
# This loop extracts all the message and enum types from all the
# dependencies of the file_proto. This is necessary to create the
# scope of available message types when defining the passed in
# file proto.
for dependency in built_deps:
scope.update(self._ExtractSymbols(
dependency.message_types_by_name.values()))
scope.update((_PrefixWithDot(enum.full_name), enum)
for enum in dependency.enum_types_by_name.values())
for message_type in file_proto.message_type:
message_desc = self._ConvertMessageDescriptor(
message_type, file_proto.package, file_descriptor, scope,
file_proto.syntax)
file_descriptor.message_types_by_name[message_desc.name] = (
message_desc)
for enum_type in file_proto.enum_type:
file_descriptor.enum_types_by_name[enum_type.name] = (
self._ConvertEnumDescriptor(enum_type, file_proto.package,
file_descriptor, None, scope))
for index, extension_proto in enumerate(file_proto.extension):
extension_desc = self._MakeFieldDescriptor(
extension_proto, file_proto.package, index, is_extension=True)
extension_desc.containing_type = self._GetTypeFromScope(
file_descriptor.package, extension_proto.extendee, scope)
self._SetFieldType(extension_proto, extension_desc,
file_descriptor.package, scope)
file_descriptor.extensions_by_name[extension_desc.name] = (
extension_desc)
for desc_proto in file_proto.message_type:
self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
if file_proto.package:
desc_proto_prefix = _PrefixWithDot(file_proto.package)
else:
desc_proto_prefix = ''
desc_proto_prefix = ''
for desc_proto in file_proto.message_type:
desc = self._GetTypeFromScope(
desc_proto_prefix, desc_proto.name, scope)
file_descriptor.message_types_by_name[desc_proto.name] = desc
for desc_proto in file_proto.message_type:
desc = self._GetTypeFromScope(
desc_proto_prefix, desc_proto.name, scope)
file_descriptor.message_types_by_name[desc_proto.name] = desc
for index, service_proto in enumerate(file_proto.service):
file_descriptor.services_by_name[service_proto.name] = (
self._MakeServiceDescriptor(service_proto, index, scope,
file_proto.package, file_descriptor))
for index, service_proto in enumerate(file_proto.service):
file_descriptor.services_by_name[service_proto.name] = (
self._MakeServiceDescriptor(service_proto, index, scope,
file_proto.package, file_descriptor))
self.Add(file_proto)
self._file_descriptors[file_proto.name] = file_descriptor
@ -413,6 +404,7 @@ class DescriptorPool(object):
package: The package the proto should be located in.
file_desc: The file containing this message.
scope: Dict mapping short and full symbols to message and enum types.
syntax: string indicating syntax of the file ("proto2" or "proto3")
Returns:
The added descriptor.
@ -463,7 +455,7 @@ class DescriptorPool(object):
nested_types=nested,
enum_types=enums,
extensions=extensions,
options=desc_proto.options,
options=_OptionsOrNone(desc_proto),
is_extendable=is_extendable,
extension_ranges=extension_ranges,
file=file_desc,
@ -517,7 +509,7 @@ class DescriptorPool(object):
file=file_desc,
values=values,
containing_type=containing_type,
options=enum_proto.options)
options=_OptionsOrNone(enum_proto))
scope['.%s' % enum_name] = desc
self._enum_descriptors[enum_name] = desc
return desc
@ -562,7 +554,7 @@ class DescriptorPool(object):
default_value=None,
is_extension=is_extension,
extension_scope=None,
options=field_proto.options)
options=_OptionsOrNone(field_proto))
def _SetAllFieldTypes(self, package, desc_proto, scope):
"""Sets all the descriptor's fields's types.
@ -681,7 +673,7 @@ class DescriptorPool(object):
name=value_proto.name,
index=index,
number=value_proto.number,
options=value_proto.options,
options=_OptionsOrNone(value_proto),
type=None)
def _MakeServiceDescriptor(self, service_proto, service_index, scope,
@ -711,7 +703,7 @@ class DescriptorPool(object):
full_name=service_name,
index=service_index,
methods=methods,
options=service_proto.options,
options=_OptionsOrNone(service_proto),
file=file_desc)
return desc
@ -740,7 +732,7 @@ class DescriptorPool(object):
containing_service=None,
input_type=input_type,
output_type=output_type,
options=method_proto.options)
options=_OptionsOrNone(method_proto))
def _ExtractSymbols(self, descriptors):
"""Pulls out all the symbols from descriptor protos.

@ -30,13 +30,21 @@
// Author: jieluo@google.com (Jie Luo)
syntax = "proto3";
syntax = "proto2";
package google.protobuf.internal;
import "google/protobuf/any.proto";
message TestAny {
google.protobuf.Any value = 1;
int32 int_value = 2;
optional google.protobuf.Any value = 1;
optional int32 int_value = 2;
extensions 10 to max;
}
message TestAnyExtension1 {
extend TestAny {
optional TestAnyExtension1 extension1 = 98418603;
}
optional int32 i = 15;
}

@ -436,9 +436,11 @@ class ScalarMap(MutableMapping):
"""Simple, type-checked, dict-like container for holding repeated scalars."""
# Disallows assignment to other attributes.
__slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener']
__slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener',
'_entry_descriptor']
def __init__(self, message_listener, key_checker, value_checker):
def __init__(self, message_listener, key_checker, value_checker,
entry_descriptor):
"""
Args:
message_listener: A MessageListener implementation.
@ -448,10 +450,12 @@ class ScalarMap(MutableMapping):
inserted into this container.
value_checker: A type_checkers.ValueChecker instance to run on values
inserted into this container.
entry_descriptor: The MessageDescriptor of a map entry: key and value.
"""
self._message_listener = message_listener
self._key_checker = key_checker
self._value_checker = value_checker
self._entry_descriptor = entry_descriptor
self._values = {}
def __getitem__(self, key):
@ -513,6 +517,9 @@ class ScalarMap(MutableMapping):
self._values.clear()
self._message_listener.Modified()
def GetEntryClass(self):
return self._entry_descriptor._concrete_class
class MessageMap(MutableMapping):
@ -520,9 +527,10 @@ class MessageMap(MutableMapping):
# Disallows assignment to other attributes.
__slots__ = ['_key_checker', '_values', '_message_listener',
'_message_descriptor']
'_message_descriptor', '_entry_descriptor']
def __init__(self, message_listener, message_descriptor, key_checker):
def __init__(self, message_listener, message_descriptor, key_checker,
entry_descriptor):
"""
Args:
message_listener: A MessageListener implementation.
@ -532,10 +540,12 @@ class MessageMap(MutableMapping):
inserted into this container.
value_checker: A type_checkers.ValueChecker instance to run on values
inserted into this container.
entry_descriptor: The MessageDescriptor of a map entry: key and value.
"""
self._message_listener = message_listener
self._message_descriptor = message_descriptor
self._key_checker = key_checker
self._entry_descriptor = entry_descriptor
self._values = {}
def __getitem__(self, key):
@ -613,3 +623,6 @@ class MessageMap(MutableMapping):
def clear(self):
self._values.clear()
self._message_listener.Modified()
def GetEntryClass(self):
return self._entry_descriptor._concrete_class

@ -119,6 +119,7 @@ class DescriptorPoolTest(unittest.TestCase):
self.assertEqual('google.protobuf.python.internal.Factory1Message',
msg1.full_name)
self.assertEqual(None, msg1.containing_type)
self.assertFalse(msg1.has_options)
nested_msg1 = msg1.nested_types[0]
self.assertEqual('NestedFactory1Message', nested_msg1.name)
@ -202,6 +203,7 @@ class DescriptorPoolTest(unittest.TestCase):
self.assertIsInstance(enum1, descriptor.EnumDescriptor)
self.assertEqual(0, enum1.values_by_name['FACTORY_1_VALUE_0'].number)
self.assertEqual(1, enum1.values_by_name['FACTORY_1_VALUE_1'].number)
self.assertFalse(enum1.has_options)
nested_enum1 = self.pool.FindEnumTypeByName(
'google.protobuf.python.internal.Factory1Message.NestedFactory1Enum')
@ -234,6 +236,8 @@ class DescriptorPoolTest(unittest.TestCase):
'google.protobuf.python.internal.Factory1Message.list_value')
self.assertEqual(field.name, 'list_value')
self.assertEqual(field.label, field.LABEL_REPEATED)
self.assertFalse(field.has_options)
with self.assertRaises(KeyError):
self.pool.FindFieldByName('Does not exist')
@ -448,6 +452,7 @@ class EnumField(object):
test.assertTrue(field_desc.has_default_value)
test.assertEqual(enum_desc.values_by_name[self.default_value].number,
field_desc.default_value)
test.assertFalse(enum_desc.values_by_name[self.default_value].has_options)
test.assertEqual(msg_desc, field_desc.containing_type)
test.assertEqual(enum_desc, field_desc.enum_type)

@ -766,6 +766,8 @@ class MakeDescriptorTest(unittest.TestCase):
'Foo2.Sub.bar_field')
self.assertEqual(result.nested_types[0].fields[0].enum_type,
result.nested_types[0].enum_types[0])
self.assertFalse(result.has_options)
self.assertFalse(result.fields[0].has_options)
def testMakeDescriptorWithUnsignedIntField(self):
file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
@ -818,6 +820,23 @@ class MakeDescriptorTest(unittest.TestCase):
self.assertEqual(result.fields[index].camelcase_name,
camelcase_names[index])
def testJsonName(self):
descriptor_proto = descriptor_pb2.DescriptorProto()
descriptor_proto.name = 'TestJsonName'
names = ['field_name', 'fieldName', 'FieldName',
'_field_name', 'FIELD_NAME', 'json_name']
json_names = ['fieldName', 'fieldName', 'FieldName',
'FieldName', 'FIELDNAME', '@type']
for index in range(len(names)):
field = descriptor_proto.field.add()
field.number = index + 1
field.name = names[index]
field.json_name = '@type'
result = descriptor.MakeDescriptor(descriptor_proto)
for index in range(len(json_names)):
self.assertEqual(result.fields[index].json_name,
json_names[index])
if __name__ == '__main__':
unittest.main()

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save