Integrate internal changes
This commit is contained in:
parent
b5bbdb0967
commit
98835fb8f8
@ -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.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
646
java/src/main/java/com/google/protobuf/AbstractMessage.java
Executable file
646
java/src/main/java/com/google/protobuf/AbstractMessage.java
Executable file
@ -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;
|
||||
}
|
||||
}
|
384
java/src/main/java/com/google/protobuf/AbstractMessageLite.java
Executable file
384
java/src/main/java/com/google/protobuf/AbstractMessageLite.java
Executable file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
258
java/src/main/java/com/google/protobuf/AbstractParser.java
Executable file
258
java/src/main/java/com/google/protobuf/AbstractParser.java
Executable file
@ -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);
|
||||
}
|
||||
}
|
180
java/src/main/java/com/google/protobuf/AbstractProtobufList.java
Executable file
180
java/src/main/java/com/google/protobuf/AbstractProtobufList.java
Executable file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
51
java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
Executable file
51
java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
Executable file
@ -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;
|
||||
}
|
64
java/src/main/java/com/google/protobuf/BlockingService.java
Executable file
64
java/src/main/java/com/google/protobuf/BlockingService.java
Executable file
@ -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',
|
||||
|
22
js/map.js
22
js/map.js
@ -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.
|
||||
*
|
||||
|
359
js/maps_test.js
Executable file
359
js/maps_test.js
Executable file
@ -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");
|
||||
});
|
154
js/message.js
154
js/message.js
@ -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;
|
||||
|
1385
php/tests/test.pb.php
Normal file
1385
php/tests/test.pb.php
Normal file
File diff suppressed because it is too large
Load Diff
36
php/tests/test_include.pb.php
Normal file
36
php/tests/test_include.pb.php
Normal file
@ -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 = {}
|
||||
desc_proto_prefix = ''
|
||||
|
||||
# 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 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 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 = ''
|
||||
|
||||
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…
Reference in New Issue
Block a user