Răsfoiți Sursa

Merge pull request #2234 from TeBoring/master

Merge 3.1.x branch into master.
Paul Yang 9 ani în urmă
părinte
comite
fd046f6263
100 a modificat fișierele cu 2957 adăugiri și 2194 ștergeri
  1. 1 0
      .travis.yml
  2. 2 0
      BUILD
  3. 80 0
      CHANGES.txt
  4. 57 1
      Makefile.am
  5. 1 1
      Protobuf.podspec
  6. 3 3
      appveyor.yml
  7. 1 0
      cmake/extract_includes.bat.in
  8. 2 0
      cmake/tests.cmake
  9. 2 2
      configure.ac
  10. 8 8
      conformance/Makefile.am
  11. 6 2
      conformance/conformance_python.py
  12. 196 173
      conformance/conformance_test.cc
  13. 48 5
      conformance/conformance_test.h
  14. 12 0
      conformance/conformance_test_runner.cc
  15. 44 45
      conformance/failure_list_cpp.txt
  16. 6 4
      conformance/failure_list_csharp.txt
  17. 43 45
      conformance/failure_list_java.txt
  18. 19 46
      conformance/failure_list_python.txt
  19. 35 62
      conformance/failure_list_python_cpp.txt
  20. 209 213
      conformance/failure_list_ruby.txt
  21. 1 1
      csharp/Google.Protobuf.Tools.nuspec
  22. 52 0
      csharp/build_tools.sh
  23. 61 71
      csharp/src/Google.Protobuf/Reflection/Descriptor.cs
  24. 3 3
      csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
  25. 3 3
      csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
  26. 7 1
      csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
  27. 4 4
      csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
  28. 6 6
      csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
  29. 3 3
      csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
  30. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
  31. 7 9
      csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
  32. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
  33. 3 3
      csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
  34. 1 1
      csharp/src/Google.Protobuf/project.json
  35. 1 1
      java/core/pom.xml
  36. 14 0
      java/core/src/main/java/com/google/protobuf/ByteString.java
  37. 149 729
      java/core/src/main/java/com/google/protobuf/CodedInputStream.java
  38. 383 17
      java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
  39. 9 22
      java/core/src/main/java/com/google/protobuf/Descriptors.java
  40. 145 21
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  41. 10 0
      java/core/src/main/java/com/google/protobuf/Internal.java
  42. 14 2
      java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
  43. 9 0
      java/core/src/main/java/com/google/protobuf/MapEntry.java
  44. 5 4
      java/core/src/main/java/com/google/protobuf/NioByteString.java
  45. 1 0
      java/core/src/main/java/com/google/protobuf/RopeByteString.java
  46. 15 7
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  47. 2 1
      java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
  48. 25 6
      java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
  49. 102 17
      java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
  50. 4 0
      java/core/src/main/java/com/google/protobuf/WireFormat.java
  51. 1 3
      java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
  52. 1 2
      java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
  53. 1 2
      java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
  54. 1 3
      java/core/src/test/java/com/google/protobuf/ByteStringTest.java
  55. 439 363
      java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
  56. 37 18
      java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
  57. 1 3
      java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
  58. 13 2
      java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
  59. 1 2
      java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
  60. 1 3
      java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
  61. 39 8
      java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
  62. 1 2
      java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
  63. 1 3
      java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  64. 1 2
      java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
  65. 1 3
      java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
  66. 1 3
      java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
  67. 1 3
      java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
  68. 1 2
      java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
  69. 1 3
      java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
  70. 0 9
      java/core/src/test/java/com/google/protobuf/LiteTest.java
  71. 1 2
      java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
  72. 1 2
      java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
  73. 1 3
      java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
  74. 8 2
      java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
  75. 168 2
      java/core/src/test/java/com/google/protobuf/MapTest.java
  76. 1 3
      java/core/src/test/java/com/google/protobuf/MessageTest.java
  77. 1 3
      java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
  78. 1 2
      java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
  79. 3 5
      java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
  80. 1 3
      java/core/src/test/java/com/google/protobuf/ParserTest.java
  81. 1 2
      java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
  82. 1 3
      java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
  83. 4 4
      java/core/src/test/java/com/google/protobuf/ServiceTest.java
  84. 1 2
      java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
  85. 8 3
      java/core/src/test/java/com/google/protobuf/TestUtil.java
  86. 26 3
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  87. 1 3
      java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
  88. 1 3
      java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
  89. 1 2
      java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
  90. 1 3
      java/core/src/test/java/com/google/protobuf/WireFormatTest.java
  91. 0 1
      java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
  92. 36 1
      java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
  93. 36 1
      java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
  94. 38 1
      java/core/src/test/proto/com/google/protobuf/map_test.proto
  95. 0 1
      java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
  96. 1 1
      java/pom.xml
  97. 1 1
      java/util/pom.xml
  98. 116 66
      java/util/src/main/java/com/google/protobuf/util/Durations.java
  99. 10 5
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  100. 129 78
      java/util/src/main/java/com/google/protobuf/util/Timestamps.java

+ 1 - 0
.travis.yml

@@ -31,6 +31,7 @@ env:
   - CONFIG=ruby21
   - CONFIG=ruby22
   - CONFIG=jruby
+  - CONFIG=php5.6_mac
 matrix:
   exclude:
     # It's nontrivial to programmatically install a new JDK from the command

+ 2 - 0
BUILD

@@ -391,8 +391,10 @@ RELATIVE_TEST_PROTOS = [
     "google/protobuf/util/internal/testdata/field_mask.proto",
     "google/protobuf/util/internal/testdata/maps.proto",
     "google/protobuf/util/internal/testdata/oneofs.proto",
+    "google/protobuf/util/internal/testdata/proto3.proto",
     "google/protobuf/util/internal/testdata/struct.proto",
     "google/protobuf/util/internal/testdata/timestamp_duration.proto",
+    "google/protobuf/util/internal/testdata/wrappers.proto",
     "google/protobuf/util/json_format_proto3.proto",
     "google/protobuf/util/message_differencer_unittest.proto",
 ]

+ 80 - 0
CHANGES.txt

@@ -1,3 +1,83 @@
+2016-09-23 version 3.1.0 (C++/Java/Python/PHP/Ruby/Objective-C/C#/JavaScript/Lite)
+  General
+  * Proto3 support in PHP (alpha).
+  * Various bug fixes.
+
+  C++
+  * Added MessageLite::ByteSizeLong() that’s equivalent to
+    MessageLite::ByteSize() but returns the value in size_t. Useful to check
+    whether a message is over the 2G size limit that protobuf can support.
+  * Moved default_instances to global variables. This allows default_instance
+    addresses to be known at compile time.
+  * Adding missing generic gcc 64-bit atomicops.
+  * Restore New*Callback into google::protobuf namespace since these are used
+    by the service stubs code
+  * JSON support.
+    * Fixed some conformance issues.
+  * Fixed a JSON serialization bug for bytes fields.
+
+  Java
+  * Fixed a bug in TextFormat that doesn’t accept empty repeated fields (i.e.,
+    “field: [ ]”).
+  * JSON support
+    * Fixed JsonFormat to do correct snake_case-to-camelCase conversion for
+      non-style-conforming field names.
+    * Fixed JsonFormat to parse empty Any message correctly.
+    * Added an option to JsonFormat.Parser to ignore unknown fields.
+  * Experimental API
+    * Added UnsafeByteOperations.unsafeWrap(byte[]) to wrap a byte array into
+      ByteString without copy.
+
+  Python
+  * JSON support
+    * Fixed some conformance issues.
+
+  PHP (Alpha)
+  * We have added the proto3 support for PHP via both a pure PHP package and a
+    native c extension. The pure PHP package is intended to provide usability
+    to wider range of PHP platforms, while the c extension is intended to
+    provide higher performance. Both implementations provide the same runtime
+    APIs and share the same generated code. Users don’t need to re-generate
+    code for the same proto definition when they want to switch the
+    implementation later. The pure PHP package is included in the php/src
+    directory, and the c extension is included in the php/ext directory. 
+   
+    Both implementations provide idiomatic PHP APIs:
+    * All messages and enums are defined as PHP classes.
+    * All message fields can only be accessed via getter/setter.
+    * Both repeated field elements and map elements are stored in containers
+      that act like a normal PHP array.
+  
+    Unlike several existing third-party PHP implementations for protobuf, our
+    implementations are built on a "strongly-typed" philosophy: message fields
+    and array/map containers will throw exceptions eagerly when values of the
+    incorrect type (not including those that can be type converted, e.g.,
+    double <-> integer <-> numeric string) are inserted.
+  
+    Currently, pure PHP runtime supports php5.5, 5.6 and 7 on linux. C
+    extension runtime supports php5.5 and 5.6 on linux.
+  
+    See php/README.md for more details about installment. See
+    https://developers.google.com/protocol-buffers/docs/phptutorial for more
+    details about APIs.
+
+  Objective-C
+  * Helpers are now provided for working the the Any well known type (see
+    GPBWellKnownTypes.h for the api additions).
+  * Some improvements in startup code (especially when extensions aren’t used).
+
+  Javascript
+  * Fixed missing import of jspb.Map
+  * Fixed valueWriterFn variable name
+
+  Ruby
+  * Fixed hash computation for JRuby's RubyMessage
+  * Make sure map parsing frames are GC-rooted.
+  * Added API support for well-known types.
+
+  C#
+  * Removed check on dependency in the C# reflection API.
+
 2016-09-06 version 3.0.2 (C++/Java/Python/Ruby/Objective-C/C#/JavaScript/Lite)
   General
   * Various bug fixes.

+ 57 - 1
Makefile.am

@@ -54,6 +54,7 @@ csharp_EXTRA_DIST=                                                           \
   csharp/Google.Protobuf.Tools.nuspec                                        \
   csharp/README.md                                                           \
   csharp/build_packages.bat                                                  \
+  csharp/build_tools.sh                                                      \
   csharp/buildall.sh                                                         \
   csharp/generate_protos.sh                                                  \
   csharp/keys/Google.Protobuf.public.snk                                     \
@@ -571,6 +572,57 @@ objectivec_EXTRA_DIST=                                                       \
   objectivec/Tests/UnitTests-Info.plist                                       \
   Protobuf.podspec
 
+php_EXTRA_DIST=                                              \
+  php/src/phpdoc.dist.xml                                    \
+  php/src/Google/Protobuf/Internal/DescriptorPool.php        \
+  php/src/Google/Protobuf/Internal/OneofField.php            \
+  php/src/Google/Protobuf/Internal/MapEntry.php              \
+  php/src/Google/Protobuf/Internal/Type.php                  \
+  php/src/Google/Protobuf/Internal/InputStream.php           \
+  php/src/Google/Protobuf/Internal/OutputStream.php          \
+  php/src/Google/Protobuf/Internal/MessageBuilderContext.php \
+  php/src/Google/Protobuf/Internal/MapField.php              \
+  php/src/Google/Protobuf/Internal/RepeatedField.php         \
+  php/src/Google/Protobuf/Internal/Message.php               \
+  php/src/Google/Protobuf/Internal/GPBWire.php               \
+  php/src/Google/Protobuf/Internal/GPBType.php               \
+  php/src/Google/Protobuf/Internal/GPBLabel.php              \
+  php/src/Google/Protobuf/Internal/EnumBuilderContext.php    \
+  php/src/Google/Protobuf/Internal/GPBUtil.php               \
+  php/src/Google/Protobuf/descriptor_internal.pb.php         \
+  php/src/Google/Protobuf/descriptor.php                     \
+  php/tests/encode_decode_test.php                           \
+  php/tests/test.sh                                          \
+  php/tests/generated_class_test.php                         \
+  php/tests/array_test.php                                   \
+  php/tests/php_implementation_test.php                      \
+  php/tests/test_include.proto                               \
+  php/tests/test_include.pb.php                              \
+  php/tests/map_field_test.php                               \
+  php/tests/test_base.php                                    \
+  php/tests/test_util.php                                    \
+  php/tests/test.proto                                       \
+  php/tests/test.pb.php                                      \
+  php/tests/memory_leak_test.php                             \
+  php/README.md                                              \
+  php/ext/google/protobuf/utf8.h                             \
+  php/ext/google/protobuf/message.c                          \
+  php/ext/google/protobuf/utf8.c                             \
+  php/ext/google/protobuf/package.xml                        \
+  php/ext/google/protobuf/upb.h                              \
+  php/ext/google/protobuf/array.c                            \
+  php/ext/google/protobuf/encode_decode.c                    \
+  php/ext/google/protobuf/protobuf.h                         \
+  php/ext/google/protobuf/type_check.c                       \
+  php/ext/google/protobuf/def.c                              \
+  php/ext/google/protobuf/storage.c                          \
+  php/ext/google/protobuf/map.c                              \
+  php/ext/google/protobuf/config.m4                          \
+  php/ext/google/protobuf/upb.c                              \
+  php/ext/google/protobuf/protobuf.c                         \
+  phpunit.xml                                                \
+  composer.json
+
 python_EXTRA_DIST=                                                           \
   python/MANIFEST.in                                                         \
   python/google/__init__.py                                                  \
@@ -617,6 +669,7 @@ python_EXTRA_DIST=                                                           \
   python/google/protobuf/internal/symbol_database_test.py                    \
   python/google/protobuf/internal/test_bad_identifiers.proto                 \
   python/google/protobuf/internal/test_util.py                               \
+  python/google/protobuf/internal/testing_refleaks.py                        \
   python/google/protobuf/internal/text_encoding_test.py                      \
   python/google/protobuf/internal/text_format_test.py                        \
   python/google/protobuf/internal/type_checkers.py                           \
@@ -648,6 +701,8 @@ python_EXTRA_DIST=                                                           \
   python/google/protobuf/pyext/map_container.h                               \
   python/google/protobuf/pyext/message.cc                                    \
   python/google/protobuf/pyext/message.h                                     \
+  python/google/protobuf/pyext/message_factory.cc                            \
+  python/google/protobuf/pyext/message_factory.h                             \
   python/google/protobuf/pyext/message_module.cc                             \
   python/google/protobuf/pyext/proto2_api_test.proto                         \
   python/google/protobuf/pyext/python.proto                                  \
@@ -748,6 +803,7 @@ js_EXTRA_DIST=                              \
   js/gulpfile.js                            \
   js/jasmine.json                           \
   js/map.js                                 \
+  js/maps_test.js                           \
   js/message.js                             \
   js/message_test.js                        \
   js/node_loader.js                         \
@@ -763,7 +819,7 @@ js_EXTRA_DIST=                              \
   js/testbinary.proto                       \
   js/testempty.proto
 
-all_EXTRA_DIST=$(csharp_EXTRA_DIST) $(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(objectivec_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST) $(js_EXTRA_DIST)
+all_EXTRA_DIST=$(csharp_EXTRA_DIST) $(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(objectivec_EXTRA_DIST) $(php_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST) $(js_EXTRA_DIST)
 
 EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST)   \
   autogen.sh                             \

+ 1 - 1
Protobuf.podspec

@@ -5,7 +5,7 @@
 # dependent projects use the :git notation to refer to the library.
 Pod::Spec.new do |s|
   s.name     = 'Protobuf'
-  s.version  = '3.0.2'
+  s.version  = '3.1.0'
   s.summary  = 'Protocol Buffers v.3 runtime library for Objective-C.'
   s.homepage = 'https://github.com/google/protobuf'
   s.license  = 'New BSD'

+ 3 - 3
appveyor.yml

@@ -20,16 +20,16 @@ environment:
 test: off
 
 install:
-  - ps: Start-FileDownload https://github.com/google/googlemock/archive/release-1.7.0.zip
+  - curl -L -o release-1.7.0.zip https://github.com/google/googlemock/archive/release-1.7.0.zip
   - 7z x release-1.7.0.zip
   - del /Q release-1.7.0.zip
   - rename googlemock-release-1.7.0 gmock
-  - ps: Start-FileDownload https://github.com/google/googletest/archive/release-1.7.0.zip
+  - curl -L -o release-1.7.0.zip "https://github.com/google/googletest/archive/release-1.7.0.zip"
   - 7z x release-1.7.0.zip
   - del /Q release-1.7.0.zip
   - rename googletest-release-1.7.0 gtest
   - move gtest gmock
-  - ps: Start-FileDownload https://go.microsoft.com/fwlink/?LinkID=809122 -FileName dotnetsdk.exe
+  - curl -L -o dotnetsdk.exe "https://go.microsoft.com/fwlink/?LinkID=809122"
   - dotnetsdk.exe /install /quiet /norestart
 
 before_build:

+ 1 - 0
cmake/extract_includes.bat.in

@@ -49,6 +49,7 @@ copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_reflect
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_util.h include\google\protobuf\generated_enum_util.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_reflection.h include\google\protobuf\generated_message_reflection.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_util.h include\google\protobuf\generated_message_util.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\has_bits.h include\google\protobuf\has_bits.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\coded_stream.h include\google\protobuf\io\coded_stream.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\gzip_stream.h include\google\protobuf\io\gzip_stream.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\printer.h include\google\protobuf\io\printer.h

+ 2 - 0
cmake/tests.cmake

@@ -63,8 +63,10 @@ set(tests_protos
   google/protobuf/util/internal/testdata/field_mask.proto
   google/protobuf/util/internal/testdata/maps.proto
   google/protobuf/util/internal/testdata/oneofs.proto
+  google/protobuf/util/internal/testdata/proto3.proto
   google/protobuf/util/internal/testdata/struct.proto
   google/protobuf/util/internal/testdata/timestamp_duration.proto
+  google/protobuf/util/internal/testdata/wrappers.proto
   google/protobuf/util/json_format_proto3.proto
   google/protobuf/util/message_differencer_unittest.proto
 )

+ 2 - 2
configure.ac

@@ -17,7 +17,7 @@ AC_PREREQ(2.59)
 # In the SVN trunk, the version should always be the next anticipated release
 # version with the "-pre" suffix.  (We used to use "-SNAPSHOT" but this pushed
 # the size of one file name in the dist tarfile over the 99-char limit.)
-AC_INIT([Protocol Buffers],[3.0.2],[protobuf@googlegroups.com],[protobuf])
+AC_INIT([Protocol Buffers],[3.1.0],[protobuf@googlegroups.com],[protobuf])
 
 AM_MAINTAINER_MODE([enable])
 
@@ -31,7 +31,7 @@ AC_CONFIG_MACRO_DIR([m4])
 AC_ARG_VAR(DIST_LANG, [language to include in the distribution package (i.e., make dist)])
 case "$DIST_LANG" in
   "") DIST_LANG=all ;;
-  all | cpp | csharp | java | python | javanano | objectivec | ruby | js) ;;
+  all | cpp | csharp | java | python | javanano | objectivec | ruby | js | php) ;;
   *) AC_MSG_FAILURE([unknown language: $DIST_LANG]) ;;
 esac
 AC_SUBST(DIST_LANG)

+ 8 - 8
conformance/Makefile.am

@@ -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_recommended --failure_list failure_list_objc.txt ./conformance-objc
 
 endif

+ 6 - 2
conformance/conformance_python.py

@@ -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)

Fișier diff suprimat deoarece este prea mare
+ 196 - 173
conformance/conformance_test.cc


+ 48 - 5
conformance/conformance_test.h

@@ -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,31 +155,42 @@ 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,
+                            ConformanceLevel level,
                             const conformance::TestAllTypes& input,
                             const string& equivalent_text_format);
 
   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 +198,7 @@ class ConformanceTestSuite {
   int successes_;
   int expected_failures_;
   bool verbose_;
+  bool enforce_recommended_;
   std::string output_;
   std::string failure_list_filename_;
 

+ 12 - 0
conformance/conformance_test_runner.cc

@@ -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();

+ 44 - 45
conformance/failure_list_cpp.txt

@@ -7,48 +7,47 @@
 # 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.FieldNameWithDoubleUnderscores.JsonOutput
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
+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.JsonInput.FieldNameInLowerCamelCase.Validator
+Required.JsonInput.FieldNameInSnakeCase.JsonOutput
+Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
+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

+ 6 - 4
conformance/failure_list_csharp.txt

@@ -1,4 +1,6 @@
-JsonInput.FieldNameWithMixedCases.JsonOutput
-JsonInput.FieldNameWithMixedCases.ProtobufOutput
-JsonInput.FieldNameWithMixedCases.Validator
-JsonInput.OriginalProtoFieldName.JsonOutput
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
+Required.JsonInput.FieldNameInSnakeCase.JsonOutput
+Required.JsonInput.FieldNameWithMixedCases.JsonOutput
+Required.JsonInput.FieldNameWithMixedCases.ProtobufOutput
+Required.JsonInput.FieldNameWithMixedCases.Validator
+Required.JsonInput.OriginalProtoFieldName.JsonOutput

+ 43 - 45
conformance/failure_list_java.txt

@@ -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.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.Uint32MapFieldKeyNotQuoted
+Recommended.JsonInput.Uint64MapFieldKeyNotQuoted
+Required.JsonInput.EnumFieldNotQuoted
+Required.JsonInput.FieldNameInLowerCamelCase.Validator
+Required.JsonInput.FieldNameInSnakeCase.JsonOutput
+Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
+Required.JsonInput.Int32FieldLeadingZero
+Required.JsonInput.Int32FieldNegativeWithLeadingZero
+Required.JsonInput.Int32FieldPlusSign
+Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
+Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
+Required.JsonInput.StringFieldNotAString

+ 19 - 46
conformance/failure_list_python.txt

@@ -1,46 +1,19 @@
-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.FieldNameWithDoubleUnderscores.JsonOutput
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
+Recommended.JsonInput.FloatFieldInfinityNotQuoted
+Recommended.JsonInput.FloatFieldNanNotQuoted
+Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
+Required.JsonInput.BytesFieldInvalidBase64Characters
+Required.JsonInput.DoubleFieldTooSmall
+Required.JsonInput.EnumFieldUnknownValue.Validator
+Required.JsonInput.FieldNameInLowerCamelCase.Validator
+Required.JsonInput.FieldNameInSnakeCase.JsonOutput
+Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
+Required.JsonInput.FloatFieldTooLarge
+Required.JsonInput.FloatFieldTooSmall
+Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
+Required.JsonInput.TimestampJsonInputLowercaseT

+ 35 - 62
conformance/failure_list_python_cpp.txt

@@ -7,65 +7,38 @@
 # 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.FieldNameWithDoubleUnderscores.JsonOutput
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
+Recommended.JsonInput.FloatFieldInfinityNotQuoted
+Recommended.JsonInput.FloatFieldNanNotQuoted
+Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
+Required.JsonInput.BytesFieldInvalidBase64Characters
+Required.JsonInput.DoubleFieldTooSmall
+Required.JsonInput.EnumFieldUnknownValue.Validator
+Required.JsonInput.FieldNameInLowerCamelCase.Validator
+Required.JsonInput.FieldNameInSnakeCase.JsonOutput
+Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
+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

+ 209 - 213
conformance/failure_list_ruby.txt

@@ -1,213 +1,209 @@
-DurationProtoInputTooLarge.JsonOutput
-DurationProtoInputTooSmall.JsonOutput
-FieldMaskNumbersDontRoundTrip.JsonOutput
-FieldMaskPathsDontRoundTrip.JsonOutput
-FieldMaskTooManyUnderscore.JsonOutput
-JsonInput.Any.JsonOutput
-JsonInput.Any.ProtobufOutput
-JsonInput.AnyNested.JsonOutput
-JsonInput.AnyNested.ProtobufOutput
-JsonInput.AnyUnorderedTypeTag.JsonOutput
-JsonInput.AnyUnorderedTypeTag.ProtobufOutput
-JsonInput.AnyWithDuration.JsonOutput
-JsonInput.AnyWithDuration.ProtobufOutput
-JsonInput.AnyWithFieldMask.JsonOutput
-JsonInput.AnyWithFieldMask.ProtobufOutput
-JsonInput.AnyWithInt32ValueWrapper.JsonOutput
-JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
-JsonInput.AnyWithStruct.JsonOutput
-JsonInput.AnyWithStruct.ProtobufOutput
-JsonInput.AnyWithTimestamp.JsonOutput
-JsonInput.AnyWithTimestamp.ProtobufOutput
-JsonInput.AnyWithValueForInteger.JsonOutput
-JsonInput.AnyWithValueForInteger.ProtobufOutput
-JsonInput.AnyWithValueForJsonObject.JsonOutput
-JsonInput.AnyWithValueForJsonObject.ProtobufOutput
-JsonInput.BoolFieldIntegerOne
-JsonInput.BoolFieldIntegerZero
-JsonInput.DoubleFieldInfinity.JsonOutput
-JsonInput.DoubleFieldInfinity.ProtobufOutput
-JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
-JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
-JsonInput.DoubleFieldMaxPositiveValue.JsonOutput
-JsonInput.DoubleFieldMaxPositiveValue.ProtobufOutput
-JsonInput.DoubleFieldMinNegativeValue.JsonOutput
-JsonInput.DoubleFieldMinNegativeValue.ProtobufOutput
-JsonInput.DoubleFieldMinPositiveValue.JsonOutput
-JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
-JsonInput.DoubleFieldNan.JsonOutput
-JsonInput.DoubleFieldNan.ProtobufOutput
-JsonInput.DoubleFieldNegativeInfinity.JsonOutput
-JsonInput.DoubleFieldNegativeInfinity.ProtobufOutput
-JsonInput.DoubleFieldQuotedValue.JsonOutput
-JsonInput.DoubleFieldQuotedValue.ProtobufOutput
-JsonInput.DurationHas3FractionalDigits.Validator
-JsonInput.DurationHas6FractionalDigits.Validator
-JsonInput.DurationHas9FractionalDigits.Validator
-JsonInput.DurationHasZeroFractionalDigit.Validator
-JsonInput.DurationMaxValue.JsonOutput
-JsonInput.DurationMaxValue.ProtobufOutput
-JsonInput.DurationMinValue.JsonOutput
-JsonInput.DurationMinValue.ProtobufOutput
-JsonInput.DurationRepeatedValue.JsonOutput
-JsonInput.DurationRepeatedValue.ProtobufOutput
-JsonInput.EnumFieldNumericValueNonZero.JsonOutput
-JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
-JsonInput.EnumFieldNumericValueZero.JsonOutput
-JsonInput.EnumFieldNumericValueZero.ProtobufOutput
-JsonInput.EnumFieldUnknownValue.Validator
-JsonInput.FieldMask.JsonOutput
-JsonInput.FieldMask.ProtobufOutput
-JsonInput.FieldNameInLowerCamelCase.Validator
-JsonInput.FieldNameInSnakeCase.JsonOutput
-JsonInput.FieldNameInSnakeCase.ProtobufOutput
-JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
-JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
-JsonInput.FieldNameWithDoubleUnderscores.Validator
-JsonInput.FieldNameWithMixedCases.JsonOutput
-JsonInput.FieldNameWithMixedCases.ProtobufOutput
-JsonInput.FieldNameWithMixedCases.Validator
-JsonInput.FloatFieldInfinity.JsonOutput
-JsonInput.FloatFieldInfinity.ProtobufOutput
-JsonInput.FloatFieldNan.JsonOutput
-JsonInput.FloatFieldNan.ProtobufOutput
-JsonInput.FloatFieldNegativeInfinity.JsonOutput
-JsonInput.FloatFieldNegativeInfinity.ProtobufOutput
-JsonInput.FloatFieldQuotedValue.JsonOutput
-JsonInput.FloatFieldQuotedValue.ProtobufOutput
-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.Int32FieldStringValue.JsonOutput
-JsonInput.Int32FieldStringValue.ProtobufOutput
-JsonInput.Int32FieldStringValueEscaped.JsonOutput
-JsonInput.Int32FieldStringValueEscaped.ProtobufOutput
-JsonInput.Int32MapEscapedKey.JsonOutput
-JsonInput.Int32MapEscapedKey.ProtobufOutput
-JsonInput.Int32MapField.JsonOutput
-JsonInput.Int32MapField.ProtobufOutput
-JsonInput.Int64FieldBeString.Validator
-JsonInput.Int64FieldMaxValue.JsonOutput
-JsonInput.Int64FieldMaxValue.ProtobufOutput
-JsonInput.Int64FieldMinValue.JsonOutput
-JsonInput.Int64FieldMinValue.ProtobufOutput
-JsonInput.Int64MapEscapedKey.JsonOutput
-JsonInput.Int64MapEscapedKey.ProtobufOutput
-JsonInput.Int64MapField.JsonOutput
-JsonInput.Int64MapField.ProtobufOutput
-JsonInput.MessageField.JsonOutput
-JsonInput.MessageField.ProtobufOutput
-JsonInput.MessageMapField.JsonOutput
-JsonInput.MessageMapField.ProtobufOutput
-JsonInput.MessageRepeatedField.JsonOutput
-JsonInput.MessageRepeatedField.ProtobufOutput
-JsonInput.OneofZeroDouble.JsonOutput
-JsonInput.OneofZeroDouble.ProtobufOutput
-JsonInput.OneofZeroFloat.JsonOutput
-JsonInput.OneofZeroFloat.ProtobufOutput
-JsonInput.OneofZeroUint32.JsonOutput
-JsonInput.OneofZeroUint32.ProtobufOutput
-JsonInput.OneofZeroUint64.JsonOutput
-JsonInput.OneofZeroUint64.ProtobufOutput
-JsonInput.OptionalBoolWrapper.JsonOutput
-JsonInput.OptionalBoolWrapper.ProtobufOutput
-JsonInput.OptionalBytesWrapper.JsonOutput
-JsonInput.OptionalBytesWrapper.ProtobufOutput
-JsonInput.OptionalDoubleWrapper.JsonOutput
-JsonInput.OptionalDoubleWrapper.ProtobufOutput
-JsonInput.OptionalFloatWrapper.JsonOutput
-JsonInput.OptionalFloatWrapper.ProtobufOutput
-JsonInput.OptionalInt32Wrapper.JsonOutput
-JsonInput.OptionalInt32Wrapper.ProtobufOutput
-JsonInput.OptionalInt64Wrapper.JsonOutput
-JsonInput.OptionalInt64Wrapper.ProtobufOutput
-JsonInput.OptionalStringWrapper.JsonOutput
-JsonInput.OptionalStringWrapper.ProtobufOutput
-JsonInput.OptionalUint32Wrapper.JsonOutput
-JsonInput.OptionalUint32Wrapper.ProtobufOutput
-JsonInput.OptionalUint64Wrapper.JsonOutput
-JsonInput.OptionalUint64Wrapper.ProtobufOutput
-JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
-JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
-JsonInput.OriginalProtoFieldName.JsonOutput
-JsonInput.PrimitiveRepeatedField.JsonOutput
-JsonInput.PrimitiveRepeatedField.ProtobufOutput
-JsonInput.RepeatedBoolWrapper.JsonOutput
-JsonInput.RepeatedBoolWrapper.ProtobufOutput
-JsonInput.RepeatedBytesWrapper.JsonOutput
-JsonInput.RepeatedBytesWrapper.ProtobufOutput
-JsonInput.RepeatedDoubleWrapper.JsonOutput
-JsonInput.RepeatedDoubleWrapper.ProtobufOutput
-JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
-JsonInput.RepeatedFloatWrapper.JsonOutput
-JsonInput.RepeatedFloatWrapper.ProtobufOutput
-JsonInput.RepeatedInt32Wrapper.JsonOutput
-JsonInput.RepeatedInt32Wrapper.ProtobufOutput
-JsonInput.RepeatedInt64Wrapper.JsonOutput
-JsonInput.RepeatedInt64Wrapper.ProtobufOutput
-JsonInput.RepeatedStringWrapper.JsonOutput
-JsonInput.RepeatedStringWrapper.ProtobufOutput
-JsonInput.RepeatedUint32Wrapper.JsonOutput
-JsonInput.RepeatedUint32Wrapper.ProtobufOutput
-JsonInput.RepeatedUint64Wrapper.JsonOutput
-JsonInput.RepeatedUint64Wrapper.ProtobufOutput
-JsonInput.StringEndsWithEscapeChar
-JsonInput.StringFieldNotAString
-JsonInput.StringFieldSurrogateInWrongOrder
-JsonInput.StringFieldSurrogatePair.JsonOutput
-JsonInput.StringFieldSurrogatePair.ProtobufOutput
-JsonInput.StringFieldUnpairedHighSurrogate
-JsonInput.StringFieldUnpairedLowSurrogate
-JsonInput.Struct.JsonOutput
-JsonInput.Struct.ProtobufOutput
-JsonInput.TimestampHas3FractionalDigits.Validator
-JsonInput.TimestampHas6FractionalDigits.Validator
-JsonInput.TimestampHas9FractionalDigits.Validator
-JsonInput.TimestampHasZeroFractionalDigit.Validator
-JsonInput.TimestampMaxValue.JsonOutput
-JsonInput.TimestampMaxValue.ProtobufOutput
-JsonInput.TimestampMinValue.JsonOutput
-JsonInput.TimestampMinValue.ProtobufOutput
-JsonInput.TimestampRepeatedValue.JsonOutput
-JsonInput.TimestampRepeatedValue.ProtobufOutput
-JsonInput.TimestampWithNegativeOffset.JsonOutput
-JsonInput.TimestampWithNegativeOffset.ProtobufOutput
-JsonInput.TimestampWithPositiveOffset.JsonOutput
-JsonInput.TimestampWithPositiveOffset.ProtobufOutput
-JsonInput.TimestampZeroNormalized.Validator
-JsonInput.Uint32FieldMaxFloatValue.JsonOutput
-JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
-JsonInput.Uint32MapField.JsonOutput
-JsonInput.Uint32MapField.ProtobufOutput
-JsonInput.Uint64FieldBeString.Validator
-JsonInput.Uint64FieldMaxValue.JsonOutput
-JsonInput.Uint64FieldMaxValue.ProtobufOutput
-JsonInput.Uint64MapField.JsonOutput
-JsonInput.Uint64MapField.ProtobufOutput
-JsonInput.ValueAcceptBool.JsonOutput
-JsonInput.ValueAcceptBool.ProtobufOutput
-JsonInput.ValueAcceptFloat.JsonOutput
-JsonInput.ValueAcceptFloat.ProtobufOutput
-JsonInput.ValueAcceptInteger.JsonOutput
-JsonInput.ValueAcceptInteger.ProtobufOutput
-JsonInput.ValueAcceptList.JsonOutput
-JsonInput.ValueAcceptList.ProtobufOutput
-JsonInput.ValueAcceptNull.JsonOutput
-JsonInput.ValueAcceptNull.ProtobufOutput
-JsonInput.ValueAcceptObject.JsonOutput
-JsonInput.ValueAcceptObject.ProtobufOutput
-JsonInput.ValueAcceptString.JsonOutput
-JsonInput.ValueAcceptString.ProtobufOutput
-ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
-ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
-ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
-ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
-TimestampProtoInputTooLarge.JsonOutput
-TimestampProtoInputTooSmall.JsonOutput
+Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
+Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
+Recommended.FieldMaskTooManyUnderscore.JsonOutput
+Recommended.JsonInput.BoolFieldIntegerOne
+Recommended.JsonInput.BoolFieldIntegerZero
+Recommended.JsonInput.DurationHas3FractionalDigits.Validator
+Recommended.JsonInput.DurationHas6FractionalDigits.Validator
+Recommended.JsonInput.DurationHas9FractionalDigits.Validator
+Recommended.JsonInput.DurationHasZeroFractionalDigit.Validator
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
+Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
+Recommended.JsonInput.Int64FieldBeString.Validator
+Recommended.JsonInput.OneofZeroDouble.JsonOutput
+Recommended.JsonInput.OneofZeroDouble.ProtobufOutput
+Recommended.JsonInput.OneofZeroFloat.JsonOutput
+Recommended.JsonInput.OneofZeroFloat.ProtobufOutput
+Recommended.JsonInput.OneofZeroUint32.JsonOutput
+Recommended.JsonInput.OneofZeroUint32.ProtobufOutput
+Recommended.JsonInput.OneofZeroUint64.JsonOutput
+Recommended.JsonInput.OneofZeroUint64.ProtobufOutput
+Recommended.JsonInput.StringEndsWithEscapeChar
+Recommended.JsonInput.StringFieldSurrogateInWrongOrder
+Recommended.JsonInput.StringFieldUnpairedHighSurrogate
+Recommended.JsonInput.StringFieldUnpairedLowSurrogate
+Recommended.JsonInput.TimestampHas3FractionalDigits.Validator
+Recommended.JsonInput.TimestampHas6FractionalDigits.Validator
+Recommended.JsonInput.TimestampHas9FractionalDigits.Validator
+Recommended.JsonInput.TimestampHasZeroFractionalDigit.Validator
+Recommended.JsonInput.TimestampZeroNormalized.Validator
+Recommended.JsonInput.Uint64FieldBeString.Validator
+Required.DurationProtoInputTooLarge.JsonOutput
+Required.DurationProtoInputTooSmall.JsonOutput
+Required.JsonInput.Any.JsonOutput
+Required.JsonInput.Any.ProtobufOutput
+Required.JsonInput.AnyNested.JsonOutput
+Required.JsonInput.AnyNested.ProtobufOutput
+Required.JsonInput.AnyUnorderedTypeTag.JsonOutput
+Required.JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+Required.JsonInput.AnyWithDuration.JsonOutput
+Required.JsonInput.AnyWithDuration.ProtobufOutput
+Required.JsonInput.AnyWithFieldMask.JsonOutput
+Required.JsonInput.AnyWithFieldMask.ProtobufOutput
+Required.JsonInput.AnyWithInt32ValueWrapper.JsonOutput
+Required.JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
+Required.JsonInput.AnyWithStruct.JsonOutput
+Required.JsonInput.AnyWithStruct.ProtobufOutput
+Required.JsonInput.AnyWithTimestamp.JsonOutput
+Required.JsonInput.AnyWithTimestamp.ProtobufOutput
+Required.JsonInput.AnyWithValueForInteger.JsonOutput
+Required.JsonInput.AnyWithValueForInteger.ProtobufOutput
+Required.JsonInput.AnyWithValueForJsonObject.JsonOutput
+Required.JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+Required.JsonInput.DoubleFieldInfinity.JsonOutput
+Required.JsonInput.DoubleFieldInfinity.ProtobufOutput
+Required.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
+Required.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
+Required.JsonInput.DoubleFieldMaxPositiveValue.JsonOutput
+Required.JsonInput.DoubleFieldMaxPositiveValue.ProtobufOutput
+Required.JsonInput.DoubleFieldMinNegativeValue.JsonOutput
+Required.JsonInput.DoubleFieldMinNegativeValue.ProtobufOutput
+Required.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
+Required.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
+Required.JsonInput.DoubleFieldNan.JsonOutput
+Required.JsonInput.DoubleFieldNan.ProtobufOutput
+Required.JsonInput.DoubleFieldNegativeInfinity.JsonOutput
+Required.JsonInput.DoubleFieldNegativeInfinity.ProtobufOutput
+Required.JsonInput.DoubleFieldQuotedValue.JsonOutput
+Required.JsonInput.DoubleFieldQuotedValue.ProtobufOutput
+Required.JsonInput.DurationMaxValue.JsonOutput
+Required.JsonInput.DurationMaxValue.ProtobufOutput
+Required.JsonInput.DurationMinValue.JsonOutput
+Required.JsonInput.DurationMinValue.ProtobufOutput
+Required.JsonInput.DurationRepeatedValue.JsonOutput
+Required.JsonInput.DurationRepeatedValue.ProtobufOutput
+Required.JsonInput.EnumFieldNumericValueNonZero.JsonOutput
+Required.JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
+Required.JsonInput.EnumFieldNumericValueZero.JsonOutput
+Required.JsonInput.EnumFieldNumericValueZero.ProtobufOutput
+Required.JsonInput.EnumFieldUnknownValue.Validator
+Required.JsonInput.FieldMask.JsonOutput
+Required.JsonInput.FieldMask.ProtobufOutput
+Required.JsonInput.FieldNameInLowerCamelCase.Validator
+Required.JsonInput.FieldNameInSnakeCase.JsonOutput
+Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
+Required.JsonInput.FloatFieldInfinity.JsonOutput
+Required.JsonInput.FloatFieldInfinity.ProtobufOutput
+Required.JsonInput.FloatFieldNan.JsonOutput
+Required.JsonInput.FloatFieldNan.ProtobufOutput
+Required.JsonInput.FloatFieldNegativeInfinity.JsonOutput
+Required.JsonInput.FloatFieldNegativeInfinity.ProtobufOutput
+Required.JsonInput.FloatFieldQuotedValue.JsonOutput
+Required.JsonInput.FloatFieldQuotedValue.ProtobufOutput
+Required.JsonInput.FloatFieldTooLarge
+Required.JsonInput.FloatFieldTooSmall
+Required.JsonInput.Int32FieldExponentialFormat.JsonOutput
+Required.JsonInput.Int32FieldExponentialFormat.ProtobufOutput
+Required.JsonInput.Int32FieldFloatTrailingZero.JsonOutput
+Required.JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
+Required.JsonInput.Int32FieldMaxFloatValue.JsonOutput
+Required.JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
+Required.JsonInput.Int32FieldMinFloatValue.JsonOutput
+Required.JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+Required.JsonInput.Int32FieldStringValue.JsonOutput
+Required.JsonInput.Int32FieldStringValue.ProtobufOutput
+Required.JsonInput.Int32FieldStringValueEscaped.JsonOutput
+Required.JsonInput.Int32FieldStringValueEscaped.ProtobufOutput
+Required.JsonInput.Int32MapEscapedKey.JsonOutput
+Required.JsonInput.Int32MapEscapedKey.ProtobufOutput
+Required.JsonInput.Int32MapField.JsonOutput
+Required.JsonInput.Int32MapField.ProtobufOutput
+Required.JsonInput.Int64FieldMaxValue.JsonOutput
+Required.JsonInput.Int64FieldMaxValue.ProtobufOutput
+Required.JsonInput.Int64FieldMinValue.JsonOutput
+Required.JsonInput.Int64FieldMinValue.ProtobufOutput
+Required.JsonInput.Int64MapEscapedKey.JsonOutput
+Required.JsonInput.Int64MapEscapedKey.ProtobufOutput
+Required.JsonInput.Int64MapField.JsonOutput
+Required.JsonInput.Int64MapField.ProtobufOutput
+Required.JsonInput.MessageField.JsonOutput
+Required.JsonInput.MessageField.ProtobufOutput
+Required.JsonInput.MessageMapField.JsonOutput
+Required.JsonInput.MessageMapField.ProtobufOutput
+Required.JsonInput.MessageRepeatedField.JsonOutput
+Required.JsonInput.MessageRepeatedField.ProtobufOutput
+Required.JsonInput.OptionalBoolWrapper.JsonOutput
+Required.JsonInput.OptionalBoolWrapper.ProtobufOutput
+Required.JsonInput.OptionalBytesWrapper.JsonOutput
+Required.JsonInput.OptionalBytesWrapper.ProtobufOutput
+Required.JsonInput.OptionalDoubleWrapper.JsonOutput
+Required.JsonInput.OptionalDoubleWrapper.ProtobufOutput
+Required.JsonInput.OptionalFloatWrapper.JsonOutput
+Required.JsonInput.OptionalFloatWrapper.ProtobufOutput
+Required.JsonInput.OptionalInt32Wrapper.JsonOutput
+Required.JsonInput.OptionalInt32Wrapper.ProtobufOutput
+Required.JsonInput.OptionalInt64Wrapper.JsonOutput
+Required.JsonInput.OptionalInt64Wrapper.ProtobufOutput
+Required.JsonInput.OptionalStringWrapper.JsonOutput
+Required.JsonInput.OptionalStringWrapper.ProtobufOutput
+Required.JsonInput.OptionalUint32Wrapper.JsonOutput
+Required.JsonInput.OptionalUint32Wrapper.ProtobufOutput
+Required.JsonInput.OptionalUint64Wrapper.JsonOutput
+Required.JsonInput.OptionalUint64Wrapper.ProtobufOutput
+Required.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
+Required.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
+Required.JsonInput.PrimitiveRepeatedField.JsonOutput
+Required.JsonInput.PrimitiveRepeatedField.ProtobufOutput
+Required.JsonInput.RepeatedBoolWrapper.JsonOutput
+Required.JsonInput.RepeatedBoolWrapper.ProtobufOutput
+Required.JsonInput.RepeatedBytesWrapper.JsonOutput
+Required.JsonInput.RepeatedBytesWrapper.ProtobufOutput
+Required.JsonInput.RepeatedDoubleWrapper.JsonOutput
+Required.JsonInput.RepeatedDoubleWrapper.ProtobufOutput
+Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
+Required.JsonInput.RepeatedFloatWrapper.JsonOutput
+Required.JsonInput.RepeatedFloatWrapper.ProtobufOutput
+Required.JsonInput.RepeatedInt32Wrapper.JsonOutput
+Required.JsonInput.RepeatedInt32Wrapper.ProtobufOutput
+Required.JsonInput.RepeatedInt64Wrapper.JsonOutput
+Required.JsonInput.RepeatedInt64Wrapper.ProtobufOutput
+Required.JsonInput.RepeatedStringWrapper.JsonOutput
+Required.JsonInput.RepeatedStringWrapper.ProtobufOutput
+Required.JsonInput.RepeatedUint32Wrapper.JsonOutput
+Required.JsonInput.RepeatedUint32Wrapper.ProtobufOutput
+Required.JsonInput.RepeatedUint64Wrapper.JsonOutput
+Required.JsonInput.RepeatedUint64Wrapper.ProtobufOutput
+Required.JsonInput.StringFieldNotAString
+Required.JsonInput.StringFieldSurrogatePair.JsonOutput
+Required.JsonInput.StringFieldSurrogatePair.ProtobufOutput
+Required.JsonInput.Struct.JsonOutput
+Required.JsonInput.Struct.ProtobufOutput
+Required.JsonInput.TimestampMaxValue.JsonOutput
+Required.JsonInput.TimestampMaxValue.ProtobufOutput
+Required.JsonInput.TimestampMinValue.JsonOutput
+Required.JsonInput.TimestampMinValue.ProtobufOutput
+Required.JsonInput.TimestampRepeatedValue.JsonOutput
+Required.JsonInput.TimestampRepeatedValue.ProtobufOutput
+Required.JsonInput.TimestampWithNegativeOffset.JsonOutput
+Required.JsonInput.TimestampWithNegativeOffset.ProtobufOutput
+Required.JsonInput.TimestampWithPositiveOffset.JsonOutput
+Required.JsonInput.TimestampWithPositiveOffset.ProtobufOutput
+Required.JsonInput.Uint32FieldMaxFloatValue.JsonOutput
+Required.JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
+Required.JsonInput.Uint32MapField.JsonOutput
+Required.JsonInput.Uint32MapField.ProtobufOutput
+Required.JsonInput.Uint64FieldMaxValue.JsonOutput
+Required.JsonInput.Uint64FieldMaxValue.ProtobufOutput
+Required.JsonInput.Uint64MapField.JsonOutput
+Required.JsonInput.Uint64MapField.ProtobufOutput
+Required.JsonInput.ValueAcceptBool.JsonOutput
+Required.JsonInput.ValueAcceptBool.ProtobufOutput
+Required.JsonInput.ValueAcceptFloat.JsonOutput
+Required.JsonInput.ValueAcceptFloat.ProtobufOutput
+Required.JsonInput.ValueAcceptInteger.JsonOutput
+Required.JsonInput.ValueAcceptInteger.ProtobufOutput
+Required.JsonInput.ValueAcceptList.JsonOutput
+Required.JsonInput.ValueAcceptList.ProtobufOutput
+Required.JsonInput.ValueAcceptNull.JsonOutput
+Required.JsonInput.ValueAcceptNull.ProtobufOutput
+Required.JsonInput.ValueAcceptObject.JsonOutput
+Required.JsonInput.ValueAcceptObject.ProtobufOutput
+Required.JsonInput.ValueAcceptString.JsonOutput
+Required.JsonInput.ValueAcceptString.ProtobufOutput
+Required.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
+Required.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
+Required.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
+Required.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
+Required.TimestampProtoInputTooLarge.JsonOutput
+Required.TimestampProtoInputTooSmall.JsonOutput

+ 1 - 1
csharp/Google.Protobuf.Tools.nuspec

@@ -5,7 +5,7 @@
     <title>Google Protocol Buffers tools</title>
     <summary>Tools for Protocol Buffers - Google's data interchange format.</summary>
     <description>See project site for more info.</description>
-    <version>3.0.2</version>
+    <version>3.1.0</version>
     <authors>Google Inc.</authors>
     <owners>protobuf-packages</owners>
     <licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>

+ 52 - 0
csharp/build_tools.sh

@@ -0,0 +1,52 @@
+#!/bin/bash
+
+if [ $# -ne 1 ]; then
+  cat <<EOF
+Usage: $0 <VERSION_NUMBER>
+
+Example:
+  $ $0 3.0.0
+
+This script will download pre-built protoc binaries from maven repository and
+create the Google.Protobuf.Tools package. Well-known type .proto files will also
+be included.
+EOF
+  exit 1
+fi
+
+VERSION_NUMBER=$1
+# <directory name> <binary file name> pairs.
+declare -a FILE_NAMES=(          \
+  windows_x86 windows-x86_32.exe \
+  windows_x64 windows-x86_64.exe \
+  macosx_x86  osx-x86_32.exe     \
+  macosx_x64  osx-x86_64.exe     \
+  linux_x86   linux-x86_32.exe   \
+  linux_x64   linux-x86_64.exe   \
+)
+
+set -e
+
+mkdir -p protoc
+# Create a zip file for each binary.
+for((i=0;i<${#FILE_NAMES[@]};i+=2));do
+  DIR_NAME=${FILE_NAMES[$i]}
+  mkdir -p protoc/$DIR_NAME
+
+  if [ ${DIR_NAME:0:3} = "win" ]; then
+    TARGET_BINARY="protoc.exe"
+  else
+    TARGET_BINARY="protoc"
+  fi
+
+  BINARY_NAME=${FILE_NAMES[$(($i+1))]}
+  BINARY_URL=http://repo1.maven.org/maven2/com/google/protobuf/protoc/${VERSION_NUMBER}/protoc-${VERSION_NUMBER}-${BINARY_NAME}
+
+  if ! wget ${BINARY_URL} -O protoc/$DIR_NAME/$TARGET_BINARY &> /dev/null; then
+    echo "[ERROR] Failed to download ${BINARY_URL}" >&2
+    echo "[ERROR] Skipped $protoc-${VERSION_NAME}-${DIR_NAME}" >&2
+    continue
+  fi
+done
+
+nuget pack Google.Protobuf.Tools.nuspec

+ 61 - 71
csharp/src/Google.Protobuf/Reflection/Descriptor.cs

@@ -80,66 +80,66 @@ namespace Google.Protobuf.Reflection {
             "ASgJEhMKC291dHB1dF90eXBlGAMgASgJEi8KB29wdGlvbnMYBCABKAsyHi5n",
             "b29nbGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxIfChBjbGllbnRfc3RyZWFt",
             "aW5nGAUgASgIOgVmYWxzZRIfChBzZXJ2ZXJfc3RyZWFtaW5nGAYgASgIOgVm",
-            "YWxzZSKHBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwK",
+            "YWxzZSKEBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwK",
             "FGphdmFfb3V0ZXJfY2xhc3NuYW1lGAggASgJEiIKE2phdmFfbXVsdGlwbGVf",
-            "ZmlsZXMYCiABKAg6BWZhbHNlEiwKHWphdmFfZ2VuZXJhdGVfZXF1YWxzX2Fu",
-            "ZF9oYXNoGBQgASgIOgVmYWxzZRIlChZqYXZhX3N0cmluZ19jaGVja191dGY4",
-            "GBsgASgIOgVmYWxzZRJGCgxvcHRpbWl6ZV9mb3IYCSABKA4yKS5nb29nbGUu",
-            "cHJvdG9idWYuRmlsZU9wdGlvbnMuT3B0aW1pemVNb2RlOgVTUEVFRBISCgpn",
-            "b19wYWNrYWdlGAsgASgJEiIKE2NjX2dlbmVyaWNfc2VydmljZXMYECABKAg6",
-            "BWZhbHNlEiQKFWphdmFfZ2VuZXJpY19zZXJ2aWNlcxgRIAEoCDoFZmFsc2US",
-            "IgoTcHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USGQoKZGVwcmVj",
-            "YXRlZBgXIAEoCDoFZmFsc2USHwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoF",
-            "ZmFsc2USGQoRb2JqY19jbGFzc19wcmVmaXgYJCABKAkSGAoQY3NoYXJwX25h",
-            "bWVzcGFjZRglIAEoCRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsy",
-            "JC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiI6CgxPcHRp",
-            "bWl6ZU1vZGUSCQoFU1BFRUQQARINCglDT0RFX1NJWkUQAhIQCgxMSVRFX1JV",
-            "TlRJTUUQAyoJCOgHEICAgIACSgQIJhAnIuYBCg5NZXNzYWdlT3B0aW9ucxIm",
-            "ChdtZXNzYWdlX3NldF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USLgofbm9f",
-            "c3RhbmRhcmRfZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2USGQoK",
-            "ZGVwcmVjYXRlZBgDIAEoCDoFZmFsc2USEQoJbWFwX2VudHJ5GAcgASgIEkMK",
-            "FHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1",
-            "Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIimAMKDEZpZWxkT3B0",
-            "aW9ucxI6CgVjdHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9w",
-            "dGlvbnMuQ1R5cGU6BlNUUklORxIOCgZwYWNrZWQYAiABKAgSPwoGanN0eXBl",
-            "GAYgASgOMiQuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5KU1R5cGU6",
-            "CUpTX05PUk1BTBITCgRsYXp5GAUgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVk",
-            "GAMgASgIOgVmYWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRJDChR1bmludGVy",
-            "cHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRl",
-            "cnByZXRlZE9wdGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAES",
-            "EAoMU1RSSU5HX1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0K",
-            "CUpTX1NUUklORxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAIiXgoMT25l",
-            "b2ZPcHRpb25zEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdv",
-            "b2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIi",
-            "jQEKC0VudW1PcHRpb25zEhMKC2FsbG93X2FsaWFzGAIgASgIEhkKCmRlcHJl",
-            "Y2F0ZWQYAyABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcH",
+            "ZmlsZXMYCiABKAg6BWZhbHNlEikKHWphdmFfZ2VuZXJhdGVfZXF1YWxzX2Fu",
+            "ZF9oYXNoGBQgASgIQgIYARIlChZqYXZhX3N0cmluZ19jaGVja191dGY4GBsg",
+            "ASgIOgVmYWxzZRJGCgxvcHRpbWl6ZV9mb3IYCSABKA4yKS5nb29nbGUucHJv",
+            "dG9idWYuRmlsZU9wdGlvbnMuT3B0aW1pemVNb2RlOgVTUEVFRBISCgpnb19w",
+            "YWNrYWdlGAsgASgJEiIKE2NjX2dlbmVyaWNfc2VydmljZXMYECABKAg6BWZh",
+            "bHNlEiQKFWphdmFfZ2VuZXJpY19zZXJ2aWNlcxgRIAEoCDoFZmFsc2USIgoT",
+            "cHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
+            "ZBgXIAEoCDoFZmFsc2USHwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoFZmFs",
+            "c2USGQoRb2JqY19jbGFzc19wcmVmaXgYJCABKAkSGAoQY3NoYXJwX25hbWVz",
+            "cGFjZRglIAEoCRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5n",
+            "b29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiI6CgxPcHRpbWl6",
+            "ZU1vZGUSCQoFU1BFRUQQARINCglDT0RFX1NJWkUQAhIQCgxMSVRFX1JVTlRJ",
+            "TUUQAyoJCOgHEICAgIACSgQIJhAnIuwBCg5NZXNzYWdlT3B0aW9ucxImChdt",
+            "ZXNzYWdlX3NldF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USLgofbm9fc3Rh",
+            "bmRhcmRfZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2USGQoKZGVw",
+            "cmVjYXRlZBgDIAEoCDoFZmFsc2USEQoJbWFwX2VudHJ5GAcgASgIEkMKFHVu",
+            "aW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5V",
+            "bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAJKBAgIEAkingMKDEZpZWxk",
+            "T3B0aW9ucxI6CgVjdHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90b2J1Zi5GaWVs",
+            "ZE9wdGlvbnMuQ1R5cGU6BlNUUklORxIOCgZwYWNrZWQYAiABKAgSPwoGanN0",
+            "eXBlGAYgASgOMiQuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5KU1R5",
+            "cGU6CUpTX05PUk1BTBITCgRsYXp5GAUgASgIOgVmYWxzZRIZCgpkZXByZWNh",
+            "dGVkGAMgASgIOgVmYWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRJDChR1bmlu",
+            "dGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5p",
+            "bnRlcnByZXRlZE9wdGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JE",
+            "EAESEAoMU1RSSU5HX1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAA",
+            "Eg0KCUpTX1NUUklORxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAJKBAgE",
+            "EAUiXgoMT25lb2ZPcHRpb25zEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcH",
             "IAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI",
-            "6AcQgICAgAIifQoQRW51bVZhbHVlT3B0aW9ucxIZCgpkZXByZWNhdGVkGAEg",
-            "ASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5n",
-            "b29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIAC",
-            "InsKDlNlcnZpY2VPcHRpb25zEhkKCmRlcHJlY2F0ZWQYISABKAg6BWZhbHNl",
-            "EkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90",
-            "b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIiegoNTWV0aG9k",
-            "T3B0aW9ucxIZCgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZRJDChR1bmludGVy",
-            "cHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRl",
-            "cnByZXRlZE9wdGlvbioJCOgHEICAgIACIp4CChNVbmludGVycHJldGVkT3B0",
-            "aW9uEjsKBG5hbWUYAiADKAsyLS5nb29nbGUucHJvdG9idWYuVW5pbnRlcnBy",
-            "ZXRlZE9wdGlvbi5OYW1lUGFydBIYChBpZGVudGlmaWVyX3ZhbHVlGAMgASgJ",
-            "EhoKEnBvc2l0aXZlX2ludF92YWx1ZRgEIAEoBBIaChJuZWdhdGl2ZV9pbnRf",
-            "dmFsdWUYBSABKAMSFAoMZG91YmxlX3ZhbHVlGAYgASgBEhQKDHN0cmluZ192",
-            "YWx1ZRgHIAEoDBIXCg9hZ2dyZWdhdGVfdmFsdWUYCCABKAkaMwoITmFtZVBh",
-            "cnQSEQoJbmFtZV9wYXJ0GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCCLV",
-            "AQoOU291cmNlQ29kZUluZm8SOgoIbG9jYXRpb24YASADKAsyKC5nb29nbGUu",
-            "cHJvdG9idWYuU291cmNlQ29kZUluZm8uTG9jYXRpb24ahgEKCExvY2F0aW9u",
-            "EhAKBHBhdGgYASADKAVCAhABEhAKBHNwYW4YAiADKAVCAhABEhgKEGxlYWRp",
-            "bmdfY29tbWVudHMYAyABKAkSGQoRdHJhaWxpbmdfY29tbWVudHMYBCABKAkS",
-            "IQoZbGVhZGluZ19kZXRhY2hlZF9jb21tZW50cxgGIAMoCSKnAQoRR2VuZXJh",
-            "dGVkQ29kZUluZm8SQQoKYW5ub3RhdGlvbhgBIAMoCzItLmdvb2dsZS5wcm90",
-            "b2J1Zi5HZW5lcmF0ZWRDb2RlSW5mby5Bbm5vdGF0aW9uGk8KCkFubm90YXRp",
-            "b24SEAoEcGF0aBgBIAMoBUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoF",
-            "YmVnaW4YAyABKAUSCwoDZW5kGAQgASgFQlsKE2NvbS5nb29nbGUucHJvdG9i",
-            "dWZCEERlc2NyaXB0b3JQcm90b3NIAVoKZGVzY3JpcHRvcqABAaICA0dQQqoC",
-            "Gkdvb2dsZS5Qcm90b2J1Zi5SZWZsZWN0aW9u"));
+            "6AcQgICAgAIijQEKC0VudW1PcHRpb25zEhMKC2FsbG93X2FsaWFzGAIgASgI",
+            "EhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRf",
+            "b3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVk",
+            "T3B0aW9uKgkI6AcQgICAgAIifQoQRW51bVZhbHVlT3B0aW9ucxIZCgpkZXBy",
+            "ZWNhdGVkGAEgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjn",
+            "ByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJ",
+            "COgHEICAgIACInsKDlNlcnZpY2VPcHRpb25zEhkKCmRlcHJlY2F0ZWQYISAB",
+            "KAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdv",
+            "b2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIi",
+            "egoNTWV0aG9kT3B0aW9ucxIZCgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZRJD",
+            "ChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9i",
+            "dWYuVW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACIp4CChNVbmludGVy",
+            "cHJldGVkT3B0aW9uEjsKBG5hbWUYAiADKAsyLS5nb29nbGUucHJvdG9idWYu",
+            "VW5pbnRlcnByZXRlZE9wdGlvbi5OYW1lUGFydBIYChBpZGVudGlmaWVyX3Zh",
+            "bHVlGAMgASgJEhoKEnBvc2l0aXZlX2ludF92YWx1ZRgEIAEoBBIaChJuZWdh",
+            "dGl2ZV9pbnRfdmFsdWUYBSABKAMSFAoMZG91YmxlX3ZhbHVlGAYgASgBEhQK",
+            "DHN0cmluZ192YWx1ZRgHIAEoDBIXCg9hZ2dyZWdhdGVfdmFsdWUYCCABKAka",
+            "MwoITmFtZVBhcnQSEQoJbmFtZV9wYXJ0GAEgAigJEhQKDGlzX2V4dGVuc2lv",
+            "bhgCIAIoCCLVAQoOU291cmNlQ29kZUluZm8SOgoIbG9jYXRpb24YASADKAsy",
+            "KC5nb29nbGUucHJvdG9idWYuU291cmNlQ29kZUluZm8uTG9jYXRpb24ahgEK",
+            "CExvY2F0aW9uEhAKBHBhdGgYASADKAVCAhABEhAKBHNwYW4YAiADKAVCAhAB",
+            "EhgKEGxlYWRpbmdfY29tbWVudHMYAyABKAkSGQoRdHJhaWxpbmdfY29tbWVu",
+            "dHMYBCABKAkSIQoZbGVhZGluZ19kZXRhY2hlZF9jb21tZW50cxgGIAMoCSKn",
+            "AQoRR2VuZXJhdGVkQ29kZUluZm8SQQoKYW5ub3RhdGlvbhgBIAMoCzItLmdv",
+            "b2dsZS5wcm90b2J1Zi5HZW5lcmF0ZWRDb2RlSW5mby5Bbm5vdGF0aW9uGk8K",
+            "CkFubm90YXRpb24SEAoEcGF0aBgBIAMoBUICEAESEwoLc291cmNlX2ZpbGUY",
+            "AiABKAkSDQoFYmVnaW4YAyABKAUSCwoDZW5kGAQgASgFQlgKE2NvbS5nb29n",
+            "bGUucHJvdG9idWZCEERlc2NyaXB0b3JQcm90b3NIAVoKZGVzY3JpcHRvcqIC",
+            "A0dQQqoCGkdvb2dsZS5Qcm90b2J1Zi5SZWZsZWN0aW9u"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
@@ -2865,19 +2865,9 @@ namespace Google.Protobuf.Reflection {
     public const int JavaGenerateEqualsAndHashFieldNumber = 20;
     private bool javaGenerateEqualsAndHash_;
     /// <summary>
-    ///  If set true, then the Java code generator will generate equals() and
-    ///  hashCode() methods for all messages defined in the .proto file.
-    ///  This increases generated code size, potentially substantially for large
-    ///  protos, which may harm a memory-constrained application.
-    ///  - In the full runtime this is a speed optimization, as the
-    ///  AbstractMessage base class includes reflection-based implementations of
-    ///  these methods.
-    ///  - In the lite runtime, setting this option changes the semantics of
-    ///  equals() and hashCode() to more closely match those of the full runtime;
-    ///  the generated methods compute their results based on field values rather
-    ///  than object identity. (Implementations should not assume that hashcodes
-    ///  will be consistent across runtimes or versions of the protocol compiler.)
+    ///  This option does nothing.
     /// </summary>
+    [global::System.ObsoleteAttribute]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     public bool JavaGenerateEqualsAndHash {
       get { return javaGenerateEqualsAndHash_; }
@@ -3764,7 +3754,7 @@ namespace Google.Protobuf.Reflection {
     ///  to require exclusive access.
     ///
     ///  Note that implementations may choose not to check required fields within
-    ///  a lazy sub-message.  That is, calling IsInitialized() on the outher message
+    ///  a lazy sub-message.  That is, calling IsInitialized() on the outer message
     ///  may return true even if the inner message has missing required fields.
     ///  This is necessary because otherwise the inner message would have to be
     ///  parsed in order to perform the check, defeating the purpose of lazy

+ 3 - 3
csharp/src/Google.Protobuf/WellKnownTypes/Any.cs

@@ -23,10 +23,10 @@ namespace Google.Protobuf.WellKnownTypes {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
             "Chlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvEg9nb29nbGUucHJvdG9idWYi",
-            "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQnIKE2Nv",
+            "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQm8KE2Nv",
             "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAFaJWdpdGh1Yi5jb20vZ29s",
-            "YW5nL3Byb3RvYnVmL3B0eXBlcy9hbnmgAQGiAgNHUEKqAh5Hb29nbGUuUHJv",
-            "dG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
+            "YW5nL3Byb3RvYnVmL3B0eXBlcy9hbnmiAgNHUEKqAh5Hb29nbGUuUHJvdG9i",
+            "dWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {

+ 3 - 3
csharp/src/Google.Protobuf/WellKnownTypes/Api.cs

@@ -35,9 +35,9 @@ namespace Google.Protobuf.WellKnownTypes {
             "ChFyZXNwb25zZV90eXBlX3VybBgEIAEoCRIaChJyZXNwb25zZV9zdHJlYW1p",
             "bmcYBSABKAgSKAoHb3B0aW9ucxgGIAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5P",
             "cHRpb24SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3RvYnVmLlN5bnRh",
-            "eCIjCgVNaXhpbhIMCgRuYW1lGAEgASgJEgwKBHJvb3QYAiABKAlCSwoTY29t",
-            "Lmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJvdG9QAaABAaICA0dQQqoCHkdvb2ds",
-            "ZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
+            "eCIjCgVNaXhpbhIMCgRuYW1lGAEgASgJEgwKBHJvb3QYAiABKAlCSAoTY29t",
+            "Lmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJvdG9QAaICA0dQQqoCHkdvb2dsZS5Q",
+            "cm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {

+ 7 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs

@@ -25,7 +25,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "Ch5nb29nbGUvcHJvdG9idWYvZHVyYXRpb24ucHJvdG8SD2dvb2dsZS5wcm90",
             "b2J1ZiIqCghEdXJhdGlvbhIPCgdzZWNvbmRzGAEgASgDEg0KBW5hbm9zGAIg",
             "ASgFQnwKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAVoq",
-            "Z2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL2R1cmF0aW9uoAEB",
+            "Z2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL2R1cmF0aW9u+AEB",
             "ogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90",
             "bzM="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
@@ -79,6 +79,12 @@ namespace Google.Protobuf.WellKnownTypes {
   ///        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)
   /// </summary>
   public sealed partial class Duration : pb::IMessage<Duration> {
     private static readonly pb::MessageParser<Duration> _parser = new pb::MessageParser<Duration>(() => new Duration());

+ 4 - 4
csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs

@@ -23,10 +23,10 @@ namespace Google.Protobuf.WellKnownTypes {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
             "Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1",
-            "ZiIHCgVFbXB0eUJ5ChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv",
-            "UAFaJ2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy9lbXB0eaAB",
-            "AfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
-            "cHJvdG8z"));
+            "ZiIHCgVFbXB0eUJ2ChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv",
+            "UAFaJ2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy9lbXB0efgB",
+            "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv",
+            "dG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {

+ 6 - 6
csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs

@@ -23,9 +23,9 @@ namespace Google.Protobuf.WellKnownTypes {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
             "CiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxIPZ29vZ2xlLnBy",
-            "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUJRChNjb20uZ29v",
-            "Z2xlLnByb3RvYnVmQg5GaWVsZE1hc2tQcm90b1ABoAEBogIDR1BCqgIeR29v",
-            "Z2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
+            "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUJOChNjb20uZ29v",
+            "Z2xlLnByb3RvYnVmQg5GaWVsZE1hc2tQcm90b1ABogIDR1BCqgIeR29vZ2xl",
+            "LlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
@@ -79,7 +79,7 @@ namespace Google.Protobuf.WellKnownTypes {
   ///      }
   ///
   ///  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
@@ -106,8 +106,8 @@ namespace Google.Protobuf.WellKnownTypes {
   ///
   ///  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

+ 3 - 3
csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs

@@ -24,9 +24,9 @@ namespace Google.Protobuf.WellKnownTypes {
           string.Concat(
             "CiRnb29nbGUvcHJvdG9idWYvc291cmNlX2NvbnRleHQucHJvdG8SD2dvb2ds",
             "ZS5wcm90b2J1ZiIiCg1Tb3VyY2VDb250ZXh0EhEKCWZpbGVfbmFtZRgBIAEo",
-            "CUJVChNjb20uZ29vZ2xlLnByb3RvYnVmQhJTb3VyY2VDb250ZXh0UHJvdG9Q",
-            "AaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
-            "cHJvdG8z"));
+            "CUJSChNjb20uZ29vZ2xlLnByb3RvYnVmQhJTb3VyY2VDb250ZXh0UHJvdG9Q",
+            "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv",
+            "dG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs

@@ -35,7 +35,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "Lmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSobCglOdWxsVmFsdWUSDgoKTlVMTF9W",
             "QUxVRRAAQoEBChNjb20uZ29vZ2xlLnByb3RvYnVmQgtTdHJ1Y3RQcm90b1AB",
             "WjFnaXRodWIuY29tL2dvbGFuZy9wcm90b2J1Zi9wdHlwZXMvc3RydWN0O3N0",
-            "cnVjdHBioAEBogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5",
+            "cnVjdHBi+AEBogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5",
             "cGVzYgZwcm90bzM="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },

+ 7 - 9
csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs

@@ -24,10 +24,10 @@ namespace Google.Protobuf.WellKnownTypes {
           string.Concat(
             "Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv",
             "dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY",
-            "AiABKAVCgQEKE2NvbS5nb29nbGUucHJvdG9idWZCDlRpbWVzdGFtcFByb3Rv",
-            "UAFaK2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy90aW1lc3Rh",
-            "bXCgAQH4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw",
-            "ZXNiBnByb3RvMw=="));
+            "AiABKAVCfgoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q",
+            "AVorZ2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL3RpbWVzdGFt",
+            "cPgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
+            "cHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
@@ -87,10 +87,8 @@ namespace Google.Protobuf.WellKnownTypes {
   ///
   ///  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()
   /// </summary>
   public sealed partial class Timestamp : pb::IMessage<Timestamp> {
     private static readonly pb::MessageParser<Timestamp> _parser = new pb::MessageParser<Timestamp>(() => new Timestamp());
@@ -130,7 +128,7 @@ namespace Google.Protobuf.WellKnownTypes {
     private long seconds_;
     /// <summary>
     ///  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.
     /// </summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Type.cs

@@ -55,7 +55,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "IjsKBk9wdGlvbhIMCgRuYW1lGAEgASgJEiMKBXZhbHVlGAIgASgLMhQuZ29v",
             "Z2xlLnByb3RvYnVmLkFueSouCgZTeW50YXgSEQoNU1lOVEFYX1BST1RPMhAA",
             "EhEKDVNZTlRBWF9QUk9UTzMQAUJMChNjb20uZ29vZ2xlLnByb3RvYnVmQglU",
-            "eXBlUHJvdG9QAaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25v",
+            "eXBlUHJvdG9QAfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25v",
             "d25UeXBlc2IGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, },

+ 3 - 3
csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs

@@ -28,10 +28,10 @@ namespace Google.Protobuf.WellKnownTypes {
             "KAMiHAoLVUludDY0VmFsdWUSDQoFdmFsdWUYASABKAQiGwoKSW50MzJWYWx1",
             "ZRINCgV2YWx1ZRgBIAEoBSIcCgtVSW50MzJWYWx1ZRINCgV2YWx1ZRgBIAEo",
             "DSIaCglCb29sVmFsdWUSDQoFdmFsdWUYASABKAgiHAoLU3RyaW5nVmFsdWUS",
-            "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJ/",
+            "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJ8",
             "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAFaKmdpdGh1",
-            "Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy93cmFwcGVyc6ABAfgBAaIC",
-            "A0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
+            "Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy93cmFwcGVyc/gBAaICA0dQ",
+            "QqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {

+ 1 - 1
csharp/src/Google.Protobuf/project.json

@@ -1,5 +1,5 @@
 {
-  "version": "3.0.2",
+  "version": "3.1.0",
   "title": "Google Protocol Buffers",
   "description": "See project site for more info.",
   "authors": [ "Google Inc." ],

+ 1 - 1
java/core/pom.xml

@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.0.2</version>
+    <version>3.1.0</version>
   </parent>
 
   <artifactId>protobuf-java</artifactId>

+ 14 - 0
java/core/src/main/java/com/google/protobuf/ByteString.java

@@ -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.

Fișier diff suprimat deoarece este prea mare
+ 149 - 729
java/core/src/main/java/com/google/protobuf/CodedInputStream.java


+ 383 - 17
java/core/src/main/java/com/google/protobuf/CodedOutputStream.java

@@ -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.
    */

+ 9 - 22
java/core/src/main/java/com/google/protobuf/Descriptors.java

@@ -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()) {

+ 145 - 21
java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java

@@ -45,6 +45,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,24 +1610,6 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
     FieldDescriptor getDescriptor();
   }
 
-  private abstract static class CachedDescriptorRetriever
-      implements ExtensionDescriptorRetriever {
-    private volatile FieldDescriptor descriptor;
-    protected abstract FieldDescriptor loadDescriptor();
-
-    @Override
-    public FieldDescriptor getDescriptor() {
-      if (descriptor == null) {
-        synchronized (this) {
-          if (descriptor == null) {
-            descriptor = loadDescriptor();
-          }
-        }
-      }
-      return descriptor;
-    }
-  }
-
   // =================================================================
 
   /** Calls Class.getMethod and throws a RuntimeException if it fails. */
@@ -2223,6 +2206,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 +2275,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 +2710,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());
+    }
+  }
 }

+ 10 - 0
java/core/src/main/java/com/google/protobuf/Internal.java

@@ -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.

+ 14 - 2
java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java

@@ -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.  " +

+ 9 - 0
java/core/src/main/java/com/google/protobuf/MapEntry.java

@@ -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);
       }

+ 5 - 4
java/core/src/main/java/com/google/protobuf/NioByteString.java

@@ -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);
   }
 
   /**

+ 1 - 0
java/core/src/main/java/com/google/protobuf/RopeByteString.java

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

+ 15 - 7
java/core/src/main/java/com/google/protobuf/TextFormat.java

@@ -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,

+ 2 - 1
java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java

@@ -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.
  */

+ 25 - 6
java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java

@@ -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);
   }
+
 }

+ 102 - 17
java/core/src/main/java/com/google/protobuf/UnsafeUtil.java

@@ -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) {

+ 4 - 0
java/core/src/main/java/com/google/protobuf/WireFormat.java

@@ -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;

+ 1 - 3
java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java

@@ -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.
    */

+ 1 - 2
java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java

@@ -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}.

+ 1 - 2
java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/ByteStringTest.java

@@ -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"

+ 439 - 363
java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java

@@ -30,20 +30,20 @@
 
 package com.google.protobuf;
 
+import static org.junit.Assert.assertArrayEquals;
+
 import protobuf_unittest.UnittestProto.BoolMessage;
 import protobuf_unittest.UnittestProto.Int32Message;
 import protobuf_unittest.UnittestProto.Int64Message;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestRecursiveMessage;
-
-import junit.framework.TestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import junit.framework.TestCase;
 
 /**
  * Unit test for {@link CodedInputStream}.
@@ -51,10 +51,45 @@ import java.nio.ByteBuffer;
  * @author kenton@google.com Kenton Varda
  */
 public class CodedInputStreamTest extends TestCase {
+  private enum InputType {
+    ARRAY {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        return CodedInputStream.newInstance(data);
+      }
+    },
+    NIO_HEAP {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        return CodedInputStream.newInstance(ByteBuffer.wrap(data));
+      }
+    },
+    NIO_DIRECT {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
+        buffer.put(data);
+        buffer.flip();
+        return CodedInputStream.newInstance(buffer);
+      }
+    },
+    STREAM {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        return CodedInputStream.newInstance(new SmallBlockInputStream(data, blockSize));
+      }
+    };
+
+    CodedInputStream newDecoder(byte[] data) {
+      return newDecoder(data, data.length);
+    }
+
+    abstract CodedInputStream newDecoder(byte[] data, int blockSize);
+  }
+
   /**
-   * Helper to construct a byte array from a bunch of bytes.  The inputs are
-   * actually ints so that I can use hex notation and not get stupid errors
-   * about precision.
+   * Helper to construct a byte array from a bunch of bytes. The inputs are actually ints so that I
+   * can use hex notation and not get stupid errors about precision.
    */
   private byte[] bytes(int... bytesAsInts) {
     byte[] bytes = new byte[bytesAsInts.length];
@@ -65,19 +100,14 @@ public class CodedInputStreamTest extends TestCase {
   }
 
   /**
-   * An InputStream which limits the number of bytes it reads at a time.
-   * We use this to make sure that CodedInputStream doesn't screw up when
-   * reading in small blocks.
+   * An InputStream which limits the number of bytes it reads at a time. We use this to make sure
+   * that CodedInputStream doesn't screw up when reading in small blocks.
    */
   private static final class SmallBlockInputStream extends FilterInputStream {
     private final int blockSize;
 
     public SmallBlockInputStream(byte[] data, int blockSize) {
-      this(new ByteArrayInputStream(data), blockSize);
-    }
-
-    public SmallBlockInputStream(InputStream in, int blockSize) {
-      super(in);
+      super(new ByteArrayInputStream(data));
       this.blockSize = blockSize;
     }
 
@@ -92,54 +122,36 @@ public class CodedInputStreamTest extends TestCase {
     }
   }
 
-  private void assertDataConsumed(byte[] data, CodedInputStream input)
+  private void assertDataConsumed(String msg, byte[] data, CodedInputStream input)
       throws IOException {
-    assertEquals(data.length, input.getTotalBytesRead());
-    assertTrue(input.isAtEnd());
+    assertEquals(msg, data.length, input.getTotalBytesRead());
+    assertTrue(msg, input.isAtEnd());
   }
 
   /**
-   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
-   * checks that the result matches the given value.
+   * Parses the given bytes using readRawVarint32() and readRawVarint64() and checks that the result
+   * matches the given value.
    */
   private void assertReadVarint(byte[] data, long value) throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals((int) value, input.readRawVarint32());
-    assertDataConsumed(data, input);
-
-    input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawVarint64());
-    assertDataConsumed(data, input);
-
-    input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawVarint64SlowPath());
-    assertDataConsumed(data, input);
-
-    input = CodedInputStream.newInstance(data);
-    assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
-    assertDataConsumed(data, input);
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals((int) value, input.readRawVarint32());
-      assertDataConsumed(data, input);
-
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawVarint64());
-      assertDataConsumed(data, input);
-
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawVarint64SlowPath());
-      assertDataConsumed(data, input);
-
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
-      assertDataConsumed(data, input);
+    for (InputType inputType : InputType.values()) {
+      // Try different block sizes.
+      for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+        CodedInputStream input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), (int) value, input.readRawVarint32());
+        assertDataConsumed(inputType.name(), data, input);
+
+        input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), value, input.readRawVarint64());
+        assertDataConsumed(inputType.name(), data, input);
+
+        input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), value, input.readRawVarint64SlowPath());
+        assertDataConsumed(inputType.name(), data, input);
+
+        input = inputType.newDecoder(data, blockSize);
+        assertTrue(inputType.name(), input.skipField(WireFormat.WIRETYPE_VARINT));
+        assertDataConsumed(inputType.name(), data, input);
+      }
     }
 
     // Try reading direct from an InputStream.  We want to verify that it
@@ -153,35 +165,26 @@ public class CodedInputStreamTest extends TestCase {
   }
 
   /**
-   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
-   * expects them to fail with an InvalidProtocolBufferException whose
-   * description matches the given one.
+   * Parses the given bytes using readRawVarint32() and readRawVarint64() and expects them to fail
+   * with an InvalidProtocolBufferException whose description matches the given one.
    */
-  private void assertReadVarintFailure(
-      InvalidProtocolBufferException expected, byte[] data)
+  private void assertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data)
       throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    try {
-      input.readRawVarint32();
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
-    }
-
-    input = CodedInputStream.newInstance(data);
-    try {
-      input.readRawVarint64();
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
-    }
-
-    input = CodedInputStream.newInstance(data);
-    try {
-      input.readRawVarint64SlowPath();
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
+    for (InputType inputType : InputType.values()) {
+      try {
+        CodedInputStream input = inputType.newDecoder(data);
+        input.readRawVarint32();
+        fail(inputType.name() + ": Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+        assertEquals(inputType.name(), expected.getMessage(), e.getMessage());
+      }
+      try {
+        CodedInputStream input = inputType.newDecoder(data);
+        input.readRawVarint64();
+        fail(inputType.name() + ": Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+        assertEquals(inputType.name(), expected.getMessage(), e.getMessage());
+      }
     }
 
     // Make sure we get the same error when reading direct from an InputStream.
@@ -201,72 +204,74 @@ public class CodedInputStreamTest extends TestCase {
     // 14882
     assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
     // 2961488830
-    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x0bL << 28));
+    assertReadVarint(
+        bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+        (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x0bL << 28));
 
     // 64-bit
     // 7256456126
-    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x1bL << 28));
+    assertReadVarint(
+        bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+        (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x1bL << 28));
     // 41256202580718336
     assertReadVarint(
-      bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
-      (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
-      (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+        bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+        (0x00 << 0)
+            | (0x66 << 7)
+            | (0x6b << 14)
+            | (0x1c << 21)
+            | (0x43L << 28)
+            | (0x49L << 35)
+            | (0x24L << 42)
+            | (0x49L << 49));
     // 11964378330978735131
     assertReadVarint(
-      bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
-      (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
-      (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
-      (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+        bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+        (0x1b << 0)
+            | (0x28 << 7)
+            | (0x79 << 14)
+            | (0x42 << 21)
+            | (0x3bL << 28)
+            | (0x56L << 35)
+            | (0x00L << 42)
+            | (0x05L << 49)
+            | (0x26L << 56)
+            | (0x01L << 63));
 
     // Failures
     assertReadVarintFailure(
-      InvalidProtocolBufferException.malformedVarint(),
-      bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-            0x00));
-    assertReadVarintFailure(
-      InvalidProtocolBufferException.truncatedMessage(),
-      bytes(0x80));
+        InvalidProtocolBufferException.malformedVarint(),
+        bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00));
+    assertReadVarintFailure(InvalidProtocolBufferException.truncatedMessage(), bytes(0x80));
   }
 
   /**
-   * Parses the given bytes using readRawLittleEndian32() and checks
-   * that the result matches the given value.
+   * Parses the given bytes using readRawLittleEndian32() and checks that the result matches the
+   * given value.
    */
-  private void assertReadLittleEndian32(byte[] data, int value)
-                                        throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawLittleEndian32());
-    assertTrue(input.isAtEnd());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawLittleEndian32());
-      assertTrue(input.isAtEnd());
+  private void assertReadLittleEndian32(byte[] data, int value) throws Exception {
+    for (InputType inputType : InputType.values()) {
+      // Try different block sizes.
+      for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+        CodedInputStream input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), value, input.readRawLittleEndian32());
+        assertTrue(inputType.name(), input.isAtEnd());
+      }
     }
   }
 
   /**
-   * Parses the given bytes using readRawLittleEndian64() and checks
-   * that the result matches the given value.
+   * Parses the given bytes using readRawLittleEndian64() and checks that the result matches the
+   * given value.
    */
-  private void assertReadLittleEndian64(byte[] data, long value)
-                                        throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawLittleEndian64());
-    assertTrue(input.isAtEnd());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawLittleEndian64());
-      assertTrue(input.isAtEnd());
+  private void assertReadLittleEndian64(byte[] data, long value) throws Exception {
+    for (InputType inputType : InputType.values()) {
+      // Try different block sizes.
+      for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+        CodedInputStream input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), value, input.readRawLittleEndian64());
+        assertTrue(inputType.name(), input.isAtEnd());
+      }
     }
   }
 
@@ -276,40 +281,32 @@ public class CodedInputStreamTest extends TestCase {
     assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
 
     assertReadLittleEndian64(
-      bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
-      0x123456789abcdef0L);
+        bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), 0x123456789abcdef0L);
     assertReadLittleEndian64(
-      bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
-      0x9abcdef012345678L);
+        bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678L);
   }
 
   /** Test decodeZigZag32() and decodeZigZag64(). */
   public void testDecodeZigZag() throws Exception {
-    assertEquals( 0, CodedInputStream.decodeZigZag32(0));
+    assertEquals(0, CodedInputStream.decodeZigZag32(0));
     assertEquals(-1, CodedInputStream.decodeZigZag32(1));
-    assertEquals( 1, CodedInputStream.decodeZigZag32(2));
+    assertEquals(1, CodedInputStream.decodeZigZag32(2));
     assertEquals(-2, CodedInputStream.decodeZigZag32(3));
     assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
     assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
     assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
     assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
 
-    assertEquals( 0, CodedInputStream.decodeZigZag64(0));
+    assertEquals(0, CodedInputStream.decodeZigZag64(0));
     assertEquals(-1, CodedInputStream.decodeZigZag64(1));
-    assertEquals( 1, CodedInputStream.decodeZigZag64(2));
+    assertEquals(1, CodedInputStream.decodeZigZag64(2));
     assertEquals(-2, CodedInputStream.decodeZigZag64(3));
-    assertEquals(0x000000003FFFFFFFL,
-                 CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
-    assertEquals(0xFFFFFFFFC0000000L,
-                 CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
-    assertEquals(0x000000007FFFFFFFL,
-                 CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
-    assertEquals(0xFFFFFFFF80000000L,
-                 CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
-    assertEquals(0x7FFFFFFFFFFFFFFFL,
-                 CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
-    assertEquals(0x8000000000000000L,
-                 CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
+    assertEquals(0x000000003FFFFFFFL, CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
+    assertEquals(0xFFFFFFFFC0000000L, CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
+    assertEquals(0x000000007FFFFFFFL, CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
+    assertEquals(0xFFFFFFFF80000000L, CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
+    assertEquals(0x7FFFFFFFFFFFFFFFL, CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
+    assertEquals(0x8000000000000000L, CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
   }
 
   /** Tests reading and parsing a whole message with every field type. */
@@ -319,14 +316,12 @@ public class CodedInputStreamTest extends TestCase {
     byte[] rawBytes = message.toByteArray();
     assertEquals(rawBytes.length, message.getSerializedSize());
 
-    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
-    TestUtil.assertAllFieldsSet(message2);
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
-      message2 = TestAllTypes.parseFrom(
-        new SmallBlockInputStream(rawBytes, blockSize));
-      TestUtil.assertAllFieldsSet(message2);
+    for (InputType inputType : InputType.values()) {
+      // Try different block sizes.
+      for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+        TestAllTypes message2 = TestAllTypes.parseFrom(inputType.newDecoder(rawBytes, blockSize));
+        TestUtil.assertAllFieldsSet(message2);
+      }
     }
   }
 
@@ -335,57 +330,65 @@ public class CodedInputStreamTest extends TestCase {
     TestAllTypes message = TestUtil.getAllSet();
     byte[] rawBytes = message.toByteArray();
 
-    // Create two parallel inputs.  Parse one as unknown fields while using
-    // skipField() to skip each field on the other.  Expect the same tags.
-    CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
-    CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
+    InputType[] inputTypes = InputType.values();
+    CodedInputStream[] inputs = new CodedInputStream[inputTypes.length];
+    for (int i = 0; i < inputs.length; ++i) {
+      inputs[i] = inputTypes[i].newDecoder(rawBytes);
+    }
     UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
 
     while (true) {
+      CodedInputStream input1 = inputs[0];
       int tag = input1.readTag();
-      assertEquals(tag, input2.readTag());
+      // Ensure that the rest match.
+      for (int i = 1; i < inputs.length; ++i) {
+        assertEquals(inputTypes[i].name(), tag, inputs[i].readTag());
+      }
       if (tag == 0) {
         break;
       }
       unknownFields.mergeFieldFrom(tag, input1);
-      input2.skipField(tag);
+      // Skip the field for the rest of the inputs.
+      for (int i = 1; i < inputs.length; ++i) {
+        inputs[i].skipField(tag);
+      }
     }
   }
 
 
   /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * exactly up to a limit, this should not break things.
+   * Test that a bug in skipRawBytes() has been fixed: if the skip skips exactly up to a limit, this
+   * should not break things.
    */
   public void testSkipRawBytesBug() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2 };
-    CodedInputStream input = CodedInputStream.newInstance(rawBytes);
-
-    int limit = input.pushLimit(1);
-    input.skipRawBytes(1);
-    input.popLimit(limit);
-    assertEquals(2, input.readRawByte());
+    byte[] rawBytes = new byte[] {1, 2};
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawBytes);
+      int limit = input.pushLimit(1);
+      input.skipRawBytes(1);
+      input.popLimit(limit);
+      assertEquals(inputType.name(), 2, input.readRawByte());
+    }
   }
 
   /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * past the end of a buffer with a limit that has been set past the end of
-   * that buffer, this should not break things.
+   * Test that a bug in skipRawBytes() has been fixed: if the skip skips past the end of a buffer
+   * with a limit that has been set past the end of that buffer, this should not break things.
    */
   public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(rawBytes, 3));
-
-    int limit = input.pushLimit(4);
-    // In order to expose the bug we need to read at least one byte to prime the
-    // buffer inside the CodedInputStream.
-    assertEquals(1, input.readRawByte());
-    // Skip to the end of the limit.
-    input.skipRawBytes(3);
-    assertTrue(input.isAtEnd());
-    input.popLimit(limit);
-    assertEquals(5, input.readRawByte());
+    byte[] rawBytes = new byte[] {1, 2, 3, 4, 5};
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawBytes);
+      int limit = input.pushLimit(4);
+      // In order to expose the bug we need to read at least one byte to prime the
+      // buffer inside the CodedInputStream.
+      assertEquals(inputType.name(), 1, input.readRawByte());
+      // Skip to the end of the limit.
+      input.skipRawBytes(3);
+      assertTrue(inputType.name(), input.isAtEnd());
+      input.popLimit(limit);
+      assertEquals(inputType.name(), 5, input.readRawByte());
+    }
   }
 
   public void testReadHugeBlob() throws Exception {
@@ -401,19 +404,22 @@ public class CodedInputStreamTest extends TestCase {
     builder.setOptionalBytes(ByteString.copyFrom(blob));
     TestAllTypes message = builder.build();
 
-    // Serialize and parse it.  Make sure to parse from an InputStream, not
-    // directly from a ByteString, so that CodedInputStream uses buffered
-    // reading.
-    TestAllTypes message2 =
-      TestAllTypes.parseFrom(message.toByteString().newInput());
-
-    assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
-
-    // Make sure all the other fields were parsed correctly.
-    TestAllTypes message3 = TestAllTypes.newBuilder(message2)
-      .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
-      .build();
-    TestUtil.assertAllFieldsSet(message3);
+    byte[] data = message.toByteArray();
+    for (InputType inputType : InputType.values()) {
+      // Serialize and parse it.  Make sure to parse from an InputStream, not
+      // directly from a ByteString, so that CodedInputStream uses buffered
+      // reading.
+      TestAllTypes message2 = TestAllTypes.parseFrom(inputType.newDecoder(data));
+
+      assertEquals(inputType.name(), message.getOptionalBytes(), message2.getOptionalBytes());
+
+      // Make sure all the other fields were parsed correctly.
+      TestAllTypes message3 =
+          TestAllTypes.newBuilder(message2)
+              .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
+              .build();
+      TestUtil.assertAllFieldsSet(message3);
+    }
   }
 
   public void testReadMaliciouslyLargeBlob() throws Exception {
@@ -423,17 +429,19 @@ public class CodedInputStreamTest extends TestCase {
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
     output.writeRawVarint32(tag);
     output.writeRawVarint32(0x7FFFFFFF);
-    output.writeRawBytes(new byte[32]);  // Pad with a few random bytes.
+    output.writeRawBytes(new byte[32]); // Pad with a few random bytes.
     output.flush();
 
-    CodedInputStream input = rawOutput.toByteString().newCodedInput();
-    assertEquals(tag, input.readTag());
-
-    try {
-      input.readBytes();
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
+    byte[] data = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(data);
+      assertEquals(tag, input.readTag());
+      try {
+        input.readBytes();
+        fail(inputType.name() + ": Should have thrown an exception!");
+      } catch (InvalidProtocolBufferException e) {
+        // success.
+      }
     }
   }
 
@@ -441,54 +449,55 @@ public class CodedInputStreamTest extends TestCase {
     if (depth == 0) {
       return TestRecursiveMessage.newBuilder().setI(5).build();
     } else {
-      return TestRecursiveMessage.newBuilder()
-        .setA(makeRecursiveMessage(depth - 1)).build();
+      return TestRecursiveMessage.newBuilder().setA(makeRecursiveMessage(depth - 1)).build();
     }
   }
 
-  private void assertMessageDepth(TestRecursiveMessage message, int depth) {
+  private void assertMessageDepth(String msg, TestRecursiveMessage message, int depth) {
     if (depth == 0) {
-      assertFalse(message.hasA());
-      assertEquals(5, message.getI());
+      assertFalse(msg, message.hasA());
+      assertEquals(msg, 5, message.getI());
     } else {
-      assertTrue(message.hasA());
-      assertMessageDepth(message.getA(), depth - 1);
+      assertTrue(msg, message.hasA());
+      assertMessageDepth(msg, message.getA(), depth - 1);
     }
   }
 
   public void testMaliciousRecursion() throws Exception {
-    ByteString data100 = makeRecursiveMessage(100).toByteString();
-    ByteString data101 = makeRecursiveMessage(101).toByteString();
+    byte[] data100 = makeRecursiveMessage(100).toByteArray();
+    byte[] data101 = makeRecursiveMessage(101).toByteArray();
 
-    assertMessageDepth(TestRecursiveMessage.parseFrom(data100), 100);
+    for (InputType inputType : InputType.values()) {
+      assertMessageDepth(
+          inputType.name(), TestRecursiveMessage.parseFrom(inputType.newDecoder(data100)), 100);
 
-    try {
-      TestRecursiveMessage.parseFrom(data101);
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
-    }
+      try {
+        TestRecursiveMessage.parseFrom(inputType.newDecoder(data101));
+        fail("Should have thrown an exception!");
+      } catch (InvalidProtocolBufferException e) {
+        // success.
+      }
 
-    CodedInputStream input = data100.newCodedInput();
-    input.setRecursionLimit(8);
-    try {
-      TestRecursiveMessage.parseFrom(input);
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
+      CodedInputStream input = inputType.newDecoder(data100);
+      input.setRecursionLimit(8);
+      try {
+        TestRecursiveMessage.parseFrom(input);
+        fail(inputType.name() + ": Should have thrown an exception!");
+      } catch (InvalidProtocolBufferException e) {
+        // success.
+      }
     }
   }
 
   private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
-      assertEquals(
-          InvalidProtocolBufferException.sizeLimitExceeded().getMessage(),
-          e.getMessage());
+    assertEquals(InvalidProtocolBufferException.sizeLimitExceeded().getMessage(), e.getMessage());
   }
 
   public void testSizeLimit() throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(
-            TestUtil.getAllSet().toByteString().newInput(), 16));
+    // NOTE: Size limit only applies to the stream-backed CIS.
+    CodedInputStream input =
+        CodedInputStream.newInstance(
+            new SmallBlockInputStream(TestUtil.getAllSet().toByteArray(), 16));
     input.setSizeLimit(16);
 
     try {
@@ -500,8 +509,9 @@ public class CodedInputStreamTest extends TestCase {
   }
 
   public void testResetSizeCounter() throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(new byte[256], 8));
+    // NOTE: Size limit only applies to the stream-backed CIS.
+    CodedInputStream input =
+        CodedInputStream.newInstance(new SmallBlockInputStream(new byte[256], 8));
     input.setSizeLimit(16);
     input.readRawBytes(16);
     assertEquals(16, input.getTotalBytesRead());
@@ -515,7 +525,7 @@ public class CodedInputStreamTest extends TestCase {
 
     input.resetSizeCounter();
     assertEquals(0, input.getTotalBytesRead());
-    input.readRawByte();  // No exception thrown.
+    input.readRawByte(); // No exception thrown.
     input.resetSizeCounter();
     assertEquals(0, input.getTotalBytesRead());
     input.readRawBytes(16);
@@ -523,7 +533,7 @@ public class CodedInputStreamTest extends TestCase {
     input.resetSizeCounter();
 
     try {
-      input.readRawBytes(17);  // Hits limit again.
+      input.readRawBytes(17); // Hits limit again.
       fail("Should have thrown an exception!");
     } catch (InvalidProtocolBufferException expected) {
       checkSizeLimitExceeded(expected);
@@ -531,12 +541,12 @@ public class CodedInputStreamTest extends TestCase {
   }
 
   public void testSizeLimitMultipleMessages() throws Exception {
+    // NOTE: Size limit only applies to the stream-backed CIS.
     byte[] bytes = new byte[256];
     for (int i = 0; i < bytes.length; i++) {
       bytes[i] = (byte) i;
     }
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(bytes, 7));
+    CodedInputStream input = CodedInputStream.newInstance(new SmallBlockInputStream(bytes, 7));
     input.setSizeLimit(16);
     for (int i = 0; i < 256 / 16; i++) {
       byte[] message = input.readRawBytes(16);
@@ -566,12 +576,13 @@ public class CodedInputStreamTest extends TestCase {
     output.writeRawBytes(bytes);
     output.flush();
 
-    CodedInputStream input =
-        CodedInputStream.newInstance(
-            new ByteArrayInputStream(rawOutput.toByteString().toByteArray()));
-    assertEquals(tag, input.readTag());
-    String text = input.readString();
-    assertEquals(lorem, text);
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawInput);
+      assertEquals(inputType.name(), tag, input.readTag());
+      String text = input.readString();
+      assertEquals(inputType.name(), lorem, text);
+    }
   }
 
   public void testReadStringRequireUtf8() throws Exception {
@@ -591,18 +602,18 @@ public class CodedInputStreamTest extends TestCase {
     output.writeRawBytes(bytes);
     output.flush();
 
-    CodedInputStream input =
-        CodedInputStream.newInstance(
-            new ByteArrayInputStream(rawOutput.toByteString().toByteArray()));
-    assertEquals(tag, input.readTag());
-    String text = input.readStringRequireUtf8();
-    assertEquals(lorem, text);
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawInput);
+      assertEquals(inputType.name(), tag, input.readTag());
+      String text = input.readStringRequireUtf8();
+      assertEquals(inputType.name(), lorem, text);
+    }
   }
 
   /**
-   * Tests that if we readString invalid UTF-8 bytes, no exception
-   * is thrown.  Instead, the invalid bytes are replaced with the Unicode
-   * "replacement character" U+FFFD.
+   * Tests that if we readString invalid UTF-8 bytes, no exception is thrown. Instead, the invalid
+   * bytes are replaced with the Unicode "replacement character" U+FFFD.
    */
   public void testReadStringInvalidUtf8() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
@@ -611,18 +622,21 @@ public class CodedInputStreamTest extends TestCase {
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
     output.writeRawVarint32(tag);
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 0x80 });
+    output.writeRawBytes(new byte[] {(byte) 0x80});
     output.flush();
 
-    CodedInputStream input = rawOutput.toByteString().newCodedInput();
-    assertEquals(tag, input.readTag());
-    String text = input.readString();
-    assertEquals(0xfffd, text.charAt(0));
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawInput);
+      assertEquals(inputType.name(), tag, input.readTag());
+      String text = input.readString();
+      assertEquals(inputType.name(), 0xfffd, text.charAt(0));
+    }
   }
 
   /**
-   * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an
-   * InvalidProtocolBufferException is thrown.
+   * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an InvalidProtocolBufferException
+   * is thrown.
    */
   public void testReadStringRequireUtf8InvalidUtf8() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
@@ -631,16 +645,20 @@ public class CodedInputStreamTest extends TestCase {
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
     output.writeRawVarint32(tag);
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 0x80 });
+    output.writeRawBytes(new byte[] {(byte) 0x80});
     output.flush();
 
-    CodedInputStream input = rawOutput.toByteString().newCodedInput();
-    assertEquals(tag, input.readTag());
-    try {
-      input.readStringRequireUtf8();
-      fail("Expected invalid UTF-8 exception.");
-    } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawInput);
+      assertEquals(tag, input.readTag());
+      try {
+        input.readStringRequireUtf8();
+        fail(inputType.name() + ": Expected invalid UTF-8 exception.");
+      } catch (InvalidProtocolBufferException exception) {
+        assertEquals(
+            inputType.name(), "Protocol message had invalid UTF-8.", exception.getMessage());
+      }
     }
   }
 
@@ -660,13 +678,17 @@ public class CodedInputStreamTest extends TestCase {
   public void testInvalidTag() throws Exception {
     // Any tag number which corresponds to field number zero is invalid and
     // should throw InvalidProtocolBufferException.
-    for (int i = 0; i < 8; i++) {
-      try {
-        CodedInputStream.newInstance(bytes(i)).readTag();
-        fail("Should have thrown an exception.");
-      } catch (InvalidProtocolBufferException e) {
-        assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(),
-                     e.getMessage());
+    for (InputType inputType : InputType.values()) {
+      for (int i = 0; i < 8; i++) {
+        try {
+          inputType.newDecoder(bytes(i)).readTag();
+          fail(inputType.name() + ": Should have thrown an exception.");
+        } catch (InvalidProtocolBufferException e) {
+          assertEquals(
+              inputType.name(),
+              InvalidProtocolBufferException.invalidTag().getMessage(),
+              e.getMessage());
+        }
       }
     }
   }
@@ -678,10 +700,10 @@ public class CodedInputStreamTest extends TestCase {
     output.writeRawVarint32(0);
     // One one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 23 });
+    output.writeRawBytes(new byte[] {(byte) 23});
     // Another one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 45 });
+    output.writeRawBytes(new byte[] {(byte) 45});
     // A bytes field large enough that won't fit into the 4K buffer.
     final int bytesLength = 16 * 1024;
     byte[] bytes = new byte[bytesLength];
@@ -691,20 +713,24 @@ public class CodedInputStreamTest extends TestCase {
     output.writeRawBytes(bytes);
 
     output.flush();
-    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
-
-    byte[] result = inputStream.readByteArray();
-    assertEquals(0, result.length);
-    result = inputStream.readByteArray();
-    assertEquals(1, result.length);
-    assertEquals((byte) 23, result[0]);
-    result = inputStream.readByteArray();
-    assertEquals(1, result.length);
-    assertEquals((byte) 45, result[0]);
-    result = inputStream.readByteArray();
-    assertEquals(bytesLength, result.length);
-    assertEquals((byte) 67, result[0]);
-    assertEquals((byte) 89, result[bytesLength - 1]);
+
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream inputStream = inputType.newDecoder(rawInput);
+
+      byte[] result = inputStream.readByteArray();
+      assertEquals(inputType.name(), 0, result.length);
+      result = inputStream.readByteArray();
+      assertEquals(inputType.name(), 1, result.length);
+      assertEquals(inputType.name(), (byte) 23, result[0]);
+      result = inputStream.readByteArray();
+      assertEquals(inputType.name(), 1, result.length);
+      assertEquals(inputType.name(), (byte) 45, result[0]);
+      result = inputStream.readByteArray();
+      assertEquals(inputType.name(), bytesLength, result.length);
+      assertEquals(inputType.name(), (byte) 67, result[0]);
+      assertEquals(inputType.name(), (byte) 89, result[bytesLength - 1]);
+    }
   }
 
   public void testReadByteBuffer() throws Exception {
@@ -714,10 +740,10 @@ public class CodedInputStreamTest extends TestCase {
     output.writeRawVarint32(0);
     // One one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 23});
+    output.writeRawBytes(new byte[] {(byte) 23});
     // Another one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 45});
+    output.writeRawBytes(new byte[] {(byte) 45});
     // A bytes field large enough that won't fit into the 4K buffer.
     final int bytesLength = 16 * 1024;
     byte[] bytes = new byte[bytesLength];
@@ -727,21 +753,25 @@ public class CodedInputStreamTest extends TestCase {
     output.writeRawBytes(bytes);
 
     output.flush();
-    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
-
-    ByteBuffer result = inputStream.readByteBuffer();
-    assertEquals(0, result.capacity());
-    result = inputStream.readByteBuffer();
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 23, result.get());
-    result = inputStream.readByteBuffer();
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 45, result.get());
-    result = inputStream.readByteBuffer();
-    assertEquals(bytesLength, result.capacity());
-    assertEquals((byte) 67, result.get());
-    result.position(bytesLength - 1);
-    assertEquals((byte) 89, result.get());
+
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream inputStream = inputType.newDecoder(rawInput);
+
+      ByteBuffer result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 0, result.capacity());
+      result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 23, result.get());
+      result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 45, result.get());
+      result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), bytesLength, result.capacity());
+      assertEquals(inputType.name(), (byte) 67, result.get());
+      result.position(bytesLength - 1);
+      assertEquals(inputType.name(), (byte) 89, result.get());
+    }
   }
 
   public void testReadByteBufferAliasing() throws Exception {
@@ -751,10 +781,10 @@ public class CodedInputStreamTest extends TestCase {
     output.writeRawVarint32(0);
     // One one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 23});
+    output.writeRawBytes(new byte[] {(byte) 23});
     // Another one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 45});
+    output.writeRawBytes(new byte[] {(byte) 45});
     // A bytes field large enough that won't fit into the 4K buffer.
     final int bytesLength = 16 * 1024;
     byte[] bytes = new byte[bytesLength];
@@ -763,59 +793,105 @@ public class CodedInputStreamTest extends TestCase {
     output.writeRawVarint32(bytesLength);
     output.writeRawBytes(bytes);
     output.flush();
+
     byte[] data = byteArrayStream.toByteArray();
 
-    // Without aliasing
-    CodedInputStream inputStream = CodedInputStream.newInstance(data);
-    ByteBuffer result = inputStream.readByteBuffer();
-    assertEquals(0, result.capacity());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() != data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 23, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() != data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 45, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() != data);
-    assertEquals(bytesLength, result.capacity());
-    assertEquals((byte) 67, result.get());
-    result.position(bytesLength - 1);
-    assertEquals((byte) 89, result.get());
-
-    // Enable aliasing
-    inputStream = CodedInputStream.newInstance(data);
-    inputStream.enableAliasing(true);
-    result = inputStream.readByteBuffer();
-    assertEquals(0, result.capacity());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() == data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 23, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() == data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 45, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() == data);
-    assertEquals(bytesLength, result.capacity());
-    assertEquals((byte) 67, result.get());
-    result.position(bytesLength - 1);
-    assertEquals((byte) 89, result.get());
+    for (InputType inputType : InputType.values()) {
+      if (inputType == InputType.STREAM) {
+        // Aliasing doesn't apply to stream-backed CIS.
+        continue;
+      }
+
+      // Without aliasing
+      CodedInputStream inputStream = inputType.newDecoder(data);
+      ByteBuffer result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 0, result.capacity());
+      result = inputStream.readByteBuffer();
+      assertTrue(inputType.name(), result.array() != data);
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 23, result.get());
+      result = inputStream.readByteBuffer();
+      assertTrue(inputType.name(), result.array() != data);
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 45, result.get());
+      result = inputStream.readByteBuffer();
+      assertTrue(inputType.name(), result.array() != data);
+      assertEquals(inputType.name(), bytesLength, result.capacity());
+      assertEquals(inputType.name(), (byte) 67, result.get());
+      result.position(bytesLength - 1);
+      assertEquals(inputType.name(), (byte) 89, result.get());
+
+      // Enable aliasing
+      inputStream = inputType.newDecoder(data);
+      inputStream.enableAliasing(true);
+      result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 0, result.capacity());
+      result = inputStream.readByteBuffer();
+      if (result.hasArray()) {
+        assertTrue(inputType.name(), result.array() == data);
+      }
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 23, result.get());
+      result = inputStream.readByteBuffer();
+      if (result.hasArray()) {
+        assertTrue(inputType.name(), result.array() == data);
+      }
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 45, result.get());
+      result = inputStream.readByteBuffer();
+      if (result.hasArray()) {
+        assertTrue(inputType.name(), result.array() == data);
+      }
+      assertEquals(inputType.name(), bytesLength, result.capacity());
+      assertEquals(inputType.name(), (byte) 67, result.get());
+      result.position(bytesLength - 1);
+      assertEquals(inputType.name(), (byte) 89, result.get());
+    }
   }
 
   public void testCompatibleTypes() throws Exception {
     long data = 0x100000000L;
     Int64Message message = Int64Message.newBuilder().setData(data).build();
-    ByteString serialized = message.toByteString();
+    byte[] serialized = message.toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream inputStream = inputType.newDecoder(serialized);
+
+      // Test int64(long) is compatible with bool(boolean)
+      BoolMessage msg2 = BoolMessage.parseFrom(inputStream);
+      assertTrue(msg2.getData());
+
+      // Test int64(long) is compatible with int32(int)
+      inputStream = inputType.newDecoder(serialized);
+      Int32Message msg3 = Int32Message.parseFrom(inputStream);
+      assertEquals((int) data, msg3.getData());
+    }
+  }
 
-    // Test int64(long) is compatible with bool(boolean)
-    BoolMessage msg2 = BoolMessage.parseFrom(serialized);
-    assertTrue(msg2.getData());
+  public void testSkipInvalidVarint_FastPath() throws Exception {
+    // Fast path: We have >= 10 bytes available. Ensure we properly recognize a non-ending varint.
+    byte[] data = new byte[] {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0};
+    for (InputType inputType : InputType.values()) {
+      try {
+        CodedInputStream input = inputType.newDecoder(data);
+        input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
+        fail(inputType.name() + ": Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+        // Expected
+      }
+    }
+  }
 
-    // Test int64(long) is compatible with int32(int)
-    Int32Message msg3 = Int32Message.parseFrom(serialized);
-    assertEquals((int) data, msg3.getData());
+  public void testSkipInvalidVarint_SlowPath() throws Exception {
+    // Slow path: < 10 bytes available. Ensure we properly recognize a non-ending varint.
+    byte[] data = new byte[] {-1, -1, -1, -1, -1, -1, -1, -1, -1};
+    for (InputType inputType : InputType.values()) {
+      try {
+        CodedInputStream input = inputType.newDecoder(data);
+        input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
+        fail(inputType.name() + ": Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+        // Expected
+      }
+    }
   }
 }

+ 37 - 18
java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java

@@ -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());
     }
   }
 

+ 1 - 3
java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java

@@ -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

+ 13 - 2
java/core/src/test/java/com/google/protobuf/DescriptorsTest.java

@@ -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());
+  }
 }

+ 1 - 2
java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java

@@ -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

+ 39 - 8
java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java

@@ -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()));

+ 1 - 2
java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java

@@ -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

+ 1 - 2
java/core/src/test/java/com/google/protobuf/IntArrayListTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/LazyFieldTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java

@@ -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.

+ 1 - 2
java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java

@@ -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

+ 0 - 9
java/core/src/test/java/com/google/protobuf/LiteTest.java

@@ -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);

+ 1 - 2
java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java

@@ -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()}.

+ 1 - 2
java/core/src/test/java/com/google/protobuf/LongArrayListTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java

@@ -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.

+ 8 - 2
java/core/src/test/java/com/google/protobuf/MapForProto2Test.java

@@ -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);

+ 168 - 2
java/core/src/test/java/com/google/protobuf/MapTest.java

@@ -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);

+ 1 - 3
java/core/src/test/java/com/google/protobuf/MessageTest.java

@@ -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

+ 1 - 3
java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java

@@ -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

+ 1 - 2
java/core/src/test/java/com/google/protobuf/NioByteStringTest.java

@@ -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}.

+ 3 - 5
java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java

@@ -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}

+ 1 - 3
java/core/src/test/java/com/google/protobuf/ParserTest.java

@@ -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}.

+ 1 - 2
java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java

@@ -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.

+ 4 - 4
java/core/src/test/java/com/google/protobuf/ServiceTest.java

@@ -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());
   }
 
+
+
   // =================================================================
 
   /**

+ 1 - 2
java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java

@@ -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

+ 8 - 3
java/core/src/test/java/com/google/protobuf/TestUtil.java

@@ -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)}.

+ 26 - 3
java/core/src/test/java/com/google/protobuf/TextFormatTest.java

@@ -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");
   }
 
   // =======================================================================

+ 1 - 3
java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java

@@ -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.

+ 1 - 2
java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java

@@ -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}.

+ 1 - 3
java/core/src/test/java/com/google/protobuf/WireFormatTest.java

@@ -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.

+ 0 - 1
java/core/src/test/proto/com/google/protobuf/field_presence_test.proto

@@ -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 {

+ 36 - 1
java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto

@@ -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;

+ 36 - 1
java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto

@@ -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
+}

+ 38 - 1
java/core/src/test/proto/com/google/protobuf/map_test.proto

@@ -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
+}

+ 0 - 1
java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto

@@ -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;

+ 1 - 1
java/pom.xml

@@ -11,7 +11,7 @@
 
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-parent</artifactId>
-  <version>3.0.2</version>
+  <version>3.1.0</version>
   <packaging>pom</packaging>
 
   <name>Protocol Buffers [Parent]</name>

+ 1 - 1
java/util/pom.xml

@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.0.2</version>
+    <version>3.1.0</version>
   </parent>
 
   <artifactId>protobuf-java-util</artifactId>

+ 116 - 66
java/util/src/main/java/com/google/protobuf/util/Durations.java

@@ -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);
   }
 }

+ 10 - 5
java/util/src/main/java/com/google/protobuf/util/JsonFormat.java

@@ -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()));
     }
 

+ 129 - 78
java/util/src/main/java/com/google/protobuf/util/Timestamps.java

@@ -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);

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff