Merge tag 'refs/tags/sync-piper' into sync-stage
diff --git a/benchmarks/README.md b/benchmarks/README.md
index 7678817..9c25c78 100644
--- a/benchmarks/README.md
+++ b/benchmarks/README.md
@@ -19,10 +19,8 @@
 benchmark tool for testing cpp. This will be automatically made during build the
 cpp benchmark.
 
-The cpp protobuf performance can be improved by linking with [tcmalloc library](
-https://gperftools.github.io/gperftools/tcmalloc.html). For using tcmalloc, you
-need to build [gpertools](https://github.com/gperftools/gperftools) to generate
-libtcmallc.so library.
+The cpp protobuf performance can be improved by linking with
+[TCMalloc](https://google.github.io/tcmalloc).
 
 ### Java
 We're using maven to build the java benchmarks, which is the same as to build
diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in
index d2ab2de..990a57f 100644
--- a/cmake/extract_includes.bat.in
+++ b/cmake/extract_includes.bat.in
@@ -58,6 +58,7 @@
 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\implicit_weak_message.h" include\google\protobuf\implicit_weak_message.h
+copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\inlined_string_field.h" include\google\protobuf\inlined_string_field.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\io_win32.h" include\google\protobuf\io\io_win32.h
@@ -87,6 +88,7 @@
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h" include\google\protobuf\repeated_field.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\service.h" include\google\protobuf\service.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.pb.h" include\google\protobuf\source_context.pb.h
+copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\string_member_robber.h" include\google\protobuf\string_member_robber.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.pb.h" include\google\protobuf\struct.pb.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\bytestream.h" include\google\protobuf\stubs\bytestream.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\callback.h" include\google\protobuf\stubs\callback.h
diff --git a/cmake/tests.cmake b/cmake/tests.cmake
index 4a54b70..225db93 100644
--- a/cmake/tests.cmake
+++ b/cmake/tests.cmake
@@ -114,6 +114,7 @@
 set(common_test_files
   ${protobuf_source_dir}/src/google/protobuf/arena_test_util.cc
   ${protobuf_source_dir}/src/google/protobuf/map_test_util.inc
+  ${protobuf_source_dir}/src/google/protobuf/reflection_tester.cc
   ${protobuf_source_dir}/src/google/protobuf/test_util.cc
   ${protobuf_source_dir}/src/google/protobuf/test_util.inc
   ${protobuf_source_dir}/src/google/protobuf/testing/file.cc
@@ -199,6 +200,7 @@
   ${protobuf_source_dir}/src/google/protobuf/util/type_resolver_util_test.cc
   ${protobuf_source_dir}/src/google/protobuf/well_known_types_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/wire_format_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/wire_format_unittest.inc
 )
 
 set(non_msvc_tests_files
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs
index 48f9b80..8a52209 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs
@@ -198,12 +198,13 @@
             "cHRpb25hbGdyb3VwGOwHIAEoCjJCLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMu",
             "cHJvdG8yLlVua25vd25Ub1Rlc3RBbGxUeXBlcy5PcHRpb25hbEdyb3VwEhYK",
             "DW9wdGlvbmFsX2Jvb2wY7gcgASgIEhcKDnJlcGVhdGVkX2ludDMyGPMHIAMo",
-            "BRoaCg1PcHRpb25hbEdyb3VwEgkKAWEYASABKAUqRgoRRm9yZWlnbkVudW1Q",
-            "cm90bzISDwoLRk9SRUlHTl9GT08QABIPCgtGT1JFSUdOX0JBUhABEg8KC0ZP",
-            "UkVJR05fQkFaEAI6SgoPZXh0ZW5zaW9uX2ludDMyEjEucHJvdG9idWZfdGVz",
-            "dF9tZXNzYWdlcy5wcm90bzIuVGVzdEFsbFR5cGVzUHJvdG8yGHggASgFQi8K",
-            "KGNvbS5nb29nbGUucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzJIAfgB",
-            "AQ=="));
+            "BRoaCg1PcHRpb25hbEdyb3VwEgkKAWEYASABKAUiFgoUTnVsbEh5cG90aGVz",
+            "aXNQcm90bzIiLwoORW51bU9ubHlQcm90bzIiHQoEQm9vbBIKCgZrRmFsc2UQ",
+            "ABIJCgVrVHJ1ZRABKkYKEUZvcmVpZ25FbnVtUHJvdG8yEg8KC0ZPUkVJR05f",
+            "Rk9PEAASDwoLRk9SRUlHTl9CQVIQARIPCgtGT1JFSUdOX0JBWhACOkoKD2V4",
+            "dGVuc2lvbl9pbnQzMhIxLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8y",
+            "LlRlc3RBbGxUeXBlc1Byb3RvMhh4IAEoBUIvCihjb20uZ29vZ2xlLnByb3Rv",
+            "YnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8ySAH4AQE="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ProtobufTestMessages.Proto2.ForeignEnumProto2), }, new pb::Extension[] { TestMessagesProto2Extensions.ExtensionInt32 }, new pbr::GeneratedClrTypeInfo[] {
@@ -213,7 +214,9 @@
             new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1.Parser, new[]{ "Str" }, null, null, new pb::Extension[] { global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1.Extensions.MessageSetExtension }, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension2), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension2.Parser, new[]{ "I" }, null, null, new pb::Extension[] { global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension2.Extensions.MessageSetExtension }, null)}),
             new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.ForeignMessageProto2), global::ProtobufTestMessages.Proto2.ForeignMessageProto2.Parser, new[]{ "C" }, null, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes), global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Parser, new[]{ "OptionalInt32", "OptionalString", "NestedMessage", "OptionalGroup", "OptionalBool", "RepeatedInt32" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Types.OptionalGroup), global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Types.OptionalGroup.Parser, new[]{ "A" }, null, null, null, null)})
+            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes), global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Parser, new[]{ "OptionalInt32", "OptionalString", "NestedMessage", "OptionalGroup", "OptionalBool", "RepeatedInt32" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Types.OptionalGroup), global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Types.OptionalGroup.Parser, new[]{ "A" }, null, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.NullHypothesisProto2), global::ProtobufTestMessages.Proto2.NullHypothesisProto2.Parser, null, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2), global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Parser, null, null, new[]{ typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Types.Bool) }, null, null)
           }));
     }
     #endregion
@@ -6981,6 +6984,323 @@
 
   }
 
+  public sealed partial class NullHypothesisProto2 : pb::IMessage<NullHypothesisProto2>
+  #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      , pb::IBufferMessage
+  #endif
+  {
+    private static readonly pb::MessageParser<NullHypothesisProto2> _parser = new pb::MessageParser<NullHypothesisProto2>(() => new NullHypothesisProto2());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pb::MessageParser<NullHypothesisProto2> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::ProtobufTestMessages.Proto2.TestMessagesProto2Reflection.Descriptor.MessageTypes[3]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public NullHypothesisProto2() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public NullHypothesisProto2(NullHypothesisProto2 other) : this() {
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public NullHypothesisProto2 Clone() {
+      return new NullHypothesisProto2(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override bool Equals(object other) {
+      return Equals(other as NullHypothesisProto2);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool Equals(NullHypothesisProto2 other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void WriteTo(pb::CodedOutputStream output) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      output.WriteRawMessage(this);
+    #else
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(ref output);
+      }
+    }
+    #endif
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public int CalculateSize() {
+      int size = 0;
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(NullHypothesisProto2 other) {
+      if (other == null) {
+        return;
+      }
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(pb::CodedInputStream input) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      input.ReadRawMessage(this);
+    #else
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+            break;
+        }
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+            break;
+        }
+      }
+    }
+    #endif
+
+  }
+
+  public sealed partial class EnumOnlyProto2 : pb::IMessage<EnumOnlyProto2>
+  #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      , pb::IBufferMessage
+  #endif
+  {
+    private static readonly pb::MessageParser<EnumOnlyProto2> _parser = new pb::MessageParser<EnumOnlyProto2>(() => new EnumOnlyProto2());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pb::MessageParser<EnumOnlyProto2> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::ProtobufTestMessages.Proto2.TestMessagesProto2Reflection.Descriptor.MessageTypes[4]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public EnumOnlyProto2() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public EnumOnlyProto2(EnumOnlyProto2 other) : this() {
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public EnumOnlyProto2 Clone() {
+      return new EnumOnlyProto2(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override bool Equals(object other) {
+      return Equals(other as EnumOnlyProto2);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool Equals(EnumOnlyProto2 other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void WriteTo(pb::CodedOutputStream output) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      output.WriteRawMessage(this);
+    #else
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(ref output);
+      }
+    }
+    #endif
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public int CalculateSize() {
+      int size = 0;
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(EnumOnlyProto2 other) {
+      if (other == null) {
+        return;
+      }
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(pb::CodedInputStream input) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      input.ReadRawMessage(this);
+    #else
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+            break;
+        }
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+            break;
+        }
+      }
+    }
+    #endif
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the EnumOnlyProto2 message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static partial class Types {
+      public enum Bool {
+        [pbr::OriginalName("kFalse")] KFalse = 0,
+        [pbr::OriginalName("kTrue")] KTrue = 1,
+      }
+
+    }
+    #endregion
+
+  }
+
   #endregion
 
 }
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.cs b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.cs
index 0e00150..71e803c 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.cs
@@ -227,16 +227,20 @@
             "A0JBUhABEgcKA0JBWhACEhAKA05FRxD///////////8BIlkKC0FsaWFzZWRF",
             "bnVtEg0KCUFMSUFTX0ZPTxAAEg0KCUFMSUFTX0JBUhABEg0KCUFMSUFTX0JB",
             "WhACEgcKA1FVWBACEgcKA3F1eBACEgcKA2JBehACGgIQAUINCgtvbmVvZl9m",
-            "aWVsZEoGCPUDEP8DIhsKDkZvcmVpZ25NZXNzYWdlEgkKAWMYASABKAUqQAoL",
-            "Rm9yZWlnbkVudW0SDwoLRk9SRUlHTl9GT08QABIPCgtGT1JFSUdOX0JBUhAB",
-            "Eg8KC0ZPUkVJR05fQkFaEAJCOAooY29tLmdvb2dsZS5wcm90b2J1Zl90ZXN0",
-            "X21lc3NhZ2VzLnByb3RvM0gB+AEBogIGUHJvdG8zYgZwcm90bzM="));
+            "aWVsZEoGCPUDEP8DIhsKDkZvcmVpZ25NZXNzYWdlEgkKAWMYASABKAUiFgoU",
+            "TnVsbEh5cG90aGVzaXNQcm90bzMiLwoORW51bU9ubHlQcm90bzMiHQoEQm9v",
+            "bBIKCgZrRmFsc2UQABIJCgVrVHJ1ZRABKkAKC0ZvcmVpZ25FbnVtEg8KC0ZP",
+            "UkVJR05fRk9PEAASDwoLRk9SRUlHTl9CQVIQARIPCgtGT1JFSUdOX0JBWhAC",
+            "QjgKKGNvbS5nb29nbGUucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzNI",
+            "AfgBAaICBlByb3RvM2IGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor, },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ProtobufTestMessages.Proto3.ForeignEnum), }, null, new pbr::GeneratedClrTypeInfo[] {
             new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto3.TestAllTypesProto3), global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Parser, new[]{ "OptionalInt32", "OptionalInt64", "OptionalUint32", "OptionalUint64", "OptionalSint32", "OptionalSint64", "OptionalFixed32", "OptionalFixed64", "OptionalSfixed32", "OptionalSfixed64", "OptionalFloat", "OptionalDouble", "OptionalBool", "OptionalString", "OptionalBytes", "OptionalNestedMessage", "OptionalForeignMessage", "OptionalNestedEnum", "OptionalForeignEnum", "OptionalAliasedEnum", "OptionalStringPiece", "OptionalCord", "RecursiveMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedStringPiece", "RepeatedCord", "PackedInt32", "PackedInt64", "PackedUint32", "PackedUint64", "PackedSint32", "PackedSint64", "PackedFixed32", "PackedFixed64", "PackedSfixed32", "PackedSfixed64", "PackedFloat", "PackedDouble", "PackedBool", "PackedNestedEnum", "UnpackedInt32", "UnpackedInt64", "UnpackedUint32", "UnpackedUint64", "UnpackedSint32", "UnpackedSint64", "UnpackedFixed32", "UnpackedFixed64", "UnpackedSfixed32", "UnpackedSfixed64", "UnpackedFloat", "UnpackedDouble", "UnpackedBool", "UnpackedNestedEnum", "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapStringBytes", "MapStringNestedMessage", "MapStringForeignMessage", "MapStringNestedEnum", "MapStringForeignEnum", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes", "OneofBool", "OneofUint64", "OneofFloat", "OneofDouble", "OneofEnum", "OneofNullValue", "OptionalBoolWrapper", "OptionalInt32Wrapper", "OptionalInt64Wrapper", "OptionalUint32Wrapper", "OptionalUint64Wrapper", "OptionalFloatWrapper", "OptionalDoubleWrapper", "OptionalStringWrapper", "OptionalBytesWrapper", "RepeatedBoolWrapper", "RepeatedInt32Wrapper", "RepeatedInt64Wrapper", "RepeatedUint32Wrapper", "RepeatedUint64Wrapper", "RepeatedFloatWrapper", "RepeatedDoubleWrapper", "RepeatedStringWrapper", "RepeatedBytesWrapper", "OptionalDuration", "OptionalTimestamp", "OptionalFieldMask", "OptionalStruct", "OptionalAny", "OptionalValue", "OptionalNullValue", "RepeatedDuration", "RepeatedTimestamp", "RepeatedFieldmask", "RepeatedStruct", "RepeatedAny", "RepeatedValue", "RepeatedListValue", "Fieldname1", "FieldName2", "FieldName3", "FieldName4", "Field0Name5", "Field0Name6", "FieldName7", "FieldName8", "FieldName9", "FieldName10", "FIELDNAME11", "FIELDName12", "FieldName13", "FieldName14", "FieldName15", "FieldName16", "FieldName17", "FieldName18" }, new[]{ "OneofField" }, new[]{ typeof(global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Types.NestedEnum), typeof(global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Types.AliasedEnum) }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Types.NestedMessage), global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Types.NestedMessage.Parser, new[]{ "A", "Corecursive" }, null, null, null, null),
             null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
-            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto3.ForeignMessage), global::ProtobufTestMessages.Proto3.ForeignMessage.Parser, new[]{ "C" }, null, null, null, null)
+            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto3.ForeignMessage), global::ProtobufTestMessages.Proto3.ForeignMessage.Parser, new[]{ "C" }, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto3.NullHypothesisProto3), global::ProtobufTestMessages.Proto3.NullHypothesisProto3.Parser, null, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto3.EnumOnlyProto3), global::ProtobufTestMessages.Proto3.EnumOnlyProto3.Parser, null, null, new[]{ typeof(global::ProtobufTestMessages.Proto3.EnumOnlyProto3.Types.Bool) }, null, null)
           }));
     }
     #endregion
@@ -5862,6 +5866,323 @@
 
   }
 
+  public sealed partial class NullHypothesisProto3 : pb::IMessage<NullHypothesisProto3>
+  #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      , pb::IBufferMessage
+  #endif
+  {
+    private static readonly pb::MessageParser<NullHypothesisProto3> _parser = new pb::MessageParser<NullHypothesisProto3>(() => new NullHypothesisProto3());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pb::MessageParser<NullHypothesisProto3> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::ProtobufTestMessages.Proto3.TestMessagesProto3Reflection.Descriptor.MessageTypes[2]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public NullHypothesisProto3() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public NullHypothesisProto3(NullHypothesisProto3 other) : this() {
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public NullHypothesisProto3 Clone() {
+      return new NullHypothesisProto3(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override bool Equals(object other) {
+      return Equals(other as NullHypothesisProto3);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool Equals(NullHypothesisProto3 other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void WriteTo(pb::CodedOutputStream output) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      output.WriteRawMessage(this);
+    #else
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(ref output);
+      }
+    }
+    #endif
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public int CalculateSize() {
+      int size = 0;
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(NullHypothesisProto3 other) {
+      if (other == null) {
+        return;
+      }
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(pb::CodedInputStream input) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      input.ReadRawMessage(this);
+    #else
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+            break;
+        }
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+            break;
+        }
+      }
+    }
+    #endif
+
+  }
+
+  public sealed partial class EnumOnlyProto3 : pb::IMessage<EnumOnlyProto3>
+  #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      , pb::IBufferMessage
+  #endif
+  {
+    private static readonly pb::MessageParser<EnumOnlyProto3> _parser = new pb::MessageParser<EnumOnlyProto3>(() => new EnumOnlyProto3());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pb::MessageParser<EnumOnlyProto3> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::ProtobufTestMessages.Proto3.TestMessagesProto3Reflection.Descriptor.MessageTypes[3]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public EnumOnlyProto3() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public EnumOnlyProto3(EnumOnlyProto3 other) : this() {
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public EnumOnlyProto3 Clone() {
+      return new EnumOnlyProto3(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override bool Equals(object other) {
+      return Equals(other as EnumOnlyProto3);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool Equals(EnumOnlyProto3 other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void WriteTo(pb::CodedOutputStream output) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      output.WriteRawMessage(this);
+    #else
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(ref output);
+      }
+    }
+    #endif
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public int CalculateSize() {
+      int size = 0;
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(EnumOnlyProto3 other) {
+      if (other == null) {
+        return;
+      }
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(pb::CodedInputStream input) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      input.ReadRawMessage(this);
+    #else
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+            break;
+        }
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+            break;
+        }
+      }
+    }
+    #endif
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the EnumOnlyProto3 message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static partial class Types {
+      public enum Bool {
+        [pbr::OriginalName("kFalse")] KFalse = 0,
+        [pbr::OriginalName("kTrue")] KTrue = 1,
+      }
+
+    }
+    #endregion
+
+  }
+
   #endregion
 
 }
diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb
index 42ecd3a..caf5164 100644
--- a/csharp/src/Google.Protobuf.Test/testprotos.pb
+++ b/csharp/src/Google.Protobuf.Test/testprotos.pb
Binary files differ
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
index 1060c5a..8717f9e 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -61,14 +61,14 @@
  */
 public abstract class CodedInputStream {
   private static final int DEFAULT_BUFFER_SIZE = 4096;
-  private static final int DEFAULT_RECURSION_LIMIT = 100;
   // Integer.MAX_VALUE == 0x7FFFFFF == INT_MAX from limits.h
   private static final int DEFAULT_SIZE_LIMIT = Integer.MAX_VALUE;
+  private static volatile int defaultRecursionLimit = 100;
 
   /** Visible for subclasses. See setRecursionLimit() */
   int recursionDepth;
 
-  int recursionLimit = DEFAULT_RECURSION_LIMIT;
+  int recursionLimit = defaultRecursionLimit;
 
   /** Visible for subclasses. See setSizeLimit() */
   int sizeLimit = DEFAULT_SIZE_LIMIT;
@@ -195,6 +195,11 @@
     return newInstance(buffer, 0, buffer.length, true);
   }
 
+  public void checkRecursionLimit() throws InvalidProtocolBufferException {
+    if (recursionDepth >= recursionLimit) {
+      throw InvalidProtocolBufferException.recursionLimitExceeded();
+    }
+  }
   /** Disable construction/inheritance outside of this class. */
   private CodedInputStream() {}
 
@@ -827,9 +832,7 @@
         final MessageLite.Builder builder,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       ++recursionDepth;
       builder.mergeFrom(this, extensionRegistry);
       checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
@@ -843,9 +846,7 @@
         final Parser<T> parser,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       ++recursionDepth;
       T result = parser.parsePartialFrom(this, extensionRegistry);
       checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
@@ -865,9 +866,7 @@
         final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
         throws IOException {
       final int length = readRawVarint32();
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       final int oldLimit = pushLimit(length);
       ++recursionDepth;
       builder.mergeFrom(this, extensionRegistry);
@@ -884,9 +883,7 @@
     public <T extends MessageLite> T readMessage(
         final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException {
       int length = readRawVarint32();
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       final int oldLimit = pushLimit(length);
       ++recursionDepth;
       T result = parser.parsePartialFrom(this, extensionRegistry);
@@ -1555,9 +1552,7 @@
         final MessageLite.Builder builder,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       ++recursionDepth;
       builder.mergeFrom(this, extensionRegistry);
       checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
@@ -1571,9 +1566,7 @@
         final Parser<T> parser,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       ++recursionDepth;
       T result = parser.parsePartialFrom(this, extensionRegistry);
       checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
@@ -1593,9 +1586,7 @@
         final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
         throws IOException {
       final int length = readRawVarint32();
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       final int oldLimit = pushLimit(length);
       ++recursionDepth;
       builder.mergeFrom(this, extensionRegistry);
@@ -1612,9 +1603,7 @@
     public <T extends MessageLite> T readMessage(
         final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException {
       int length = readRawVarint32();
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       final int oldLimit = pushLimit(length);
       ++recursionDepth;
       T result = parser.parsePartialFrom(this, extensionRegistry);
@@ -2358,9 +2347,7 @@
         final MessageLite.Builder builder,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       ++recursionDepth;
       builder.mergeFrom(this, extensionRegistry);
       checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
@@ -2374,9 +2361,7 @@
         final Parser<T> parser,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       ++recursionDepth;
       T result = parser.parsePartialFrom(this, extensionRegistry);
       checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
@@ -2396,9 +2381,7 @@
         final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
         throws IOException {
       final int length = readRawVarint32();
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       final int oldLimit = pushLimit(length);
       ++recursionDepth;
       builder.mergeFrom(this, extensionRegistry);
@@ -2415,9 +2398,7 @@
     public <T extends MessageLite> T readMessage(
         final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException {
       int length = readRawVarint32();
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       final int oldLimit = pushLimit(length);
       ++recursionDepth;
       T result = parser.parsePartialFrom(this, extensionRegistry);
@@ -3461,9 +3442,7 @@
         final MessageLite.Builder builder,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       ++recursionDepth;
       builder.mergeFrom(this, extensionRegistry);
       checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
@@ -3477,9 +3456,7 @@
         final Parser<T> parser,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       ++recursionDepth;
       T result = parser.parsePartialFrom(this, extensionRegistry);
       checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
@@ -3499,9 +3476,7 @@
         final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
         throws IOException {
       final int length = readRawVarint32();
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       final int oldLimit = pushLimit(length);
       ++recursionDepth;
       builder.mergeFrom(this, extensionRegistry);
@@ -3518,9 +3493,7 @@
     public <T extends MessageLite> T readMessage(
         final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException {
       int length = readRawVarint32();
-      if (recursionDepth >= recursionLimit) {
-        throw InvalidProtocolBufferException.recursionLimitExceeded();
-      }
+      checkRecursionLimit();
       final int oldLimit = pushLimit(length);
       ++recursionDepth;
       T result = parser.parsePartialFrom(this, extensionRegistry);
diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
index e56a18e..7b14584 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -1309,11 +1309,14 @@
       SINT32(JavaType.INT),
       SINT64(JavaType.LONG);
 
-      Type(final JavaType javaType) {
+      // Private copy to avoid repeated allocations from calls to values() in valueOf().
+      private static final Type[] types = values();
+
+      Type(JavaType javaType) {
         this.javaType = javaType;
       }
 
-      private JavaType javaType;
+      private final JavaType javaType;
 
       public FieldDescriptorProto.Type toProto() {
         return FieldDescriptorProto.Type.forNumber(ordinal() + 1);
@@ -1324,13 +1327,13 @@
       }
 
       public static Type valueOf(final FieldDescriptorProto.Type type) {
-        return values()[type.getNumber() - 1];
+        return types[type.getNumber() - 1];
       }
     }
 
     static {
       // Refuse to init if someone added a new declared type.
-      if (Type.values().length != FieldDescriptorProto.Type.values().length) {
+      if (Type.types.length != FieldDescriptorProto.Type.values().length) {
         throw new RuntimeException(
             "descriptor.proto has a new declared type but Descriptors.java wasn't updated.");
       }
diff --git a/java/core/src/main/java/com/google/protobuf/LazyField.java b/java/core/src/main/java/com/google/protobuf/LazyField.java
index 891171d..035ea60 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyField.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyField.java
@@ -35,10 +35,10 @@
 
 /**
  * LazyField encapsulates the logic of lazily parsing message fields. It stores the message in a
- * ByteString initially and then parse it on-demand.
+ * ByteString initially and then parses it on-demand.
  *
- * <p>Most of key methods are implemented in {@link LazyFieldLite} but this class can contain
- * default instance of the message to provide {@code hashCode()}, {@code euqals()} and {@code
+ * <p>Most methods are implemented in {@link LazyFieldLite} but this class can contain a
+ * default instance of the message to provide {@code hashCode()}, {@code equals()}, and {@code
  * toString()}.
  *
  * @author [email protected] (Xiang Li)
@@ -46,7 +46,7 @@
 public class LazyField extends LazyFieldLite {
 
   /**
-   * Carry a message's default instance which is used by {@code hashCode()}, {@code euqals()} and
+   * Carry a message's default instance which is used by {@code hashCode()}, {@code equals()}, and
    * {@code toString()}.
    */
   private final MessageLite defaultInstance;
diff --git a/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java b/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
index d66f5c4..1735a08 100644
--- a/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
+++ b/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
@@ -181,32 +181,8 @@
     this.defaultInstance = defaultInstance;
     this.info = info;
     this.objects = objects;
-    int value;
-    try {
-      value = (int) info.charAt(0);
-    } catch (StringIndexOutOfBoundsException e) {
-      // This is a fix for issues
-      // that error out on a subset of phones on charAt(0) with an index out of bounds exception.
-      char[] infoChars = info.toCharArray();
-      info = new String(infoChars);
-      try {
-        value = (int) info.charAt(0);
-      } catch (StringIndexOutOfBoundsException e2) {
-        try {
-          char[] infoChars2 = new char[info.length()];
-          info.getChars(0, info.length(), infoChars2, 0);
-          info = new String(infoChars2);
-          value = (int) info.charAt(0);
-        } catch (StringIndexOutOfBoundsException | ArrayIndexOutOfBoundsException e3) {
-          throw new IllegalStateException(
-              String.format(
-                  "Failed parsing '%s' with charArray.length of %d", info, infoChars.length),
-              e3);
-        }
-      }
-    }
-    int position = 1;
-
+    int position = 0;
+    int value = (int) info.charAt(position++);
     if (value < 0xD800) {
       flags = value;
     } else {
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
index 4bc8d10..5588b06 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
 import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
 
@@ -44,14 +46,13 @@
 import protobuf_unittest.UnittestProto.TestRequiredForeign;
 import protobuf_unittest.UnittestProto.TestUnpackedTypes;
 import java.util.Map;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Unit test for {@link AbstractMessage}.
- *
- * @author [email protected] Kenton Varda
- */
-public class AbstractMessageTest extends TestCase {
+/** Unit test for {@link AbstractMessage}. */
+@RunWith(JUnit4.class)
+public class AbstractMessageTest {
   /**
    * Extends AbstractMessage and wraps some other message object. The methods of the Message
    * interface which aren't explicitly implemented by AbstractMessage are forwarded to the wrapped
@@ -238,6 +239,7 @@
       new TestUtil.ReflectionTester(
           TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry());
 
+  @Test
   public void testClear() throws Exception {
     AbstractMessageWrapper message =
         new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder(TestUtil.getAllSet()))
@@ -246,6 +248,7 @@
     TestUtil.assertClear((TestAllTypes) message.wrappedMessage);
   }
 
+  @Test
   public void testCopy() throws Exception {
     AbstractMessageWrapper message =
         new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
@@ -254,28 +257,35 @@
     TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
   }
 
+  @Test
   public void testSerializedSize() throws Exception {
     TestAllTypes message = TestUtil.getAllSet();
     Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
-
-    assertEquals(message.getSerializedSize(), abstractMessage.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(abstractMessage.getSerializedSize());
   }
 
+  @Test
   public void testSerialization() throws Exception {
     Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
-
-    TestUtil.assertAllFieldsSet(TestAllTypes.parseFrom(abstractMessage.toByteString()));
-
-    assertEquals(TestUtil.getAllSet().toByteString(), abstractMessage.toByteString());
+    TestUtil.assertAllFieldsSet(
+        TestAllTypes.parseFrom(
+            abstractMessage.toByteString(), ExtensionRegistryLite.getEmptyRegistry()));
+    assertThat(TestUtil.getAllSet().toByteString()).isEqualTo(abstractMessage.toByteString());
   }
 
+  @Test
   public void testParsing() throws Exception {
     AbstractMessageWrapper.Builder builder =
         new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
-    AbstractMessageWrapper message = builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
+    AbstractMessageWrapper message =
+        builder
+            .mergeFrom(
+                TestUtil.getAllSet().toByteString(), ExtensionRegistryLite.getEmptyRegistry())
+            .build();
     TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
   }
 
+  @Test
   public void testParsingUninitialized() throws Exception {
     TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
     builder.getOptionalMessageBuilder().setDummy2(10);
@@ -283,10 +293,13 @@
     Message.Builder abstractMessageBuilder =
         new AbstractMessageWrapper.Builder(TestRequiredForeign.newBuilder());
     // mergeFrom() should not throw initialization error.
-    Message unused1 = abstractMessageBuilder.mergeFrom(bytes).buildPartial();
+    Message unused1 =
+        abstractMessageBuilder
+            .mergeFrom(bytes, ExtensionRegistryLite.getEmptyRegistry())
+            .buildPartial();
     try {
-      abstractMessageBuilder.mergeFrom(bytes).build();
-      fail();
+      abstractMessageBuilder.mergeFrom(bytes, ExtensionRegistryLite.getEmptyRegistry()).build();
+      assertWithMessage("shouldn't pass").fail();
     } catch (UninitializedMessageException ex) {
       // pass
     }
@@ -295,115 +308,140 @@
     Message.Builder dynamicMessageBuilder =
         DynamicMessage.newBuilder(TestRequiredForeign.getDescriptor());
     // mergeFrom() should not throw initialization error.
-    Message unused2 = dynamicMessageBuilder.mergeFrom(bytes).buildPartial();
+    Message unused2 =
+        dynamicMessageBuilder
+            .mergeFrom(bytes, ExtensionRegistryLite.getEmptyRegistry())
+            .buildPartial();
     try {
-      dynamicMessageBuilder.mergeFrom(bytes).build();
-      fail();
+      dynamicMessageBuilder.mergeFrom(bytes, ExtensionRegistryLite.getEmptyRegistry()).build();
+      assertWithMessage("shouldn't pass").fail();
     } catch (UninitializedMessageException ex) {
       // pass
     }
   }
 
+  @Test
   public void testPackedSerialization() throws Exception {
     Message abstractMessage = new AbstractMessageWrapper(TestUtil.getPackedSet());
-
-    TestUtil.assertPackedFieldsSet(TestPackedTypes.parseFrom(abstractMessage.toByteString()));
-
-    assertEquals(TestUtil.getPackedSet().toByteString(), abstractMessage.toByteString());
+    TestUtil.assertPackedFieldsSet(
+        TestPackedTypes.parseFrom(
+            abstractMessage.toByteString(), ExtensionRegistryLite.getEmptyRegistry()));
+    assertThat(TestUtil.getPackedSet().toByteString()).isEqualTo(abstractMessage.toByteString());
   }
 
+  @Test
   public void testPackedParsing() throws Exception {
     AbstractMessageWrapper.Builder builder =
         new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
     AbstractMessageWrapper message =
-        builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
+        builder
+            .mergeFrom(
+                TestUtil.getPackedSet().toByteString(), ExtensionRegistryLite.getEmptyRegistry())
+            .build();
     TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
   }
 
+  @Test
   public void testUnpackedSerialization() throws Exception {
     Message abstractMessage = new AbstractMessageWrapper(TestUtil.getUnpackedSet());
-
-    TestUtil.assertUnpackedFieldsSet(TestUnpackedTypes.parseFrom(abstractMessage.toByteString()));
-
-    assertEquals(TestUtil.getUnpackedSet().toByteString(), abstractMessage.toByteString());
+    TestUtil.assertUnpackedFieldsSet(
+        TestUnpackedTypes.parseFrom(
+            abstractMessage.toByteString(), ExtensionRegistryLite.getEmptyRegistry()));
+    assertThat(TestUtil.getUnpackedSet().toByteString()).isEqualTo(abstractMessage.toByteString());
   }
 
+  @Test
   public void testParsePackedToUnpacked() throws Exception {
     AbstractMessageWrapper.Builder builder =
         new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
     AbstractMessageWrapper message =
-        builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
+        builder
+            .mergeFrom(
+                TestUtil.getPackedSet().toByteString(), ExtensionRegistryLite.getEmptyRegistry())
+            .build();
     TestUtil.assertUnpackedFieldsSet((TestUnpackedTypes) message.wrappedMessage);
   }
 
+  @Test
   public void testParseUnpackedToPacked() throws Exception {
     AbstractMessageWrapper.Builder builder =
         new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
     AbstractMessageWrapper message =
-        builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
+        builder
+            .mergeFrom(
+                TestUtil.getUnpackedSet().toByteString(), ExtensionRegistryLite.getEmptyRegistry())
+            .build();
     TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
   }
 
+  @Test
   public void testUnpackedParsing() throws Exception {
     AbstractMessageWrapper.Builder builder =
         new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
     AbstractMessageWrapper message =
-        builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
+        builder
+            .mergeFrom(
+                TestUtil.getUnpackedSet().toByteString(), ExtensionRegistryLite.getEmptyRegistry())
+            .build();
     TestUtil.assertUnpackedFieldsSet((TestUnpackedTypes) message.wrappedMessage);
   }
 
+  @Test
   public void testOptimizedForSize() throws Exception {
     // We're mostly only checking that this class was compiled successfully.
     TestOptimizedForSize message = TestOptimizedForSize.newBuilder().setI(1).build();
-    message = TestOptimizedForSize.parseFrom(message.toByteString());
-    assertEquals(2, message.getSerializedSize());
+    message =
+        TestOptimizedForSize.parseFrom(
+            message.toByteString(), ExtensionRegistryLite.getEmptyRegistry());
+    assertThat(message.getSerializedSize()).isEqualTo(2);
   }
 
   // -----------------------------------------------------------------
   // Tests for isInitialized().
 
+  @Test
   public void testIsInitialized() throws Exception {
     TestRequired.Builder builder = TestRequired.newBuilder();
     AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
 
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals("a, b, c", abstractBuilder.getInitializationErrorString());
+    assertThat(abstractBuilder.isInitialized()).isFalse();
+    assertThat(abstractBuilder.getInitializationErrorString()).isEqualTo("a, b, c");
     builder.setA(1);
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals("b, c", abstractBuilder.getInitializationErrorString());
+    assertThat(abstractBuilder.isInitialized()).isFalse();
+    assertThat(abstractBuilder.getInitializationErrorString()).isEqualTo("b, c");
     builder.setB(1);
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals("c", abstractBuilder.getInitializationErrorString());
+    assertThat(abstractBuilder.isInitialized()).isFalse();
+    assertThat(abstractBuilder.getInitializationErrorString()).isEqualTo("c");
     builder.setC(1);
-    assertTrue(abstractBuilder.isInitialized());
-    assertEquals("", abstractBuilder.getInitializationErrorString());
+    assertThat(abstractBuilder.isInitialized()).isTrue();
+    assertThat(abstractBuilder.getInitializationErrorString()).isEmpty();
   }
 
+  @Test
   public void testForeignIsInitialized() throws Exception {
     TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
     AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
 
-    assertTrue(abstractBuilder.isInitialized());
-    assertEquals("", abstractBuilder.getInitializationErrorString());
+    assertThat(abstractBuilder.isInitialized()).isTrue();
+    assertThat(abstractBuilder.getInitializationErrorString()).isEmpty();
 
     builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals(
-        "optional_message.b, optional_message.c", abstractBuilder.getInitializationErrorString());
+    assertThat(abstractBuilder.isInitialized()).isFalse();
+    assertThat(abstractBuilder.getInitializationErrorString())
+        .isEqualTo("optional_message.b, optional_message.c");
 
     builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
-    assertTrue(abstractBuilder.isInitialized());
-    assertEquals("", abstractBuilder.getInitializationErrorString());
+    assertThat(abstractBuilder.isInitialized()).isTrue();
+    assertThat(abstractBuilder.getInitializationErrorString()).isEmpty();
 
     builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals(
-        "repeated_message[0].b, repeated_message[0].c",
-        abstractBuilder.getInitializationErrorString());
+    assertThat(abstractBuilder.isInitialized()).isFalse();
+    assertThat(abstractBuilder.getInitializationErrorString())
+        .isEqualTo("repeated_message[0].b, repeated_message[0].c");
 
     builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
-    assertTrue(abstractBuilder.isInitialized());
-    assertEquals("", abstractBuilder.getInitializationErrorString());
+    assertThat(abstractBuilder.isInitialized()).isTrue();
+    assertThat(abstractBuilder.getInitializationErrorString()).isEmpty();
   }
 
   // -----------------------------------------------------------------
@@ -436,21 +474,23 @@
           + "repeated_string: \"qux\"\n"
           + "repeated_string: \"bar\"\n";
 
+  @Test
   public void testMergeFrom() throws Exception {
     AbstractMessageWrapper result =
         new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder(MERGE_DEST))
             .mergeFrom(MERGE_SOURCE)
             .build();
 
-    assertEquals(MERGE_RESULT_TEXT, result.toString());
+    assertThat(result.toString()).isEqualTo(MERGE_RESULT_TEXT);
   }
 
   // -----------------------------------------------------------------
   // Tests for equals and hashCode
 
+  @Test
   public void testEqualsAndHashCode() throws Exception {
     TestAllTypes a = TestUtil.getAllSet();
-    TestAllTypes b = TestAllTypes.newBuilder().build();
+    TestAllTypes b = TestAllTypes.getDefaultInstance();
     TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build();
     TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build();
     TestAllExtensions e = TestUtil.getAllExtensionsSet();
@@ -489,23 +529,26 @@
     // Deserializing into the TestEmptyMessage such that every field
     // is an {@link UnknownFieldSet.Field}.
     UnittestProto.TestEmptyMessage eUnknownFields =
-        UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
+        UnittestProto.TestEmptyMessage.parseFrom(
+            e.toByteArray(), ExtensionRegistryLite.getEmptyRegistry());
     UnittestProto.TestEmptyMessage fUnknownFields =
-        UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray());
+        UnittestProto.TestEmptyMessage.parseFrom(
+            f.toByteArray(), ExtensionRegistryLite.getEmptyRegistry());
     checkNotEqual(eUnknownFields, fUnknownFields);
     checkEqualsIsConsistent(eUnknownFields);
     checkEqualsIsConsistent(fUnknownFields);
 
     // Subsequent reconstitutions should be identical
     UnittestProto.TestEmptyMessage eUnknownFields2 =
-        UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
+        UnittestProto.TestEmptyMessage.parseFrom(
+            e.toByteArray(), ExtensionRegistryLite.getEmptyRegistry());
     checkEqualsIsConsistent(eUnknownFields, eUnknownFields2);
   }
 
   /** Asserts that the given proto has symmetric equals and hashCode methods. */
   private void checkEqualsIsConsistent(Message message) {
-    // Object should be equal to itself.
-    assertEquals(message, message);
+    // Test equals explicitly.
+    assertThat(message.equals(message)).isTrue();
 
     // Object should be equal to a dynamic copy of itself.
     DynamicMessage dynamic = DynamicMessage.newBuilder(message).build();
@@ -514,9 +557,9 @@
 
   /** Asserts that the given protos are equal and have the same hash code. */
   private void checkEqualsIsConsistent(Message message1, Message message2) {
-    assertEquals(message1, message2);
-    assertEquals(message2, message1);
-    assertEquals(message2.hashCode(), message1.hashCode());
+    assertThat(message1).isEqualTo(message2);
+    assertThat(message2).isEqualTo(message1);
+    assertThat(message2.hashCode()).isEqualTo(message1.hashCode());
   }
 
   /**
@@ -527,28 +570,33 @@
    */
   private void checkNotEqual(Message m1, Message m2) {
     String equalsError = String.format("%s should not be equal to %s", m1, m2);
-    assertFalse(equalsError, m1.equals(m2));
-    assertFalse(equalsError, m2.equals(m1));
+    assertWithMessage(equalsError).that(m1.equals(m2)).isFalse();
+    assertWithMessage(equalsError).that(m2.equals(m1)).isFalse();
 
-    assertFalse(
-        String.format("%s should have a different hash code from %s", m1, m2),
-        m1.hashCode() == m2.hashCode());
+    assertWithMessage(String.format("%s should have a different hash code from %s", m1, m2))
+        .that(m1.hashCode())
+        .isNotEqualTo(m2.hashCode());
   }
 
+  @Test
   public void testCheckByteStringIsUtf8OnUtf8() {
     ByteString byteString = ByteString.copyFromUtf8("some text");
     AbstractMessageLite.checkByteStringIsUtf8(byteString);
     // No exception thrown.
   }
 
+  @Test
   public void testCheckByteStringIsUtf8OnNonUtf8() {
     ByteString byteString =
         ByteString.copyFrom(new byte[] {(byte) 0x80}); // A lone continuation byte.
     try {
       AbstractMessageLite.checkByteStringIsUtf8(byteString);
-      fail("Expected AbstractMessageLite.checkByteStringIsUtf8 to throw IllegalArgumentException");
+      assertWithMessage(
+              "Expected AbstractMessageLite.checkByteStringIsUtf8 to throw"
+                  + " IllegalArgumentException")
+          .fail();
     } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Byte string is not UTF-8.");
     }
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractProto2LiteSchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractProto2LiteSchemaTest.java
index 5d3fd3b..7eb0ace 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractProto2LiteSchemaTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractProto2LiteSchemaTest.java
@@ -30,9 +30,8 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import com.google.protobuf.testing.Proto2TestingLite.Proto2EmptyLite;
 import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite;
@@ -73,8 +72,8 @@
 
     Proto2MessageLite merged =
         ExperimentalSerializationUtil.fromByteArray(data, Proto2MessageLite.class);
-    assertEquals(789, merged.getFieldMessage10().getFieldInt643());
-    assertEquals(456, merged.getFieldMessage10().getFieldInt325());
+    assertThat(merged.getFieldMessage10().getFieldInt643()).isEqualTo(789);
+    assertThat(merged.getFieldMessage10().getFieldInt325()).isEqualTo(456);
   }
 
   @Test
@@ -133,7 +132,7 @@
     byte[] roundtripBytes = ExperimentalSerializationUtil.toByteArray(empty);
     Proto2MessageLite roundtripMessage =
         ExperimentalSerializationUtil.fromByteArray(roundtripBytes, Proto2MessageLite.class);
-    assertEquals(expectedMessage, roundtripMessage);
+    assertThat(roundtripMessage).isEqualTo(expectedMessage);
   }
 
   @Test
@@ -141,7 +140,7 @@
     // Use unknown fields to hold invalid enum values.
     UnknownFieldSetLite unknowns = UnknownFieldSetLite.newInstance();
     final int outOfRange = 1000;
-    assertNull(TestEnum.forNumber(outOfRange));
+    assertThat(TestEnum.forNumber(outOfRange)).isNull();
     unknowns.storeField(
         WireFormat.makeTag(
             Proto2MessageLite.FIELD_ENUM_13_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT),
@@ -184,16 +183,18 @@
 
     Proto2MessageLite parsed =
         ExperimentalSerializationUtil.fromByteArray(output, Proto2MessageLite.class);
-    assertFalse("out-of-range singular enum should not be in message", parsed.hasFieldEnum13());
-    assertEquals(
-        "out-of-range repeated enum should not be in message", 2, parsed.getFieldEnumList30Count());
-    assertEquals(TestEnum.ONE, parsed.getFieldEnumList30(0));
-    assertEquals(TestEnum.TWO, parsed.getFieldEnumList30(1));
-    assertEquals(
-        "out-of-range packed repeated enum should not be in message",
-        2,
-        parsed.getFieldEnumListPacked44Count());
-    assertEquals(TestEnum.ONE, parsed.getFieldEnumListPacked44(0));
-    assertEquals(TestEnum.TWO, parsed.getFieldEnumListPacked44(1));
+    assertWithMessage("out-of-range singular enum should not be in message")
+        .that(parsed.hasFieldEnum13())
+        .isFalse();
+    assertWithMessage("out-of-range repeated enum should not be in message")
+        .that(parsed.getFieldEnumList30Count())
+        .isEqualTo(2);
+    assertThat(parsed.getFieldEnumList30(0)).isEqualTo(TestEnum.ONE);
+    assertThat(parsed.getFieldEnumList30(1)).isEqualTo(TestEnum.TWO);
+    assertWithMessage("out-of-range packed repeated enum should not be in message")
+        .that(parsed.getFieldEnumListPacked44Count())
+        .isEqualTo(2);
+    assertThat(parsed.getFieldEnumListPacked44(0)).isEqualTo(TestEnum.ONE);
+    assertThat(parsed.getFieldEnumListPacked44(1)).isEqualTo(TestEnum.TWO);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractProto2SchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractProto2SchemaTest.java
index 0c16818..39980a7 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractProto2SchemaTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractProto2SchemaTest.java
@@ -30,9 +30,8 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import com.google.protobuf.testing.Proto2Testing.Proto2Empty;
 import com.google.protobuf.testing.Proto2Testing.Proto2Message;
@@ -72,8 +71,8 @@
     byte[] data = output.toByteArray();
 
     Proto2Message merged = ExperimentalSerializationUtil.fromByteArray(data, Proto2Message.class);
-    assertEquals(789, merged.getFieldMessage10().getFieldInt643());
-    assertEquals(456, merged.getFieldMessage10().getFieldInt325());
+    assertThat(merged.getFieldMessage10().getFieldInt643()).isEqualTo(789);
+    assertThat(merged.getFieldMessage10().getFieldInt325()).isEqualTo(456);
   }
 
   @Test
@@ -125,10 +124,10 @@
     // Merge serialized bytes into an empty message, then reserialize and merge it to a new
     // Proto2Message. Make sure the two messages equal.
     byte[] roundtripBytes = ExperimentalSerializationUtil.toByteArray(empty);
-    assertEquals(serializedBytes.length, roundtripBytes.length);
+    assertThat(serializedBytes).hasLength(roundtripBytes.length);
     Proto2Message roundtripMessage =
         ExperimentalSerializationUtil.fromByteArray(roundtripBytes, Proto2Message.class);
-    assertEquals(expectedMessage, roundtripMessage);
+    assertThat(roundtripMessage).isEqualTo(expectedMessage);
   }
 
   @Test
@@ -136,7 +135,7 @@
     // Use unknown fields to hold invalid enum values.
     UnknownFieldSetLite unknowns = UnknownFieldSetLite.newInstance();
     final int outOfRange = 1000;
-    assertNull(TestEnum.forNumber(outOfRange));
+    assertThat(TestEnum.forNumber(outOfRange)).isNull();
     unknowns.storeField(
         WireFormat.makeTag(Proto2Message.FIELD_ENUM_13_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT),
         (long) outOfRange);
@@ -177,15 +176,17 @@
     codedOutput.flush();
 
     Proto2Message parsed = ExperimentalSerializationUtil.fromByteArray(output, Proto2Message.class);
-    assertFalse("out-of-range singular enum should not be in message", parsed.hasFieldEnum13());
+    assertWithMessage("out-of-range singular enum should not be in message")
+        .that(parsed.hasFieldEnum13())
+        .isFalse();
     {
       List<Long> singularEnum =
           parsed
               .getUnknownFields()
               .getField(Proto2Message.FIELD_ENUM_13_FIELD_NUMBER)
               .getVarintList();
-      assertEquals(1, singularEnum.size());
-      assertEquals((Long) (long) outOfRange, singularEnum.get(0));
+      assertThat(singularEnum).hasSize(1);
+      assertThat((Long) (long) outOfRange).isEqualTo(singularEnum.get(0));
     }
     {
       List<Long> repeatedEnum =
@@ -193,8 +194,8 @@
               .getUnknownFields()
               .getField(Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER)
               .getVarintList();
-      assertEquals(1, repeatedEnum.size());
-      assertEquals((Long) (long) outOfRange, repeatedEnum.get(0));
+      assertThat(repeatedEnum).hasSize(1);
+      assertThat((Long) (long) outOfRange).isEqualTo(repeatedEnum.get(0));
     }
     {
       List<Long> packedRepeatedEnum =
@@ -202,19 +203,19 @@
               .getUnknownFields()
               .getField(Proto2Message.FIELD_ENUM_LIST_PACKED_44_FIELD_NUMBER)
               .getVarintList();
-      assertEquals(1, packedRepeatedEnum.size());
-      assertEquals((Long) (long) outOfRange, packedRepeatedEnum.get(0));
+      assertThat(packedRepeatedEnum).hasSize(1);
+      assertThat((Long) (long) outOfRange).isEqualTo(packedRepeatedEnum.get(0));
     }
-    assertEquals(
-        "out-of-range repeated enum should not be in message", 2, parsed.getFieldEnumList30Count());
-    assertEquals(TestEnum.ONE, parsed.getFieldEnumList30(0));
-    assertEquals(TestEnum.TWO, parsed.getFieldEnumList30(1));
-    assertEquals(
-        "out-of-range packed repeated enum should not be in message",
-        2,
-        parsed.getFieldEnumListPacked44Count());
-    assertEquals(TestEnum.ONE, parsed.getFieldEnumListPacked44(0));
-    assertEquals(TestEnum.TWO, parsed.getFieldEnumListPacked44(1));
+    assertWithMessage("out-of-range repeated enum should not be in message")
+        .that(parsed.getFieldEnumList30Count())
+        .isEqualTo(2);
+    assertThat(parsed.getFieldEnumList30(0)).isEqualTo(TestEnum.ONE);
+    assertThat(parsed.getFieldEnumList30(1)).isEqualTo(TestEnum.TWO);
+    assertWithMessage("out-of-range packed repeated enum should not be in message")
+        .that(parsed.getFieldEnumListPacked44Count())
+        .isEqualTo(2);
+    assertThat(parsed.getFieldEnumListPacked44(0)).isEqualTo(TestEnum.ONE);
+    assertThat(parsed.getFieldEnumListPacked44(1)).isEqualTo(TestEnum.TWO);
   }
 
   @Override
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractProto3LiteSchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractProto3LiteSchemaTest.java
index 9cc04ec..ea53a17 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractProto3LiteSchemaTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractProto3LiteSchemaTest.java
@@ -30,7 +30,7 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.protobuf.testing.Proto3TestingLite.Proto3EmptyLite;
 import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLite;
@@ -94,8 +94,8 @@
 
     Proto3MessageLite merged =
         ExperimentalSerializationUtil.fromByteArray(data, Proto3MessageLite.class);
-    assertEquals(789, merged.getFieldMessage10().getFieldInt643());
-    assertEquals(456, merged.getFieldMessage10().getFieldInt325());
+    assertThat(merged.getFieldMessage10().getFieldInt643()).isEqualTo(789);
+    assertThat(merged.getFieldMessage10().getFieldInt325()).isEqualTo(456);
   }
 
   @Test
@@ -126,7 +126,7 @@
     Proto3EmptyLite empty =
         ExperimentalSerializationUtil.fromByteArray(
             expectedMessage.toByteArray(), Proto3EmptyLite.class);
-    assertEquals(expectedMessage.getSerializedSize(), empty.getSerializedSize());
+    assertThat(empty.getSerializedSize()).isEqualTo(expectedMessage.getSerializedSize());
   }
 
   @Test
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractProto3SchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractProto3SchemaTest.java
index 358f1e3..5d9883f 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractProto3SchemaTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractProto3SchemaTest.java
@@ -30,7 +30,7 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.protobuf.testing.Proto3Testing.Proto3Empty;
 import com.google.protobuf.testing.Proto3Testing.Proto3Message;
@@ -93,8 +93,8 @@
     byte[] data = output.toByteArray();
 
     Proto3Message merged = ExperimentalSerializationUtil.fromByteArray(data, Proto3Message.class);
-    assertEquals(789, merged.getFieldMessage10().getFieldInt643());
-    assertEquals(456, merged.getFieldMessage10().getFieldInt325());
+    assertThat(merged.getFieldMessage10().getFieldInt643()).isEqualTo(789);
+    assertThat(merged.getFieldMessage10().getFieldInt325()).isEqualTo(456);
   }
 
   @Test
@@ -124,8 +124,8 @@
     Proto3Empty empty =
         ExperimentalSerializationUtil.fromByteArray(
             expectedMessage.toByteArray(), Proto3Empty.class);
-    assertEquals(expectedMessage.getSerializedSize(), empty.getSerializedSize());
-    assertEquals(expectedMessage.toByteString(), empty.toByteString());
+    assertThat(empty.getSerializedSize()).isEqualTo(expectedMessage.getSerializedSize());
+    assertThat(empty.toByteString()).isEqualTo(expectedMessage.toByteString());
   }
 
   @Test
@@ -134,7 +134,7 @@
     // supported in proto3, e.g. groups.
     byte[] payload = new Proto2MessageFactory(10, 20, 2, 2).newMessage().toByteArray();
     Proto3Empty empty = ExperimentalSerializationUtil.fromByteArray(payload, Proto3Empty.class);
-    assertEquals(payload.length, empty.getSerializedSize());
+    assertThat(empty.getSerializedSize()).isEqualTo(payload.length);
   }
 
   @Test
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractSchemaTest.java b/java/core/src/test/java/com/google/protobuf/AbstractSchemaTest.java
index c69a4fd..7ca5e03 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractSchemaTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractSchemaTest.java
@@ -30,10 +30,8 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.fail;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -80,7 +78,7 @@
       T newMsg = schema.newInstance();
       try {
         schema.mergeFrom(newMsg, reader, ExtensionRegistryLite.getEmptyRegistry());
-        fail("should throw invalid ");
+        assertWithMessage("should throw invalid").fail();
       } catch (InvalidProtocolBufferException expected) {
       }
     }
@@ -106,13 +104,15 @@
         exceptionCount += 1;
       }
     }
-    assertNotEquals(0, exceptionCount);
+    assertThat(exceptionCount).isNotEqualTo(0);
   }
 
   protected static final <M extends MessageLite> void roundtrip(
       String failureMessage, M msg, Schema<M> schema) throws IOException {
     byte[] serializedBytes = ExperimentalSerializationUtil.toByteArray(msg, schema);
-    assertEquals(failureMessage, msg.getSerializedSize(), serializedBytes.length);
+    assertWithMessage(failureMessage)
+        .that(serializedBytes.length)
+        .isEqualTo(msg.getSerializedSize());
 
     // Now read it back in and verify it matches the original.
     if (Android.isOnAndroidDevice()) {
@@ -121,14 +121,14 @@
       schema.mergeFrom(
           newMsg, serializedBytes, 0, serializedBytes.length, new ArrayDecoders.Registers());
       schema.makeImmutable(newMsg);
-      assertEquals(failureMessage, msg, newMsg);
+      assertWithMessage(failureMessage).that(newMsg).isEqualTo(msg);
     }
     M newMsg = schema.newInstance();
     Reader reader = BinaryReader.newInstance(ByteBuffer.wrap(serializedBytes), true);
     schema.mergeFrom(newMsg, reader, ExtensionRegistryLite.getEmptyRegistry());
     schema.makeImmutable(newMsg);
 
-    assertEquals(failureMessage, msg, newMsg);
+    assertWithMessage(failureMessage).that(newMsg).isEqualTo(msg);
   }
 
   protected final void roundtrip(String failureMessage, T msg) throws IOException {
@@ -148,10 +148,10 @@
   public void testRequiredFields() throws Exception {
     for (T msg : newMessagesMissingRequiredFields()) {
       if (schema.isInitialized(msg)) {
-        assertEquals("", msg.toString());
+        assertThat(msg.toString()).isEmpty();
         msg = (T) msg.toBuilder().build();
       }
-      assertFalse(schema.isInitialized(msg));
+      assertThat(schema.isInitialized(msg)).isFalse();
     }
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/AnyTest.java b/java/core/src/test/java/com/google/protobuf/AnyTest.java
index d660ca7..ee13ef1 100644
--- a/java/core/src/test/java/com/google/protobuf/AnyTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AnyTest.java
@@ -30,13 +30,21 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import any_test.AnyTestProto.TestAny;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import java.util.Objects;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Unit tests for Any message. */
-public class AnyTest extends TestCase {
+@RunWith(JUnit4.class)
+public class AnyTest {
+
+  @Test
   public void testAnyGeneratedApi() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
@@ -44,8 +52,8 @@
 
     TestAny container = TestAny.newBuilder().setValue(Any.pack(message)).build();
 
-    assertTrue(container.getValue().is(TestAllTypes.class));
-    assertFalse(container.getValue().is(TestAny.class));
+    assertThat(container.getValue().is(TestAllTypes.class)).isTrue();
+    assertThat(container.getValue().is(TestAny.class)).isFalse();
 
     TestAllTypes result = container.getValue().unpack(TestAllTypes.class);
     TestUtil.assertAllFieldsSet(result);
@@ -54,7 +62,7 @@
     // Unpacking to a wrong type will throw an exception.
     try {
       container.getValue().unpack(TestAny.class);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (InvalidProtocolBufferException e) {
       // expected.
     }
@@ -65,12 +73,13 @@
     container = containerBuilder.build();
     try {
       container.getValue().unpack(TestAllTypes.class);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (InvalidProtocolBufferException e) {
       // expected.
     }
   }
 
+  @Test
   public void testCustomTypeUrls() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
@@ -78,38 +87,39 @@
 
     TestAny container = TestAny.newBuilder().setValue(Any.pack(message, "xxx.com")).build();
 
-    assertEquals(
-        "xxx.com/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
+    assertThat(container.getValue().getTypeUrl())
+        .isEqualTo("xxx.com/" + TestAllTypes.getDescriptor().getFullName());
 
-    assertTrue(container.getValue().is(TestAllTypes.class));
-    assertFalse(container.getValue().is(TestAny.class));
+    assertThat(container.getValue().is(TestAllTypes.class)).isTrue();
+    assertThat(container.getValue().is(TestAny.class)).isFalse();
 
     TestAllTypes result = container.getValue().unpack(TestAllTypes.class);
     TestUtil.assertAllFieldsSet(result);
 
     container = TestAny.newBuilder().setValue(Any.pack(message, "yyy.com/")).build();
 
-    assertEquals(
-        "yyy.com/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
+    assertThat(container.getValue().getTypeUrl())
+        .isEqualTo("yyy.com/" + TestAllTypes.getDescriptor().getFullName());
 
-    assertTrue(container.getValue().is(TestAllTypes.class));
-    assertFalse(container.getValue().is(TestAny.class));
+    assertThat(container.getValue().is(TestAllTypes.class)).isTrue();
+    assertThat(container.getValue().is(TestAny.class)).isFalse();
 
     result = container.getValue().unpack(TestAllTypes.class);
     TestUtil.assertAllFieldsSet(result);
 
     container = TestAny.newBuilder().setValue(Any.pack(message, "")).build();
 
-    assertEquals(
-        "/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
+    assertThat(container.getValue().getTypeUrl())
+        .isEqualTo("/" + TestAllTypes.getDescriptor().getFullName());
 
-    assertTrue(container.getValue().is(TestAllTypes.class));
-    assertFalse(container.getValue().is(TestAny.class));
+    assertThat(container.getValue().is(TestAllTypes.class)).isTrue();
+    assertThat(container.getValue().is(TestAny.class)).isFalse();
 
     result = container.getValue().unpack(TestAllTypes.class);
     TestUtil.assertAllFieldsSet(result);
   }
 
+  @Test
   public void testCachedUnpackResult() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
@@ -117,10 +127,10 @@
 
     TestAny container = TestAny.newBuilder().setValue(Any.pack(message)).build();
 
-    assertTrue(container.getValue().is(TestAllTypes.class));
+    assertThat(container.getValue().is(TestAllTypes.class)).isTrue();
 
     TestAllTypes result1 = container.getValue().unpack(TestAllTypes.class);
     TestAllTypes result2 = container.getValue().unpack(TestAllTypes.class);
-    assertTrue(Objects.equals(result1, result2));
+    assertThat(Objects.equals(result1, result2)).isTrue();
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/ArrayDecodersTest.java b/java/core/src/test/java/com/google/protobuf/ArrayDecodersTest.java
index 037173b..895c9bd 100644
--- a/java/core/src/test/java/com/google/protobuf/ArrayDecodersTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ArrayDecodersTest.java
@@ -30,11 +30,17 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.google.protobuf.ArrayDecoders.Registers;
 import java.io.IOException;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class ArrayDecodersTest extends TestCase {
+@RunWith(JUnit4.class)
+public class ArrayDecodersTest {
 
   private static final int TAG = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
   private static final ByteString NEGATIVE_SIZE_0 = generateNegativeLength(0);
@@ -42,36 +48,40 @@
 
   private Registers registers;
 
-  @Override
+  @Before
   public void setUp() {
     registers = new Registers();
     registers.int1 = TAG;
   }
 
+  @Test
   public void testException_decodeString() {
     try {
       ArrayDecoders.decodeString(NEGATIVE_SIZE_0.toByteArray(), 0, registers);
-      fail();
+      assertWithMessage("should throw exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeStringRequireUtf8() {
     try {
       ArrayDecoders.decodeStringRequireUtf8(NEGATIVE_SIZE_0.toByteArray(), 0, registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeBytes() {
     try {
       ArrayDecoders.decodeBytes(NEGATIVE_SIZE_0.toByteArray(), 0, registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeStringList_first() {
     try {
       ArrayDecoders.decodeStringList(
@@ -81,11 +91,12 @@
           NEGATIVE_SIZE_0.size(),
           new ProtobufArrayList<Object>(),
           registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeStringList_second() {
     try {
       ArrayDecoders.decodeStringList(
@@ -95,11 +106,12 @@
           NEGATIVE_SIZE_1.size(),
           new ProtobufArrayList<Object>(),
           registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeStringListRequireUtf8_first() {
     try {
       ArrayDecoders.decodeStringListRequireUtf8(
@@ -109,11 +121,12 @@
           NEGATIVE_SIZE_0.size(),
           new ProtobufArrayList<Object>(),
           registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeStringListRequireUtf8_second() {
     try {
       ArrayDecoders.decodeStringListRequireUtf8(
@@ -123,11 +136,12 @@
           NEGATIVE_SIZE_1.size(),
           new ProtobufArrayList<Object>(),
           registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeBytesList_first() {
     try {
       ArrayDecoders.decodeBytesList(
@@ -137,11 +151,12 @@
           NEGATIVE_SIZE_0.size(),
           new ProtobufArrayList<Object>(),
           registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeBytesList_second() {
     try {
       ArrayDecoders.decodeBytesList(
@@ -151,11 +166,12 @@
           NEGATIVE_SIZE_1.size(),
           new ProtobufArrayList<Object>(),
           registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeUnknownField() {
     try {
       ArrayDecoders.decodeUnknownField(
@@ -165,11 +181,12 @@
           NEGATIVE_SIZE_0.size(),
           UnknownFieldSetLite.newInstance(),
           registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testException_decodeHugeField() {
     byte[] badBytes =
         new byte[] {
@@ -178,13 +195,13 @@
     try {
       ArrayDecoders.decodeUnknownField(
           TAG, badBytes, 0, badBytes.length, UnknownFieldSetLite.newInstance(), registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
 
     try {
       ArrayDecoders.decodeBytes(badBytes, 0, registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
 
@@ -206,7 +223,7 @@
     try {
       ArrayDecoders.decodeBytesList(
           TAG, badBytesList, 0, badBytes.length, new ProtobufArrayList<>(), registers);
-      fail();
+      assertWithMessage("should throw an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
diff --git a/java/core/src/test/java/com/google/protobuf/BinaryProtocolTest.java b/java/core/src/test/java/com/google/protobuf/BinaryProtocolTest.java
index cda2998..0853b9a 100644
--- a/java/core/src/test/java/com/google/protobuf/BinaryProtocolTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BinaryProtocolTest.java
@@ -30,11 +30,10 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.protobuf.testing.Proto2Testing.Proto2Message;
 import com.google.protobuf.testing.Proto3Testing.Proto3Message;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -58,15 +57,15 @@
     // Deserialize with BinaryReader and verify that the message matches the original.
     Proto3Message result =
         ExperimentalSerializationUtil.fromByteArray(expectedBytes, Proto3Message.class);
-    assertEquals(expected, result);
+    assertThat(result).isEqualTo(expected);
 
     // Now write it back out using BinaryWriter and verify the output length.
     byte[] actualBytes = ExperimentalSerializationUtil.toByteArray(result);
-    Assert.assertEquals(expectedBytes.length, actualBytes.length);
+    assertThat(actualBytes).hasLength(expectedBytes.length);
 
     // Read back in the bytes and verify that it matches the original message.
     Proto3Message actual = Proto3Message.parseFrom(actualBytes);
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
   @Test
@@ -77,14 +76,14 @@
     // Deserialize with BinaryReader and verify that the message matches the original.
     Proto2Message result =
         ExperimentalSerializationUtil.fromByteArray(expectedBytes, Proto2Message.class);
-    assertEquals(expected, result);
+    assertThat(result).isEqualTo(expected);
 
     // Now write it back out using BinaryWriter and verify the output length.
     byte[] actualBytes = ExperimentalSerializationUtil.toByteArray(result);
-    Assert.assertEquals(expectedBytes.length, actualBytes.length);
+    assertThat(actualBytes).hasLength(expectedBytes.length);
 
     // Read back in the bytes and verify that it matches the original message.
     Proto2Message actual = Proto2Message.parseFrom(actualBytes);
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
index 805b7b0..2050507 100644
--- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -30,20 +30,22 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static java.util.Arrays.asList;
 
 import com.google.protobuf.Internal.BooleanList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests for {@link BooleanArrayList}.
- *
- * @author [email protected] (Daniel Weis)
- */
-public class BooleanArrayListTest extends TestCase {
+/** Tests for {@link BooleanArrayList}. */
+@RunWith(JUnit4.class)
+public class BooleanArrayListTest {
 
   private static final BooleanArrayList UNARY_LIST = newImmutableBooleanArrayList(true);
   private static final BooleanArrayList TERTIARY_LIST =
@@ -51,19 +53,22 @@
 
   private BooleanArrayList list;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     list = new BooleanArrayList();
   }
 
+  @Test
   public void testEmptyListReturnsSameInstance() {
-    assertSame(BooleanArrayList.emptyList(), BooleanArrayList.emptyList());
+    assertThat(BooleanArrayList.emptyList()).isSameInstanceAs(BooleanArrayList.emptyList());
   }
 
+  @Test
   public void testEmptyListIsImmutable() {
     assertImmutable(BooleanArrayList.emptyList());
   }
 
+  @Test
   public void testMakeImmutable() {
     list.addBoolean(true);
     list.addBoolean(false);
@@ -73,19 +78,20 @@
     assertImmutable(list);
   }
 
+  @Test
   public void testModificationWithIteration() {
     list.addAll(asList(true, false, true, false));
     Iterator<Boolean> iterator = list.iterator();
-    assertEquals(4, list.size());
-    assertEquals(true, (boolean) list.get(0));
-    assertEquals(true, (boolean) iterator.next());
+    assertThat(list).hasSize(4);
+    assertThat((boolean) list.get(0)).isEqualTo(true);
+    assertThat((boolean) iterator.next()).isEqualTo(true);
     list.set(0, true);
-    assertEquals(false, (boolean) iterator.next());
+    assertThat((boolean) iterator.next()).isEqualTo(false);
 
     list.remove(0);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
@@ -94,191 +100,211 @@
     list.add(0, false);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
   }
 
+  @Test
   public void testGet() {
-    assertEquals(true, (boolean) TERTIARY_LIST.get(0));
-    assertEquals(false, (boolean) TERTIARY_LIST.get(1));
-    assertEquals(true, (boolean) TERTIARY_LIST.get(2));
+    assertThat((boolean) TERTIARY_LIST.get(0)).isEqualTo(true);
+    assertThat((boolean) TERTIARY_LIST.get(1)).isEqualTo(false);
+    assertThat((boolean) TERTIARY_LIST.get(2)).isEqualTo(true);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testGetBoolean() {
-    assertEquals(true, TERTIARY_LIST.getBoolean(0));
-    assertEquals(false, TERTIARY_LIST.getBoolean(1));
-    assertEquals(true, TERTIARY_LIST.getBoolean(2));
+    assertThat(TERTIARY_LIST.getBoolean(0)).isEqualTo(true);
+    assertThat(TERTIARY_LIST.getBoolean(1)).isEqualTo(false);
+    assertThat(TERTIARY_LIST.getBoolean(2)).isEqualTo(true);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testIndexOf_nullElement() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(null));
+    assertThat(TERTIARY_LIST.indexOf(null)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_incompatibleElementType() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(new Object()));
+    assertThat(TERTIARY_LIST.indexOf(new Object())).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInList() {
-    assertEquals(-1, UNARY_LIST.indexOf(false));
+    assertThat(UNARY_LIST.indexOf(false)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInListWithDuplicates() {
     BooleanArrayList listWithDupes = newImmutableBooleanArrayList(true, true);
-    assertEquals(-1, listWithDupes.indexOf(false));
+    assertThat(listWithDupes.indexOf(false)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_inList() {
-    assertEquals(1, TERTIARY_LIST.indexOf(false));
+    assertThat(TERTIARY_LIST.indexOf(false)).isEqualTo(1);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchAtHead() {
     BooleanArrayList listWithDupes = newImmutableBooleanArrayList(true, true, false);
-    assertEquals(0, listWithDupes.indexOf(true));
+    assertThat(listWithDupes.indexOf(true)).isEqualTo(0);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchMidList() {
     BooleanArrayList listWithDupes = newImmutableBooleanArrayList(false, true, true, false);
-    assertEquals(1, listWithDupes.indexOf(true));
+    assertThat(listWithDupes.indexOf(true)).isEqualTo(1);
   }
 
+  @Test
   public void testContains_nullElement() {
-    assertEquals(false, TERTIARY_LIST.contains(null));
+    assertThat(TERTIARY_LIST).doesNotContain(null);
   }
 
+  @Test
   public void testContains_incompatibleElementType() {
-    assertEquals(false, TERTIARY_LIST.contains(new Object()));
+    assertThat(TERTIARY_LIST).doesNotContain(new Object());
   }
 
+  @Test
   public void testContains_notInList() {
-    assertEquals(false, UNARY_LIST.contains(false));
+    assertThat(UNARY_LIST).doesNotContain(false);
   }
 
+  @Test
   public void testContains_notInListWithDuplicates() {
     BooleanArrayList listWithDupes = newImmutableBooleanArrayList(true, true);
-    assertEquals(false, listWithDupes.contains(false));
+    assertThat(listWithDupes).doesNotContain(false);
   }
 
+  @Test
   public void testContains_inList() {
-    assertEquals(true, TERTIARY_LIST.contains(false));
+    assertThat(TERTIARY_LIST).contains(false);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchAtHead() {
     BooleanArrayList listWithDupes = newImmutableBooleanArrayList(true, true, false);
-    assertEquals(true, listWithDupes.contains(true));
+    assertThat(listWithDupes).contains(true);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchMidList() {
     BooleanArrayList listWithDupes = newImmutableBooleanArrayList(false, true, true, false);
-    assertEquals(true, listWithDupes.contains(true));
+    assertThat(listWithDupes).contains(true);
   }
 
+  @Test
   public void testSize() {
-    assertEquals(0, BooleanArrayList.emptyList().size());
-    assertEquals(1, UNARY_LIST.size());
-    assertEquals(3, TERTIARY_LIST.size());
+    assertThat(BooleanArrayList.emptyList()).isEmpty();
+    assertThat(UNARY_LIST).hasSize(1);
+    assertThat(TERTIARY_LIST).hasSize(3);
 
     list.addBoolean(true);
     list.addBoolean(false);
     list.addBoolean(false);
     list.addBoolean(false);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
 
     list.remove(0);
-    assertEquals(3, list.size());
+    assertThat(list).hasSize(3);
 
     list.add(true);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
   }
 
+  @Test
   public void testSet() {
     list.addBoolean(false);
     list.addBoolean(false);
 
-    assertEquals(false, (boolean) list.set(0, true));
-    assertEquals(true, list.getBoolean(0));
+    assertThat((boolean) list.set(0, true)).isEqualTo(false);
+    assertThat(list.getBoolean(0)).isEqualTo(true);
 
-    assertEquals(false, (boolean) list.set(1, false));
-    assertEquals(false, list.getBoolean(1));
+    assertThat((boolean) list.set(1, false)).isEqualTo(false);
+    assertThat(list.getBoolean(1)).isEqualTo(false);
 
     try {
       list.set(-1, false);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.set(2, false);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testSetBoolean() {
     list.addBoolean(true);
     list.addBoolean(true);
 
-    assertEquals(true, list.setBoolean(0, false));
-    assertEquals(false, list.getBoolean(0));
+    assertThat(list.setBoolean(0, false)).isEqualTo(true);
+    assertThat(list.getBoolean(0)).isEqualTo(false);
 
-    assertEquals(true, list.setBoolean(1, false));
-    assertEquals(false, list.getBoolean(1));
+    assertThat(list.setBoolean(1, false)).isEqualTo(true);
+    assertThat(list.getBoolean(1)).isEqualTo(false);
 
     try {
       list.setBoolean(-1, false);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.setBoolean(2, false);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testAdd() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.add(false));
-    assertEquals(asList(false), list);
+    assertThat(list.add(false)).isTrue();
+    assertThat(list).containsExactly(false);
 
-    assertTrue(list.add(true));
+    assertThat(list.add(true)).isTrue();
     list.add(0, false);
-    assertEquals(asList(false, false, true), list);
+    assertThat(list).containsExactly(false, false, true).inOrder();
 
     list.add(0, true);
     list.add(0, false);
@@ -286,8 +312,9 @@
     for (int i = 0; i < 6; i++) {
       list.add(i % 2 == 0);
     }
-    assertEquals(
-        asList(false, true, false, false, true, true, false, true, false, true, false), list);
+    assertThat(list)
+        .containsExactly(false, true, false, false, true, true, false, true, false, true, false)
+        .inOrder();
 
     try {
       list.add(-1, true);
@@ -302,237 +329,247 @@
     }
   }
 
+  @Test
   public void testAddBoolean() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
     list.addBoolean(false);
-    assertEquals(asList(false), list);
+    assertThat(list).containsExactly(false);
 
     list.addBoolean(true);
-    assertEquals(asList(false, true), list);
+    assertThat(list).containsExactly(false, true).inOrder();
   }
 
+  @Test
   public void testAddAll() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.addAll(Collections.singleton(true)));
-    assertEquals(1, list.size());
-    assertEquals(true, (boolean) list.get(0));
-    assertEquals(true, list.getBoolean(0));
+    assertThat(list.addAll(Collections.singleton(true))).isTrue();
+    assertThat(list).hasSize(1);
+    assertThat((boolean) list.get(0)).isEqualTo(true);
+    assertThat(list.getBoolean(0)).isEqualTo(true);
 
-    assertTrue(list.addAll(asList(false, true, false, true, false)));
-    assertEquals(asList(true, false, true, false, true, false), list);
+    assertThat(list.addAll(asList(false, true, false, true, false))).isTrue();
+    assertThat(list).containsExactly(true, false, true, false, true, false).inOrder();
 
-    assertTrue(list.addAll(TERTIARY_LIST));
-    assertEquals(asList(true, false, true, false, true, false, true, false, true), list);
+    assertThat(list.addAll(TERTIARY_LIST)).isTrue();
+    assertThat(list)
+        .containsExactly(true, false, true, false, true, false, true, false, true)
+        .inOrder();
 
-    assertFalse(list.addAll(Collections.<Boolean>emptyList()));
-    assertFalse(list.addAll(BooleanArrayList.emptyList()));
+    assertThat(list.addAll(Collections.<Boolean>emptyList())).isFalse();
+    assertThat(list.addAll(BooleanArrayList.emptyList())).isFalse();
   }
 
+  @Test
   public void testEquals() {
     BooleanArrayList list1 = new BooleanArrayList();
     BooleanArrayList list2 = new BooleanArrayList();
 
-    assertEquals(list1, list2);
+    assertThat(list1).isEqualTo(list2);
   }
 
+  @Test
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
-    assertEquals(true, (boolean) list.remove(0));
-    assertEquals(asList(false, true), list);
+    assertThat((boolean) list.remove(0)).isEqualTo(true);
+    assertThat(list).containsExactly(false, true).inOrder();
 
-    assertTrue(list.remove(Boolean.TRUE));
-    assertEquals(asList(false), list);
+    assertThat(list.remove(Boolean.TRUE)).isTrue();
+    assertThat(list).containsExactly(false);
 
-    assertFalse(list.remove(Boolean.TRUE));
-    assertEquals(asList(false), list);
+    assertThat(list.remove(Boolean.TRUE)).isFalse();
+    assertThat(list).containsExactly(false);
 
-    assertEquals(false, (boolean) list.remove(0));
-    assertEquals(asList(), list);
+    assertThat((boolean) list.remove(0)).isEqualTo(false);
+    assertThat(list).isEmpty();
 
     try {
       list.remove(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.remove(0);
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testRemoveEnd_listAtCapacity() {
     BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addBoolean(true);
     toRemove.remove(0);
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
+  @Test
   public void testRemove_listAtCapacity() {
     BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(2);
     toRemove.addBoolean(true);
     toRemove.addBoolean(false);
     toRemove.remove(0);
-    assertEquals(1, toRemove.size());
-    assertEquals(false, (boolean) toRemove.get(0));
+    assertThat(toRemove).hasSize(1);
+    assertThat((boolean) toRemove.get(0)).isEqualTo(false);
   }
 
+  @Test
   public void testSublistRemoveEndOfCapacity() {
     BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addBoolean(true);
     toRemove.subList(0, 1).clear();
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
   private void assertImmutable(BooleanList list) {
 
     try {
       list.add(true);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.add(0, true);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.<Boolean>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.singletonList(true));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(new BooleanArrayList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.singleton(true));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.<Boolean>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addBoolean(false);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.clear();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.<Boolean>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.singleton(Boolean.TRUE));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(Collections.<Boolean>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.singleton(Boolean.TRUE));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.set(0, false);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.setBoolean(0, false);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
diff --git a/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
index 654d62b..656d2c3 100644
--- a/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
@@ -30,24 +30,30 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.UnsupportedEncodingException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * This class tests {@link BoundedByteString}, which extends {@link LiteralByteString}, by
  * inheriting the tests from {@link LiteralByteStringTest}. The only method which is strange enough
  * that it needs to be overridden here is {@link #testToString()}.
- *
- * @author [email protected] (Carl Haverl)
  */
+@RunWith(JUnit4.class)
 public class BoundedByteStringTest extends LiteralByteStringTest {
 
   @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     classUnderTest = "BoundedByteString";
     byte[] sourceBytes = ByteStringTest.getTestBytes(2341, 11337766L);
     int from = 100;
@@ -59,40 +65,39 @@
   }
 
   @Override
+  @Test
   public void testToString() throws UnsupportedEncodingException {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
     ByteString chopped = unicode.substring(2, unicode.size() - 6);
-    assertEquals(
-        classUnderTest + ".substring() must have the expected type",
-        classUnderTest,
-        getActualClassName(chopped));
+    assertWithMessage("%s.substring() must have the expected type", classUnderTest)
+        .that(classUnderTest)
+        .isEqualTo(getActualClassName(chopped));
 
     String roundTripString = chopped.toString(UTF_8);
-    assertEquals(
-        classUnderTest + " unicode bytes must match",
-        testString.substring(2, testString.length() - 6),
-        roundTripString);
+    assertWithMessage("%s unicode bytes must match", classUnderTest)
+        .that(testString.substring(2, testString.length() - 6))
+        .isEqualTo(roundTripString);
   }
 
   @Override
+  @Test
   public void testCharsetToString() {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
     ByteString chopped = unicode.substring(2, unicode.size() - 6);
-    assertEquals(
-        classUnderTest + ".substring() must have the expected type",
-        classUnderTest,
-        getActualClassName(chopped));
+    assertWithMessage("%s.substring() must have the expected type", classUnderTest)
+        .that(classUnderTest)
+        .isEqualTo(getActualClassName(chopped));
 
     String roundTripString = chopped.toString(Internal.UTF_8);
-    assertEquals(
-        classUnderTest + " unicode bytes must match",
-        testString.substring(2, testString.length() - 6),
-        roundTripString);
+    assertWithMessage("%s unicode bytes must match", classUnderTest)
+        .that(testString.substring(2, testString.length() - 6))
+        .isEqualTo(roundTripString);
   }
 
   @Override
+  @Test
   public void testJavaSerialization() throws Exception {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(out);
@@ -102,7 +107,7 @@
     InputStream in = new ByteArrayInputStream(pickled);
     ObjectInputStream ois = new ObjectInputStream(in);
     Object o = ois.readObject();
-    assertTrue("Didn't get a ByteString back", o instanceof ByteString);
-    assertEquals("Should get an equal ByteString back", stringUnderTest, o);
+    assertWithMessage("Didn't get a ByteString back").that(o).isInstanceOf(ByteString.class);
+    assertWithMessage("Should get an equal ByteString back").that(stringUnderTest).isEqualTo(o);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
index 5f0ef62..11cdb02 100644
--- a/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
@@ -30,22 +30,29 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Random;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Tests for {@link ByteBufferWriter}. */
-public class ByteBufferWriterTest extends TestCase {
+@RunWith(JUnit4.class)
+public class ByteBufferWriterTest {
 
+  @Test
   public void testHeapBuffer() throws IOException {
     // Test a small and large buffer.
     testWrite(ByteBuffer.allocate(100));
     testWrite(ByteBuffer.allocate(1024 * 100));
   }
 
+  @Test
   public void testDirectBuffer() throws IOException {
     // Test a small and large buffer.
     testWrite(ByteBuffer.allocateDirect(100));
@@ -56,8 +63,8 @@
     fillRandom(buffer);
     ByteArrayOutputStream os = new ByteArrayOutputStream(buffer.remaining());
     ByteBufferWriter.write(buffer, os);
-    assertEquals(0, buffer.position());
-    assertTrue(Arrays.equals(toArray(buffer), os.toByteArray()));
+    assertThat(buffer.position()).isEqualTo(0);
+    assertThat(Arrays.equals(toArray(buffer), os.toByteArray())).isTrue();
   }
 
   private void fillRandom(ByteBuffer buf) {
diff --git a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
index 1b1a786..3f97e31 100644
--- a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.google.protobuf.ByteString.Output;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -46,15 +49,16 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Random;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Test methods with implementations in {@link ByteString}, plus do some top-level "integration"
  * tests.
- *
- * @author [email protected] (Carl Haverl)
  */
-public class ByteStringTest extends TestCase {
+@RunWith(JUnit4.class)
+public class ByteStringTest {
 
   private static final Charset UTF_16 = Charset.forName("UTF-16");
 
@@ -87,17 +91,18 @@
     return left.length == right.length && isArrayRange(left, right, 0, left.length);
   }
 
+  @Test
   public void testCompare_equalByteStrings_compareEqual() throws Exception {
     byte[] referenceBytes = getTestBytes();
     ByteString string1 = ByteString.copyFrom(referenceBytes);
     ByteString string2 = ByteString.copyFrom(referenceBytes);
 
-    assertEquals(
-        "ByteString instances containing the same data must compare equal.",
-        0,
-        ByteString.unsignedLexicographicalComparator().compare(string1, string2));
+    assertWithMessage("ByteString instances containing the same data must compare equal.")
+        .that(ByteString.unsignedLexicographicalComparator().compare(string1, string2))
+        .isEqualTo(0);
   }
 
+  @Test
   public void testCompare_byteStringsSortLexicographically() throws Exception {
     ByteString app = ByteString.copyFromUtf8("app");
     ByteString apple = ByteString.copyFromUtf8("apple");
@@ -105,93 +110,109 @@
 
     Comparator<ByteString> comparator = ByteString.unsignedLexicographicalComparator();
 
-    assertTrue("ByteString(app) < ByteString(apple)", comparator.compare(app, apple) < 0);
-    assertTrue("ByteString(app) < ByteString(banana)", comparator.compare(app, banana) < 0);
-    assertTrue("ByteString(apple) < ByteString(banana)", comparator.compare(apple, banana) < 0);
+    assertWithMessage("ByteString(app) < ByteString(apple)")
+        .that(comparator.compare(app, apple) < 0)
+        .isTrue();
+    assertWithMessage("ByteString(app) < ByteString(banana)")
+        .that(comparator.compare(app, banana) < 0)
+        .isTrue();
+    assertWithMessage("ByteString(apple) < ByteString(banana)")
+        .that(comparator.compare(apple, banana) < 0)
+        .isTrue();
   }
 
+  @Test
   public void testCompare_interpretsByteValuesAsUnsigned() throws Exception {
     // Two's compliment of `-1` == 0b11111111 == 255
     ByteString twoHundredFiftyFive = ByteString.copyFrom(new byte[] {-1});
     // 0b00000001 == 1
     ByteString one = ByteString.copyFrom(new byte[] {1});
 
-    assertTrue(
-        "ByteString comparison treats bytes as unsigned values",
-        ByteString.unsignedLexicographicalComparator().compare(one, twoHundredFiftyFive) < 0);
+    assertWithMessage("ByteString comparison treats bytes as unsigned values")
+        .that(ByteString.unsignedLexicographicalComparator().compare(one, twoHundredFiftyFive) < 0)
+        .isTrue();
   }
 
+  @Test
   public void testSubstring_BeginIndex() {
     byte[] bytes = getTestBytes();
     ByteString substring = ByteString.copyFrom(bytes).substring(500);
-    assertTrue(
-        "substring must contain the tail of the string",
-        isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500));
+    assertWithMessage("substring must contain the tail of the string")
+        .that(isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500))
+        .isTrue();
   }
 
+  @Test
   public void testCopyFrom_BytesOffsetSize() {
     byte[] bytes = getTestBytes();
     ByteString byteString = ByteString.copyFrom(bytes, 500, 200);
-    assertTrue(
-        "copyFrom sub-range must contain the expected bytes",
-        isArrayRange(byteString.toByteArray(), bytes, 500, 200));
+    assertWithMessage("copyFrom sub-range must contain the expected bytes")
+        .that(isArrayRange(byteString.toByteArray(), bytes, 500, 200))
+        .isTrue();
   }
 
+  @Test
   public void testCopyFrom_Bytes() {
     byte[] bytes = getTestBytes();
     ByteString byteString = ByteString.copyFrom(bytes);
-    assertTrue(
-        "copyFrom must contain the expected bytes", isArray(byteString.toByteArray(), bytes));
+    assertWithMessage("copyFrom must contain the expected bytes")
+        .that(isArray(byteString.toByteArray(), bytes))
+        .isTrue();
   }
 
+  @Test
   public void testCopyFrom_ByteBufferSize() {
     byte[] bytes = getTestBytes();
     ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
     byteBuffer.put(bytes);
     byteBuffer.position(500);
     ByteString byteString = ByteString.copyFrom(byteBuffer, 200);
-    assertTrue(
-        "copyFrom byteBuffer sub-range must contain the expected bytes",
-        isArrayRange(byteString.toByteArray(), bytes, 500, 200));
+    assertWithMessage("copyFrom byteBuffer sub-range must contain the expected bytes")
+        .that(isArrayRange(byteString.toByteArray(), bytes, 500, 200))
+        .isTrue();
   }
 
+  @Test
   public void testCopyFrom_ByteBuffer() {
     byte[] bytes = getTestBytes();
     ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
     byteBuffer.put(bytes);
     byteBuffer.position(500);
     ByteString byteString = ByteString.copyFrom(byteBuffer);
-    assertTrue(
-        "copyFrom byteBuffer sub-range must contain the expected bytes",
-        isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500));
+    assertWithMessage("copyFrom byteBuffer sub-range must contain the expected bytes")
+        .that(isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500))
+        .isTrue();
   }
 
+  @Test
   public void testCopyFrom_StringEncoding() {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString byteString = ByteString.copyFrom(testString, UTF_16);
     byte[] testBytes = testString.getBytes(UTF_16);
-    assertTrue(
-        "copyFrom string must respect the charset",
-        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+    assertWithMessage("copyFrom string must respect the charset")
+        .that(isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length))
+        .isTrue();
   }
 
+  @Test
   public void testCopyFrom_Utf8() {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString byteString = ByteString.copyFromUtf8(testString);
     byte[] testBytes = testString.getBytes(Internal.UTF_8);
-    assertTrue(
-        "copyFromUtf8 string must respect the charset",
-        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+    assertWithMessage("copyFromUtf8 string must respect the charset")
+        .that(isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length))
+        .isTrue();
   }
 
+  @Test
   public void testCopyFrom_Iterable() {
     byte[] testBytes = getTestBytes(77777, 113344L);
     final List<ByteString> pieces = makeConcretePieces(testBytes);
     // Call copyFrom() on a Collection
     ByteString byteString = ByteString.copyFrom(pieces);
-    assertTrue(
-        "copyFrom a List must contain the expected bytes",
-        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+    assertWithMessage("copyFrom a List must contain the expected bytes")
+        .that(isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length))
+        .isTrue();
     // Call copyFrom on an iteration that's not a collection
     ByteString byteStringAlt =
         ByteString.copyFrom(
@@ -201,60 +222,65 @@
                 return pieces.iterator();
               }
             });
-    assertEquals(
-        "copyFrom from an Iteration must contain the expected bytes", byteString, byteStringAlt);
+    assertWithMessage("copyFrom from an Iteration must contain the expected bytes")
+        .that(byteString)
+        .isEqualTo(byteStringAlt);
   }
 
+  @Test
   public void testCopyFrom_LengthTooBig() {
     byte[] testBytes = getTestBytes(100);
     try {
       ByteString.copyFrom(testBytes, 0, 200);
-      fail("Should throw");
+      assertWithMessage("Should throw").fail();
     } catch (IndexOutOfBoundsException expected) {
     }
 
     try {
       ByteString.copyFrom(testBytes, 99, 2);
-      fail();
+      assertWithMessage("Should throw").fail();
     } catch (IndexOutOfBoundsException expected) {
     }
 
     ByteBuffer buf = ByteBuffer.wrap(testBytes);
     try {
       ByteString.copyFrom(buf, 101);
-      fail();
+      assertWithMessage("Should throw").fail();
     } catch (IndexOutOfBoundsException expected) {
     }
 
     try {
       ByteString.copyFrom(testBytes, -1, 10);
-      fail("Should throw");
+      assertWithMessage("Should throw").fail();
     } catch (IndexOutOfBoundsException expected) {
     }
   }
 
+  @Test
   public void testCopyTo_TargetOffset() {
     byte[] bytes = getTestBytes();
     ByteString byteString = ByteString.copyFrom(bytes);
     byte[] target = new byte[bytes.length + 1000];
     byteString.copyTo(target, 400);
-    assertTrue(
-        "copyFrom byteBuffer sub-range must contain the expected bytes",
-        isArrayRange(bytes, target, 400, bytes.length));
+    assertWithMessage("copyFrom byteBuffer sub-range must contain the expected bytes")
+        .that(isArrayRange(bytes, target, 400, bytes.length))
+        .isTrue();
   }
 
+  @Test
   public void testReadFrom_emptyStream() throws IOException {
     ByteString byteString = ByteString.readFrom(new ByteArrayInputStream(new byte[0]));
-    assertSame(
-        "reading an empty stream must result in the EMPTY constant byte string",
-        ByteString.EMPTY,
-        byteString);
+    assertWithMessage("reading an empty stream must result in the EMPTY constant byte string")
+        .that(ByteString.EMPTY)
+        .isSameInstanceAs(byteString);
   }
 
+  @Test
   public void testReadFrom_smallStream() throws IOException {
     assertReadFrom(getTestBytes(10));
   }
 
+  @Test
   public void testReadFrom_mutating() throws IOException {
     EvilInputStream eis = new EvilInputStream();
     ByteString byteString = ByteString.readFrom(eis);
@@ -266,12 +292,13 @@
     }
 
     byte[] newValue = byteString.toByteArray();
-    assertTrue(
-        "copyFrom byteBuffer must not grant access to underlying array",
-        Arrays.equals(originalValue, newValue));
+    assertWithMessage("copyFrom byteBuffer must not grant access to underlying array")
+        .that(Arrays.equals(originalValue, newValue))
+        .isTrue();
   }
 
   // Tests sizes that are near the rope copy-out threshold.
+  @Test
   public void testReadFrom_mediumStream() throws IOException {
     assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE - 1));
     assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE));
@@ -280,6 +307,7 @@
   }
 
   // Tests sizes that are over multi-segment rope threshold.
+  @Test
   public void testReadFrom_largeStream() throws IOException {
     assertReadFrom(getTestBytes(0x100));
     assertReadFrom(getTestBytes(0x101));
@@ -293,6 +321,7 @@
   }
 
   // Tests sizes that are near the read buffer size.
+  @Test
   public void testReadFrom_byteBoundaries() throws IOException {
     final int min = ByteString.MIN_READ_FROM_CHUNK_SIZE;
     final int max = ByteString.MAX_READ_FROM_CHUNK_SIZE;
@@ -323,26 +352,30 @@
   }
 
   // Tests that IOExceptions propagate through ByteString.readFrom().
+  @Test
   public void testReadFrom_IOExceptions() {
     try {
       ByteString.readFrom(new FailStream());
-      fail("readFrom must throw the underlying IOException");
+      assertWithMessage("readFrom must throw the underlying IOException").fail();
 
     } catch (IOException e) {
-      assertEquals(
-          "readFrom must throw the expected exception", "synthetic failure", e.getMessage());
+      assertWithMessage("readFrom must throw the expected exception")
+          .that(e)
+          .hasMessageThat()
+          .isEqualTo("synthetic failure");
     }
   }
 
   // Tests that ByteString.readFrom works with streams that don't
   // always fill their buffers.
+  @Test
   public void testReadFrom_reluctantStream() throws IOException {
     final byte[] data = getTestBytes(0x1000);
 
     ByteString byteString = ByteString.readFrom(new ReluctantStream(data));
-    assertTrue(
-        "readFrom byte stream must contain the expected bytes",
-        isArray(byteString.toByteArray(), data));
+    assertWithMessage("readFrom byte stream must contain the expected bytes")
+        .that(isArray(byteString.toByteArray(), data))
+        .isTrue();
 
     // Same test as above, but with some specific chunk sizes.
     assertReadFromReluctantStream(data, 100);
@@ -358,27 +391,29 @@
   // reluctant stream with the given chunkSize parameter.
   private void assertReadFromReluctantStream(byte[] bytes, int chunkSize) throws IOException {
     ByteString b = ByteString.readFrom(new ReluctantStream(bytes), chunkSize);
-    assertTrue(
-        "readFrom byte stream must contain the expected bytes", isArray(b.toByteArray(), bytes));
+    assertWithMessage("readFrom byte stream must contain the expected bytes")
+        .that(isArray(b.toByteArray(), bytes))
+        .isTrue();
   }
 
   // Tests that ByteString.readFrom works with streams that implement
   // available().
+  @Test
   public void testReadFrom_available() throws IOException {
     final byte[] data = getTestBytes(0x1001);
 
     ByteString byteString = ByteString.readFrom(new AvailableStream(data));
-    assertTrue(
-        "readFrom byte stream must contain the expected bytes",
-        isArray(byteString.toByteArray(), data));
+    assertWithMessage("readFrom byte stream must contain the expected bytes")
+        .that(isArray(byteString.toByteArray(), data))
+        .isTrue();
   }
 
   // Fails unless ByteString.readFrom reads the bytes correctly.
   private void assertReadFrom(byte[] bytes) throws IOException {
     ByteString byteString = ByteString.readFrom(new ByteArrayInputStream(bytes));
-    assertTrue(
-        "readFrom byte stream must contain the expected bytes",
-        isArray(byteString.toByteArray(), bytes));
+    assertWithMessage("readFrom byte stream must contain the expected bytes")
+        .that(isArray(byteString.toByteArray(), bytes))
+        .isTrue();
   }
 
   // A stream that fails when read.
@@ -478,45 +513,53 @@
     }
   }
 
+  @Test
   public void testToStringUtf8() {
     String testString = "I love unicode \u1234\u5678 characters";
     byte[] testBytes = testString.getBytes(Internal.UTF_8);
     ByteString byteString = ByteString.copyFrom(testBytes);
-    assertEquals(
-        "copyToStringUtf8 must respect the charset", testString, byteString.toStringUtf8());
+    assertWithMessage("copyToStringUtf8 must respect the charset")
+        .that(testString)
+        .isEqualTo(byteString.toStringUtf8());
   }
 
+  @Test
   public void testToString() {
     String toString =
         ByteString.copyFrom("Here are some bytes: \t\u00a1".getBytes(Internal.UTF_8)).toString();
-    assertTrue(toString, toString.contains("size=24"));
-    assertTrue(toString, toString.contains("contents=\"Here are some bytes: \\t\\302\\241\""));
+    assertWithMessage(toString).that(toString.contains("size=24")).isTrue();
+    assertWithMessage(toString)
+        .that(toString.contains("contents=\"Here are some bytes: \\t\\302\\241\""))
+        .isTrue();
   }
 
+  @Test
   public void testToString_long() {
     String toString =
         ByteString.copyFrom(
                 "123456789012345678901234567890123456789012345678901234567890"
                     .getBytes(Internal.UTF_8))
             .toString();
-    assertTrue(toString, toString.contains("size=60"));
-    assertTrue(
-        toString,
-        toString.contains("contents=\"12345678901234567890123456789012345678901234567...\""));
+    assertWithMessage(toString).that(toString.contains("size=60")).isTrue();
+    assertWithMessage(toString)
+        .that(toString.contains("contents=\"12345678901234567890123456789012345678901234567...\""))
+        .isTrue();
   }
 
+  @Test
   public void testNewOutput_InitialCapacity() throws IOException {
     byte[] bytes = getTestBytes();
     ByteString.Output output = ByteString.newOutput(bytes.length + 100);
     output.write(bytes);
     ByteString byteString = output.toByteString();
-    assertTrue(
-        "String built from newOutput(int) must contain the expected bytes",
-        isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+    assertWithMessage("String built from newOutput(int) must contain the expected bytes")
+        .that(isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length))
+        .isTrue();
   }
 
   // Test newOutput() using a variety of buffer sizes and a variety of (fixed)
   // write sizes
+  @Test
   public void testNewOutput_ArrayWrite() {
     byte[] bytes = getTestBytes();
     int length = bytes.length;
@@ -533,15 +576,16 @@
           output.write(bytes, i, Math.min(writeSize, length - i));
         }
         ByteString byteString = output.toByteString();
-        assertTrue(
-            "String built from newOutput() must contain the expected bytes",
-            isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+        assertWithMessage("String built from newOutput() must contain the expected bytes")
+            .that(isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length))
+            .isTrue();
       }
     }
   }
 
   // Test newOutput() using a variety of buffer sizes, but writing all the
   // characters using write(byte);
+  @Test
   public void testNewOutput_WriteChar() {
     byte[] bytes = getTestBytes();
     int length = bytes.length;
@@ -554,14 +598,15 @@
         output.write(byteValue);
       }
       ByteString byteString = output.toByteString();
-      assertTrue(
-          "String built from newOutput() must contain the expected bytes",
-          isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+      assertWithMessage("String built from newOutput() must contain the expected bytes")
+          .that(isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length))
+          .isTrue();
     }
   }
 
   // Test newOutput() in which we write the bytes using a variety of methods
   // and sizes, and in which we repeatedly call toByteString() in the middle.
+  @Test
   public void testNewOutput_Mixed() {
     Random rng = new Random(1);
     byte[] bytes = getTestBytes();
@@ -584,24 +629,26 @@
           output.write(bytes[position]);
           position++;
         }
-        assertEquals("size() returns the right value", position, output.size());
-        assertTrue(
-            "newOutput() substring must have correct bytes",
-            isArrayRange(output.toByteString().toByteArray(), bytes, 0, position));
+        assertWithMessage("size() returns the right value").that(position).isEqualTo(output.size());
+        assertWithMessage("newOutput() substring must have correct bytes")
+            .that(isArrayRange(output.toByteString().toByteArray(), bytes, 0, position))
+            .isTrue();
       }
       ByteString byteString = output.toByteString();
-      assertTrue(
-          "String built from newOutput() must contain the expected bytes",
-          isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+      assertWithMessage("String built from newOutput() must contain the expected bytes")
+          .that(isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length))
+          .isTrue();
     }
   }
 
+  @Test
   public void testNewOutputEmpty() {
     // Make sure newOutput() correctly builds empty byte strings
     ByteString byteString = ByteString.newOutput().toByteString();
-    assertEquals(ByteString.EMPTY, byteString);
+    assertThat(ByteString.EMPTY).isEqualTo(byteString);
   }
 
+  @Test
   public void testNewOutput_Mutating() throws IOException {
     Output os = ByteString.newOutput(5);
     os.write(new byte[] {1, 2, 3, 4, 5});
@@ -612,21 +659,23 @@
     byte[] oldValue = byteString.toByteArray();
     Arrays.fill(capturedArray, (byte) 0);
     byte[] newValue = byteString.toByteArray();
-    assertTrue(
-        "Output must not provide access to the underlying byte array",
-        Arrays.equals(oldValue, newValue));
+    assertWithMessage("Output must not provide access to the underlying byte array")
+        .that(Arrays.equals(oldValue, newValue))
+        .isTrue();
   }
 
+  @Test
   public void testNewCodedBuilder() throws IOException {
     byte[] bytes = getTestBytes();
     ByteString.CodedBuilder builder = ByteString.newCodedBuilder(bytes.length);
     builder.getCodedOutput().writeRawBytes(bytes);
     ByteString byteString = builder.build();
-    assertTrue(
-        "String built from newCodedBuilder() must contain the expected bytes",
-        isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+    assertWithMessage("String built from newCodedBuilder() must contain the expected bytes")
+        .that(isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length))
+        .isTrue();
   }
 
+  @Test
   public void testSubstringParity() {
     byte[] bigBytes = getTestBytes(2048 * 1024, 113344L);
     int start = 512 * 1024 - 3333;
@@ -636,16 +685,18 @@
     for (int i = start; ok && i < end; ++i) {
       ok = (bigBytes[i] == concreteSubstring.byteAt(i - start));
     }
-    assertTrue("Concrete substring didn't capture the right bytes", ok);
+    assertWithMessage("Concrete substring didn't capture the right bytes").that(ok).isTrue();
 
     ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start);
-    assertEquals("Substring must be equal to literal string", literalString, concreteSubstring);
-    assertEquals(
-        "Substring must have same hashcode as literal string",
-        literalString.hashCode(),
-        concreteSubstring.hashCode());
+    assertWithMessage("Substring must be equal to literal string")
+        .that(literalString)
+        .isEqualTo(concreteSubstring);
+    assertWithMessage("Substring must have same hashcode as literal string")
+        .that(literalString.hashCode())
+        .isEqualTo(concreteSubstring.hashCode());
   }
 
+  @Test
   public void testCompositeSubstring() {
     byte[] referenceBytes = getTestBytes(77748, 113344L);
 
@@ -660,34 +711,32 @@
     for (int i = 0; stillEqual && i < to - from; ++i) {
       stillEqual = referenceBytes[from + i] == substringBytes[i];
     }
-    assertTrue("Substring must return correct bytes", stillEqual);
+    assertWithMessage("Substring must return correct bytes").that(stillEqual).isTrue();
 
     stillEqual = true;
     for (int i = 0; stillEqual && i < to - from; ++i) {
       stillEqual = referenceBytes[from + i] == compositeSubstring.byteAt(i);
     }
-    assertTrue("Substring must support byteAt() correctly", stillEqual);
+    assertWithMessage("Substring must support byteAt() correctly").that(stillEqual).isTrue();
 
     ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to - from);
-    assertEquals(
-        "Composite substring must equal a literal substring over the same bytes",
-        literalSubstring,
-        compositeSubstring);
-    assertEquals(
-        "Literal substring must equal a composite substring over the same bytes",
-        compositeSubstring,
-        literalSubstring);
+    assertWithMessage("Composite substring must equal a literal substring over the same bytes")
+        .that(literalSubstring)
+        .isEqualTo(compositeSubstring);
+    assertWithMessage("Literal substring must equal a composite substring over the same bytes")
+        .that(compositeSubstring)
+        .isEqualTo(literalSubstring);
 
-    assertEquals(
-        "We must get the same hashcodes for composite and literal substrings",
-        literalSubstring.hashCode(),
-        compositeSubstring.hashCode());
+    assertWithMessage("We must get the same hashcodes for composite and literal substrings")
+        .that(literalSubstring.hashCode())
+        .isEqualTo(compositeSubstring.hashCode());
 
-    assertFalse(
-        "We can't be equal to a proper substring",
-        compositeSubstring.equals(literalSubstring.substring(0, literalSubstring.size() - 1)));
+    assertWithMessage("We can't be equal to a proper substring")
+        .that(compositeSubstring.equals(literalSubstring.substring(0, literalSubstring.size() - 1)))
+        .isFalse();
   }
 
+  @Test
   public void testCopyFromList() {
     byte[] referenceBytes = getTestBytes(77748, 113344L);
     ByteString literalString = ByteString.copyFrom(referenceBytes);
@@ -695,13 +744,15 @@
     List<ByteString> pieces = makeConcretePieces(referenceBytes);
     ByteString listString = ByteString.copyFrom(pieces);
 
-    assertEquals("Composite string must be equal to literal string", literalString, listString);
-    assertEquals(
-        "Composite string must have same hashcode as literal string",
-        literalString.hashCode(),
-        listString.hashCode());
+    assertWithMessage("Composite string must be equal to literal string")
+        .that(literalString)
+        .isEqualTo(listString);
+    assertWithMessage("Composite string must have same hashcode as literal string")
+        .that(literalString.hashCode())
+        .isEqualTo(listString.hashCode());
   }
 
+  @Test
   public void testConcat() {
     byte[] referenceBytes = getTestBytes(77748, 113344L);
     ByteString literalString = ByteString.copyFrom(referenceBytes);
@@ -714,18 +765,19 @@
       concatenatedString = concatenatedString.concat(iter.next());
     }
 
-    assertEquals(
-        "Concatenated string must be equal to literal string", literalString, concatenatedString);
-    assertEquals(
-        "Concatenated string must have same hashcode as literal string",
-        literalString.hashCode(),
-        concatenatedString.hashCode());
+    assertWithMessage("Concatenated string must be equal to literal string")
+        .that(literalString)
+        .isEqualTo(concatenatedString);
+    assertWithMessage("Concatenated string must have same hashcode as literal string")
+        .that(literalString.hashCode())
+        .isEqualTo(concatenatedString.hashCode());
   }
 
   /**
    * Test the Rope implementation can deal with Empty nodes, even though we guard against them. See
    * also {@link LiteralByteStringTest#testConcat_empty()}.
    */
+  @Test
   public void testConcat_empty() {
     byte[] referenceBytes = getTestBytes(7748, 113344L);
     ByteString literalString = ByteString.copyFrom(referenceBytes);
@@ -737,11 +789,12 @@
             RopeByteString.newInstanceForTest(ByteString.EMPTY, literalString));
     ByteString quintet = RopeByteString.newInstanceForTest(temp, ByteString.EMPTY);
 
-    assertEquals("String with concatenated nulls must equal simple concatenate", quintet, duo);
-    assertEquals(
-        "String with concatenated nulls have same hashcode as simple concatenate",
-        duo.hashCode(),
-        quintet.hashCode());
+    assertWithMessage("String with concatenated nulls must equal simple concatenate")
+        .that(quintet)
+        .isEqualTo(duo);
+    assertWithMessage("String with concatenated nulls have same hashcode as simple concatenate")
+        .that(duo.hashCode())
+        .isEqualTo(quintet.hashCode());
 
     ByteString.ByteIterator duoIter = duo.iterator();
     ByteString.ByteIterator quintetIter = quintet.iterator();
@@ -749,17 +802,17 @@
     while (stillEqual && quintetIter.hasNext()) {
       stillEqual = (duoIter.nextByte() == quintetIter.nextByte());
     }
-    assertTrue("We must get the same characters by iterating", stillEqual);
-    assertFalse("Iterator must be exhausted", duoIter.hasNext());
+    assertWithMessage("We must get the same characters by iterating").that(stillEqual).isTrue();
+    assertWithMessage("Iterator must be exhausted").that(duoIter.hasNext()).isFalse();
     try {
       duoIter.nextByte();
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NoSuchElementException e) {
       // This is success
     }
     try {
       quintetIter.nextByte();
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NoSuchElementException e) {
       // This is success
     }
@@ -771,45 +824,47 @@
     // It is possible, using the testing factory method to create deeply nested
     // trees of empty leaves, to make a string that will fail this test.
     for (int i = 1; i < duo.size(); ++i) {
-      assertTrue(
-          "Substrings of size() < 2 must not be RopeByteStrings",
-          duo.substring(i - 1, i) instanceof ByteString.LeafByteString);
+      assertWithMessage("Substrings of size() < 2 must not be RopeByteStrings")
+          .that(duo.substring(i - 1, i) instanceof ByteString.LeafByteString)
+          .isTrue();
     }
     for (int i = 1; i < quintet.size(); ++i) {
-      assertTrue(
-          "Substrings of size() < 2 must not be RopeByteStrings",
-          quintet.substring(i - 1, i) instanceof ByteString.LeafByteString);
+      assertWithMessage("Substrings of size() < 2 must not be RopeByteStrings")
+          .that(quintet.substring(i - 1, i) instanceof ByteString.LeafByteString)
+          .isTrue();
     }
   }
 
+  @Test
   public void testStartsWith() {
     byte[] bytes = getTestBytes(1000, 1234L);
     ByteString string = ByteString.copyFrom(bytes);
     ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
     ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
-    assertTrue(string.startsWith(ByteString.EMPTY));
-    assertTrue(string.startsWith(string));
-    assertTrue(string.startsWith(prefix));
-    assertFalse(string.startsWith(suffix));
-    assertFalse(prefix.startsWith(suffix));
-    assertFalse(suffix.startsWith(prefix));
-    assertFalse(ByteString.EMPTY.startsWith(prefix));
-    assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY));
+    assertThat(string.startsWith(ByteString.EMPTY)).isTrue();
+    assertThat(string.startsWith(string)).isTrue();
+    assertThat(string.startsWith(prefix)).isTrue();
+    assertThat(string.startsWith(suffix)).isFalse();
+    assertThat(prefix.startsWith(suffix)).isFalse();
+    assertThat(suffix.startsWith(prefix)).isFalse();
+    assertThat(ByteString.EMPTY.startsWith(prefix)).isFalse();
+    assertThat(ByteString.EMPTY.startsWith(ByteString.EMPTY)).isTrue();
   }
 
+  @Test
   public void testEndsWith() {
     byte[] bytes = getTestBytes(1000, 1234L);
     ByteString string = ByteString.copyFrom(bytes);
     ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
     ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
-    assertTrue(string.endsWith(ByteString.EMPTY));
-    assertTrue(string.endsWith(string));
-    assertTrue(string.endsWith(suffix));
-    assertFalse(string.endsWith(prefix));
-    assertFalse(suffix.endsWith(prefix));
-    assertFalse(prefix.endsWith(suffix));
-    assertFalse(ByteString.EMPTY.endsWith(suffix));
-    assertTrue(ByteString.EMPTY.endsWith(ByteString.EMPTY));
+    assertThat(string.endsWith(ByteString.EMPTY)).isTrue();
+    assertThat(string.endsWith(string)).isTrue();
+    assertThat(string.endsWith(suffix)).isTrue();
+    assertThat(string.endsWith(prefix)).isFalse();
+    assertThat(suffix.endsWith(prefix)).isFalse();
+    assertThat(prefix.endsWith(suffix)).isFalse();
+    assertThat(ByteString.EMPTY.endsWith(suffix)).isFalse();
+    assertThat(ByteString.EMPTY.endsWith(ByteString.EMPTY)).isTrue();
   }
 
   static List<ByteString> makeConcretePieces(byte[] referenceBytes) {
@@ -832,6 +887,7 @@
     return output.toByteArray();
   }
 
+  @Test
   public void testWriteToOutputStream() throws Exception {
     // Choose a size large enough so when two ByteStrings are concatenated they
     // won't be merged into one byte array due to some optimizations.
@@ -842,8 +898,8 @@
     // Test LiteralByteString.writeTo(OutputStream,int,int)
     ByteString left = ByteString.wrap(data1);
     byte[] result = substringUsingWriteTo(left, 1, 1);
-    assertEquals(1, result.length);
-    assertEquals((byte) 11, result[0]);
+    assertThat(result).hasLength(1);
+    assertThat(result[0]).isEqualTo((byte) 11);
 
     byte[] data2 = new byte[dataSize];
     Arrays.fill(data2, 0, data1.length, (byte) 2);
@@ -852,27 +908,28 @@
     ByteString root = left.concat(right);
     // Make sure we are actually testing a RopeByteString with a simple tree
     // structure.
-    assertEquals(1, root.getTreeDepth());
+    assertThat(root.getTreeDepth()).isEqualTo(1);
     // Write parts of the left node.
     result = substringUsingWriteTo(root, 0, dataSize);
-    assertEquals(dataSize, result.length);
-    assertEquals((byte) 1, result[0]);
-    assertEquals((byte) 1, result[dataSize - 1]);
+    assertThat(result).hasLength(dataSize);
+    assertThat(result[0]).isEqualTo((byte) 1);
+    assertThat(result[dataSize - 1]).isEqualTo((byte) 1);
     // Write parts of the right node.
     result = substringUsingWriteTo(root, dataSize, dataSize);
-    assertEquals(dataSize, result.length);
-    assertEquals((byte) 2, result[0]);
-    assertEquals((byte) 2, result[dataSize - 1]);
+    assertThat(result).hasLength(dataSize);
+    assertThat(result[0]).isEqualTo((byte) 2);
+    assertThat(result[dataSize - 1]).isEqualTo((byte) 2);
     // Write a segment of bytes that runs across both nodes.
     result = substringUsingWriteTo(root, dataSize / 2, dataSize);
-    assertEquals(dataSize, result.length);
-    assertEquals((byte) 1, result[0]);
-    assertEquals((byte) 1, result[dataSize - dataSize / 2 - 1]);
-    assertEquals((byte) 2, result[dataSize - dataSize / 2]);
-    assertEquals((byte) 2, result[dataSize - 1]);
+    assertThat(result).hasLength(dataSize);
+    assertThat(result[0]).isEqualTo((byte) 1);
+    assertThat(result[dataSize - dataSize / 2 - 1]).isEqualTo((byte) 1);
+    assertThat(result[dataSize - dataSize / 2]).isEqualTo((byte) 2);
+    assertThat(result[dataSize - 1]).isEqualTo((byte) 2);
   }
 
   /** Tests ByteString uses Arrays based byte copier when running under Hotstop VM. */
+  @Test
   public void testByteArrayCopier() throws Exception {
     if (Android.isOnAndroidDevice()) {
       return;
@@ -880,9 +937,9 @@
     Field field = ByteString.class.getDeclaredField("byteArrayCopier");
     field.setAccessible(true);
     Object byteArrayCopier = field.get(null);
-    assertNotNull(byteArrayCopier);
-    assertTrue(
-        byteArrayCopier.toString(),
-        byteArrayCopier.getClass().getSimpleName().endsWith("ArraysByteArrayCopier"));
+    assertThat(byteArrayCopier).isNotNull();
+    assertWithMessage(byteArrayCopier.toString())
+        .that(byteArrayCopier.getClass().getSimpleName().endsWith("ArraysByteArrayCopier"))
+        .isTrue();
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/CachedFieldSizeTest.java b/java/core/src/test/java/com/google/protobuf/CachedFieldSizeTest.java
index 96319d9..dc0ceb6 100644
--- a/java/core/src/test/java/com/google/protobuf/CachedFieldSizeTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CachedFieldSizeTest.java
@@ -30,7 +30,7 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
 
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import proto3_unittest.UnittestProto3;
@@ -59,7 +59,7 @@
     byte[] data3 = message.getProto3Child().toByteArray();
 
     // Make sure the serialized data is correct.
-    assertEquals(message.getProto2Child(), TestPackedTypes.parseFrom(data2));
-    assertEquals(message.getProto3Child(), UnittestProto3.TestPackedTypes.parseFrom(data3));
+    assertThat(TestPackedTypes.parseFrom(data2)).isEqualTo(message.getProto2Child());
+    assertThat(UnittestProto3.TestPackedTypes.parseFrom(data3)).isEqualTo(message.getProto3Child());
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
index e276225..458529c 100644
--- a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
@@ -30,97 +30,112 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import proto2_test_check_utf8.TestCheckUtf8.BytesWrapper;
 import proto2_test_check_utf8.TestCheckUtf8.StringWrapper;
 import proto2_test_check_utf8_size.TestCheckUtf8Size.BytesWrapperSize;
 import proto2_test_check_utf8_size.TestCheckUtf8Size.StringWrapperSize;
 import java.io.ByteArrayInputStream;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Test that protos generated with file option java_string_check_utf8 do in fact perform appropriate
  * UTF-8 checks.
- *
- * @author [email protected] (Jacob Butcher)
  */
-public class CheckUtf8Test extends TestCase {
+@RunWith(JUnit4.class)
+public class CheckUtf8Test {
 
   private static final String UTF8_BYTE_STRING_TEXT = "some text";
   private static final ByteString UTF8_BYTE_STRING = ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT);
   private static final ByteString NON_UTF8_BYTE_STRING =
       ByteString.copyFrom(new byte[] {(byte) 0x80}); // A lone continuation byte.
 
+  @Test
   public void testBuildRequiredStringWithGoodUtf8() throws Exception {
-    assertEquals(
-        UTF8_BYTE_STRING_TEXT, StringWrapper.newBuilder().setReqBytes(UTF8_BYTE_STRING).getReq());
+    assertThat(StringWrapper.newBuilder().setReqBytes(UTF8_BYTE_STRING).getReq())
+        .isEqualTo(UTF8_BYTE_STRING_TEXT);
   }
 
+  @Test
   public void testParseRequiredStringWithGoodUtf8() throws Exception {
     ByteString serialized =
         BytesWrapper.newBuilder().setReq(UTF8_BYTE_STRING).build().toByteString();
-    assertEquals(UTF8_BYTE_STRING_TEXT, StringWrapper.parser().parseFrom(serialized).getReq());
+    assertThat(StringWrapper.parser().parseFrom(serialized).getReq())
+        .isEqualTo(UTF8_BYTE_STRING_TEXT);
   }
 
+  @Test
   public void testBuildRequiredStringWithBadUtf8() throws Exception {
     try {
       StringWrapper.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+      assertWithMessage("Expected IllegalArgumentException for non UTF-8 byte string.").fail();
     } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Byte string is not UTF-8.");
     }
   }
 
+  @Test
   public void testBuildOptionalStringWithBadUtf8() throws Exception {
     try {
       StringWrapper.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+      assertWithMessage("Expected IllegalArgumentException for non UTF-8 byte string.").fail();
     } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Byte string is not UTF-8.");
     }
   }
 
+  @Test
   public void testBuildRepeatedStringWithBadUtf8() throws Exception {
     try {
       StringWrapper.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+      assertWithMessage("Expected IllegalArgumentException for non UTF-8 byte string.").fail();
     } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Byte string is not UTF-8.");
     }
   }
 
+  @Test
   public void testParseRequiredStringWithBadUtf8() throws Exception {
     byte[] serialized =
         BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteArray();
     assertParseBadUtf8(StringWrapper.getDefaultInstance(), serialized);
   }
 
+  @Test
   public void testBuildRequiredStringWithBadUtf8Size() throws Exception {
     try {
       StringWrapperSize.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+      assertWithMessage("Expected IllegalArgumentException for non UTF-8 byte string.").fail();
     } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Byte string is not UTF-8.");
     }
   }
 
+  @Test
   public void testBuildOptionalStringWithBadUtf8Size() throws Exception {
     try {
       StringWrapperSize.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+      assertWithMessage("Expected IllegalArgumentException for non UTF-8 byte string.").fail();
     } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Byte string is not UTF-8.");
     }
   }
 
+  @Test
   public void testBuildRepeatedStringWithBadUtf8Size() throws Exception {
     try {
       StringWrapperSize.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+      assertWithMessage("Expected IllegalArgumentException for non UTF-8 byte string.").fail();
     } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Byte string is not UTF-8.");
     }
   }
 
+  @Test
   public void testParseRequiredStringWithBadUtf8Size() throws Exception {
     byte[] serialized =
         BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteArray();
@@ -131,27 +146,31 @@
     // Check combinations of (parser vs. builder) x (byte[] vs. InputStream)
     try {
       defaultInstance.getParserForType().parseFrom(data);
-      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+      assertWithMessage("Expected InvalidProtocolBufferException for non UTF-8 byte string.")
+          .fail();
     } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Protocol message had invalid UTF-8.");
     }
     try {
       defaultInstance.newBuilderForType().mergeFrom(data);
-      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+      assertWithMessage("Expected InvalidProtocolBufferException for non UTF-8 byte string.")
+          .fail();
     } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Protocol message had invalid UTF-8.");
     }
     try {
       defaultInstance.getParserForType().parseFrom(new ByteArrayInputStream(data));
-      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+      assertWithMessage("Expected InvalidProtocolBufferException for non UTF-8 byte string.")
+          .fail();
     } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Protocol message had invalid UTF-8.");
     }
     try {
       defaultInstance.newBuilderForType().mergeFrom(new ByteArrayInputStream(data));
-      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+      assertWithMessage("Expected InvalidProtocolBufferException for non UTF-8 byte string.")
+          .fail();
     } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+      assertThat(exception).hasMessageThat().isEqualTo("Protocol message had invalid UTF-8.");
     }
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/CodedAdapterTest.java b/java/core/src/test/java/com/google/protobuf/CodedAdapterTest.java
index a24b48b..6f5bf0c 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedAdapterTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedAdapterTest.java
@@ -30,7 +30,7 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.protobuf.testing.Proto2Testing.Proto2Message;
 import com.google.protobuf.testing.Proto3Testing.Proto3Message;
@@ -57,14 +57,14 @@
 
     // Deserialize with BinaryReader and verify that the message matches the original.
     Proto3Message result = fromByteArray(expectedBytes, Proto3Message.class);
-    assertEquals(expected, result);
+    assertThat(result).isEqualTo(expected);
 
     // Now write it back out using BinaryWriter and verify the output length.
     byte[] actualBytes = toByteArray(result, expectedBytes.length);
 
     // Read back in the bytes and verify that it matches the original message.
     Proto3Message actual = Proto3Message.parseFrom(actualBytes);
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
   @Test
@@ -74,14 +74,14 @@
 
     // Deserialize with BinaryReader and verify that the message matches the original.
     Proto2Message result = fromByteArray(expectedBytes, Proto2Message.class);
-    assertEquals(expected, result);
+    assertThat(result).isEqualTo(expected);
 
     // Now write it back out using BinaryWriter and verify the output length.
     byte[] actualBytes = toByteArray(result, expectedBytes.length);
 
     // Read back in the bytes and verify that it matches the original message.
     Proto2Message actual = Proto2Message.parseFrom(actualBytes);
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
   public static <T> byte[] toByteArray(T msg, int size) throws Exception {
@@ -90,7 +90,7 @@
     CodedOutputStreamWriter writer =
         CodedOutputStreamWriter.forCodedOutput(CodedOutputStream.newInstance(out));
     schema.writeTo(msg, writer);
-    assertEquals(out.length, writer.getTotalBytesWritten());
+    assertThat(writer.getTotalBytesWritten()).isEqualTo(out.length);
     return out;
   }
 
diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
index 10d156e..f5bb31f 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static org.junit.Assert.assertArrayEquals;
 import protobuf_unittest.UnittestProto.BoolMessage;
 import protobuf_unittest.UnittestProto.Int32Message;
@@ -45,14 +47,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Unit test for {@link CodedInputStream}.
- *
- * @author [email protected] Kenton Varda
- */
-public class CodedInputStreamTest extends TestCase {
+/** Unit test for {@link CodedInputStream}. */
+@RunWith(JUnit4.class)
+public class CodedInputStreamTest {
 
   private static final int DEFAULT_BLOCK_SIZE = 4096;
 
@@ -179,8 +180,8 @@
 
   private void assertDataConsumed(String msg, byte[] data, CodedInputStream input)
       throws IOException {
-    assertEquals(msg, data.length, input.getTotalBytesRead());
-    assertTrue(msg, input.isAtEnd());
+    assertWithMessage(msg).that(data).hasLength(input.getTotalBytesRead());
+    assertWithMessage(msg).that(input.isAtEnd()).isTrue();
   }
 
   /**
@@ -192,19 +193,21 @@
       // 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());
+        assertWithMessage(inputType.name()).that(input.readRawVarint32()).isEqualTo((int) value);
         assertDataConsumed(inputType.name(), data, input);
 
         input = inputType.newDecoder(data, blockSize);
-        assertEquals(inputType.name(), value, input.readRawVarint64());
+        assertWithMessage(inputType.name()).that(input.readRawVarint64()).isEqualTo(value);
         assertDataConsumed(inputType.name(), data, input);
 
         input = inputType.newDecoder(data, blockSize);
-        assertEquals(inputType.name(), value, input.readRawVarint64SlowPath());
+        assertWithMessage(inputType.name()).that(input.readRawVarint64SlowPath()).isEqualTo(value);
         assertDataConsumed(inputType.name(), data, input);
 
         input = inputType.newDecoder(data, blockSize);
-        assertTrue(inputType.name(), input.skipField(WireFormat.WIRETYPE_VARINT));
+        assertWithMessage(inputType.name())
+            .that(input.skipField(WireFormat.WIRETYPE_VARINT))
+            .isTrue();
         assertDataConsumed(inputType.name(), data, input);
       }
     }
@@ -215,8 +218,8 @@
     byte[] longerData = new byte[data.length + 1];
     System.arraycopy(data, 0, longerData, 0, data.length);
     InputStream rawInput = new ByteArrayInputStream(longerData);
-    assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput));
-    assertEquals(1, rawInput.available());
+    assertThat(CodedInputStream.readRawVarint32(rawInput)).isEqualTo((int) value);
+    assertThat(rawInput.available()).isEqualTo(1);
   }
 
   /**
@@ -229,29 +232,36 @@
       try {
         CodedInputStream input = inputType.newDecoder(data);
         input.readRawVarint32();
-        fail(inputType.name() + ": Should have thrown an exception.");
+        assertWithMessage("%s: Should have thrown an exception.", inputType.name()).fail();
       } catch (InvalidProtocolBufferException e) {
-        assertEquals(inputType.name(), expected.getMessage(), e.getMessage());
+        assertWithMessage(inputType.name())
+            .that(e)
+            .hasMessageThat()
+            .isEqualTo(expected.getMessage());
       }
       try {
         CodedInputStream input = inputType.newDecoder(data);
         input.readRawVarint64();
-        fail(inputType.name() + ": Should have thrown an exception.");
+        assertWithMessage("%s: Should have thrown an exception.", inputType.name()).fail();
       } catch (InvalidProtocolBufferException e) {
-        assertEquals(inputType.name(), expected.getMessage(), e.getMessage());
+        assertWithMessage(inputType.name())
+            .that(e)
+            .hasMessageThat()
+            .isEqualTo(expected.getMessage());
       }
     }
 
     // Make sure we get the same error when reading direct from an InputStream.
     try {
       CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo(expected.getMessage());
     }
   }
 
   /** Tests readRawVarint32() and readRawVarint64(). */
+  @Test
   public void testReadVarint() throws Exception {
     assertReadVarint(bytes(0x00), 0);
     assertReadVarint(bytes(0x01), 1);
@@ -309,8 +319,8 @@
       // 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());
+        assertWithMessage(inputType.name()).that(input.readRawLittleEndian32()).isEqualTo(value);
+        assertWithMessage(inputType.name()).that(input.isAtEnd()).isTrue();
       }
     }
   }
@@ -324,13 +334,14 @@
       // 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());
+        assertWithMessage(inputType.name()).that(input.readRawLittleEndian64()).isEqualTo(value);
+        assertWithMessage(inputType.name()).that(input.isAtEnd()).isTrue();
       }
     }
   }
 
   /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
+  @Test
   public void testReadLittleEndian() throws Exception {
     assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
     assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
@@ -342,34 +353,36 @@
   }
 
   /** Test decodeZigZag32() and decodeZigZag64(). */
+  @Test
   public void testDecodeZigZag() throws Exception {
-    assertEquals(0, CodedInputStream.decodeZigZag32(0));
-    assertEquals(-1, CodedInputStream.decodeZigZag32(1));
-    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));
+    assertThat(CodedInputStream.decodeZigZag32(0)).isEqualTo(0);
+    assertThat(CodedInputStream.decodeZigZag32(1)).isEqualTo(-1);
+    assertThat(CodedInputStream.decodeZigZag32(2)).isEqualTo(1);
+    assertThat(CodedInputStream.decodeZigZag32(3)).isEqualTo(-2);
+    assertThat(CodedInputStream.decodeZigZag32(0x7FFFFFFE)).isEqualTo(0x3FFFFFFF);
+    assertThat(CodedInputStream.decodeZigZag32(0x7FFFFFFF)).isEqualTo(0xC0000000);
+    assertThat(CodedInputStream.decodeZigZag32(0xFFFFFFFE)).isEqualTo(0x7FFFFFFF);
+    assertThat(CodedInputStream.decodeZigZag32(0xFFFFFFFF)).isEqualTo(0x80000000);
 
-    assertEquals(0, CodedInputStream.decodeZigZag64(0));
-    assertEquals(-1, CodedInputStream.decodeZigZag64(1));
-    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));
+    assertThat(CodedInputStream.decodeZigZag64(0)).isEqualTo(0);
+    assertThat(CodedInputStream.decodeZigZag64(1)).isEqualTo(-1);
+    assertThat(CodedInputStream.decodeZigZag64(2)).isEqualTo(1);
+    assertThat(CodedInputStream.decodeZigZag64(3)).isEqualTo(-2);
+    assertThat(CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL)).isEqualTo(0x000000003FFFFFFFL);
+    assertThat(CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL)).isEqualTo(0xFFFFFFFFC0000000L);
+    assertThat(CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL)).isEqualTo(0x000000007FFFFFFFL);
+    assertThat(CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL)).isEqualTo(0xFFFFFFFF80000000L);
+    assertThat(CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL)).isEqualTo(0x7FFFFFFFFFFFFFFFL);
+    assertThat(CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL)).isEqualTo(0x8000000000000000L);
   }
 
   /** Tests reading and parsing a whole message with every field type. */
+  @Test
   public void testReadWholeMessage() throws Exception {
     TestAllTypes message = TestUtil.getAllSet();
 
     byte[] rawBytes = message.toByteArray();
-    assertEquals(rawBytes.length, message.getSerializedSize());
+    assertThat(rawBytes).hasLength(message.getSerializedSize());
 
     for (InputType inputType : InputType.values()) {
       // Try different block sizes.
@@ -381,6 +394,7 @@
   }
 
   /** Tests skipField(). */
+  @Test
   public void testSkipWholeMessage() throws Exception {
     TestAllTypes message = TestUtil.getAllSet();
     byte[] rawBytes = message.toByteArray();
@@ -397,7 +411,7 @@
       int tag = input1.readTag();
       // Ensure that the rest match.
       for (int i = 1; i < inputs.length; ++i) {
-        assertEquals(inputTypes[i].name(), tag, inputs[i].readTag());
+        assertWithMessage(inputTypes[i].name()).that(inputs[i].readTag()).isEqualTo(tag);
       }
       if (tag == 0) {
         break;
@@ -415,6 +429,7 @@
    * Test that a bug in skipRawBytes() has been fixed: if the skip skips exactly up to a limit, this
    * should not break things.
    */
+  @Test
   public void testSkipRawBytesBug() throws Exception {
     byte[] rawBytes = new byte[] {1, 2};
     for (InputType inputType : InputType.values()) {
@@ -422,7 +437,7 @@
       int limit = input.pushLimit(1);
       input.skipRawBytes(1);
       input.popLimit(limit);
-      assertEquals(inputType.name(), 2, input.readRawByte());
+      assertWithMessage(inputType.name()).that(input.readRawByte()).isEqualTo(2);
     }
   }
 
@@ -430,6 +445,7 @@
    * 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
   public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
     byte[] rawBytes = new byte[] {1, 2, 3, 4, 5};
     for (InputType inputType : InputType.values()) {
@@ -437,12 +453,12 @@
       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());
+      assertWithMessage(inputType.name()).that(input.readRawByte()).isEqualTo(1);
       // Skip to the end of the limit.
       input.skipRawBytes(3);
-      assertTrue(inputType.name(), input.isAtEnd());
+      assertWithMessage(inputType.name()).that(input.isAtEnd()).isTrue();
       input.popLimit(limit);
-      assertEquals(inputType.name(), 5, input.readRawByte());
+      assertWithMessage(inputType.name()).that(input.readRawByte()).isEqualTo(5);
     }
   }
 
@@ -450,15 +466,17 @@
    * Test that calling skipRawBytes (when not merging a message) actually skips from the underlying
    * inputstream, regardless of the buffer size used.
    */
+  @Test
   public void testSkipRawBytesActuallySkips() throws Exception {
     SmallBlockInputStream bytes = new SmallBlockInputStream(new byte[] {1, 2, 3, 4, 5}, 3);
     CodedInputStream input = CodedInputStream.newInstance(bytes, 1); // Tiny buffer
     input.skipRawBytes(3);
     input.skipRawBytes(2);
-    assertEquals(2, bytes.skipCalls);
-    assertEquals(0, bytes.readCalls);
+    assertThat(bytes.skipCalls).isEqualTo(2);
+    assertThat(bytes.readCalls).isEqualTo(0);
   }
 
+  @Test
   public void testSkipHugeBlob() throws Exception {
     // Allocate and initialize a 1MB blob.
     int blobSize = 1 << 20;
@@ -476,11 +494,13 @@
   }
 
   /** Skipping a huge blob should not allocate excessive memory, so there should be no limit */
+  @Test
   public void testSkipMaliciouslyHugeBlob() throws Exception {
     InputStream is = new RepeatingInputStream(new byte[]{1}, Integer.MAX_VALUE);
     CodedInputStream.newInstance(is).skipRawBytes(Integer.MAX_VALUE);
   }
 
+  @Test
   public void testReadHugeBlob() throws Exception {
     // Allocate and initialize a 1MB blob.
     byte[] blob = new byte[1 << 20];
@@ -501,7 +521,9 @@
       // reading.
       TestAllTypes message2 = TestAllTypes.parseFrom(inputType.newDecoder(data));
 
-      assertEquals(inputType.name(), message.getOptionalBytes(), message2.getOptionalBytes());
+      assertWithMessage(inputType.name())
+          .that(message.getOptionalBytes())
+          .isEqualTo(message2.getOptionalBytes());
 
       // Make sure all the other fields were parsed correctly.
       TestAllTypes message3 =
@@ -512,6 +534,7 @@
     }
   }
 
+  @Test
   public void testReadMaliciouslyLargeBlob() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
@@ -525,10 +548,10 @@
     byte[] data = rawOutput.toByteString().toByteArray();
     for (InputType inputType : InputType.values()) {
       CodedInputStream input = inputType.newDecoder(data);
-      assertEquals(tag, input.readTag());
+      assertThat(input.readTag()).isEqualTo(tag);
       try {
         input.readBytes();
-        fail(inputType.name() + ": Should have thrown an exception!");
+        assertWithMessage("%s: Should have thrown an exception!", inputType.name()).fail();
       } catch (InvalidProtocolBufferException e) {
         // success.
       }
@@ -541,6 +564,7 @@
    *
    * @throws IOException
    */
+  @Test
   public void testParseMessagesCloseTo2G() throws IOException {
     byte[] serializedMessage = getBigSerializedMessage();
     // How many of these big messages do we need to take us near our 2G limit?
@@ -558,6 +582,7 @@
    *
    * @throws IOException
    */
+  @Test
   public void testParseMessagesOver2G() throws IOException {
     byte[] serializedMessage = getBigSerializedMessage();
     // How many of these big messages do we need to take us near our 2G limit?
@@ -569,9 +594,9 @@
     InputStream is = new RepeatingInputStream(serializedMessage, count);
     try {
       TestAllTypes.parseFrom(is);
-      fail("Should have thrown an exception!");
+      assertWithMessage("Should have thrown an exception!").fail();
     } catch (InvalidProtocolBufferException e) {
-      assertTrue(e.getMessage().contains("too large"));
+      assertThat(e).hasMessageThat().contains("too large");
     }
   }
 
@@ -623,14 +648,15 @@
 
   private void assertMessageDepth(String msg, TestRecursiveMessage message, int depth) {
     if (depth == 0) {
-      assertFalse(msg, message.hasA());
-      assertEquals(msg, 5, message.getI());
+      assertWithMessage(msg).that(message.hasA()).isFalse();
+      assertWithMessage(msg).that(message.getI()).isEqualTo(5);
     } else {
-      assertTrue(msg, message.hasA());
+      assertWithMessage(msg).that(message.hasA()).isTrue();
       assertMessageDepth(msg, message.getA(), depth - 1);
     }
   }
 
+  @Test
   public void testMaliciousRecursion() throws Exception {
     byte[] data100 = makeRecursiveMessage(100).toByteArray();
     byte[] data101 = makeRecursiveMessage(101).toByteArray();
@@ -641,16 +667,17 @@
 
       try {
         TestRecursiveMessage.parseFrom(inputType.newDecoder(data101));
-        fail("Should have thrown an exception!");
+        assertWithMessage("Should have thrown an exception!").fail();
       } catch (InvalidProtocolBufferException e) {
         // success.
       }
 
+
       CodedInputStream input = inputType.newDecoder(data100);
       input.setRecursionLimit(8);
       try {
         TestRecursiveMessage.parseFrom(input);
-        fail(inputType.name() + ": Should have thrown an exception!");
+        assertWithMessage("%s: Should have thrown an exception!", inputType.name()).fail();
       } catch (InvalidProtocolBufferException e) {
         // success.
       }
@@ -658,9 +685,12 @@
   }
 
   private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
-    assertEquals(InvalidProtocolBufferException.sizeLimitExceeded().getMessage(), e.getMessage());
+    assertThat(e)
+        .hasMessageThat()
+        .isEqualTo(InvalidProtocolBufferException.sizeLimitExceeded().getMessage());
   }
 
+  @Test
   public void testSizeLimit() throws Exception {
     // NOTE: Size limit only applies to the stream-backed CIS.
     CodedInputStream input =
@@ -670,44 +700,46 @@
 
     try {
       TestAllTypes.parseFrom(input);
-      fail("Should have thrown an exception!");
+      assertWithMessage("Should have thrown an exception!").fail();
     } catch (InvalidProtocolBufferException expected) {
       checkSizeLimitExceeded(expected);
     }
   }
 
+  @Test
   public void testResetSizeCounter() throws Exception {
     // 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());
+    assertThat(input.getTotalBytesRead()).isEqualTo(16);
 
     try {
       input.readRawByte();
-      fail("Should have thrown an exception!");
+      assertWithMessage("Should have thrown an exception!").fail();
     } catch (InvalidProtocolBufferException expected) {
       checkSizeLimitExceeded(expected);
     }
 
     input.resetSizeCounter();
-    assertEquals(0, input.getTotalBytesRead());
+    assertThat(input.getTotalBytesRead()).isEqualTo(0);
     input.readRawByte(); // No exception thrown.
     input.resetSizeCounter();
-    assertEquals(0, input.getTotalBytesRead());
+    assertThat(input.getTotalBytesRead()).isEqualTo(0);
     input.readRawBytes(16);
-    assertEquals(16, input.getTotalBytesRead());
+    assertThat(input.getTotalBytesRead()).isEqualTo(16);
     input.resetSizeCounter();
 
     try {
       input.readRawBytes(17); // Hits limit again.
-      fail("Should have thrown an exception!");
+      assertWithMessage("Should have thrown an exception!").fail();
     } catch (InvalidProtocolBufferException expected) {
       checkSizeLimitExceeded(expected);
     }
   }
 
+  @Test
   public void testRefillBufferWithCorrectSize() throws Exception {
     // NOTE: refillBuffer only applies to the stream-backed CIS.
     byte[] bytes = "123456789".getBytes("UTF-8");
@@ -736,26 +768,28 @@
       input.readString();
       try {
         input.readRawByte(); // Hits limit.
-        fail("Should have thrown an exception!");
+        assertWithMessage("Should have thrown an exception!").fail();
       } catch (InvalidProtocolBufferException expected) {
         checkSizeLimitExceeded(expected);
       }
     }
   }
 
+  @Test
   public void testIsAtEnd() throws Exception {
     CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(new byte[5]));
     try {
       for (int i = 0; i < 5; i++) {
-        assertEquals(false, input.isAtEnd());
+        assertThat(input.isAtEnd()).isFalse();
         input.readRawByte();
       }
-      assertEquals(true, input.isAtEnd());
+      assertThat(input.isAtEnd()).isTrue();
     } catch (Exception e) {
       throw new AssertionError("Catch exception in the testIsAtEnd", e);
     }
   }
 
+  @Test
   public void testCurrentLimitExceeded() throws Exception {
     byte[] bytes = "123456789".getBytes("UTF-8");
     ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
@@ -776,13 +810,15 @@
     input.pushLimit(5);
     try {
       input.readString();
-      fail("Should have thrown an exception");
+      assertWithMessage("Should have thrown an exception").fail();
     } catch (InvalidProtocolBufferException expected) {
-      assertEquals(
-          expected.getMessage(), InvalidProtocolBufferException.truncatedMessage().getMessage());
+      assertThat(expected)
+          .hasMessageThat()
+          .isEqualTo(InvalidProtocolBufferException.truncatedMessage().getMessage());
     }
   }
 
+  @Test
   public void testSizeLimitMultipleMessages() throws Exception {
     // NOTE: Size limit only applies to the stream-backed CIS.
     byte[] bytes = new byte[256];
@@ -794,14 +830,15 @@
     for (int i = 0; i < 256 / 16; i++) {
       byte[] message = input.readRawBytes(16);
       for (int j = 0; j < message.length; j++) {
-        assertEquals(i * 16 + j, message[j] & 0xff);
+        assertThat(message[j] & 0xff).isEqualTo(i * 16 + j);
       }
-      assertEquals(16, input.getTotalBytesRead());
+      assertThat(input.getTotalBytesRead()).isEqualTo(16);
       input.resetSizeCounter();
-      assertEquals(0, input.getTotalBytesRead());
+      assertThat(input.getTotalBytesRead()).isEqualTo(0);
     }
   }
 
+  @Test
   public void testReadString() throws Exception {
     String lorem = "Lorem ipsum dolor sit amet ";
     StringBuilder builder = new StringBuilder();
@@ -822,12 +859,13 @@
     byte[] rawInput = rawOutput.toByteString().toByteArray();
     for (InputType inputType : InputType.values()) {
       CodedInputStream input = inputType.newDecoder(rawInput);
-      assertEquals(inputType.name(), tag, input.readTag());
+      assertWithMessage(inputType.name()).that(tag).isEqualTo(input.readTag());
       String text = input.readString();
-      assertEquals(inputType.name(), lorem, text);
+      assertWithMessage(inputType.name()).that(lorem).isEqualTo(text);
     }
   }
 
+  @Test
   public void testReadStringRequireUtf8() throws Exception {
     String lorem = "Lorem ipsum dolor sit amet ";
     StringBuilder builder = new StringBuilder();
@@ -848,9 +886,9 @@
     byte[] rawInput = rawOutput.toByteString().toByteArray();
     for (InputType inputType : InputType.values()) {
       CodedInputStream input = inputType.newDecoder(rawInput);
-      assertEquals(inputType.name(), tag, input.readTag());
+      assertWithMessage(inputType.name()).that(tag).isEqualTo(input.readTag());
       String text = input.readStringRequireUtf8();
-      assertEquals(inputType.name(), lorem, text);
+      assertWithMessage(inputType.name()).that(lorem).isEqualTo(text);
     }
   }
 
@@ -858,6 +896,7 @@
    * 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.
    */
+  @Test
   public void testReadStringInvalidUtf8() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
@@ -871,9 +910,9 @@
     byte[] rawInput = rawOutput.toByteString().toByteArray();
     for (InputType inputType : InputType.values()) {
       CodedInputStream input = inputType.newDecoder(rawInput);
-      assertEquals(inputType.name(), tag, input.readTag());
+      assertWithMessage(inputType.name()).that(input.readTag()).isEqualTo(tag);
       String text = input.readString();
-      assertEquals(inputType.name(), 0xfffd, text.charAt(0));
+      assertWithMessage(inputType.name()).that(text.charAt(0)).isEqualTo(0xfffd);
     }
   }
 
@@ -881,6 +920,7 @@
    * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an InvalidProtocolBufferException
    * is thrown.
    */
+  @Test
   public void testReadStringRequireUtf8InvalidUtf8() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
@@ -894,30 +934,34 @@
     byte[] rawInput = rawOutput.toByteString().toByteArray();
     for (InputType inputType : InputType.values()) {
       CodedInputStream input = inputType.newDecoder(rawInput);
-      assertEquals(tag, input.readTag());
+      assertThat(input.readTag()).isEqualTo(tag);
       try {
         input.readStringRequireUtf8();
-        fail(inputType.name() + ": Expected invalid UTF-8 exception.");
+        assertWithMessage("%s: Expected invalid UTF-8 exception.", inputType.name()).fail();
       } catch (InvalidProtocolBufferException exception) {
-        assertEquals(
-            inputType.name(), "Protocol message had invalid UTF-8.", exception.getMessage());
+        assertWithMessage(inputType.name())
+            .that(exception)
+            .hasMessageThat()
+            .isEqualTo("Protocol message had invalid UTF-8.");
       }
     }
   }
 
+  @Test
   public void testReadFromSlice() throws Exception {
     byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
     CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
-    assertEquals(0, in.getTotalBytesRead());
+    assertThat(in.getTotalBytesRead()).isEqualTo(0);
     for (int i = 3; i < 8; i++) {
-      assertEquals(i, in.readRawByte());
-      assertEquals(i - 2, in.getTotalBytesRead());
+      assertThat(in.readRawByte()).isEqualTo(i);
+      assertThat(in.getTotalBytesRead()).isEqualTo(i - 2);
     }
     // eof
-    assertEquals(0, in.readTag());
-    assertEquals(5, in.getTotalBytesRead());
+    assertThat(in.readTag()).isEqualTo(0);
+    assertThat(in.getTotalBytesRead()).isEqualTo(5);
   }
 
+  @Test
   public void testInvalidTag() throws Exception {
     // Any tag number which corresponds to field number zero is invalid and
     // should throw InvalidProtocolBufferException.
@@ -925,17 +969,18 @@
       for (int i = 0; i < 8; i++) {
         try {
           inputType.newDecoder(bytes(i)).readTag();
-          fail(inputType.name() + ": Should have thrown an exception.");
+          assertWithMessage("%s: Should have thrown an exception.", inputType.name()).fail();
         } catch (InvalidProtocolBufferException e) {
-          assertEquals(
-              inputType.name(),
-              InvalidProtocolBufferException.invalidTag().getMessage(),
-              e.getMessage());
+          assertWithMessage(inputType.name())
+              .that(e)
+              .hasMessageThat()
+              .isEqualTo(InvalidProtocolBufferException.invalidTag().getMessage());
         }
       }
     }
   }
 
+  @Test
   public void testReadByteArray() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
@@ -962,20 +1007,21 @@
       CodedInputStream inputStream = inputType.newDecoder(rawInput);
 
       byte[] result = inputStream.readByteArray();
-      assertEquals(inputType.name(), 0, result.length);
+      assertWithMessage(inputType.name()).that(result).isEmpty();
       result = inputStream.readByteArray();
-      assertEquals(inputType.name(), 1, result.length);
-      assertEquals(inputType.name(), (byte) 23, result[0]);
+      assertWithMessage(inputType.name()).that(result).hasLength(1);
+      assertWithMessage(inputType.name()).that(result[0]).isEqualTo((byte) 23);
       result = inputStream.readByteArray();
-      assertEquals(inputType.name(), 1, result.length);
-      assertEquals(inputType.name(), (byte) 45, result[0]);
+      assertWithMessage(inputType.name()).that(result).hasLength(1);
+      assertWithMessage(inputType.name()).that(result[0]).isEqualTo((byte) 45);
       result = inputStream.readByteArray();
-      assertEquals(inputType.name(), bytesLength, result.length);
-      assertEquals(inputType.name(), (byte) 67, result[0]);
-      assertEquals(inputType.name(), (byte) 89, result[bytesLength - 1]);
+      assertWithMessage(inputType.name()).that(result).hasLength(bytesLength);
+      assertWithMessage(inputType.name()).that(result[0]).isEqualTo((byte) 67);
+      assertWithMessage(inputType.name()).that(result[bytesLength - 1]).isEqualTo((byte) 89);
     }
   }
 
+  @Test
   public void testReadLargeByteStringFromInputStream() throws Exception {
     byte[] bytes = new byte[1024 * 1024];
     for (int i = 0; i < bytes.length; i++) {
@@ -997,9 +1043,10 @@
               }
             });
     ByteString result = input.readBytes();
-    assertEquals(ByteString.copyFrom(bytes), result);
+    assertThat(ByteString.copyFrom(bytes)).isEqualTo(result);
   }
 
+  @Test
   public void testReadLargeByteArrayFromInputStream() throws Exception {
     byte[] bytes = new byte[1024 * 1024];
     for (int i = 0; i < bytes.length; i++) {
@@ -1021,9 +1068,10 @@
               }
             });
     byte[] result = input.readByteArray();
-    assertTrue(Arrays.equals(bytes, result));
+    assertThat(Arrays.equals(bytes, result)).isTrue();
   }
 
+  @Test
   public void testReadByteBuffer() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
@@ -1050,21 +1098,22 @@
       CodedInputStream inputStream = inputType.newDecoder(rawInput);
 
       ByteBuffer result = inputStream.readByteBuffer();
-      assertEquals(inputType.name(), 0, result.capacity());
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(0);
       result = inputStream.readByteBuffer();
-      assertEquals(inputType.name(), 1, result.capacity());
-      assertEquals(inputType.name(), (byte) 23, result.get());
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(1);
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 23);
       result = inputStream.readByteBuffer();
-      assertEquals(inputType.name(), 1, result.capacity());
-      assertEquals(inputType.name(), (byte) 45, result.get());
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(1);
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 45);
       result = inputStream.readByteBuffer();
-      assertEquals(inputType.name(), bytesLength, result.capacity());
-      assertEquals(inputType.name(), (byte) 67, result.get());
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(bytesLength);
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 67);
       result.position(bytesLength - 1);
-      assertEquals(inputType.name(), (byte) 89, result.get());
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 89);
     }
   }
 
+  @Test
   public void testReadByteBufferAliasing() throws Exception {
     ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
     CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream);
@@ -1098,50 +1147,51 @@
       // Without aliasing
       CodedInputStream inputStream = inputType.newDecoder(data);
       ByteBuffer result = inputStream.readByteBuffer();
-      assertEquals(inputType.name(), 0, result.capacity());
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(0);
       result = inputStream.readByteBuffer();
-      assertTrue(inputType.name(), result.array() != data);
-      assertEquals(inputType.name(), 1, result.capacity());
-      assertEquals(inputType.name(), (byte) 23, result.get());
+      assertWithMessage(inputType.name()).that(result.array() != data).isTrue();
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(1);
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 23);
       result = inputStream.readByteBuffer();
-      assertTrue(inputType.name(), result.array() != data);
-      assertEquals(inputType.name(), 1, result.capacity());
-      assertEquals(inputType.name(), (byte) 45, result.get());
+      assertWithMessage(inputType.name()).that(result.array() != data).isTrue();
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(1);
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 45);
       result = inputStream.readByteBuffer();
-      assertTrue(inputType.name(), result.array() != data);
-      assertEquals(inputType.name(), bytesLength, result.capacity());
-      assertEquals(inputType.name(), (byte) 67, result.get());
+      assertWithMessage(inputType.name()).that(result.array() != data).isTrue();
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(bytesLength);
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 67);
       result.position(bytesLength - 1);
-      assertEquals(inputType.name(), (byte) 89, result.get());
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 89);
 
       // Enable aliasing
       inputStream = inputType.newDecoder(data, data.length);
       inputStream.enableAliasing(true);
       result = inputStream.readByteBuffer();
-      assertEquals(inputType.name(), 0, result.capacity());
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(0);
       result = inputStream.readByteBuffer();
       if (result.hasArray()) {
-        assertTrue(inputType.name(), result.array() == data);
+        assertWithMessage(inputType.name()).that(result.array() == data).isTrue();
       }
-      assertEquals(inputType.name(), 1, result.capacity());
-      assertEquals(inputType.name(), (byte) 23, result.get());
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(1);
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 23);
       result = inputStream.readByteBuffer();
       if (result.hasArray()) {
-        assertTrue(inputType.name(), result.array() == data);
+        assertWithMessage(inputType.name()).that(result.array() == data).isTrue();
       }
-      assertEquals(inputType.name(), 1, result.capacity());
-      assertEquals(inputType.name(), (byte) 45, result.get());
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(1);
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 45);
       result = inputStream.readByteBuffer();
       if (result.hasArray()) {
-        assertTrue(inputType.name(), result.array() == data);
+        assertWithMessage(inputType.name()).that(result.array() == data).isTrue();
       }
-      assertEquals(inputType.name(), bytesLength, result.capacity());
-      assertEquals(inputType.name(), (byte) 67, result.get());
+      assertWithMessage(inputType.name()).that(result.capacity()).isEqualTo(bytesLength);
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 67);
       result.position(bytesLength - 1);
-      assertEquals(inputType.name(), (byte) 89, result.get());
+      assertWithMessage(inputType.name()).that(result.get()).isEqualTo((byte) 89);
     }
   }
 
+  @Test
   public void testIterableByteBufferInputStreamReadBytesWithAlias() throws Exception {
     ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
     CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream);
@@ -1171,10 +1221,11 @@
 
     ByteString result = inputStream.readBytes();
     for (int i = 0; i < bytesLength; i++) {
-      assertEquals((byte) (i % 256), result.byteAt(i));
+      assertThat(result.byteAt(i)).isEqualTo((byte) (i % 256));
     }
   }
 
+  @Test
   public void testCompatibleTypes() throws Exception {
     long data = 0x100000000L;
     Int64Message message = Int64Message.newBuilder().setData(data).build();
@@ -1184,15 +1235,16 @@
 
       // Test int64(long) is compatible with bool(boolean)
       BoolMessage msg2 = BoolMessage.parseFrom(inputStream);
-      assertTrue(msg2.getData());
+      assertThat(msg2.getData()).isTrue();
 
       // Test int64(long) is compatible with int32(int)
       inputStream = inputType.newDecoder(serialized);
       Int32Message msg3 = Int32Message.parseFrom(inputStream);
-      assertEquals((int) data, msg3.getData());
+      assertThat(msg3.getData()).isEqualTo((int) data);
     }
   }
 
+  @Test
   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};
@@ -1200,13 +1252,14 @@
       try {
         CodedInputStream input = inputType.newDecoder(data);
         input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
-        fail(inputType.name() + ": Should have thrown an exception.");
+        assertWithMessage("%s: Should have thrown an exception.", inputType.name()).fail();
       } catch (InvalidProtocolBufferException e) {
         // Expected
       }
     }
   }
 
+  @Test
   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};
@@ -1214,22 +1267,24 @@
       try {
         CodedInputStream input = inputType.newDecoder(data);
         input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
-        fail(inputType.name() + ": Should have thrown an exception.");
+        assertWithMessage("%s: Should have thrown an exception.", inputType.name()).fail();
       } catch (InvalidProtocolBufferException e) {
         // Expected
       }
     }
   }
 
+  @Test
   public void testSkipPastEndOfByteArrayInput() throws Exception {
     try {
       CodedInputStream.newInstance(new ByteArrayInputStream(new byte[100])).skipRawBytes(101);
-      fail();
+      assertWithMessage("Should have thrown an exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Expected
     }
   }
 
+  @Test
   public void testMaliciousInputStream() throws Exception {
     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
     CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream);
@@ -1248,9 +1303,9 @@
 
     CodedInputStream codedInputStream = CodedInputStream.newInstance(inputStream, 1);
     ByteString byteString = codedInputStream.readBytes();
-    assertEquals(0x0, byteString.byteAt(0));
+    assertThat(byteString.byteAt(0)).isEqualTo(0x0);
     maliciousCapture.get(1)[0] = 0x9;
-    assertEquals(0x0, byteString.byteAt(0));
+    assertThat(byteString.byteAt(0)).isEqualTo(0x0);
 
     // test ByteBuffer
 
@@ -1258,10 +1313,9 @@
     maliciousCapture.clear();
     codedInputStream = CodedInputStream.newInstance(inputStream, 1);
     ByteBuffer byteBuffer = codedInputStream.readByteBuffer();
-    assertEquals(0x0, byteBuffer.get(0));
+    assertThat(byteBuffer.get(0)).isEqualTo(0x0);
     maliciousCapture.get(1)[0] = 0x9;
-    assertEquals(0x0, byteBuffer.get(0));
-
+    assertThat(byteBuffer.get(0)).isEqualTo(0x0);
 
     // test byte[]
 
@@ -1269,9 +1323,9 @@
     maliciousCapture.clear();
     codedInputStream = CodedInputStream.newInstance(inputStream, 1);
     byte[] byteArray = codedInputStream.readByteArray();
-    assertEquals(0x0, byteArray[0]);
+    assertThat(byteArray[0]).isEqualTo(0x0);
     maliciousCapture.get(1)[0] = 0x9;
-    assertEquals(0x9, byteArray[0]); // MODIFICATION! Should we fix?
+    assertThat(byteArray[0]).isEqualTo(0x9); // MODIFICATION! Should we fix?
 
     // test rawBytes
 
@@ -1280,11 +1334,12 @@
     codedInputStream = CodedInputStream.newInstance(inputStream, 1);
     int length = codedInputStream.readRawVarint32();
     byteArray = codedInputStream.readRawBytes(length);
-    assertEquals(0x0, byteArray[0]);
+    assertThat(byteArray[0]).isEqualTo(0x0);
     maliciousCapture.get(1)[0] = 0x9;
-    assertEquals(0x9, byteArray[0]); // MODIFICATION! Should we fix?
+    assertThat(byteArray[0]).isEqualTo(0x9); // MODIFICATION! Should we fix?
   }
 
+  @Test
   public void testInvalidInputYieldsInvalidProtocolBufferException_readTag() throws Exception {
     byte[] input = new byte[] {0x0a, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x77};
     CodedInputStream inputStream = CodedInputStream.newInstance(input);
@@ -1293,12 +1348,13 @@
       int size = inputStream.readRawVarint32();
       inputStream.pushLimit(size);
       inputStream.readTag();
-      fail();
+      assertWithMessage("Should have thrown an exception").fail();
     } catch (InvalidProtocolBufferException ex) {
       // Expected.
     }
   }
 
+  @Test
   public void testInvalidInputYieldsInvalidProtocolBufferException_readBytes() throws Exception {
     byte[] input =
         new byte[] {0x0a, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x67, 0x1a, 0x1a};
@@ -1308,7 +1364,7 @@
       int size = inputStream.readRawVarint32();
       inputStream.pushLimit(size);
       inputStream.readBytes();
-      fail();
+      assertWithMessage("Should have thrown an exception").fail();
     } catch (InvalidProtocolBufferException ex) {
       // Expected.
     }
diff --git a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
index 8dc3e4c..9934ca1 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.google.protobuf.CodedOutputStream.OutOfSpaceException;
 import protobuf_unittest.UnittestProto.SparseEnumMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes;
@@ -41,14 +44,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Unit test for {@link CodedOutputStream}.
- *
- * @author [email protected] Kenton Varda
- */
-public class CodedOutputStreamTest extends TestCase {
+/** Unit test for {@link CodedOutputStream}. */
+@RunWith(JUnit4.class)
+public class CodedOutputStreamTest {
   private interface Coder {
     CodedOutputStream stream();
 
@@ -224,6 +226,7 @@
   }
 
   /** Checks that invariants are maintained for varint round trip input and output. */
+  @Test
   public void testVarintRoundTrips() throws Exception {
     for (OutputType outputType : OutputType.values()) {
       assertVarintRoundTrip(outputType, 0L);
@@ -238,6 +241,7 @@
   }
 
   /** Tests writeRawVarint32() and writeRawVarint64(). */
+  @Test
   public void testWriteVarint() throws Exception {
     assertWriteVarint(bytes(0x00), 0);
     assertWriteVarint(bytes(0x01), 1);
@@ -281,6 +285,7 @@
   }
 
   /** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
+  @Test
   public void testWriteLittleEndian() throws Exception {
     assertWriteLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
     assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
@@ -292,50 +297,61 @@
   }
 
   /** Test encodeZigZag32() and encodeZigZag64(). */
+  @Test
   public void testEncodeZigZag() throws Exception {
-    assertEquals(0, CodedOutputStream.encodeZigZag32(0));
-    assertEquals(1, CodedOutputStream.encodeZigZag32(-1));
-    assertEquals(2, CodedOutputStream.encodeZigZag32(1));
-    assertEquals(3, CodedOutputStream.encodeZigZag32(-2));
-    assertEquals(0x7FFFFFFE, CodedOutputStream.encodeZigZag32(0x3FFFFFFF));
-    assertEquals(0x7FFFFFFF, CodedOutputStream.encodeZigZag32(0xC0000000));
-    assertEquals(0xFFFFFFFE, CodedOutputStream.encodeZigZag32(0x7FFFFFFF));
-    assertEquals(0xFFFFFFFF, CodedOutputStream.encodeZigZag32(0x80000000));
+    assertThat(CodedOutputStream.encodeZigZag32(0)).isEqualTo(0);
+    assertThat(CodedOutputStream.encodeZigZag32(-1)).isEqualTo(1);
+    assertThat(CodedOutputStream.encodeZigZag32(1)).isEqualTo(2);
+    assertThat(CodedOutputStream.encodeZigZag32(-2)).isEqualTo(3);
+    assertThat(CodedOutputStream.encodeZigZag32(0x3FFFFFFF)).isEqualTo(0x7FFFFFFE);
+    assertThat(CodedOutputStream.encodeZigZag32(0xC0000000)).isEqualTo(0x7FFFFFFF);
+    assertThat(CodedOutputStream.encodeZigZag32(0x7FFFFFFF)).isEqualTo(0xFFFFFFFE);
+    assertThat(CodedOutputStream.encodeZigZag32(0x80000000)).isEqualTo(0xFFFFFFFF);
 
-    assertEquals(0, CodedOutputStream.encodeZigZag64(0));
-    assertEquals(1, CodedOutputStream.encodeZigZag64(-1));
-    assertEquals(2, CodedOutputStream.encodeZigZag64(1));
-    assertEquals(3, CodedOutputStream.encodeZigZag64(-2));
-    assertEquals(0x000000007FFFFFFEL, CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL));
-    assertEquals(0x000000007FFFFFFFL, CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L));
-    assertEquals(0x00000000FFFFFFFEL, CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL));
-    assertEquals(0x00000000FFFFFFFFL, CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L));
-    assertEquals(0xFFFFFFFFFFFFFFFEL, CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL));
-    assertEquals(0xFFFFFFFFFFFFFFFFL, CodedOutputStream.encodeZigZag64(0x8000000000000000L));
+    assertThat(CodedOutputStream.encodeZigZag64(0)).isEqualTo(0);
+    assertThat(CodedOutputStream.encodeZigZag64(-1)).isEqualTo(1);
+    assertThat(CodedOutputStream.encodeZigZag64(1)).isEqualTo(2);
+    assertThat(CodedOutputStream.encodeZigZag64(-2)).isEqualTo(3);
+    assertThat(CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL))
+        .isEqualTo(0x000000007FFFFFFEL);
+    assertThat(CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L))
+        .isEqualTo(0x000000007FFFFFFFL);
+    assertThat(CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL))
+        .isEqualTo(0x00000000FFFFFFFEL);
+    assertThat(CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L))
+        .isEqualTo(0x00000000FFFFFFFFL);
+    assertThat(CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL))
+        .isEqualTo(0xFFFFFFFFFFFFFFFEL);
+    assertThat(CodedOutputStream.encodeZigZag64(0x8000000000000000L))
+        .isEqualTo(0xFFFFFFFFFFFFFFFFL);
 
     // Some easier-to-verify round-trip tests.  The inputs (other than 0, 1, -1)
     // were chosen semi-randomly via keyboard bashing.
-    assertEquals(0, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0)));
-    assertEquals(1, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1)));
-    assertEquals(-1, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1)));
-    assertEquals(14927, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927)));
-    assertEquals(-3612, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612)));
+    assertThat(CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0))).isEqualTo(0);
+    assertThat(CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1))).isEqualTo(1);
+    assertThat(CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1))).isEqualTo(-1);
+    assertThat(CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927)))
+        .isEqualTo(14927);
+    assertThat(CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612)))
+        .isEqualTo(-3612);
 
-    assertEquals(0, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0)));
-    assertEquals(1, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1)));
-    assertEquals(-1, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1)));
-    assertEquals(14927, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927)));
-    assertEquals(-3612, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612)));
+    assertThat(CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0))).isEqualTo(0);
+    assertThat(CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1))).isEqualTo(1);
+    assertThat(CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1))).isEqualTo(-1);
+    assertThat(CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927)))
+        .isEqualTo(14927);
+    assertThat(CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612)))
+        .isEqualTo(-3612);
 
-    assertEquals(
-        856912304801416L,
-        CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(856912304801416L)));
-    assertEquals(
-        -75123905439571256L,
-        CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-75123905439571256L)));
+    assertThat(CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(856912304801416L)))
+        .isEqualTo(856912304801416L);
+    assertThat(
+            CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-75123905439571256L)))
+        .isEqualTo(-75123905439571256L);
   }
 
   /** Tests writing a whole message with every field type. */
+  @Test
   public void testWriteWholeMessage() throws Exception {
     final byte[] expectedBytes = TestUtil.getGoldenMessage().toByteArray();
     TestAllTypes message = TestUtil.getAllSet();
@@ -361,6 +377,7 @@
    * Tests writing a whole message with every packed field type. Ensures the wire format of packed
    * fields is compatible with C++.
    */
+  @Test
   public void testWriteWholePackedFieldsMessage() throws Exception {
     byte[] expectedBytes = TestUtil.getGoldenPackedFieldsMessage().toByteArray();
     TestPackedTypes message = TestUtil.getPackedSet();
@@ -378,21 +395,23 @@
    * Test writing a message containing a negative enum value. This used to fail because the size was
    * not properly computed as a sign-extended varint.
    */
+  @Test
   public void testWriteMessageWithNegativeEnumValue() throws Exception {
     SparseEnumMessage message =
         SparseEnumMessage.newBuilder().setSparseEnum(TestSparseEnum.SPARSE_E).build();
-    assertTrue(message.getSparseEnum().getNumber() < 0);
+    assertThat(message.getSparseEnum().getNumber() < 0).isTrue();
     for (OutputType outputType : OutputType.values()) {
       Coder coder = outputType.newCoder(message.getSerializedSize());
       message.writeTo(coder.stream());
       coder.stream().flush();
       byte[] rawBytes = coder.toByteArray();
       SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
-      assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
+      assertThat(message2.getSparseEnum()).isEqualTo(TestSparseEnum.SPARSE_E);
     }
   }
 
   /** Test getTotalBytesWritten() */
+  @Test
   public void testGetTotalBytesWritten() throws Exception {
     Coder coder = OutputType.STREAM.newCoder(4 * 1024);
 
@@ -402,26 +421,29 @@
     for (int i = 0; i < 1024; ++i) {
       coder.stream().writeRawBytes(value, 0, value.length);
     }
-    assertEquals(value.length * 1024, coder.stream().getTotalBytesWritten());
+    assertThat(coder.stream().getTotalBytesWritten()).isEqualTo(value.length * 1024);
 
     // Now write an encoded string.
     String string =
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
     // Ensure we take the slower fast path.
-    assertTrue(
-        CodedOutputStream.computeUInt32SizeNoTag(string.length())
-            != CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
+    assertThat(
+            CodedOutputStream.computeUInt32SizeNoTag(string.length())
+                != CodedOutputStream.computeUInt32SizeNoTag(
+                    string.length() * Utf8.MAX_BYTES_PER_CHAR))
+        .isTrue();
 
     coder.stream().writeStringNoTag(string);
     coder.stream().flush();
     int stringSize = CodedOutputStream.computeStringSizeNoTag(string);
 
     // Verify that the total bytes written is correct
-    assertEquals((value.length * 1024) + stringSize, coder.stream().getTotalBytesWritten());
+    assertThat(coder.stream().getTotalBytesWritten()).isEqualTo((value.length * 1024) + stringSize);
   }
 
   // TODO(dweis): Write a comprehensive test suite for CodedOutputStream that covers more than just
   //    this case.
+  @Test
   public void testWriteStringNoTag_fastpath() throws Exception {
     int bufferSize = 153;
     String threeBytesPer = "\u0981";
@@ -430,10 +452,10 @@
       string += threeBytesPer;
     }
     // These checks ensure we will tickle the slower fast path.
-    assertEquals(1, CodedOutputStream.computeUInt32SizeNoTag(string.length()));
-    assertEquals(
-        2, CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
-    assertEquals(bufferSize, string.length() * Utf8.MAX_BYTES_PER_CHAR);
+    assertThat(CodedOutputStream.computeUInt32SizeNoTag(string.length())).isEqualTo(1);
+    assertThat(CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR))
+        .isEqualTo(2);
+    assertThat(bufferSize).isEqualTo(string.length() * Utf8.MAX_BYTES_PER_CHAR);
 
     for (OutputType outputType : OutputType.values()) {
       Coder coder = outputType.newCoder(bufferSize + 2);
@@ -442,6 +464,7 @@
     }
   }
 
+  @Test
   public void testWriteToByteBuffer() throws Exception {
     final int bufferSize = 16 * 1024;
     ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
@@ -462,19 +485,20 @@
     codedStream.flush();
 
     // Check that data is correctly written to the ByteBuffer.
-    assertEquals(0, buffer.remaining());
+    assertThat(buffer.remaining()).isEqualTo(0);
     buffer.flip();
     for (int i = 0; i < length1; i++) {
-      assertEquals((byte) 1, buffer.get());
+      assertThat(buffer.get()).isEqualTo((byte) 1);
     }
     for (int i = 0; i < length2; i++) {
-      assertEquals((byte) 2, buffer.get());
+      assertThat(buffer.get()).isEqualTo((byte) 2);
     }
     for (int i = 0; i < length3; i++) {
-      assertEquals((byte) 3, buffer.get());
+      assertThat(buffer.get()).isEqualTo((byte) 3);
     }
   }
 
+  @Test
   public void testWriteByteBuffer() throws Exception {
     byte[] value = "abcde".getBytes(Internal.UTF_8);
     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
@@ -484,31 +508,33 @@
     // ByteBuffer's capacity() is 5.
     codedStream.writeRawBytes(byteBuffer);
     // The above call shouldn't affect the ByteBuffer's state.
-    assertEquals(0, byteBuffer.position());
-    assertEquals(1, byteBuffer.limit());
+    assertThat(byteBuffer.position()).isEqualTo(0);
+    assertThat(byteBuffer.limit()).isEqualTo(1);
 
     // The correct way to write part of an array using ByteBuffer.
     codedStream.writeRawBytes(ByteBuffer.wrap(value, 2, 1).slice());
 
     codedStream.flush();
     byte[] result = outputStream.toByteArray();
-    assertEquals(6, result.length);
+    assertThat(result).hasLength(6);
     for (int i = 0; i < 5; i++) {
-      assertEquals(value[i], result[i]);
+      assertThat(value[i]).isEqualTo(result[i]);
     }
-    assertEquals(value[2], result[5]);
+    assertThat(value[2]).isEqualTo(result[5]);
   }
 
+  @Test
   public void testWriteByteArrayWithOffsets() throws Exception {
     byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
     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());
+      assertThat(coder.stream().getTotalBytesWritten()).isEqualTo(3);
     }
   }
 
+  @Test
   public void testSerializeUtf8_MultipleSmallWrites() throws Exception {
     final String source = "abcdefghijklmnopqrstuvwxyz";
 
@@ -533,6 +559,7 @@
     }
   }
 
+  @Test
   public void testSerializeInvalidUtf8() throws Exception {
     String[] invalidStrings =
         new String[] {
@@ -558,6 +585,7 @@
 
   // TODO(nathanmittler): This test can be deleted once we properly throw IOException while
   // encoding invalid UTF-8 strings.
+  @Test
   public void testSerializeInvalidUtf8FollowedByOutOfSpace() throws Exception {
     final int notEnoughBytes = 4;
     CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[notEnoughBytes]);
@@ -567,25 +595,25 @@
     String invalidString = newString(Character.MIN_HIGH_SURROGATE, 'f', 'o', 'o', 'b', 'a', 'r');
     try {
       outputWithArray.writeStringNoTag(invalidString);
-      fail("Expected OutOfSpaceException");
+      assertWithMessage("Expected OutOfSpaceException").fail();
     } catch (OutOfSpaceException e) {
-      assertTrue(e.getCause() instanceof IndexOutOfBoundsException);
+      assertThat(e).hasCauseThat().isInstanceOf(IndexOutOfBoundsException.class);
     }
     try {
       outputWithByteBuffer.writeStringNoTag(invalidString);
-      fail("Expected OutOfSpaceException");
+      assertWithMessage("Expected OutOfSpaceException").fail();
     } catch (OutOfSpaceException e) {
-      assertTrue(e.getCause() instanceof IndexOutOfBoundsException);
+      assertThat(e).hasCauseThat().isInstanceOf(IndexOutOfBoundsException.class);
     }
   }
 
   /** Regression test for https://github.com/protocolbuffers/protobuf/issues/292 */
+  @Test
   public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception {
     String testCase = "Foooooooo";
-    assertEquals(
-        CodedOutputStream.computeUInt32SizeNoTag(testCase.length()),
-        CodedOutputStream.computeUInt32SizeNoTag(testCase.length() * 3));
-    assertEquals(11, CodedOutputStream.computeStringSize(1, testCase));
+    assertThat(CodedOutputStream.computeUInt32SizeNoTag(testCase.length()))
+        .isEqualTo(CodedOutputStream.computeUInt32SizeNoTag(testCase.length() * 3));
+    assertThat(CodedOutputStream.computeStringSize(1, testCase)).isEqualTo(11);
     // 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 :
@@ -599,13 +627,14 @@
         Coder coder = outputType.newCoder(i);
         try {
           coder.stream().writeString(1, testCase);
-          fail("Should have thrown an out of space exception");
+          assertWithMessage("Should have thrown an out of space exception").fail();
         } catch (CodedOutputStream.OutOfSpaceException expected) {
         }
       }
     }
   }
 
+  @Test
   public void testDifferentStringLengths() throws Exception {
     // Test string serialization roundtrip using strings of the following lengths,
     // with ASCII and Unicode characters requiring different UTF-8 byte counts per
@@ -631,6 +660,7 @@
     }
   }
 
+  @Test
   public void testNioEncodersWithInitialOffsets() throws Exception {
     String value = "abc";
     for (Coder coder :
@@ -696,10 +726,9 @@
     Coder coder = outputType.newCoder(testAllTypes.getSerializedSize());
     testAllTypes.writeTo(coder.stream());
     coder.stream().flush();
-    assertEquals(
-        "OuputType: " + outputType,
-        fullString,
-        TestAllTypes.parseFrom(coder.toByteArray()).getOptionalString());
+    assertWithMessage("OuputType: " + outputType)
+        .that(fullString)
+        .isEqualTo(TestAllTypes.parseFrom(coder.toByteArray()).getOptionalString());
   }
 
   private static String fullString(char c, int length) {
@@ -730,7 +759,7 @@
   }
 
   private static void assertEqualBytes(OutputType outputType, byte[] a, byte[] b) {
-    assertEquals(outputType.name(), toList(a), toList(b));
+    assertWithMessage(outputType.name()).that(toList(a)).isEqualTo(toList(b));
   }
 
   /**
@@ -747,7 +776,7 @@
         assertEqualBytes(outputType, data, coder.toByteArray());
 
         // Also try computing size.
-        assertEquals(data.length, CodedOutputStream.computeUInt32SizeNoTag((int) value));
+        assertThat(data).hasLength(CodedOutputStream.computeUInt32SizeNoTag((int) value));
       }
 
       {
@@ -757,7 +786,7 @@
         assertEqualBytes(outputType, data, coder.toByteArray());
 
         // Also try computing size.
-        assertEquals(data.length, CodedOutputStream.computeUInt64SizeNoTag(value));
+        assertThat(data).hasLength(CodedOutputStream.computeUInt64SizeNoTag(value));
       }
     }
 
@@ -792,10 +821,11 @@
       coder.stream().writeUInt64NoTag(value);
       coder.stream().flush();
       byte[] bytes = coder.toByteArray();
-      assertEquals(
-          outputType.name(), bytes.length, CodedOutputStream.computeUInt64SizeNoTag(value));
+      assertWithMessage(outputType.name())
+          .that(bytes)
+          .hasLength(CodedOutputStream.computeUInt64SizeNoTag(value));
       CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
-      assertEquals(outputType.name(), value, input.readRawVarint64());
+      assertWithMessage(outputType.name()).that(input.readRawVarint64()).isEqualTo(value);
     }
 
     if (value == (int) value) {
@@ -803,10 +833,11 @@
       coder.stream().writeUInt32NoTag((int) value);
       coder.stream().flush();
       byte[] bytes = coder.toByteArray();
-      assertEquals(
-          outputType.name(), bytes.length, CodedOutputStream.computeUInt32SizeNoTag((int) value));
+      assertWithMessage(outputType.name())
+          .that(bytes)
+          .hasLength(CodedOutputStream.computeUInt32SizeNoTag((int) value));
       CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
-      assertEquals(outputType.name(), value, input.readRawVarint32());
+      assertWithMessage(outputType.name()).that(input.readRawVarint32()).isEqualTo(value);
     }
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
index 2addde8..fac6949 100644
--- a/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
@@ -30,47 +30,52 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import protobuf_unittest.UnittestProto.TestDeprecatedFields;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Method;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Test field deprecation
- *
- * @author [email protected] (Roberto Scaramuzzi)
- */
-public class DeprecatedFieldTest extends TestCase {
-  private String[] deprecatedGetterNames = {"hasDeprecatedInt32", "getDeprecatedInt32"};
+/** Test field deprecation. */
+@RunWith(JUnit4.class)
+public class DeprecatedFieldTest {
+  private final String[] deprecatedGetterNames = {"hasDeprecatedInt32", "getDeprecatedInt32"};
 
-  private String[] deprecatedBuilderGetterNames = {
+  private final String[] deprecatedBuilderGetterNames = {
     "hasDeprecatedInt32", "getDeprecatedInt32", "clearDeprecatedInt32"
   };
 
-  private String[] deprecatedBuilderSetterNames = {"setDeprecatedInt32"};
+  private final String[] deprecatedBuilderSetterNames = {"setDeprecatedInt32"};
 
+  @Test
   public void testDeprecatedField() throws Exception {
     Class<?> deprecatedFields = TestDeprecatedFields.class;
     Class<?> deprecatedFieldsBuilder = TestDeprecatedFields.Builder.class;
     for (String name : deprecatedGetterNames) {
       Method method = deprecatedFields.getMethod(name);
-      assertTrue("Method " + name + " should be deprecated", isDeprecated(method));
+      assertWithMessage("Method %s should be deprecated", name).that(isDeprecated(method)).isTrue();
     }
     for (String name : deprecatedBuilderGetterNames) {
       Method method = deprecatedFieldsBuilder.getMethod(name);
-      assertTrue("Method " + name + " should be deprecated", isDeprecated(method));
+      assertWithMessage("Method %s should be deprecated", name).that(isDeprecated(method)).isTrue();
     }
     for (String name : deprecatedBuilderSetterNames) {
       Method method = deprecatedFieldsBuilder.getMethod(name, int.class);
-      assertTrue("Method " + name + " should be deprecated", isDeprecated(method));
+      assertWithMessage("Method %s should be deprecated", name).that(isDeprecated(method)).isTrue();
     }
   }
 
+  @Test
   public void testDeprecatedFieldInOneof() throws Exception {
     Class<?> oneofCase = TestDeprecatedFields.OneofFieldsCase.class;
     String name = "DEPRECATED_INT32_IN_ONEOF";
     java.lang.reflect.Field enumValue = oneofCase.getField(name);
-    assertTrue("Enum value " + name + " should be deprecated.", isDeprecated(enumValue));
+    assertWithMessage("Enum value %s should be deprecated.", name)
+        .that(isDeprecated(enumValue))
+        .isTrue();
   }
 
   private boolean isDeprecated(AnnotatedElement annotated) {
diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index b98b332..6cb0bae 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -30,11 +30,9 @@
 
 package com.google.protobuf;
 
-import static junit.framework.TestCase.assertFalse;
-import static junit.framework.TestCase.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
-import protobuf_unittest.NestedExtension;
-import protobuf_unittest.NonNestedExtension;
 import com.google.protobuf.DescriptorProtos.DescriptorProto;
 import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
 import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
@@ -65,17 +63,17 @@
 import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto.TestReservedFields;
 import protobuf_unittest.UnittestProto.TestService;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import protobuf_unittest.NestedExtension;
+import protobuf_unittest.NonNestedExtension;
 
-/**
- * Unit test for {@link Descriptors}.
- *
- * @author [email protected] Kenton Varda
- */
-public class DescriptorsTest extends TestCase {
+/** Unit test for {@link Descriptors}. */
+@RunWith(JUnit4.class)
+public class DescriptorsTest {
 
   // Regression test for bug where referencing a FieldDescriptor.Type value
   // before a FieldDescriptorProto.Type value would yield a
@@ -83,110 +81,114 @@
   @SuppressWarnings("unused")
   private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
 
+  @Test
   public void testFieldTypeEnumMapping() throws Exception {
-    assertEquals(FieldDescriptor.Type.values().length, FieldDescriptorProto.Type.values().length);
+    assertThat(FieldDescriptor.Type.values()).hasLength(FieldDescriptorProto.Type.values().length);
     for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
       FieldDescriptorProto.Type protoType = type.toProto();
-      assertEquals("TYPE_" + type.name(), protoType.name());
-      assertEquals(type, FieldDescriptor.Type.valueOf(protoType));
+      assertThat(protoType.name()).isEqualTo("TYPE_" + type.name());
+      assertThat(FieldDescriptor.Type.valueOf(protoType)).isEqualTo(type);
     }
   }
 
+  @Test
   public void testFileDescriptor() throws Exception {
     FileDescriptor file = UnittestProto.getDescriptor();
 
-    assertEquals("google/protobuf/unittest.proto", file.getName());
-    assertEquals("protobuf_unittest", file.getPackage());
+    assertThat(file.getName()).isEqualTo("google/protobuf/unittest.proto");
+    assertThat(file.getPackage()).isEqualTo("protobuf_unittest");
+    assertThat(file.getOptions().getJavaOuterClassname()).isEqualTo("UnittestProto");
+    assertThat(file.toProto().getName()).isEqualTo("google/protobuf/unittest.proto");
 
-    assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
-    assertEquals("google/protobuf/unittest.proto", file.toProto().getName());
-
-    assertEquals(Arrays.asList(UnittestImport.getDescriptor()), file.getDependencies());
+    assertThat(file.getDependencies()).containsExactly(UnittestImport.getDescriptor());
 
     Descriptor messageType = TestAllTypes.getDescriptor();
-    assertEquals(messageType, file.getMessageTypes().get(0));
-    assertEquals(messageType, file.findMessageTypeByName("TestAllTypes"));
-    assertNull(file.findMessageTypeByName("NoSuchType"));
-    assertNull(file.findMessageTypeByName("protobuf_unittest.TestAllTypes"));
+    assertThat(file.getMessageTypes().get(0)).isEqualTo(messageType);
+    assertThat(file.findMessageTypeByName("TestAllTypes")).isEqualTo(messageType);
+    assertThat(file.findMessageTypeByName("NoSuchType")).isNull();
+    assertThat(file.findMessageTypeByName("protobuf_unittest.TestAllTypes")).isNull();
     for (int i = 0; i < file.getMessageTypes().size(); i++) {
-      assertEquals(i, file.getMessageTypes().get(i).getIndex());
+      assertThat(file.getMessageTypes().get(i).getIndex()).isEqualTo(i);
     }
 
     EnumDescriptor enumType = ForeignEnum.getDescriptor();
-    assertEquals(enumType, file.getEnumTypes().get(0));
-    assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
-    assertNull(file.findEnumTypeByName("NoSuchType"));
-    assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
-    assertEquals(
-        Arrays.asList(ImportEnum.getDescriptor(), ImportEnumForMap.getDescriptor()),
-        UnittestImport.getDescriptor().getEnumTypes());
+    assertThat(file.getEnumTypes().get(0)).isEqualTo(enumType);
+    assertThat(file.findEnumTypeByName("ForeignEnum")).isEqualTo(enumType);
+    assertThat(file.findEnumTypeByName("NoSuchType")).isNull();
+    assertThat(file.findEnumTypeByName("protobuf_unittest.ForeignEnum")).isNull();
+    assertThat(UnittestImport.getDescriptor().getEnumTypes())
+        .containsExactly(ImportEnum.getDescriptor(), ImportEnumForMap.getDescriptor())
+        .inOrder();
     for (int i = 0; i < file.getEnumTypes().size(); i++) {
-      assertEquals(i, file.getEnumTypes().get(i).getIndex());
+      assertThat(file.getEnumTypes().get(i).getIndex()).isEqualTo(i);
     }
 
     ServiceDescriptor service = TestService.getDescriptor();
-    assertEquals(service, file.getServices().get(0));
-    assertEquals(service, file.findServiceByName("TestService"));
-    assertNull(file.findServiceByName("NoSuchType"));
-    assertNull(file.findServiceByName("protobuf_unittest.TestService"));
-    assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getServices());
+    assertThat(file.getServices().get(0)).isEqualTo(service);
+    assertThat(file.findServiceByName("TestService")).isEqualTo(service);
+    assertThat(file.findServiceByName("NoSuchType")).isNull();
+    assertThat(file.findServiceByName("protobuf_unittest.TestService")).isNull();
+    assertThat(UnittestImport.getDescriptor().getServices()).isEqualTo(Collections.emptyList());
     for (int i = 0; i < file.getServices().size(); i++) {
-      assertEquals(i, file.getServices().get(i).getIndex());
+      assertThat(file.getServices().get(i).getIndex()).isEqualTo(i);
     }
 
     FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
-    assertEquals(extension, file.getExtensions().get(0));
-    assertEquals(extension, file.findExtensionByName("optional_int32_extension"));
-    assertNull(file.findExtensionByName("no_such_ext"));
-    assertNull(file.findExtensionByName("protobuf_unittest.optional_int32_extension"));
-    assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getExtensions());
+    assertThat(file.getExtensions().get(0)).isEqualTo(extension);
+    assertThat(file.findExtensionByName("optional_int32_extension")).isEqualTo(extension);
+    assertThat(file.findExtensionByName("no_such_ext")).isNull();
+    assertThat(file.findExtensionByName("protobuf_unittest.optional_int32_extension")).isNull();
+    assertThat(UnittestImport.getDescriptor().getExtensions()).isEqualTo(Collections.emptyList());
     for (int i = 0; i < file.getExtensions().size(); i++) {
-      assertEquals(i, file.getExtensions().get(i).getIndex());
+      assertThat(file.getExtensions().get(i).getIndex()).isEqualTo(i);
     }
   }
 
+  @Test
   public void testDescriptor() throws Exception {
     Descriptor messageType = TestAllTypes.getDescriptor();
     Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
 
-    assertEquals("TestAllTypes", messageType.getName());
-    assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
-    assertNull(messageType.getContainingType());
-    assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(), messageType.getOptions());
-    assertEquals("TestAllTypes", messageType.toProto().getName());
+    assertThat(messageType.getName()).isEqualTo("TestAllTypes");
+    assertThat(messageType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes");
+    assertThat(messageType.getFile()).isEqualTo(UnittestProto.getDescriptor());
+    assertThat(messageType.getContainingType()).isNull();
+    assertThat(messageType.getOptions())
+        .isEqualTo(DescriptorProtos.MessageOptions.getDefaultInstance());
+    assertThat(messageType.toProto().getName()).isEqualTo("TestAllTypes");
 
-    assertEquals("NestedMessage", nestedType.getName());
-    assertEquals("protobuf_unittest.TestAllTypes.NestedMessage", nestedType.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
-    assertEquals(messageType, nestedType.getContainingType());
+    assertThat(nestedType.getName()).isEqualTo("NestedMessage");
+    assertThat(nestedType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes.NestedMessage");
+    assertThat(nestedType.getFile()).isEqualTo(UnittestProto.getDescriptor());
+    assertThat(nestedType.getContainingType()).isEqualTo(messageType);
 
     FieldDescriptor field = messageType.getFields().get(0);
-    assertEquals("optional_int32", field.getName());
-    assertEquals(field, messageType.findFieldByName("optional_int32"));
-    assertNull(messageType.findFieldByName("no_such_field"));
-    assertEquals(field, messageType.findFieldByNumber(1));
-    assertNull(messageType.findFieldByNumber(571283));
+    assertThat(field.getName()).isEqualTo("optional_int32");
+    assertThat(messageType.findFieldByName("optional_int32")).isEqualTo(field);
+    assertThat(messageType.findFieldByName("no_such_field")).isNull();
+    assertThat(messageType.findFieldByNumber(1)).isEqualTo(field);
+    assertThat(messageType.findFieldByNumber(571283)).isNull();
     for (int i = 0; i < messageType.getFields().size(); i++) {
-      assertEquals(i, messageType.getFields().get(i).getIndex());
+      assertThat(messageType.getFields().get(i).getIndex()).isEqualTo(i);
     }
 
-    assertEquals(nestedType, messageType.getNestedTypes().get(0));
-    assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
-    assertNull(messageType.findNestedTypeByName("NoSuchType"));
+    assertThat(messageType.getNestedTypes().get(0)).isEqualTo(nestedType);
+    assertThat(messageType.findNestedTypeByName("NestedMessage")).isEqualTo(nestedType);
+    assertThat(messageType.findNestedTypeByName("NoSuchType")).isNull();
     for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
-      assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
+      assertThat(messageType.getNestedTypes().get(i).getIndex()).isEqualTo(i);
     }
 
     EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
-    assertEquals(enumType, messageType.getEnumTypes().get(0));
-    assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
-    assertNull(messageType.findEnumTypeByName("NoSuchType"));
+    assertThat(messageType.getEnumTypes().get(0)).isEqualTo(enumType);
+    assertThat(messageType.findEnumTypeByName("NestedEnum")).isEqualTo(enumType);
+    assertThat(messageType.findEnumTypeByName("NoSuchType")).isNull();
     for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
-      assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
+      assertThat(messageType.getEnumTypes().get(i).getIndex()).isEqualTo(i);
     }
   }
 
+  @Test
   public void testFieldDescriptor() throws Exception {
     Descriptor messageType = TestAllTypes.getDescriptor();
     FieldDescriptor primitiveField = messageType.findFieldByName("optional_int32");
@@ -196,143 +198,154 @@
     FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
     FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
 
-    assertEquals("optional_int32", primitiveField.getName());
-    assertEquals("protobuf_unittest.TestAllTypes.optional_int32", primitiveField.getFullName());
-    assertEquals(1, primitiveField.getNumber());
-    assertEquals(messageType, primitiveField.getContainingType());
-    assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
-    assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
-    assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
-    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), primitiveField.getOptions());
-    assertFalse(primitiveField.isExtension());
-    assertEquals("optional_int32", primitiveField.toProto().getName());
+    assertThat(primitiveField.getName()).isEqualTo("optional_int32");
+    assertThat(primitiveField.getFullName())
+        .isEqualTo("protobuf_unittest.TestAllTypes.optional_int32");
+    assertThat(primitiveField.getNumber()).isEqualTo(1);
+    assertThat(primitiveField.getContainingType()).isEqualTo(messageType);
+    assertThat(primitiveField.getFile()).isEqualTo(UnittestProto.getDescriptor());
+    assertThat(primitiveField.getType()).isEqualTo(FieldDescriptor.Type.INT32);
+    assertThat(primitiveField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.INT);
+    assertThat(primitiveField.getOptions())
+        .isEqualTo(DescriptorProtos.FieldOptions.getDefaultInstance());
+    assertThat(primitiveField.isExtension()).isFalse();
+    assertThat(primitiveField.toProto().getName()).isEqualTo("optional_int32");
 
-    assertEquals("optional_nested_enum", enumField.getName());
-    assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
-    assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
-    assertEquals(TestAllTypes.NestedEnum.getDescriptor(), enumField.getEnumType());
+    assertThat(enumField.getName()).isEqualTo("optional_nested_enum");
+    assertThat(enumField.getType()).isEqualTo(FieldDescriptor.Type.ENUM);
+    assertThat(enumField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.ENUM);
+    assertThat(enumField.getEnumType()).isEqualTo(TestAllTypes.NestedEnum.getDescriptor());
 
-    assertEquals("optional_foreign_message", messageField.getName());
-    assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
-    assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
-    assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
+    assertThat(messageField.getName()).isEqualTo("optional_foreign_message");
+    assertThat(messageField.getType()).isEqualTo(FieldDescriptor.Type.MESSAGE);
+    assertThat(messageField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.MESSAGE);
+    assertThat(messageField.getMessageType()).isEqualTo(ForeignMessage.getDescriptor());
 
-    assertEquals("optional_cord", cordField.getName());
-    assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
-    assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
-    assertEquals(DescriptorProtos.FieldOptions.CType.CORD, cordField.getOptions().getCtype());
+    assertThat(cordField.getName()).isEqualTo("optional_cord");
+    assertThat(cordField.getType()).isEqualTo(FieldDescriptor.Type.STRING);
+    assertThat(cordField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.STRING);
+    assertThat(cordField.getOptions().getCtype())
+        .isEqualTo(DescriptorProtos.FieldOptions.CType.CORD);
 
-    assertEquals("optional_int32_extension", extension.getName());
-    assertEquals("protobuf_unittest.optional_int32_extension", extension.getFullName());
-    assertEquals(1, extension.getNumber());
-    assertEquals(TestAllExtensions.getDescriptor(), extension.getContainingType());
-    assertEquals(UnittestProto.getDescriptor(), extension.getFile());
-    assertEquals(FieldDescriptor.Type.INT32, extension.getType());
-    assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
-    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), extension.getOptions());
-    assertTrue(extension.isExtension());
-    assertEquals(null, extension.getExtensionScope());
-    assertEquals("optional_int32_extension", extension.toProto().getName());
+    assertThat(extension.getName()).isEqualTo("optional_int32_extension");
+    assertThat(extension.getFullName()).isEqualTo("protobuf_unittest.optional_int32_extension");
+    assertThat(extension.getNumber()).isEqualTo(1);
+    assertThat(extension.getContainingType()).isEqualTo(TestAllExtensions.getDescriptor());
+    assertThat(extension.getFile()).isEqualTo(UnittestProto.getDescriptor());
+    assertThat(extension.getType()).isEqualTo(FieldDescriptor.Type.INT32);
+    assertThat(extension.getJavaType()).isEqualTo(FieldDescriptor.JavaType.INT);
+    assertThat(extension.getOptions())
+        .isEqualTo(DescriptorProtos.FieldOptions.getDefaultInstance());
+    assertThat(extension.isExtension()).isTrue();
+    assertThat(extension.getExtensionScope()).isNull();
+    assertThat(extension.toProto().getName()).isEqualTo("optional_int32_extension");
 
-    assertEquals("single", nestedExtension.getName());
-    assertEquals("protobuf_unittest.TestRequired.single", nestedExtension.getFullName());
-    assertEquals(TestRequired.getDescriptor(), nestedExtension.getExtensionScope());
+    assertThat(nestedExtension.getName()).isEqualTo("single");
+    assertThat(nestedExtension.getFullName()).isEqualTo("protobuf_unittest.TestRequired.single");
+    assertThat(nestedExtension.getExtensionScope()).isEqualTo(TestRequired.getDescriptor());
   }
 
+  @Test
   public void testFieldDescriptorLabel() throws Exception {
     FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
     FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
     FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
 
-    assertTrue(requiredField.isRequired());
-    assertFalse(requiredField.isRepeated());
-    assertFalse(optionalField.isRequired());
-    assertFalse(optionalField.isRepeated());
-    assertFalse(repeatedField.isRequired());
-    assertTrue(repeatedField.isRepeated());
+    assertThat(requiredField.isRequired()).isTrue();
+    assertThat(requiredField.isRepeated()).isFalse();
+    assertThat(optionalField.isRequired()).isFalse();
+    assertThat(optionalField.isRepeated()).isFalse();
+    assertThat(repeatedField.isRequired()).isFalse();
+    assertThat(repeatedField.isRepeated()).isTrue();
   }
 
+  @Test
   public void testFieldDescriptorJsonName() throws Exception {
     FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
     FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
     FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
-    assertEquals("a", requiredField.getJsonName());
-    assertEquals("optionalInt32", optionalField.getJsonName());
-    assertEquals("repeatedInt32", repeatedField.getJsonName());
+    assertThat(requiredField.getJsonName()).isEqualTo("a");
+    assertThat(optionalField.getJsonName()).isEqualTo("optionalInt32");
+    assertThat(repeatedField.getJsonName()).isEqualTo("repeatedInt32");
   }
 
+  @Test
   public void testFieldDescriptorDefault() throws Exception {
     Descriptor d = TestAllTypes.getDescriptor();
-    assertFalse(d.findFieldByName("optional_int32").hasDefaultValue());
-    assertEquals(0, d.findFieldByName("optional_int32").getDefaultValue());
-    assertTrue(d.findFieldByName("default_int32").hasDefaultValue());
-    assertEquals(41, d.findFieldByName("default_int32").getDefaultValue());
+    assertThat(d.findFieldByName("optional_int32").hasDefaultValue()).isFalse();
+    assertThat(d.findFieldByName("optional_int32").getDefaultValue()).isEqualTo(0);
+    assertThat(d.findFieldByName("default_int32").hasDefaultValue()).isTrue();
+    assertThat(d.findFieldByName("default_int32").getDefaultValue()).isEqualTo(41);
 
     d = TestExtremeDefaultValues.getDescriptor();
-    assertEquals(
-        ByteString.copyFrom("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
-        d.findFieldByName("escaped_bytes").getDefaultValue());
-    assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
-    assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
+    assertThat(d.findFieldByName("escaped_bytes").getDefaultValue())
+        .isEqualTo(
+            ByteString.copyFrom(
+                "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)));
+    assertThat(d.findFieldByName("large_uint32").getDefaultValue()).isEqualTo(-1);
+    assertThat(d.findFieldByName("large_uint64").getDefaultValue()).isEqualTo(-1L);
   }
 
+  @Test
   public void testEnumDescriptor() throws Exception {
     EnumDescriptor enumType = ForeignEnum.getDescriptor();
     EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
 
-    assertEquals("ForeignEnum", enumType.getName());
-    assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
-    assertNull(enumType.getContainingType());
-    assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(), enumType.getOptions());
+    assertThat(enumType.getName()).isEqualTo("ForeignEnum");
+    assertThat(enumType.getFullName()).isEqualTo("protobuf_unittest.ForeignEnum");
+    assertThat(enumType.getFile()).isEqualTo(UnittestProto.getDescriptor());
+    assertThat(enumType.getContainingType()).isNull();
+    assertThat(enumType.getOptions()).isEqualTo(DescriptorProtos.EnumOptions.getDefaultInstance());
 
-    assertEquals("NestedEnum", nestedType.getName());
-    assertEquals("protobuf_unittest.TestAllTypes.NestedEnum", nestedType.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
-    assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
+    assertThat(nestedType.getName()).isEqualTo("NestedEnum");
+    assertThat(nestedType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes.NestedEnum");
+    assertThat(nestedType.getFile()).isEqualTo(UnittestProto.getDescriptor());
+    assertThat(nestedType.getContainingType()).isEqualTo(TestAllTypes.getDescriptor());
 
     EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
-    assertEquals(value, enumType.getValues().get(0));
-    assertEquals("FOREIGN_FOO", value.getName());
-    assertEquals("FOREIGN_FOO", value.toString());
-    assertEquals(4, value.getNumber());
-    assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
-    assertEquals(value, enumType.findValueByNumber(4));
-    assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
+    assertThat(enumType.getValues().get(0)).isEqualTo(value);
+    assertThat(value.getName()).isEqualTo("FOREIGN_FOO");
+    assertThat(value.toString()).isEqualTo("FOREIGN_FOO");
+    assertThat(value.getNumber()).isEqualTo(4);
+    assertThat(enumType.findValueByName("FOREIGN_FOO")).isEqualTo(value);
+    assertThat(enumType.findValueByNumber(4)).isEqualTo(value);
+    assertThat(enumType.findValueByName("NO_SUCH_VALUE")).isNull();
     for (int i = 0; i < enumType.getValues().size(); i++) {
-      assertEquals(i, enumType.getValues().get(i).getIndex());
+      assertThat(enumType.getValues().get(i).getIndex()).isEqualTo(i);
     }
   }
 
+  @Test
   public void testServiceDescriptor() throws Exception {
     ServiceDescriptor service = TestService.getDescriptor();
 
-    assertEquals("TestService", service.getName());
-    assertEquals("protobuf_unittest.TestService", service.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), service.getFile());
+    assertThat(service.getName()).isEqualTo("TestService");
+    assertThat(service.getFullName()).isEqualTo("protobuf_unittest.TestService");
+    assertThat(service.getFile()).isEqualTo(UnittestProto.getDescriptor());
 
 
     MethodDescriptor fooMethod = service.getMethods().get(0);
-    assertEquals("Foo", fooMethod.getName());
-    assertEquals(UnittestProto.FooRequest.getDescriptor(), fooMethod.getInputType());
-    assertEquals(UnittestProto.FooResponse.getDescriptor(), fooMethod.getOutputType());
-    assertEquals(fooMethod, service.findMethodByName("Foo"));
+    assertThat(fooMethod.getName()).isEqualTo("Foo");
+    assertThat(fooMethod.getInputType()).isEqualTo(UnittestProto.FooRequest.getDescriptor());
+    assertThat(fooMethod.getOutputType()).isEqualTo(UnittestProto.FooResponse.getDescriptor());
+    assertThat(service.findMethodByName("Foo")).isEqualTo(fooMethod);
 
     MethodDescriptor barMethod = service.getMethods().get(1);
-    assertEquals("Bar", barMethod.getName());
-    assertEquals(UnittestProto.BarRequest.getDescriptor(), barMethod.getInputType());
-    assertEquals(UnittestProto.BarResponse.getDescriptor(), barMethod.getOutputType());
-    assertEquals(barMethod, service.findMethodByName("Bar"));
+    assertThat(barMethod.getName()).isEqualTo("Bar");
+    assertThat(barMethod.getInputType()).isEqualTo(UnittestProto.BarRequest.getDescriptor());
+    assertThat(barMethod.getOutputType()).isEqualTo(UnittestProto.BarResponse.getDescriptor());
+    assertThat(service.findMethodByName("Bar")).isEqualTo(barMethod);
 
 
-    assertNull(service.findMethodByName("NoSuchMethod"));
+    assertThat(service.findMethodByName("NoSuchMethod")).isNull();
 
     for (int i = 0; i < service.getMethods().size(); i++) {
-      assertEquals(i, service.getMethods().get(i).getIndex());
+      assertThat(service.getMethods().get(i).getIndex()).isEqualTo(i);
     }
   }
 
 
+  @Test
   public void testCustomOptions() throws Exception {
     // Get the descriptor indirectly from a dependent proto class. This is to
     // ensure that when a proto class is loaded, custom options defined in its
@@ -342,80 +355,81 @@
             .findFieldByName("field")
             .getMessageType();
 
-    assertTrue(descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
-    assertEquals(
-        Integer.valueOf(-56),
-        descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
+    assertThat(descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1)).isTrue();
+    assertThat(descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1))
+        .isEqualTo(Integer.valueOf(-56));
 
     FieldDescriptor field = descriptor.findFieldByName("field1");
-    assertNotNull(field);
+    assertThat(field).isNotNull();
 
-    assertTrue(field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
-    assertEquals(
-        Long.valueOf(8765432109L),
-        field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
+    assertThat(field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1)).isTrue();
+    assertThat(field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1))
+        .isEqualTo(Long.valueOf(8765432109L));
 
     OneofDescriptor oneof = descriptor.getOneofs().get(0);
-    assertNotNull(oneof);
+    assertThat(oneof).isNotNull();
 
-    assertTrue(oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
-    assertEquals(
-        Integer.valueOf(-99), oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
+    assertThat(oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1)).isTrue();
+    assertThat(oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1))
+        .isEqualTo(Integer.valueOf(-99));
 
     EnumDescriptor enumType =
         UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
 
-    assertTrue(enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
-    assertEquals(
-        Integer.valueOf(-789), enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
+    assertThat(enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1)).isTrue();
+    assertThat(enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1))
+        .isEqualTo(Integer.valueOf(-789));
 
     ServiceDescriptor service = UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
 
-    assertTrue(service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
-    assertEquals(
-        Long.valueOf(-9876543210L),
-        service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
+    assertThat(service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1)).isTrue();
+    assertThat(service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1))
+        .isEqualTo(Long.valueOf(-9876543210L));
 
     MethodDescriptor method = service.findMethodByName("Foo");
-    assertNotNull(method);
+    assertThat(method).isNotNull();
 
-    assertTrue(method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
-    assertEquals(
-        UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
-        method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
+    assertThat(method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1)).isTrue();
+    assertThat(method.getOptions().getExtension(UnittestCustomOptions.methodOpt1))
+        .isEqualTo(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2);
   }
 
   /** Test that the FieldDescriptor.Type enum is the same as the WireFormat.FieldType enum. */
+  @Test
   public void testFieldTypeTablesMatch() throws Exception {
     FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
     WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
 
-    assertEquals(values1.length, values2.length);
+    assertThat(values1).hasLength(values2.length);
 
     for (int i = 0; i < values1.length; i++) {
-      assertEquals(values1[i].toString(), values2[i].toString());
+      assertThat(values1[i].toString()).isEqualTo(values2[i].toString());
     }
   }
 
   /** Test that the FieldDescriptor.JavaType enum is the same as the WireFormat.JavaType enum. */
+  @Test
   public void testJavaTypeTablesMatch() throws Exception {
     FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
     WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
 
-    assertEquals(values1.length, values2.length);
+    assertThat(values1).hasLength(values2.length);
 
     for (int i = 0; i < values1.length; i++) {
-      assertEquals(values1[i].toString(), values2[i].toString());
+      assertThat(values1[i].toString()).isEqualTo(values2[i].toString());
     }
   }
 
+  @Test
   public void testEnormousDescriptor() throws Exception {
     // The descriptor for this file is larger than 64k, yet it did not cause
     // a compiler error due to an over-long string literal.
-    assertTrue(UnittestEnormousDescriptor.getDescriptor().toProto().getSerializedSize() > 65536);
+    assertThat(UnittestEnormousDescriptor.getDescriptor().toProto().getSerializedSize())
+        .isGreaterThan(65536);
   }
 
   /** Tests that the DescriptorValidationException works as intended. */
+  @Test
   public void testDescriptorValidatorException() throws Exception {
     FileDescriptorProto fileDescriptorProto =
         FileDescriptorProto.newBuilder()
@@ -435,14 +449,14 @@
             .build();
     try {
       Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
-      fail("DescriptorValidationException expected");
+      assertWithMessage("DescriptorValidationException expected").fail();
     } catch (DescriptorValidationException e) {
       // Expected; check that the error message contains some useful hints
-      assertTrue(e.getMessage().indexOf("foo") != -1);
-      assertTrue(e.getMessage().indexOf("Foo") != -1);
-      assertTrue(e.getMessage().indexOf("invalid") != -1);
-      assertTrue(e.getCause() instanceof NumberFormatException);
-      assertTrue(e.getCause().getMessage().indexOf("invalid") != -1);
+      assertThat(e).hasMessageThat().contains("foo");
+      assertThat(e).hasMessageThat().contains("Foo");
+      assertThat(e).hasMessageThat().contains("invalid");
+      assertThat(e).hasCauseThat().isInstanceOf(NumberFormatException.class);
+      assertThat(e).hasCauseThat().hasMessageThat().contains("invalid");
     }
   }
 
@@ -450,6 +464,7 @@
    * Tests the translate/crosslink for an example where a message field's name and type name are the
    * same.
    */
+  @Test
   public void testDescriptorComplexCrosslink() throws Exception {
     FileDescriptorProto fileDescriptorProto =
         FileDescriptorProto.newBuilder()
@@ -481,25 +496,26 @@
     FileDescriptor file =
         Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
     // verify resulting descriptors
-    assertNotNull(file);
+    assertThat(file).isNotNull();
     List<Descriptor> msglist = file.getMessageTypes();
-    assertNotNull(msglist);
-    assertTrue(msglist.size() == 2);
+    assertThat(msglist).isNotNull();
+    assertThat(msglist).hasSize(2);
     boolean barFound = false;
     for (Descriptor desc : msglist) {
       if (desc.getName().equals("Bar")) {
         barFound = true;
-        assertNotNull(desc.getFields());
+        assertThat(desc.getFields()).isNotNull();
         List<FieldDescriptor> fieldlist = desc.getFields();
-        assertNotNull(fieldlist);
-        assertTrue(fieldlist.size() == 1);
-        assertTrue(fieldlist.get(0).getType() == FieldDescriptor.Type.MESSAGE);
-        assertTrue(fieldlist.get(0).getMessageType().getName().equals("Foo"));
+        assertThat(fieldlist).isNotNull();
+        assertThat(fieldlist).hasSize(1);
+        assertThat(fieldlist.get(0).getType()).isSameInstanceAs(FieldDescriptor.Type.MESSAGE);
+        assertThat(fieldlist.get(0).getMessageType().getName().equals("Foo")).isTrue();
       }
     }
-    assertTrue(barFound);
+    assertThat(barFound).isTrue();
   }
 
+  @Test
   public void testDependencyOrder() throws Exception {
     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
     FileDescriptorProto barProto =
@@ -521,6 +537,7 @@
     Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {barFile, fooFile});
   }
 
+  @Test
   public void testInvalidPublicDependency() throws Exception {
     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
     FileDescriptorProto barProto =
@@ -532,12 +549,13 @@
     FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
     try {
       Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
-      fail("DescriptorValidationException expected");
+      assertWithMessage("DescriptorValidationException expected").fail();
     } catch (DescriptorValidationException e) {
-      assertTrue(e.getMessage().indexOf("Invalid public dependency index.") != -1);
+      assertThat(e).hasMessageThat().contains("Invalid public dependency index.");
     }
   }
 
+  @Test
   public void testUnknownFieldsDenied() throws Exception {
     FileDescriptorProto fooProto =
         FileDescriptorProto.newBuilder()
@@ -555,13 +573,14 @@
 
     try {
       Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
-      fail("DescriptorValidationException expected");
+      assertWithMessage("DescriptorValidationException expected").fail();
     } catch (DescriptorValidationException e) {
-      assertTrue(e.getMessage().indexOf("Bar") != -1);
-      assertTrue(e.getMessage().indexOf("is not defined") != -1);
+      assertThat(e).hasMessageThat().contains("Bar");
+      assertThat(e).hasMessageThat().contains("is not defined");
     }
   }
 
+  @Test
   public void testUnknownFieldsAllowed() throws Exception {
     FileDescriptorProto fooProto =
         FileDescriptorProto.newBuilder()
@@ -580,6 +599,7 @@
     Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
   }
 
+  @Test
   public void testHiddenDependency() throws Exception {
     FileDescriptorProto barProto =
         FileDescriptorProto.newBuilder()
@@ -611,13 +631,14 @@
 
     try {
       Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
-      fail("DescriptorValidationException expected");
+      assertWithMessage("DescriptorValidationException expected").fail();
     } catch (DescriptorValidationException e) {
-      assertTrue(e.getMessage().indexOf("Bar") != -1);
-      assertTrue(e.getMessage().indexOf("is not defined") != -1);
+      assertThat(e).hasMessageThat().contains("Bar");
+      assertThat(e).hasMessageThat().contains("is not defined");
     }
   }
 
+  @Test
   public void testPublicDependency() throws Exception {
     FileDescriptorProto barProto =
         FileDescriptorProto.newBuilder()
@@ -651,6 +672,7 @@
   }
 
   /** Tests the translate/crosslink for an example with a more complex namespace referencing. */
+  @Test
   public void testComplexNamespacePublicDependency() throws Exception {
     FileDescriptorProto fooProto =
         FileDescriptorProto.newBuilder()
@@ -681,73 +703,78 @@
     FileDescriptor barFile =
         Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
     // verify resulting descriptors
-    assertNotNull(barFile);
+    assertThat(barFile).isNotNull();
     List<Descriptor> msglist = barFile.getMessageTypes();
-    assertNotNull(msglist);
-    assertTrue(msglist.size() == 1);
+    assertThat(msglist).isNotNull();
+    assertThat(msglist).hasSize(1);
     Descriptor desc = msglist.get(0);
     if (desc.getName().equals("MyMessage")) {
-      assertNotNull(desc.getFields());
+      assertThat(desc.getFields()).isNotNull();
       List<FieldDescriptor> fieldlist = desc.getFields();
-      assertNotNull(fieldlist);
-      assertTrue(fieldlist.size() == 1);
+      assertThat(fieldlist).isNotNull();
+      assertThat(fieldlist).hasSize(1);
       FieldDescriptor field = fieldlist.get(0);
-      assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
-      assertTrue(field.getEnumType().getName().equals("MyEnum"));
-      assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
-      assertTrue(field.getEnumType().getFile().getPackage().equals("a.b.c.d.bar.shared"));
+      assertThat(field.getType()).isSameInstanceAs(FieldDescriptor.Type.ENUM);
+      assertThat(field.getEnumType().getName().equals("MyEnum")).isTrue();
+      assertThat(field.getEnumType().getFile().getName().equals("bar.proto")).isTrue();
+      assertThat(field.getEnumType().getFile().getPackage().equals("a.b.c.d.bar.shared")).isTrue();
     }
   }
 
+  @Test
   public void testOneofDescriptor() throws Exception {
     Descriptor messageType = TestAllTypes.getDescriptor();
     FieldDescriptor field = messageType.findFieldByName("oneof_nested_message");
     OneofDescriptor oneofDescriptor = field.getContainingOneof();
-    assertNotNull(oneofDescriptor);
-    assertSame(oneofDescriptor, messageType.getOneofs().get(0));
-    assertEquals("oneof_field", oneofDescriptor.getName());
+    assertThat(oneofDescriptor).isNotNull();
+    assertThat(messageType.getOneofs().get(0)).isSameInstanceAs(oneofDescriptor);
+    assertThat(oneofDescriptor.getName()).isEqualTo("oneof_field");
 
-    assertEquals(4, oneofDescriptor.getFieldCount());
-    assertSame(oneofDescriptor.getField(1), field);
+    assertThat(oneofDescriptor.getFieldCount()).isEqualTo(4);
+    assertThat(field).isSameInstanceAs(oneofDescriptor.getField(1));
 
-    assertEquals(4, oneofDescriptor.getFields().size());
-    assertEquals(oneofDescriptor.getFields().get(1), field);
+    assertThat(oneofDescriptor.getFields()).hasSize(4);
+    assertThat(field).isEqualTo(oneofDescriptor.getFields().get(1));
   }
 
+  @Test
   public void testMessageDescriptorExtensions() throws Exception {
-    assertFalse(TestAllTypes.getDescriptor().isExtendable());
-    assertTrue(TestAllExtensions.getDescriptor().isExtendable());
-    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtendable());
+    assertThat(TestAllTypes.getDescriptor().isExtendable()).isFalse();
+    assertThat(TestAllExtensions.getDescriptor().isExtendable()).isTrue();
+    assertThat(TestMultipleExtensionRanges.getDescriptor().isExtendable()).isTrue();
 
-    assertFalse(TestAllTypes.getDescriptor().isExtensionNumber(3));
-    assertTrue(TestAllExtensions.getDescriptor().isExtensionNumber(3));
-    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42));
-    assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43));
-    assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142));
-    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143));
+    assertThat(TestAllTypes.getDescriptor().isExtensionNumber(3)).isFalse();
+    assertThat(TestAllExtensions.getDescriptor().isExtensionNumber(3)).isTrue();
+    assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42)).isTrue();
+    assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43)).isFalse();
+    assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142)).isFalse();
+    assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143)).isTrue();
   }
 
+  @Test
   public void testReservedFields() {
     Descriptor d = TestReservedFields.getDescriptor();
-    assertTrue(d.isReservedNumber(2));
-    assertFalse(d.isReservedNumber(8));
-    assertTrue(d.isReservedNumber(9));
-    assertTrue(d.isReservedNumber(10));
-    assertTrue(d.isReservedNumber(11));
-    assertFalse(d.isReservedNumber(12));
-    assertFalse(d.isReservedName("foo"));
-    assertTrue(d.isReservedName("bar"));
-    assertTrue(d.isReservedName("baz"));
+    assertThat(d.isReservedNumber(2)).isTrue();
+    assertThat(d.isReservedNumber(8)).isFalse();
+    assertThat(d.isReservedNumber(9)).isTrue();
+    assertThat(d.isReservedNumber(10)).isTrue();
+    assertThat(d.isReservedNumber(11)).isTrue();
+    assertThat(d.isReservedNumber(12)).isFalse();
+    assertThat(d.isReservedName("foo")).isFalse();
+    assertThat(d.isReservedName("bar")).isTrue();
+    assertThat(d.isReservedName("baz")).isTrue();
   }
 
+  @Test
   public void testToString() {
-    assertEquals(
-        "protobuf_unittest.TestAllTypes.optional_uint64",
-        UnittestProto.TestAllTypes.getDescriptor()
-            .findFieldByNumber(UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER)
-            .toString());
+    assertThat(
+            UnittestProto.TestAllTypes.getDescriptor()
+                .findFieldByNumber(UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER)
+                .toString())
+        .isEqualTo("protobuf_unittest.TestAllTypes.optional_uint64");
   }
 
+  @Test
   public void testPackedEnumField() throws Exception {
     FileDescriptorProto fileDescriptorProto =
         FileDescriptorProto.newBuilder()
@@ -775,37 +802,41 @@
     Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
   }
 
+  @Test
   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());
+    assertThat(d.getFields()).hasSize(7);
+    assertThat(d.getFields().get(0).getJsonName()).isEqualTo("fieldName1");
+    assertThat(d.getFields().get(1).getJsonName()).isEqualTo("fieldName2");
+    assertThat(d.getFields().get(2).getJsonName()).isEqualTo("FieldName3");
+    assertThat(d.getFields().get(3).getJsonName()).isEqualTo("FieldName4");
+    assertThat(d.getFields().get(4).getJsonName()).isEqualTo("FIELDNAME5");
+    assertThat(d.getFields().get(5).getJsonName()).isEqualTo("@type");
+    assertThat(d.getFields().get(6).getJsonName()).isEqualTo("fieldname7");
   }
 
+  @Test
   public void testExtensionRenamesKeywords() {
-    assertTrue(NonNestedExtension.if_ instanceof GeneratedMessage.GeneratedExtension);
-    assertTrue(
-        NestedExtension.MyNestedExtension.default_
-            instanceof GeneratedMessage.GeneratedExtension);
+    assertThat(NonNestedExtension.if_).isInstanceOf(GeneratedMessage.GeneratedExtension.class);
+    assertThat(NestedExtension.MyNestedExtension.default_)
+        .isInstanceOf(GeneratedMessage.GeneratedExtension.class);
 
     NonNestedExtension.MessageToBeExtended msg =
         NonNestedExtension.MessageToBeExtended.newBuilder()
             .setExtension(NonNestedExtension.if_, "!fi")
             .build();
-    assertEquals("!fi", msg.getExtension(NonNestedExtension.if_));
+    assertThat(msg.getExtension(NonNestedExtension.if_)).isEqualTo("!fi");
 
     msg =
         NonNestedExtension.MessageToBeExtended.newBuilder()
             .setExtension(NestedExtension.MyNestedExtension.default_, 8)
             .build();
-    assertEquals(8, msg.getExtension(NestedExtension.MyNestedExtension.default_).intValue());
+    assertThat(msg.getExtension(NestedExtension.MyNestedExtension.default_).intValue())
+        .isEqualTo(8);
   }
 
+  @Test
   public void testDefaultDescriptorExtensionRange() throws Exception {
-    assertTrue(new Descriptor("default").isExtensionNumber(1));
+    assertThat(new Descriptor("default").isExtensionNumber(1)).isTrue();
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java b/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java
index 01a96ba..a130545 100644
--- a/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java
@@ -30,7 +30,7 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import protobuf_unittest.UnittestProto;
 import proto3_unittest.UnittestProto3;
@@ -83,12 +83,12 @@
     // Use DiscardUnknownFieldsParser to parse the first payload.
     int oldLimit = input.pushLimit(messageSize);
     Message parsed = DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(input);
-    assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
+    assertWithMessage(message.getClass().getName()).that(parsed.getSerializedSize()).isEqualTo(0);
     input.popLimit(oldLimit);
 
     // Use the normal parser to parse the remaining payload should have unknown fields preserved.
     parsed = message.getParserForType().parseFrom(input);
-    assertEquals(message.getClass().getName(), payload, parsed.toByteString());
+    assertWithMessage(message.getClass().getName()).that(parsed.toByteString()).isEqualTo(payload);
   }
 
   /**
@@ -99,20 +99,20 @@
       throws Exception {
     UnknownFieldSet unknownFields = UnknownFieldSet.newBuilder().mergeFrom(payload).build();
     Message built = message.newBuilderForType().setUnknownFields(unknownFields).build();
-    assertEquals(message.getClass().getName(), payload, built.toByteString());
+    assertWithMessage(message.getClass().getName()).that(built.toByteString()).isEqualTo(payload);
   }
 
   private static void assertUnknownFieldsPreserved(MessageLite message) throws Exception {
     MessageLite parsed = message.getParserForType().parseFrom(payload);
-    assertEquals(message.getClass().getName(), payload, parsed.toByteString());
+    assertWithMessage(message.getClass().getName()).that(parsed.toByteString()).isEqualTo(payload);
 
     parsed = message.newBuilderForType().mergeFrom(payload).build();
-    assertEquals(message.getClass().getName(), payload, parsed.toByteString());
+    assertWithMessage(message.getClass().getName()).that(parsed.toByteString()).isEqualTo(payload);
   }
 
   private static void assertUnknownFieldsExplicitlyDiscarded(Message message) throws Exception {
     Message parsed = DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(payload);
-    assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
+    assertWithMessage(message.getClass().getName()).that(parsed.getSerializedSize()).isEqualTo(0);
   }
 
   private static final ByteString payload =
diff --git a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
index 019b5a1..28c05a3 100644
--- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -30,39 +30,44 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static java.util.Arrays.asList;
 
 import com.google.protobuf.Internal.DoubleList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests for {@link DoubleArrayList}.
- *
- * @author [email protected] (Daniel Weis)
- */
-public class DoubleArrayListTest extends TestCase {
+/** Tests for {@link DoubleArrayList}. */
+@RunWith(JUnit4.class)
+public class DoubleArrayListTest {
 
   private static final DoubleArrayList UNARY_LIST = newImmutableDoubleArrayList(1);
   private static final DoubleArrayList TERTIARY_LIST = newImmutableDoubleArrayList(1, 2, 3);
 
   private DoubleArrayList list;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     list = new DoubleArrayList();
   }
 
+  @Test
   public void testEmptyListReturnsSameInstance() {
-    assertSame(DoubleArrayList.emptyList(), DoubleArrayList.emptyList());
+    assertThat(DoubleArrayList.emptyList()).isSameInstanceAs(DoubleArrayList.emptyList());
   }
 
+  @Test
   public void testEmptyListIsImmutable() {
     assertImmutable(DoubleArrayList.emptyList());
   }
 
+  @Test
   public void testMakeImmutable() {
     list.addDouble(3);
     list.addDouble(4);
@@ -72,19 +77,20 @@
     assertImmutable(list);
   }
 
+  @Test
   public void testModificationWithIteration() {
     list.addAll(asList(1D, 2D, 3D, 4D));
     Iterator<Double> iterator = list.iterator();
-    assertEquals(4, list.size());
-    assertEquals(1D, (double) list.get(0), 0.0);
-    assertEquals(1D, (double) iterator.next(), 0.0);
+    assertThat(list).hasSize(4);
+    assertThat((double) list.get(0)).isEqualTo(1D);
+    assertThat((double) iterator.next()).isEqualTo(1D);
     list.set(0, 1D);
-    assertEquals(2D, (double) iterator.next(), 0.0);
+    assertThat((double) iterator.next()).isEqualTo(2D);
 
     list.remove(0);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
@@ -93,191 +99,211 @@
     list.add(0, 0D);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
   }
 
+  @Test
   public void testGet() {
-    assertEquals(1D, (double) TERTIARY_LIST.get(0), 0.0);
-    assertEquals(2D, (double) TERTIARY_LIST.get(1), 0.0);
-    assertEquals(3D, (double) TERTIARY_LIST.get(2), 0.0);
+    assertThat((double) TERTIARY_LIST.get(0)).isEqualTo(1D);
+    assertThat((double) TERTIARY_LIST.get(1)).isEqualTo(2D);
+    assertThat((double) TERTIARY_LIST.get(2)).isEqualTo(3D);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testGetDouble() {
-    assertEquals(1D, TERTIARY_LIST.getDouble(0), 0.0);
-    assertEquals(2D, TERTIARY_LIST.getDouble(1), 0.0);
-    assertEquals(3D, TERTIARY_LIST.getDouble(2), 0.0);
+    assertThat(TERTIARY_LIST.getDouble(0)).isEqualTo(1D);
+    assertThat(TERTIARY_LIST.getDouble(1)).isEqualTo(2D);
+    assertThat(TERTIARY_LIST.getDouble(2)).isEqualTo(3D);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testIndexOf_nullElement() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(null));
+    assertThat(TERTIARY_LIST.indexOf(null)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_incompatibleElementType() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(new Object()));
+    assertThat(TERTIARY_LIST.indexOf(new Object())).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInList() {
-    assertEquals(-1, UNARY_LIST.indexOf(2D));
+    assertThat(UNARY_LIST.indexOf(2D)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInListWithDuplicates() {
     DoubleArrayList listWithDupes = newImmutableDoubleArrayList(1D, 1D);
-    assertEquals(-1, listWithDupes.indexOf(2D));
+    assertThat(listWithDupes.indexOf(2D)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_inList() {
-    assertEquals(1, TERTIARY_LIST.indexOf(2D));
+    assertThat(TERTIARY_LIST.indexOf(2D)).isEqualTo(1);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchAtHead() {
     DoubleArrayList listWithDupes = newImmutableDoubleArrayList(1D, 1D, 2D);
-    assertEquals(0, listWithDupes.indexOf(1D));
+    assertThat(listWithDupes.indexOf(1D)).isEqualTo(0);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchMidList() {
     DoubleArrayList listWithDupes = newImmutableDoubleArrayList(2D, 1D, 1D, 2D);
-    assertEquals(1, listWithDupes.indexOf(1D));
+    assertThat(listWithDupes.indexOf(1D)).isEqualTo(1);
   }
 
+  @Test
   public void testContains_nullElement() {
-    assertEquals(false, TERTIARY_LIST.contains(null));
+    assertThat(TERTIARY_LIST).doesNotContain(null);
   }
 
+  @Test
   public void testContains_incompatibleElementType() {
-    assertEquals(false, TERTIARY_LIST.contains(new Object()));
+    assertThat(TERTIARY_LIST).doesNotContain(new Object());
   }
 
+  @Test
   public void testContains_notInList() {
-    assertEquals(false, UNARY_LIST.contains(2D));
+    assertThat(UNARY_LIST).doesNotContain(2D);
   }
 
+  @Test
   public void testContains_notInListWithDuplicates() {
     DoubleArrayList listWithDupes = newImmutableDoubleArrayList(1D, 1D);
-    assertEquals(false, listWithDupes.contains(2D));
+    assertThat(listWithDupes).doesNotContain(2D);
   }
 
+  @Test
   public void testContains_inList() {
-    assertEquals(true, TERTIARY_LIST.contains(2D));
+    assertThat(TERTIARY_LIST).contains(2D);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchAtHead() {
     DoubleArrayList listWithDupes = newImmutableDoubleArrayList(1D, 1D, 2D);
-    assertEquals(true, listWithDupes.contains(1D));
+    assertThat(listWithDupes).contains(1D);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchMidList() {
     DoubleArrayList listWithDupes = newImmutableDoubleArrayList(2D, 1D, 1D, 2D);
-    assertEquals(true, listWithDupes.contains(1D));
+    assertThat(listWithDupes).contains(1D);
   }
 
+  @Test
   public void testSize() {
-    assertEquals(0, DoubleArrayList.emptyList().size());
-    assertEquals(1, UNARY_LIST.size());
-    assertEquals(3, TERTIARY_LIST.size());
+    assertThat(DoubleArrayList.emptyList()).isEmpty();
+    assertThat(UNARY_LIST).hasSize(1);
+    assertThat(TERTIARY_LIST).hasSize(3);
 
     list.addDouble(3);
     list.addDouble(4);
     list.addDouble(6);
     list.addDouble(8);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
 
     list.remove(0);
-    assertEquals(3, list.size());
+    assertThat(list).hasSize(3);
 
     list.add(17D);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
   }
 
+  @Test
   public void testSet() {
     list.addDouble(2);
     list.addDouble(4);
 
-    assertEquals(2D, (double) list.set(0, 3D), 0.0);
-    assertEquals(3D, list.getDouble(0), 0.0);
+    assertThat((double) list.set(0, 3D)).isEqualTo(2D);
+    assertThat(list.getDouble(0)).isEqualTo(3D);
 
-    assertEquals(4D, (double) list.set(1, 0D), 0.0);
-    assertEquals(0D, list.getDouble(1), 0.0);
+    assertThat((double) list.set(1, 0D)).isEqualTo(4D);
+    assertThat(list.getDouble(1)).isEqualTo(0D);
 
     try {
       list.set(-1, 0D);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.set(2, 0D);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testSetDouble() {
     list.addDouble(1);
     list.addDouble(3);
 
-    assertEquals(1D, list.setDouble(0, 0), 0.0);
-    assertEquals(0D, list.getDouble(0), 0.0);
+    assertThat(list.setDouble(0, 0)).isEqualTo(1D);
+    assertThat(list.getDouble(0)).isEqualTo(0D);
 
-    assertEquals(3D, list.setDouble(1, 0), 0.0);
-    assertEquals(0D, list.getDouble(1), 0.0);
+    assertThat(list.setDouble(1, 0)).isEqualTo(3D);
+    assertThat(list.getDouble(1)).isEqualTo(0D);
 
     try {
       list.setDouble(-1, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.setDouble(2, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testAdd() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.add(2D));
-    assertEquals(asList(2D), list);
+    assertThat(list.add(2D)).isTrue();
+    assertThat(list).containsExactly(2D);
 
-    assertTrue(list.add(3D));
+    assertThat(list.add(3D)).isTrue();
     list.add(0, 4D);
-    assertEquals(asList(4D, 2D, 3D), list);
+    assertThat(list).containsExactly(4D, 2D, 3D).inOrder();
 
     list.add(0, 1D);
     list.add(0, 0D);
@@ -285,7 +311,7 @@
     for (int i = 0; i < 6; i++) {
       list.add(Double.valueOf(5 + i));
     }
-    assertEquals(asList(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D), list);
+    assertThat(list).containsExactly(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D).inOrder();
 
     try {
       list.add(-1, 5D);
@@ -300,92 +326,100 @@
     }
   }
 
+  @Test
   public void testAddDouble() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
     list.addDouble(2);
-    assertEquals(asList(2D), list);
+    assertThat(list).containsExactly(2D);
 
     list.addDouble(3);
-    assertEquals(asList(2D, 3D), list);
+    assertThat(list).containsExactly(2D, 3D).inOrder();
   }
 
+  @Test
   public void testAddAll() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.addAll(Collections.singleton(1D)));
-    assertEquals(1, list.size());
-    assertEquals(1D, (double) list.get(0), 0.0);
-    assertEquals(1D, list.getDouble(0), 0.0);
+    assertThat(list.addAll(Collections.singleton(1D))).isTrue();
+    assertThat(list).hasSize(1);
+    assertThat((double) list.get(0)).isEqualTo(1D);
+    assertThat(list.getDouble(0)).isEqualTo(1D);
 
-    assertTrue(list.addAll(asList(2D, 3D, 4D, 5D, 6D)));
-    assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D), list);
+    assertThat(list.addAll(asList(2D, 3D, 4D, 5D, 6D))).isTrue();
+    assertThat(list).containsExactly(1D, 2D, 3D, 4D, 5D, 6D).inOrder();
 
-    assertTrue(list.addAll(TERTIARY_LIST));
-    assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D, 1D, 2D, 3D), list);
+    assertThat(list.addAll(TERTIARY_LIST)).isTrue();
+    assertThat(list).containsExactly(1D, 2D, 3D, 4D, 5D, 6D, 1D, 2D, 3D).inOrder();
 
-    assertFalse(list.addAll(Collections.<Double>emptyList()));
-    assertFalse(list.addAll(DoubleArrayList.emptyList()));
+    assertThat(list.addAll(Collections.<Double>emptyList())).isFalse();
+    assertThat(list.addAll(DoubleArrayList.emptyList())).isFalse();
   }
 
+  @Test
   public void testEquals() {
     DoubleArrayList list1 = new DoubleArrayList();
     DoubleArrayList list2 = new DoubleArrayList();
 
     list1.addDouble(Double.longBitsToDouble(0x7ff0000000000001L));
     list2.addDouble(Double.longBitsToDouble(0x7ff0000000000002L));
-    assertEquals(list1, list2);
+    assertThat(list1).isEqualTo(list2);
   }
 
+  @Test
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
-    assertEquals(1D, (double) list.remove(0), 0.0);
-    assertEquals(asList(2D, 3D), list);
+    assertThat((double) list.remove(0)).isEqualTo(1D);
+    assertThat(list).containsExactly(2D, 3D).inOrder();
 
-    assertTrue(list.remove(Double.valueOf(3)));
-    assertEquals(asList(2D), list);
+    assertThat(list.remove(Double.valueOf(3))).isTrue();
+    assertThat(list).containsExactly(2D);
 
-    assertFalse(list.remove(Double.valueOf(3)));
-    assertEquals(asList(2D), list);
+    assertThat(list.remove(Double.valueOf(3))).isFalse();
+    assertThat(list).containsExactly(2D);
 
-    assertEquals(2D, (double) list.remove(0), 0.0);
-    assertEquals(asList(), list);
+    assertThat((double) list.remove(0)).isEqualTo(2D);
+    assertThat(list).isEmpty();
 
     try {
       list.remove(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.remove(0);
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testRemoveEnd_listAtCapacity() {
     DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addDouble(3);
     toRemove.remove(0);
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
+  @Test
   public void testRemove_listAtCapacity() {
     DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(2);
     toRemove.addDouble(3);
     toRemove.addDouble(4);
     toRemove.remove(0);
-    assertEquals(1, toRemove.size());
-    assertEquals(4D, (double) toRemove.get(0));
+    assertThat(toRemove).hasSize(1);
+    assertThat((double) toRemove.get(0)).isEqualTo(4D);
   }
 
+  @Test
   public void testSublistRemoveEndOfCapacity() {
     DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addDouble(3);
     toRemove.subList(0, 1).clear();
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
   private void assertImmutable(DoubleList list) {
@@ -395,147 +429,147 @@
 
     try {
       list.add(1D);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.add(0, 1D);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.<Double>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.singletonList(1D));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(new DoubleArrayList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.singleton(1D));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.<Double>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addDouble(0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.clear();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.<Double>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.singleton(1D));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(Collections.<Double>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(Collections.singleton(1D));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.set(0, 0D);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.setDouble(0, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
diff --git a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
index cd40ffa..3aacdcc 100644
--- a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
@@ -39,16 +41,16 @@
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
-import java.util.Arrays;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Unit test for {@link DynamicMessage}. See also {@link MessageTest}, which tests some {@link
  * DynamicMessage} functionality.
- *
- * @author [email protected] Kenton Varda
  */
-public class DynamicMessageTest extends TestCase {
+@RunWith(JUnit4.class)
+public class DynamicMessageTest {
   TestUtil.ReflectionTester reflectionTester =
       new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
 
@@ -58,6 +60,7 @@
   TestUtil.ReflectionTester packedReflectionTester =
       new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
 
+  @Test
   public void testDynamicMessageAccessors() throws Exception {
     Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     reflectionTester.setAllFieldsViaReflection(builder);
@@ -65,6 +68,7 @@
     reflectionTester.assertAllFieldsSetViaReflection(message);
   }
 
+  @Test
   public void testSettersAfterBuild() throws Exception {
     Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     Message firstMessage = builder.build();
@@ -84,6 +88,7 @@
     reflectionTester.assertClearViaReflection(firstMessage);
   }
 
+  @Test
   public void testUnknownFields() throws Exception {
     Message.Builder builder = DynamicMessage.newBuilder(TestEmptyMessage.getDescriptor());
     builder.setUnknownFields(
@@ -92,23 +97,25 @@
             .addField(2, UnknownFieldSet.Field.newBuilder().addFixed32(1).build())
             .build());
     Message message = builder.build();
-    assertEquals(2, message.getUnknownFields().asMap().size());
+    assertThat(builder.getUnknownFields().asMap()).hasSize(2);
     // clone() with unknown fields
     Message.Builder newBuilder = builder.clone();
-    assertEquals(2, newBuilder.getUnknownFields().asMap().size());
+    assertThat(newBuilder.getUnknownFields().asMap()).hasSize(2);
     // clear() with unknown fields
     newBuilder.clear();
-    assertTrue(newBuilder.getUnknownFields().asMap().isEmpty());
+    assertThat(newBuilder.getUnknownFields().asMap()).isEmpty();
     // serialize/parse with unknown fields
     newBuilder.mergeFrom(message.toByteString());
-    assertEquals(2, newBuilder.getUnknownFields().asMap().size());
+    assertThat(newBuilder.getUnknownFields().asMap()).hasSize(2);
   }
 
+  @Test
   public void testDynamicMessageSettersRejectNull() throws Exception {
     Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     reflectionTester.assertReflectionSettersRejectNull(builder);
   }
 
+  @Test
   public void testDynamicMessageExtensionAccessors() throws Exception {
     // We don't need to extensively test DynamicMessage's handling of
     // extensions because, frankly, it doesn't do anything special with them.
@@ -119,11 +126,13 @@
     extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
   }
 
+  @Test
   public void testDynamicMessageExtensionSettersRejectNull() throws Exception {
     Message.Builder builder = DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
     extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
   }
 
+  @Test
   public void testDynamicMessageRepeatedSetters() throws Exception {
     Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     reflectionTester.setAllFieldsViaReflection(builder);
@@ -132,11 +141,13 @@
     reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
   }
 
+  @Test
   public void testDynamicMessageRepeatedSettersRejectNull() throws Exception {
     Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
   }
 
+  @Test
   public void testDynamicMessageDefaults() throws Exception {
     reflectionTester.assertClearViaReflection(
         DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor()));
@@ -144,6 +155,7 @@
         DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build());
   }
 
+  @Test
   public void testDynamicMessageSerializedSize() throws Exception {
     TestAllTypes message = TestUtil.getAllSet();
 
@@ -151,9 +163,10 @@
     reflectionTester.setAllFieldsViaReflection(dynamicBuilder);
     Message dynamicMessage = dynamicBuilder.build();
 
-    assertEquals(message.getSerializedSize(), dynamicMessage.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(dynamicMessage.getSerializedSize());
   }
 
+  @Test
   public void testDynamicMessageSerialization() throws Exception {
     Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     reflectionTester.setAllFieldsViaReflection(builder);
@@ -165,9 +178,10 @@
     TestUtil.assertAllFieldsSet(message2);
 
     // In fact, the serialized forms should be exactly the same, byte-for-byte.
-    assertEquals(TestUtil.getAllSet().toByteString(), rawBytes);
+    assertThat(rawBytes).isEqualTo(TestUtil.getAllSet().toByteString());
   }
 
+  @Test
   public void testDynamicMessageParsing() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
@@ -183,6 +197,7 @@
     reflectionTester.assertAllFieldsSetViaReflection(message3);
   }
 
+  @Test
   public void testDynamicMessageExtensionParsing() throws Exception {
     ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString();
     Message message =
@@ -196,6 +211,7 @@
     extensionsReflectionTester.assertAllFieldsSetViaReflection(message2);
   }
 
+  @Test
   public void testDynamicMessagePackedSerialization() throws Exception {
     Message.Builder builder = DynamicMessage.newBuilder(TestPackedTypes.getDescriptor());
     packedReflectionTester.setPackedFieldsViaReflection(builder);
@@ -207,9 +223,10 @@
     TestUtil.assertPackedFieldsSet(message2);
 
     // In fact, the serialized forms should be exactly the same, byte-for-byte.
-    assertEquals(TestUtil.getPackedSet().toByteString(), rawBytes);
+    assertThat(rawBytes).isEqualTo(TestUtil.getPackedSet().toByteString());
   }
 
+  @Test
   public void testDynamicMessagePackedParsing() throws Exception {
     TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
     TestUtil.setPackedFields(builder);
@@ -225,6 +242,7 @@
     packedReflectionTester.assertPackedFieldsSetViaReflection(message3);
   }
 
+  @Test
   public void testGetBuilderForExtensionField() {
     DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
     Message.Builder fieldBuilder =
@@ -233,9 +251,10 @@
     FieldDescriptor field =
         NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
     fieldBuilder.setField(field, expected);
-    assertEquals(expected, fieldBuilder.build().getField(field));
+    assertThat(fieldBuilder.build().getField(field)).isEqualTo(expected);
   }
 
+  @Test
   public void testDynamicMessageCopy() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
@@ -247,14 +266,15 @@
     // Test oneof behavior
     FieldDescriptor bytesField = TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
     FieldDescriptor uint32Field = TestAllTypes.getDescriptor().findFieldByName("oneof_uint32");
-    assertTrue(copy.hasField(bytesField));
-    assertFalse(copy.hasField(uint32Field));
+    assertThat(copy.hasField(bytesField)).isTrue();
+    assertThat(copy.hasField(uint32Field)).isFalse();
     DynamicMessage copy2 = DynamicMessage.newBuilder(message).setField(uint32Field, 123).build();
-    assertFalse(copy2.hasField(bytesField));
-    assertTrue(copy2.hasField(uint32Field));
-    assertEquals(123, copy2.getField(uint32Field));
+    assertThat(copy2.hasField(bytesField)).isFalse();
+    assertThat(copy2.hasField(uint32Field)).isTrue();
+    assertThat(copy2.getField(uint32Field)).isEqualTo(123);
   }
 
+  @Test
   public void testToBuilder() throws Exception {
     DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     reflectionTester.setAllFieldsViaReflection(builder);
@@ -270,41 +290,42 @@
 
     DynamicMessage derived = message.toBuilder().build();
     reflectionTester.assertAllFieldsSetViaReflection(derived);
-    assertEquals(
-        Arrays.asList(unknownFieldVal),
-        derived.getUnknownFields().getField(unknownFieldNum).getVarintList());
+    assertThat(derived.getUnknownFields().getField(unknownFieldNum).getVarintList())
+        .containsExactly(unknownFieldVal);
   }
 
+  @Test
   public void testDynamicOneofMessage() throws Exception {
     DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0);
-    assertFalse(builder.hasOneof(oneof));
-    assertSame(null, builder.getOneofFieldDescriptor(oneof));
+    assertThat(builder.hasOneof(oneof)).isFalse();
+    assertThat(builder.getOneofFieldDescriptor(oneof)).isNull();
 
     reflectionTester.setAllFieldsViaReflection(builder);
-    assertTrue(builder.hasOneof(oneof));
+    assertThat(builder.hasOneof(oneof)).isTrue();
     FieldDescriptor field = oneof.getField(3);
-    assertSame(field, builder.getOneofFieldDescriptor(oneof));
+    assertThat(builder.getOneofFieldDescriptor(oneof)).isSameInstanceAs(field);
 
     DynamicMessage message = builder.buildPartial();
-    assertTrue(message.hasOneof(oneof));
+    assertThat(message.hasOneof(oneof)).isTrue();
 
     DynamicMessage.Builder mergedBuilder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     FieldDescriptor mergedField = oneof.getField(0);
     mergedBuilder.setField(mergedField, 123);
-    assertTrue(mergedBuilder.hasField(mergedField));
+    assertThat(mergedBuilder.hasField(mergedField)).isTrue();
     mergedBuilder.mergeFrom(message);
-    assertTrue(mergedBuilder.hasField(field));
-    assertFalse(mergedBuilder.hasField(mergedField));
+    assertThat(mergedBuilder.hasField(field)).isTrue();
+    assertThat(mergedBuilder.hasField(mergedField)).isFalse();
 
     builder.clearOneof(oneof);
-    assertSame(null, builder.getOneofFieldDescriptor(oneof));
+    assertThat(builder.getOneofFieldDescriptor(oneof)).isNull();
     message = builder.build();
-    assertSame(null, message.getOneofFieldDescriptor(oneof));
+    assertThat(message.getOneofFieldDescriptor(oneof)).isNull();
   }
 
   // Regression test for a bug that makes setField() not work for repeated
   // enum fields.
+  @Test
   public void testSettersForRepeatedEnumField() throws Exception {
     DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
     FieldDescriptor repeatedEnumField =
@@ -312,6 +333,6 @@
     EnumDescriptor enumDescriptor = TestAllTypes.NestedEnum.getDescriptor();
     builder.setField(repeatedEnumField, enumDescriptor.getValues());
     DynamicMessage message = builder.build();
-    assertEquals(enumDescriptor.getValues(), message.getField(repeatedEnumField));
+    assertThat(message.getField(repeatedEnumField)).isEqualTo(enumDescriptor.getValues());
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/EnumTest.java b/java/core/src/test/java/com/google/protobuf/EnumTest.java
index 80c176a..6287a23 100644
--- a/java/core/src/test/java/com/google/protobuf/EnumTest.java
+++ b/java/core/src/test/java/com/google/protobuf/EnumTest.java
@@ -30,47 +30,56 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.protobuf.UnittestLite.ForeignEnumLite;
 import com.google.protobuf.UnittestLite.TestAllTypesLite;
 import protobuf_unittest.UnittestProto.ForeignEnum;
 import protobuf_unittest.UnittestProto.TestAllTypes;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class EnumTest extends TestCase {
+@RunWith(JUnit4.class)
+public class EnumTest {
 
+  @Test
   public void testForNumber() {
     ForeignEnum e = ForeignEnum.forNumber(ForeignEnum.FOREIGN_BAR.getNumber());
-    assertEquals(ForeignEnum.FOREIGN_BAR, e);
+    assertThat(e).isEqualTo(ForeignEnum.FOREIGN_BAR);
 
     e = ForeignEnum.forNumber(1000);
-    assertNull(e);
+    assertThat(e).isNull();
   }
 
+  @Test
   public void testForNumber_oneof() {
     TestAllTypes.OneofFieldCase e =
         TestAllTypes.OneofFieldCase.forNumber(
             TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
-    assertEquals(TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
+    assertThat(e).isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE);
 
     e = TestAllTypes.OneofFieldCase.forNumber(1000);
-    assertNull(e);
+    assertThat(e).isNull();
   }
 
+  @Test
   public void testForNumberLite() {
     ForeignEnumLite e = ForeignEnumLite.forNumber(ForeignEnumLite.FOREIGN_LITE_BAR.getNumber());
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, e);
+    assertThat(e).isEqualTo(ForeignEnumLite.FOREIGN_LITE_BAR);
 
     e = ForeignEnumLite.forNumber(1000);
-    assertNull(e);
+    assertThat(e).isNull();
   }
 
+  @Test
   public void testForNumberLite_oneof() {
     TestAllTypesLite.OneofFieldCase e =
         TestAllTypesLite.OneofFieldCase.forNumber(
             TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
-    assertEquals(TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
+    assertThat(e).isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE);
 
     e = TestAllTypesLite.OneofFieldCase.forNumber(1000);
-    assertNull(e);
+    assertThat(e).isNull();
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
index 70466ba..a881ece 100644
--- a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
@@ -30,18 +30,20 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.ClassPath;
 import protobuf_unittest.NonNestedExtension;
 import protobuf_unittest.NonNestedExtensionLite;
+import java.io.IOException;
 import java.lang.reflect.Method;
+import java.net.URL;
 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;
-import org.junit.Ignore;
 
 /**
  * Tests for {@link ExtensionRegistryFactory} and the {@link ExtensionRegistry} instances it
@@ -53,13 +55,8 @@
  *
  * <p>The test mechanism employed here is based on the pattern in {@code
  * com.google.common.util.concurrent.AbstractFutureFallbackAtomicHelperTest}
- *
- * <p> This test is temporarily disabled due to what appears to be a subtle change to class loading
- * behavior in Java 11. That seems to have broken the way the test uses a custom ClassLoader to
- * exercise Lite functionality.
  */
 @SuppressWarnings("JUnit4ClassUsedInJUnit3")
-@Ignore
 public class ExtensionRegistryFactoryTest extends TestCase {
 
   // A classloader which blacklists some non-Lite classes.
@@ -85,21 +82,21 @@
     public void testCreate() {
       ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
 
-      assertEquals(registry.getClass(), ExtensionRegistry.class);
+      assertThat(registry.getClass()).isEqualTo(ExtensionRegistry.class);
     }
 
     @Override
     public void testEmpty() {
       ExtensionRegistryLite emptyRegistry = ExtensionRegistryFactory.createEmpty();
 
-      assertEquals(emptyRegistry.getClass(), ExtensionRegistry.class);
-      assertEquals(emptyRegistry, ExtensionRegistry.EMPTY_REGISTRY);
+      assertThat(emptyRegistry.getClass()).isEqualTo(ExtensionRegistry.class);
+      assertThat(emptyRegistry).isEqualTo(ExtensionRegistry.EMPTY_REGISTRY);
     }
 
     @Override
     public void testIsFullRegistry() {
       ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
-      assertTrue(ExtensionRegistryFactory.isFullRegistry(registry));
+      assertThat(ExtensionRegistryFactory.isFullRegistry(registry)).isTrue();
     }
 
     @Override
@@ -115,25 +112,24 @@
       ExtensionRegistry fullRegistry1 = (ExtensionRegistry) registry1;
       ExtensionRegistry fullRegistry2 = (ExtensionRegistry) registry2;
 
-      assertTrue(
-          "Test is using a non-lite extension",
-          GeneratedMessageLite.GeneratedExtension.class.isAssignableFrom(
-              NonNestedExtensionLite.nonNestedExtensionLite.getClass()));
-      assertNull(
-          "Extension is not registered in masqueraded full registry",
-          fullRegistry1.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"));
+      assertWithMessage("Test is using a non-lite extension")
+          .that(NonNestedExtensionLite.nonNestedExtensionLite.getClass())
+          .isInstanceOf(GeneratedMessageLite.GeneratedExtension.class);
+      assertWithMessage("Extension is not registered in masqueraded full registry")
+          .that(fullRegistry1.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"))
+          .isNull();
       GeneratedMessageLite.GeneratedExtension<NonNestedExtensionLite.MessageLiteToBeExtended, ?>
           extension =
               registry1.findLiteExtensionByNumber(
                   NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
-      assertNotNull("Extension registered in lite registry", extension);
+      assertWithMessage("Extension registered in lite registry").that(extension).isNotNull();
 
-      assertTrue(
-          "Test is using a non-lite extension",
-          Extension.class.isAssignableFrom(NonNestedExtension.nonNestedExtension.getClass()));
-      assertNotNull(
-          "Extension is registered in masqueraded full registry",
-          fullRegistry2.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"));
+      assertWithMessage("Test is using a non-lite extension")
+          .that(Extension.class.isAssignableFrom(NonNestedExtension.nonNestedExtension.getClass()))
+          .isTrue();
+      assertWithMessage("Extension is registered in masqueraded full registry")
+          .that(fullRegistry2.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"))
+          .isNotNull();
     }
 
     @Override
@@ -141,24 +137,24 @@
       ExtensionRegistryLite registry1 = ExtensionRegistryLite.newInstance().getUnmodifiable();
       try {
         NonNestedExtensionLite.registerAllExtensions(registry1);
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException expected) {
       }
       try {
         registry1.add(NonNestedExtensionLite.nonNestedExtensionLite);
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException expected) {
       }
 
       ExtensionRegistryLite registry2 = ExtensionRegistryLite.newInstance().getUnmodifiable();
       try {
         NonNestedExtension.registerAllExtensions((ExtensionRegistry) registry2);
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (IllegalArgumentException expected) {
       }
       try {
         registry2.add(NonNestedExtension.nonNestedExtension);
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (IllegalArgumentException expected) {
       }
     }
@@ -171,21 +167,21 @@
     public void testCreate() {
       ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
 
-      assertEquals(registry.getClass(), ExtensionRegistryLite.class);
+      assertThat(registry.getClass()).isEqualTo(ExtensionRegistryLite.class);
     }
 
     @Override
     public void testEmpty() {
       ExtensionRegistryLite emptyRegistry = ExtensionRegistryFactory.createEmpty();
 
-      assertEquals(emptyRegistry.getClass(), ExtensionRegistryLite.class);
-      assertEquals(emptyRegistry, ExtensionRegistryLite.EMPTY_REGISTRY_LITE);
+      assertThat(emptyRegistry.getClass()).isEqualTo(ExtensionRegistryLite.class);
+      assertThat(emptyRegistry).isEqualTo(ExtensionRegistryLite.EMPTY_REGISTRY_LITE);
     }
 
     @Override
     public void testIsFullRegistry() {
       ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
-      assertFalse(ExtensionRegistryFactory.isFullRegistry(registry));
+      assertThat(ExtensionRegistryFactory.isFullRegistry(registry)).isFalse();
     }
 
     @Override
@@ -196,7 +192,7 @@
           extension =
               registry.findLiteExtensionByNumber(
                   NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
-      assertNotNull("Extension is registered in Lite registry", extension);
+      assertWithMessage("Extension is registered in Lite registry").that(extension).isNotNull();
     }
 
     @Override
@@ -204,7 +200,7 @@
       ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance().getUnmodifiable();
       try {
         NonNestedExtensionLite.registerAllExtensions(registry);
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException expected) {
       }
     }
@@ -252,19 +248,27 @@
    * determine the Lite/non-Lite runtime.
    */
   private static ClassLoader getLiteOnlyClassLoader() {
-    ClassLoader testClassLoader = ExtensionRegistryFactoryTest.class.getClassLoader();
-    final Set<String> classNamesNotInLite =
-        Collections.unmodifiableSet(
-            new HashSet<String>(
-                Arrays.asList(
-                    ExtensionRegistryFactory.FULL_REGISTRY_CLASS_NAME,
-                    ExtensionRegistry.EXTENSION_CLASS_NAME)));
+
+    ImmutableSet<ClassPath.ClassInfo> classes = ImmutableSet.of();
+    try {
+      classes = ClassPath.from(ExtensionRegistryFactoryTest.class.getClassLoader()).getAllClasses();
+    } catch (IOException ex) {
+      throw new RuntimeException(ex);
+    }
+    URL[] urls = new URL[classes.size()];
+    int i = 0;
+    for (ClassPath.ClassInfo classInfo : classes) {
+      urls[i++] = classInfo.url();
+    }
+    final ImmutableSet<String> classNamesNotInLite =
+        ImmutableSet.of(
+            ExtensionRegistryFactory.FULL_REGISTRY_CLASS_NAME,
+            ExtensionRegistry.EXTENSION_CLASS_NAME);
 
     // Construct a URLClassLoader delegating to the system ClassLoader, and looking up classes
     // in jar files based on the URLs already configured for this test's UrlClassLoader.
     // Certain classes throw a ClassNotFoundException by design.
-    return new URLClassLoader(
-        ((URLClassLoader) testClassLoader).getURLs(), ClassLoader.getSystemClassLoader()) {
+    return new URLClassLoader(urls, ClassLoader.getSystemClassLoader()) {
       @Override
       public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
         if (classNamesNotInLite.contains(name)) {
diff --git a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
index 7266729..c4830af 100644
--- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
@@ -40,12 +42,15 @@
 import com.google.protobuf.FieldPresenceTestProto.TestRepeatedFieldsOnly;
 import com.google.protobuf.testing.proto.TestProto3Optional;
 import protobuf_unittest.UnittestProto;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Unit tests for protos that doesn't support field presence test for optional non-message fields.
  */
-public class FieldPresenceTest extends TestCase {
+@RunWith(JUnit4.class)
+public class FieldPresenceTest {
   private static boolean hasMethod(Class<?> clazz, String name) {
     try {
       if (clazz.getMethod(name) != null) {
@@ -60,17 +65,18 @@
 
   private static void assertHasMethodRemoved(
       Class<?> classWithFieldPresence, Class<?> classWithoutFieldPresence, String camelName) {
-    assertTrue(hasMethod(classWithFieldPresence, "get" + camelName));
-    assertTrue(hasMethod(classWithFieldPresence, "has" + camelName));
-    assertTrue(hasMethod(classWithoutFieldPresence, "get" + camelName));
-    assertFalse(hasMethod(classWithoutFieldPresence, "has" + camelName));
+    assertThat(hasMethod(classWithFieldPresence, "get" + camelName)).isTrue();
+    assertThat(hasMethod(classWithFieldPresence, "has" + camelName)).isTrue();
+    assertThat(hasMethod(classWithoutFieldPresence, "get" + camelName)).isTrue();
+    assertThat(hasMethod(classWithoutFieldPresence, "has" + camelName)).isFalse();
   }
 
   private static void assertHasMethodExisting(Class<?> clazz, String camelName) {
-    assertTrue(hasMethod(clazz, "get" + camelName));
-    assertTrue(hasMethod(clazz, "has" + camelName));
+    assertThat(hasMethod(clazz, "get" + camelName)).isTrue();
+    assertThat(hasMethod(clazz, "has" + camelName)).isTrue();
   }
 
+  @Test
   public void testHasMethod() {
     // Optional non-message fields don't have a hasFoo() method generated.
     assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OptionalInt32");
@@ -89,113 +95,120 @@
         UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OptionalNestedEnum");
 
     // message fields still have the hasFoo() method generated.
-    assertFalse(TestAllTypes.getDefaultInstance().hasOptionalNestedMessage());
-    assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
+    assertThat(TestAllTypes.getDefaultInstance().hasOptionalNestedMessage()).isFalse();
+    assertThat(TestAllTypes.newBuilder().hasOptionalNestedMessage()).isFalse();
 
     // oneof fields support hasFoo() methods for non-message types.
     assertHasMethodExisting(TestAllTypes.class, "OneofUint32");
     assertHasMethodExisting(TestAllTypes.class, "OneofString");
     assertHasMethodExisting(TestAllTypes.class, "OneofBytes");
-    assertFalse(TestAllTypes.getDefaultInstance().hasOneofNestedMessage());
-    assertFalse(TestAllTypes.newBuilder().hasOneofNestedMessage());
+    assertThat(TestAllTypes.getDefaultInstance().hasOneofNestedMessage()).isFalse();
+    assertThat(TestAllTypes.newBuilder().hasOneofNestedMessage()).isFalse();
 
     assertHasMethodExisting(TestAllTypes.Builder.class, "OneofUint32");
     assertHasMethodExisting(TestAllTypes.Builder.class, "OneofString");
     assertHasMethodExisting(TestAllTypes.Builder.class, "OneofBytes");
   }
 
+  @Test
   public void testHasMethodForProto3Optional() throws Exception {
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalInt32());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalInt64());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalUint32());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalUint64());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalSint32());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalSint64());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalFixed32());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalFixed64());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalFloat());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalDouble());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalBool());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalString());
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalBytes());
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalInt32()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalInt64()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalUint32()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalUint64()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalSint32()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalSint64()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalFixed32()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalFixed64()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalFloat()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalDouble()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalBool()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalString()).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().hasOptionalBytes()).isFalse();
 
     TestProto3Optional.Builder builder = TestProto3Optional.newBuilder().setOptionalInt32(0);
-    assertTrue(builder.hasOptionalInt32());
-    assertTrue(builder.build().hasOptionalInt32());
+    assertThat(builder.hasOptionalInt32()).isTrue();
+    assertThat(builder.build().hasOptionalInt32()).isTrue();
 
     TestProto3Optional.Builder otherBuilder = TestProto3Optional.newBuilder().setOptionalInt32(1);
     otherBuilder.mergeFrom(builder.build());
-    assertTrue(otherBuilder.hasOptionalInt32());
-    assertEquals(0, otherBuilder.getOptionalInt32());
+    assertThat(otherBuilder.hasOptionalInt32()).isTrue();
+    assertThat(otherBuilder.getOptionalInt32()).isEqualTo(0);
 
     TestProto3Optional.Builder builder3 =
         TestProto3Optional.newBuilder().setOptionalNestedEnumValue(5);
-    assertTrue(builder3.hasOptionalNestedEnum());
+    assertThat(builder3.hasOptionalNestedEnum()).isTrue();
 
     TestProto3Optional.Builder builder4 =
         TestProto3Optional.newBuilder().setOptionalNestedEnum(TestProto3Optional.NestedEnum.FOO);
-    assertTrue(builder4.hasOptionalNestedEnum());
+    assertThat(builder4.hasOptionalNestedEnum()).isTrue();
 
     TestProto3Optional proto = TestProto3Optional.parseFrom(builder.build().toByteArray());
-    assertTrue(proto.hasOptionalInt32());
-    assertTrue(proto.toBuilder().hasOptionalInt32());
+    assertThat(proto.hasOptionalInt32()).isTrue();
+    assertThat(proto.toBuilder().hasOptionalInt32()).isTrue();
   }
 
   private static void assertProto3OptionalReflection(String name) throws Exception {
     FieldDescriptor fieldDescriptor = TestProto3Optional.getDescriptor().findFieldByName(name);
     OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof();
-    assertNotNull(fieldDescriptor.getContainingOneof());
-    assertTrue(fieldDescriptor.hasOptionalKeyword());
-    assertTrue(fieldDescriptor.hasPresence());
+    assertThat(fieldDescriptor.getContainingOneof()).isNotNull();
+    assertThat(fieldDescriptor.hasOptionalKeyword()).isTrue();
+    assertThat(fieldDescriptor.hasPresence()).isTrue();
 
-    assertFalse(TestProto3Optional.getDefaultInstance().hasOneof(oneofDescriptor));
-    assertNull(TestProto3Optional.getDefaultInstance().getOneofFieldDescriptor(oneofDescriptor));
+    assertThat(TestProto3Optional.getDefaultInstance().hasOneof(oneofDescriptor)).isFalse();
+    assertThat(TestProto3Optional.getDefaultInstance().getOneofFieldDescriptor(oneofDescriptor))
+        .isNull();
 
     TestProto3Optional.Builder builder = TestProto3Optional.newBuilder();
     builder.setField(fieldDescriptor, fieldDescriptor.getDefaultValue());
-    assertTrue(builder.hasField(fieldDescriptor));
-    assertEquals(fieldDescriptor.getDefaultValue(), builder.getField(fieldDescriptor));
-    assertTrue(builder.build().hasField(fieldDescriptor));
-    assertEquals(fieldDescriptor.getDefaultValue(), builder.build().getField(fieldDescriptor));
-    assertTrue(builder.hasOneof(oneofDescriptor));
-    assertEquals(fieldDescriptor, builder.getOneofFieldDescriptor(oneofDescriptor));
-    assertTrue(builder.build().hasOneof(oneofDescriptor));
-    assertEquals(fieldDescriptor, builder.build().getOneofFieldDescriptor(oneofDescriptor));
+    assertThat(builder.hasField(fieldDescriptor)).isTrue();
+    assertThat(builder.getField(fieldDescriptor)).isEqualTo(fieldDescriptor.getDefaultValue());
+    assertThat(builder.build().hasField(fieldDescriptor)).isTrue();
+    assertThat(builder.build().getField(fieldDescriptor))
+        .isEqualTo(fieldDescriptor.getDefaultValue());
+    assertThat(builder.hasOneof(oneofDescriptor)).isTrue();
+    assertThat(builder.getOneofFieldDescriptor(oneofDescriptor)).isEqualTo(fieldDescriptor);
+    assertThat(builder.build().hasOneof(oneofDescriptor)).isTrue();
+    assertThat(builder.build().getOneofFieldDescriptor(oneofDescriptor)).isEqualTo(fieldDescriptor);
 
     TestProto3Optional.Builder otherBuilder = TestProto3Optional.newBuilder();
     otherBuilder.mergeFrom(builder.build());
-    assertTrue(otherBuilder.hasField(fieldDescriptor));
-    assertEquals(fieldDescriptor.getDefaultValue(), otherBuilder.getField(fieldDescriptor));
+    assertThat(otherBuilder.hasField(fieldDescriptor)).isTrue();
+    assertThat(otherBuilder.getField(fieldDescriptor)).isEqualTo(fieldDescriptor.getDefaultValue());
 
     TestProto3Optional proto = TestProto3Optional.parseFrom(builder.build().toByteArray());
-    assertTrue(proto.hasField(fieldDescriptor));
-    assertTrue(proto.toBuilder().hasField(fieldDescriptor));
+    assertThat(proto.hasField(fieldDescriptor)).isTrue();
+    assertThat(proto.toBuilder().hasField(fieldDescriptor)).isTrue();
 
     DynamicMessage.Builder dynamicBuilder =
         DynamicMessage.newBuilder(TestProto3Optional.getDescriptor());
     dynamicBuilder.setField(fieldDescriptor, fieldDescriptor.getDefaultValue());
-    assertTrue(dynamicBuilder.hasField(fieldDescriptor));
-    assertEquals(fieldDescriptor.getDefaultValue(), dynamicBuilder.getField(fieldDescriptor));
-    assertTrue(dynamicBuilder.build().hasField(fieldDescriptor));
-    assertEquals(
-        fieldDescriptor.getDefaultValue(), dynamicBuilder.build().getField(fieldDescriptor));
-    assertTrue(dynamicBuilder.hasOneof(oneofDescriptor));
-    assertEquals(fieldDescriptor, dynamicBuilder.getOneofFieldDescriptor(oneofDescriptor));
-    assertTrue(dynamicBuilder.build().hasOneof(oneofDescriptor));
-    assertEquals(fieldDescriptor, dynamicBuilder.build().getOneofFieldDescriptor(oneofDescriptor));
+    assertThat(dynamicBuilder.hasField(fieldDescriptor)).isTrue();
+    assertThat(dynamicBuilder.getField(fieldDescriptor))
+        .isEqualTo(fieldDescriptor.getDefaultValue());
+    assertThat(dynamicBuilder.build().hasField(fieldDescriptor)).isTrue();
+    assertThat(dynamicBuilder.build().getField(fieldDescriptor))
+        .isEqualTo(fieldDescriptor.getDefaultValue());
+    assertThat(dynamicBuilder.hasOneof(oneofDescriptor)).isTrue();
+    assertThat(dynamicBuilder.getOneofFieldDescriptor(oneofDescriptor)).isEqualTo(fieldDescriptor);
+    assertThat(dynamicBuilder.build().hasOneof(oneofDescriptor)).isTrue();
+    assertThat(dynamicBuilder.build().getOneofFieldDescriptor(oneofDescriptor))
+        .isEqualTo(fieldDescriptor);
 
     DynamicMessage.Builder otherDynamicBuilder =
         DynamicMessage.newBuilder(TestProto3Optional.getDescriptor());
     otherDynamicBuilder.mergeFrom(dynamicBuilder.build());
-    assertTrue(otherDynamicBuilder.hasField(fieldDescriptor));
-    assertEquals(fieldDescriptor.getDefaultValue(), otherDynamicBuilder.getField(fieldDescriptor));
+    assertThat(otherDynamicBuilder.hasField(fieldDescriptor)).isTrue();
+    assertThat(otherDynamicBuilder.getField(fieldDescriptor))
+        .isEqualTo(fieldDescriptor.getDefaultValue());
 
     DynamicMessage dynamicProto =
         DynamicMessage.parseFrom(TestProto3Optional.getDescriptor(), builder.build().toByteArray());
-    assertTrue(dynamicProto.hasField(fieldDescriptor));
-    assertTrue(dynamicProto.toBuilder().hasField(fieldDescriptor));
+    assertThat(dynamicProto.hasField(fieldDescriptor)).isTrue();
+    assertThat(dynamicProto.toBuilder().hasField(fieldDescriptor)).isTrue();
   }
 
+  @Test
   public void testProto3Optional_reflection() throws Exception {
     assertProto3OptionalReflection("optional_int32");
     assertProto3OptionalReflection("optional_int64");
@@ -212,6 +225,7 @@
     assertProto3OptionalReflection("optional_bytes");
   }
 
+  @Test
   public void testOneofEquals() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes message1 = builder.build();
@@ -219,29 +233,31 @@
     // messages should be different when check with oneof case.
     builder.setOneofUint32(0);
     TestAllTypes message2 = builder.build();
-    assertFalse(message1.equals(message2));
+    assertThat(message1.equals(message2)).isFalse();
   }
 
+  @Test
   public void testLazyField() throws Exception {
     // Test default constructed message.
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes message = builder.build();
-    assertFalse(message.hasOptionalLazyMessage());
-    assertEquals(0, message.getSerializedSize());
-    assertEquals(ByteString.EMPTY, message.toByteString());
+    assertThat(message.hasOptionalLazyMessage()).isFalse();
+    assertThat(message.getSerializedSize()).isEqualTo(0);
+    assertThat(message.toByteString()).isEqualTo(ByteString.EMPTY);
 
     // Set default instance to the field.
     builder.setOptionalLazyMessage(TestAllTypes.NestedMessage.getDefaultInstance());
     message = builder.build();
-    assertTrue(message.hasOptionalLazyMessage());
-    assertEquals(2, message.getSerializedSize());
+    assertThat(message.hasOptionalLazyMessage()).isTrue();
+    assertThat(message.getSerializedSize()).isEqualTo(2);
 
     // Test parse zero-length from wire sets the presence.
     TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteString());
-    assertTrue(parsed.hasOptionalLazyMessage());
-    assertEquals(message.getOptionalLazyMessage(), parsed.getOptionalLazyMessage());
+    assertThat(parsed.hasOptionalLazyMessage()).isTrue();
+    assertThat(parsed.getOptionalLazyMessage()).isEqualTo(message.getOptionalLazyMessage());
   }
 
+  @Test
   public void testFieldPresence() {
     // Optional non-message fields set to their default value are treated the
     // same way as not set.
@@ -253,7 +269,7 @@
     builder.setOptionalBytes(ByteString.EMPTY);
     builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO);
     TestAllTypes message = builder.build();
-    assertEquals(0, message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
 
     // mergeFrom() will ignore such fields.
     TestAllTypes.Builder a = TestAllTypes.newBuilder();
@@ -268,19 +284,20 @@
     b.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO);
     a.mergeFrom(b.build());
     message = a.build();
-    assertEquals(1, message.getOptionalInt32());
-    assertEquals("x", message.getOptionalString());
-    assertEquals(ByteString.copyFromUtf8("y"), message.getOptionalBytes());
-    assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
+    assertThat(message.getOptionalInt32()).isEqualTo(1);
+    assertThat(message.getOptionalString()).isEqualTo("x");
+    assertThat(message.getOptionalBytes()).isEqualTo(ByteString.copyFromUtf8("y"));
+    assertThat(message.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.BAR);
 
     // equals()/hashCode() should produce the same results.
     TestAllTypes empty = TestAllTypes.getDefaultInstance();
     message = builder.build();
-    assertEquals(message, empty);
-    assertEquals(empty, message);
-    assertEquals(empty.hashCode(), message.hashCode());
+    assertThat(empty).isEqualTo(message);
+    assertThat(message).isEqualTo(empty);
+    assertThat(message.hashCode()).isEqualTo(empty.hashCode());
   }
 
+  @Test
   public void testFieldPresenceByReflection() {
     Descriptor descriptor = TestAllTypes.getDescriptor();
     FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32");
@@ -290,11 +307,11 @@
 
     // Field not present.
     TestAllTypes message = TestAllTypes.getDefaultInstance();
-    assertFalse(message.hasField(optionalInt32Field));
-    assertFalse(message.hasField(optionalStringField));
-    assertFalse(message.hasField(optionalBytesField));
-    assertFalse(message.hasField(optionalNestedEnumField));
-    assertEquals(0, message.getAllFields().size());
+    assertThat(message.hasField(optionalInt32Field)).isFalse();
+    assertThat(message.hasField(optionalStringField)).isFalse();
+    assertThat(message.hasField(optionalBytesField)).isFalse();
+    assertThat(message.hasField(optionalNestedEnumField)).isFalse();
+    assertThat(message.getAllFields()).isEmpty();
 
     // Field set to default value is seen as not present.
     message =
@@ -304,11 +321,11 @@
             .setOptionalBytes(ByteString.EMPTY)
             .setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO)
             .build();
-    assertFalse(message.hasField(optionalInt32Field));
-    assertFalse(message.hasField(optionalStringField));
-    assertFalse(message.hasField(optionalBytesField));
-    assertFalse(message.hasField(optionalNestedEnumField));
-    assertEquals(0, message.getAllFields().size());
+    assertThat(message.hasField(optionalInt32Field)).isFalse();
+    assertThat(message.hasField(optionalStringField)).isFalse();
+    assertThat(message.hasField(optionalBytesField)).isFalse();
+    assertThat(message.hasField(optionalNestedEnumField)).isFalse();
+    assertThat(message.getAllFields()).isEmpty();
 
     // Field set to non-default value is seen as present.
     message =
@@ -318,13 +335,14 @@
             .setOptionalBytes(ByteString.copyFromUtf8("y"))
             .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR)
             .build();
-    assertTrue(message.hasField(optionalInt32Field));
-    assertTrue(message.hasField(optionalStringField));
-    assertTrue(message.hasField(optionalBytesField));
-    assertTrue(message.hasField(optionalNestedEnumField));
-    assertEquals(4, message.getAllFields().size());
+    assertThat(message.hasField(optionalInt32Field)).isTrue();
+    assertThat(message.hasField(optionalStringField)).isTrue();
+    assertThat(message.hasField(optionalBytesField)).isTrue();
+    assertThat(message.hasField(optionalNestedEnumField)).isTrue();
+    assertThat(message.getAllFields()).hasSize(4);
   }
 
+  @Test
   public void testFieldPresenceDynamicMessage() {
     Descriptor descriptor = TestAllTypes.getDescriptor();
     FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32");
@@ -338,11 +356,11 @@
     DynamicMessage defaultInstance = DynamicMessage.getDefaultInstance(descriptor);
     // Field not present.
     DynamicMessage message = defaultInstance.newBuilderForType().build();
-    assertFalse(message.hasField(optionalInt32Field));
-    assertFalse(message.hasField(optionalStringField));
-    assertFalse(message.hasField(optionalBytesField));
-    assertFalse(message.hasField(optionalNestedEnumField));
-    assertEquals(0, message.getAllFields().size());
+    assertThat(message.hasField(optionalInt32Field)).isFalse();
+    assertThat(message.hasField(optionalStringField)).isFalse();
+    assertThat(message.hasField(optionalBytesField)).isFalse();
+    assertThat(message.hasField(optionalNestedEnumField)).isFalse();
+    assertThat(message.getAllFields()).isEmpty();
 
     // Field set to non-default value is seen as present.
     message =
@@ -353,11 +371,11 @@
             .setField(optionalBytesField, ByteString.copyFromUtf8("y"))
             .setField(optionalNestedEnumField, nonDefaultEnumValueDescriptor)
             .build();
-    assertTrue(message.hasField(optionalInt32Field));
-    assertTrue(message.hasField(optionalStringField));
-    assertTrue(message.hasField(optionalBytesField));
-    assertTrue(message.hasField(optionalNestedEnumField));
-    assertEquals(4, message.getAllFields().size());
+    assertThat(message.hasField(optionalInt32Field)).isTrue();
+    assertThat(message.hasField(optionalStringField)).isTrue();
+    assertThat(message.hasField(optionalBytesField)).isTrue();
+    assertThat(message.hasField(optionalNestedEnumField)).isTrue();
+    assertThat(message.getAllFields()).hasSize(4);
 
     // Field set to default value is seen as not present.
     message =
@@ -368,36 +386,38 @@
             .setField(optionalBytesField, ByteString.EMPTY)
             .setField(optionalNestedEnumField, defaultEnumValueDescriptor)
             .build();
-    assertFalse(message.hasField(optionalInt32Field));
-    assertFalse(message.hasField(optionalStringField));
-    assertFalse(message.hasField(optionalBytesField));
-    assertFalse(message.hasField(optionalNestedEnumField));
-    assertEquals(0, message.getAllFields().size());
+    assertThat(message.hasField(optionalInt32Field)).isFalse();
+    assertThat(message.hasField(optionalStringField)).isFalse();
+    assertThat(message.hasField(optionalBytesField)).isFalse();
+    assertThat(message.hasField(optionalNestedEnumField)).isFalse();
+    assertThat(message.getAllFields()).isEmpty();
   }
 
+  @Test
   public void testMessageField() {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    assertFalse(builder.hasOptionalNestedMessage());
-    assertFalse(builder.build().hasOptionalNestedMessage());
+    assertThat(builder.hasOptionalNestedMessage()).isFalse();
+    assertThat(builder.build().hasOptionalNestedMessage()).isFalse();
 
     TestAllTypes.NestedMessage.Builder nestedBuilder = builder.getOptionalNestedMessageBuilder();
-    assertTrue(builder.hasOptionalNestedMessage());
-    assertTrue(builder.build().hasOptionalNestedMessage());
+    assertThat(builder.hasOptionalNestedMessage()).isTrue();
+    assertThat(builder.build().hasOptionalNestedMessage()).isTrue();
 
     nestedBuilder.setValue(1);
-    assertEquals(1, builder.build().getOptionalNestedMessage().getValue());
+    assertThat(builder.build().getOptionalNestedMessage().getValue()).isEqualTo(1);
 
     builder.clearOptionalNestedMessage();
-    assertFalse(builder.hasOptionalNestedMessage());
-    assertFalse(builder.build().hasOptionalNestedMessage());
+    assertThat(builder.hasOptionalNestedMessage()).isFalse();
+    assertThat(builder.build().hasOptionalNestedMessage()).isFalse();
 
     // Unlike non-message fields, if we set a message field to its default value (i.e.,
     // default instance), the field should be seen as present.
     builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
-    assertTrue(builder.hasOptionalNestedMessage());
-    assertTrue(builder.build().hasOptionalNestedMessage());
+    assertThat(builder.hasOptionalNestedMessage()).isTrue();
+    assertThat(builder.build().hasOptionalNestedMessage()).isTrue();
   }
 
+  @Test
   public void testSerializeAndParse() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     builder.setOptionalInt32(1234);
@@ -409,20 +429,21 @@
     ByteString data = builder.build().toByteString();
 
     TestAllTypes message = TestAllTypes.parseFrom(data);
-    assertEquals(1234, message.getOptionalInt32());
-    assertEquals("hello", message.getOptionalString());
+    assertThat(message.getOptionalInt32()).isEqualTo(1234);
+    assertThat(message.getOptionalString()).isEqualTo("hello");
     // Fields not set will have the default value.
-    assertEquals(ByteString.EMPTY, message.getOptionalBytes());
-    assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum());
+    assertThat(message.getOptionalBytes()).isEqualTo(ByteString.EMPTY);
+    assertThat(message.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.FOO);
     // The message field is set despite that it's set with a default instance.
-    assertTrue(message.hasOptionalNestedMessage());
-    assertEquals(0, message.getOptionalNestedMessage().getValue());
+    assertThat(message.hasOptionalNestedMessage()).isTrue();
+    assertThat(message.getOptionalNestedMessage().getValue()).isEqualTo(0);
     // The oneof field set to its default value is also present.
-    assertEquals(TestAllTypes.OneofFieldCase.ONEOF_INT32, message.getOneofFieldCase());
+    assertThat(message.getOneofFieldCase()).isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_INT32);
   }
 
   // Regression test for b/16173397
   // Make sure we haven't screwed up the code generation for repeated fields.
+  @Test
   public void testRepeatedFields() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     builder.setOptionalInt32(1234);
@@ -434,49 +455,50 @@
     ByteString data = builder.build().toByteString();
 
     TestOptionalFieldsOnly optionalOnlyMessage = TestOptionalFieldsOnly.parseFrom(data);
-    assertEquals(1234, optionalOnlyMessage.getOptionalInt32());
-    assertEquals("hello", optionalOnlyMessage.getOptionalString());
-    assertTrue(optionalOnlyMessage.hasOptionalNestedMessage());
-    assertEquals(0, optionalOnlyMessage.getOptionalNestedMessage().getValue());
+    assertThat(optionalOnlyMessage.getOptionalInt32()).isEqualTo(1234);
+    assertThat(optionalOnlyMessage.getOptionalString()).isEqualTo("hello");
+    assertThat(optionalOnlyMessage.hasOptionalNestedMessage()).isTrue();
+    assertThat(optionalOnlyMessage.getOptionalNestedMessage().getValue()).isEqualTo(0);
 
     TestRepeatedFieldsOnly repeatedOnlyMessage = TestRepeatedFieldsOnly.parseFrom(data);
-    assertEquals(1, repeatedOnlyMessage.getRepeatedInt32Count());
-    assertEquals(4321, repeatedOnlyMessage.getRepeatedInt32(0));
-    assertEquals(1, repeatedOnlyMessage.getRepeatedStringCount());
-    assertEquals("world", repeatedOnlyMessage.getRepeatedString(0));
-    assertEquals(1, repeatedOnlyMessage.getRepeatedNestedMessageCount());
-    assertEquals(0, repeatedOnlyMessage.getRepeatedNestedMessage(0).getValue());
+    assertThat(repeatedOnlyMessage.getRepeatedInt32Count()).isEqualTo(1);
+    assertThat(repeatedOnlyMessage.getRepeatedInt32(0)).isEqualTo(4321);
+    assertThat(repeatedOnlyMessage.getRepeatedStringCount()).isEqualTo(1);
+    assertThat(repeatedOnlyMessage.getRepeatedString(0)).isEqualTo("world");
+    assertThat(repeatedOnlyMessage.getRepeatedNestedMessageCount()).isEqualTo(1);
+    assertThat(repeatedOnlyMessage.getRepeatedNestedMessage(0).getValue()).isEqualTo(0);
   }
 
+  @Test
   public void testIsInitialized() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
 
     // Test optional proto2 message fields.
     UnittestProto.TestRequired.Builder proto2Builder = builder.getOptionalProto2MessageBuilder();
-    assertFalse(builder.isInitialized());
-    assertFalse(builder.buildPartial().isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
+    assertThat(builder.buildPartial().isInitialized()).isFalse();
 
     proto2Builder.setA(1).setB(2).setC(3);
-    assertTrue(builder.isInitialized());
-    assertTrue(builder.buildPartial().isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
+    assertThat(builder.buildPartial().isInitialized()).isTrue();
 
     // Test oneof proto2 message fields.
     proto2Builder = builder.getOneofProto2MessageBuilder();
-    assertFalse(builder.isInitialized());
-    assertFalse(builder.buildPartial().isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
+    assertThat(builder.buildPartial().isInitialized()).isFalse();
 
     proto2Builder.setA(1).setB(2).setC(3);
-    assertTrue(builder.isInitialized());
-    assertTrue(builder.buildPartial().isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
+    assertThat(builder.buildPartial().isInitialized()).isTrue();
 
     // Test repeated proto2 message fields.
     proto2Builder = builder.addRepeatedProto2MessageBuilder();
-    assertFalse(builder.isInitialized());
-    assertFalse(builder.buildPartial().isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
+    assertThat(builder.buildPartial().isInitialized()).isFalse();
 
     proto2Builder.setA(1).setB(2).setC(3);
-    assertTrue(builder.isInitialized());
-    assertTrue(builder.buildPartial().isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
+    assertThat(builder.buildPartial().isInitialized()).isTrue();
   }
 
 }
diff --git a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
index 091ac5b..8fe8508 100644
--- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -30,39 +30,44 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static java.util.Arrays.asList;
 
 import com.google.protobuf.Internal.FloatList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests for {@link FloatArrayList}.
- *
- * @author [email protected] (Daniel Weis)
- */
-public class FloatArrayListTest extends TestCase {
+/** Tests for {@link FloatArrayList}. */
+@RunWith(JUnit4.class)
+public class FloatArrayListTest {
 
   private static final FloatArrayList UNARY_LIST = newImmutableFloatArrayList(1);
   private static final FloatArrayList TERTIARY_LIST = newImmutableFloatArrayList(1, 2, 3);
 
   private FloatArrayList list;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     list = new FloatArrayList();
   }
 
+  @Test
   public void testEmptyListReturnsSameInstance() {
-    assertSame(FloatArrayList.emptyList(), FloatArrayList.emptyList());
+    assertThat(FloatArrayList.emptyList()).isSameInstanceAs(FloatArrayList.emptyList());
   }
 
+  @Test
   public void testEmptyListIsImmutable() {
     assertImmutable(FloatArrayList.emptyList());
   }
 
+  @Test
   public void testMakeImmutable() {
     list.addFloat(3);
     list.addFloat(4);
@@ -72,19 +77,20 @@
     assertImmutable(list);
   }
 
+  @Test
   public void testModificationWithIteration() {
     list.addAll(asList(1F, 2F, 3F, 4F));
     Iterator<Float> iterator = list.iterator();
-    assertEquals(4, list.size());
-    assertEquals(1F, (float) list.get(0), 0.0f);
-    assertEquals(1F, (float) iterator.next(), 0.0f);
+    assertThat(list).hasSize(4);
+    assertThat((float) list.get(0)).isEqualTo(1F);
+    assertThat((float) iterator.next()).isEqualTo(1F);
     list.set(0, 1F);
-    assertEquals(2F, (float) iterator.next(), 0.0f);
+    assertThat((float) iterator.next()).isEqualTo(2F);
 
     list.remove(0);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
@@ -93,191 +99,211 @@
     list.add(0, 0F);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
   }
 
+  @Test
   public void testGet() {
-    assertEquals(1F, (float) TERTIARY_LIST.get(0), 0.0f);
-    assertEquals(2F, (float) TERTIARY_LIST.get(1), 0.0f);
-    assertEquals(3F, (float) TERTIARY_LIST.get(2), 0.0f);
+    assertThat((float) TERTIARY_LIST.get(0)).isEqualTo(1F);
+    assertThat((float) TERTIARY_LIST.get(1)).isEqualTo(2F);
+    assertThat((float) TERTIARY_LIST.get(2)).isEqualTo(3F);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testGetFloat() {
-    assertEquals(1F, TERTIARY_LIST.getFloat(0), 0.0f);
-    assertEquals(2F, TERTIARY_LIST.getFloat(1), 0.0f);
-    assertEquals(3F, TERTIARY_LIST.getFloat(2), 0.0f);
+    assertThat(TERTIARY_LIST.getFloat(0)).isEqualTo(1F);
+    assertThat(TERTIARY_LIST.getFloat(1)).isEqualTo(2F);
+    assertThat(TERTIARY_LIST.getFloat(2)).isEqualTo(3F);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testIndexOf_nullElement() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(null));
+    assertThat(TERTIARY_LIST.indexOf(null)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_incompatibleElementType() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(new Object()));
+    assertThat(TERTIARY_LIST.indexOf(new Object())).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInList() {
-    assertEquals(-1, UNARY_LIST.indexOf(2F));
+    assertThat(UNARY_LIST.indexOf(2F)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInListWithDuplicates() {
     FloatArrayList listWithDupes = newImmutableFloatArrayList(1F, 1F);
-    assertEquals(-1, listWithDupes.indexOf(2F));
+    assertThat(listWithDupes.indexOf(2F)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_inList() {
-    assertEquals(1, TERTIARY_LIST.indexOf(2F));
+    assertThat(TERTIARY_LIST.indexOf(2F)).isEqualTo(1);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchAtHead() {
     FloatArrayList listWithDupes = newImmutableFloatArrayList(1F, 1F, 2F);
-    assertEquals(0, listWithDupes.indexOf(1F));
+    assertThat(listWithDupes.indexOf(1F)).isEqualTo(0);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchMidList() {
     FloatArrayList listWithDupes = newImmutableFloatArrayList(2F, 1F, 1F, 2F);
-    assertEquals(1, listWithDupes.indexOf(1F));
+    assertThat(listWithDupes.indexOf(1F)).isEqualTo(1);
   }
 
+  @Test
   public void testContains_nullElement() {
-    assertEquals(false, TERTIARY_LIST.contains(null));
+    assertThat(TERTIARY_LIST).doesNotContain(null);
   }
 
+  @Test
   public void testContains_incompatibleElementType() {
-    assertEquals(false, TERTIARY_LIST.contains(new Object()));
+    assertThat(TERTIARY_LIST).doesNotContain(new Object());
   }
 
+  @Test
   public void testContains_notInList() {
-    assertEquals(false, UNARY_LIST.contains(2F));
+    assertThat(UNARY_LIST).doesNotContain(2F);
   }
 
+  @Test
   public void testContains_notInListWithDuplicates() {
     FloatArrayList listWithDupes = newImmutableFloatArrayList(1F, 1F);
-    assertEquals(false, listWithDupes.contains(2F));
+    assertThat(listWithDupes).doesNotContain(2F);
   }
 
+  @Test
   public void testContains_inList() {
-    assertEquals(true, TERTIARY_LIST.contains(2F));
+    assertThat(TERTIARY_LIST).contains(2F);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchAtHead() {
     FloatArrayList listWithDupes = newImmutableFloatArrayList(1F, 1F, 2F);
-    assertEquals(true, listWithDupes.contains(1F));
+    assertThat(listWithDupes).contains(1F);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchMidList() {
     FloatArrayList listWithDupes = newImmutableFloatArrayList(2F, 1F, 1F, 2F);
-    assertEquals(true, listWithDupes.contains(1F));
+    assertThat(listWithDupes).contains(1F);
   }
 
+  @Test
   public void testSize() {
-    assertEquals(0, FloatArrayList.emptyList().size());
-    assertEquals(1, UNARY_LIST.size());
-    assertEquals(3, TERTIARY_LIST.size());
+    assertThat(FloatArrayList.emptyList()).isEmpty();
+    assertThat(UNARY_LIST).hasSize(1);
+    assertThat(TERTIARY_LIST).hasSize(3);
 
     list.addFloat(3);
     list.addFloat(4);
     list.addFloat(6);
     list.addFloat(8);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
 
     list.remove(0);
-    assertEquals(3, list.size());
+    assertThat(list).hasSize(3);
 
     list.add(17F);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
   }
 
+  @Test
   public void testSet() {
     list.addFloat(2);
     list.addFloat(4);
 
-    assertEquals(2F, (float) list.set(0, 3F), 0.0f);
-    assertEquals(3F, list.getFloat(0), 0.0f);
+    assertThat((float) list.set(0, 3F)).isEqualTo(2F);
+    assertThat(list.getFloat(0)).isEqualTo(3F);
 
-    assertEquals(4F, (float) list.set(1, 0F), 0.0f);
-    assertEquals(0F, list.getFloat(1), 0.0f);
+    assertThat((float) list.set(1, 0F)).isEqualTo(4F);
+    assertThat(list.getFloat(1)).isEqualTo(0F);
 
     try {
       list.set(-1, 0F);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.set(2, 0F);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testSetFloat() {
     list.addFloat(1);
     list.addFloat(3);
 
-    assertEquals(1F, list.setFloat(0, 0), 0.0f);
-    assertEquals(0F, list.getFloat(0), 0.0f);
+    assertThat(list.setFloat(0, 0)).isEqualTo(1F);
+    assertThat(list.getFloat(0)).isEqualTo(0F);
 
-    assertEquals(3F, list.setFloat(1, 0), 0.0f);
-    assertEquals(0F, list.getFloat(1), 0.0f);
+    assertThat(list.setFloat(1, 0)).isEqualTo(3F);
+    assertThat(list.getFloat(1)).isEqualTo(0F);
 
     try {
       list.setFloat(-1, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.setFloat(2, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testAdd() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.add(2F));
-    assertEquals(asList(2F), list);
+    assertThat(list.add(2F)).isTrue();
+    assertThat(list).containsExactly(2F);
 
-    assertTrue(list.add(3F));
+    assertThat(list.add(3F)).isTrue();
     list.add(0, 4F);
-    assertEquals(asList(4F, 2F, 3F), list);
+    assertThat(list).containsExactly(4F, 2F, 3F).inOrder();
 
     list.add(0, 1F);
     list.add(0, 0F);
@@ -285,7 +311,7 @@
     for (int i = 0; i < 6; i++) {
       list.add(Float.valueOf(5 + i));
     }
-    assertEquals(asList(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F), list);
+    assertThat(list).containsExactly(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F).inOrder();
 
     try {
       list.add(-1, 5F);
@@ -300,92 +326,100 @@
     }
   }
 
+  @Test
   public void testAddFloat() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
     list.addFloat(2);
-    assertEquals(asList(2F), list);
+    assertThat(list).containsExactly(2F);
 
     list.addFloat(3);
-    assertEquals(asList(2F, 3F), list);
+    assertThat(list).containsExactly(2F, 3F).inOrder();
   }
 
+  @Test
   public void testAddAll() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.addAll(Collections.singleton(1F)));
-    assertEquals(1, list.size());
-    assertEquals(1F, (float) list.get(0), 0.0f);
-    assertEquals(1F, list.getFloat(0), 0.0f);
+    assertThat(list.addAll(Collections.singleton(1F))).isTrue();
+    assertThat(list).hasSize(1);
+    assertThat((float) list.get(0)).isEqualTo(1F);
+    assertThat(list.getFloat(0)).isEqualTo(1F);
 
-    assertTrue(list.addAll(asList(2F, 3F, 4F, 5F, 6F)));
-    assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F), list);
+    assertThat(list.addAll(asList(2F, 3F, 4F, 5F, 6F))).isTrue();
+    assertThat(list).containsExactly(1F, 2F, 3F, 4F, 5F, 6F).inOrder();
 
-    assertTrue(list.addAll(TERTIARY_LIST));
-    assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F, 1F, 2F, 3F), list);
+    assertThat(list.addAll(TERTIARY_LIST)).isTrue();
+    assertThat(list).containsExactly(1F, 2F, 3F, 4F, 5F, 6F, 1F, 2F, 3F).inOrder();
 
-    assertFalse(list.addAll(Collections.<Float>emptyList()));
-    assertFalse(list.addAll(FloatArrayList.emptyList()));
+    assertThat(list.addAll(Collections.<Float>emptyList())).isFalse();
+    assertThat(list.addAll(FloatArrayList.emptyList())).isFalse();
   }
 
+  @Test
   public void testEquals() {
     FloatArrayList list1 = new FloatArrayList();
     FloatArrayList list2 = new FloatArrayList();
 
     list1.addFloat(Float.intBitsToFloat(0xff800001));
     list2.addFloat(Float.intBitsToFloat(0xff800002));
-    assertEquals(list1, list2);
+    assertThat(list1).isEqualTo(list2);
   }
 
+  @Test
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
-    assertEquals(1F, (float) list.remove(0), 0.0f);
-    assertEquals(asList(2F, 3F), list);
+    assertThat((float) list.remove(0)).isEqualTo(1F);
+    assertThat(list).containsExactly(2F, 3F).inOrder();
 
-    assertTrue(list.remove(Float.valueOf(3)));
-    assertEquals(asList(2F), list);
+    assertThat(list.remove(Float.valueOf(3))).isTrue();
+    assertThat(list).containsExactly(2F);
 
-    assertFalse(list.remove(Float.valueOf(3)));
-    assertEquals(asList(2F), list);
+    assertThat(list.remove(Float.valueOf(3))).isFalse();
+    assertThat(list).containsExactly(2F);
 
-    assertEquals(2F, (float) list.remove(0), 0.0f);
-    assertEquals(asList(), list);
+    assertThat((float) list.remove(0)).isEqualTo(2F);
+    assertThat(list).isEmpty();
 
     try {
       list.remove(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.remove(0);
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testRemoveEnd_listAtCapacity() {
     FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addFloat(3);
     toRemove.remove(0);
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
+  @Test
   public void testRemove_listAtCapacity() {
     FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(2);
     toRemove.addFloat(3);
     toRemove.addFloat(4);
     toRemove.remove(0);
-    assertEquals(1, toRemove.size());
-    assertEquals(4F, (float) toRemove.get(0));
+    assertThat(toRemove).hasSize(1);
+    assertThat((float) toRemove.get(0)).isEqualTo(4F);
   }
 
+  @Test
   public void testSublistRemoveEndOfCapacity() {
     FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addFloat(3);
     toRemove.subList(0, 1).clear();
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
   private void assertImmutable(FloatList list) {
@@ -395,147 +429,147 @@
 
     try {
       list.add(1F);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.add(0, 1F);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.<Float>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.singletonList(1F));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(new FloatArrayList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.singleton(1F));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.<Float>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addFloat(0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.clear();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.<Float>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.singleton(1F));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(Collections.<Float>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(Collections.singleton(1F));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.set(0, 0F);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.setFloat(0, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
index 840e13e..fbba612 100644
--- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.test.UnittestImport;
@@ -68,24 +71,27 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Unit test for generated messages and generated code. See also {@link MessageTest}, which tests
  * some generated message functionality.
- *
- * @author [email protected] Kenton Varda
  */
 @SuppressWarnings({"ProtoBuilderReturnValueIgnored", "ReturnValueIgnored"})
-public class GeneratedMessageTest extends TestCase {
+@RunWith(JUnit4.class)
+public class GeneratedMessageTest {
   TestUtil.ReflectionTester reflectionTester =
       new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
 
-  @Override
+  @After
   public void tearDown() {
     GeneratedMessageV3.setAlwaysUseFieldBuildersForTesting(false);
   }
 
+  @Test
   public void testGetFieldBuilderForExtensionField() {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     Message.Builder fieldBuilder =
@@ -94,18 +100,17 @@
     FieldDescriptor field =
         NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+    assertThat(builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb())
+        .isEqualTo(expected);
 
     // fieldBuilder still updates the builder after builder build() has been called.
     expected += 100;
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+    assertThat(builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb())
+        .isEqualTo(expected);
   }
 
+  @Test
   public void testGetFieldBuilderWithExistingMessage() {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     builder.setExtension(
@@ -117,18 +122,17 @@
     FieldDescriptor field =
         NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+    assertThat(builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb())
+        .isEqualTo(expected);
 
     // fieldBuilder still updates the builder after builder build() has been called.
     expected += 100;
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+    assertThat(builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb())
+        .isEqualTo(expected);
   }
 
+  @Test
   public void testGetFieldBuilderWithExistingBuilder() {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     NestedMessage.Builder nestedMessageBuilder = NestedMessage.newBuilder().setBb(123);
@@ -140,25 +144,23 @@
     FieldDescriptor field =
         NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+    assertThat(builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb())
+        .isEqualTo(expected);
 
     // Existing nestedMessageBuilder will also update builder.
     expected += 100;
     nestedMessageBuilder.setBb(expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+    assertThat(builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb())
+        .isEqualTo(expected);
 
     // fieldBuilder still updates the builder.
     expected += 100;
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+    assertThat(builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb())
+        .isEqualTo(expected);
   }
 
+  @Test
   public void testGetRepeatedFieldBuilderForExtensionField() {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     builder.addExtension(
@@ -171,18 +173,19 @@
     FieldDescriptor field =
         NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+    assertThat(
+            builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb())
+        .isEqualTo(expected);
 
     // fieldBuilder still updates the builder after builder build() has been called.
     expected += 100;
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+    assertThat(
+            builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb())
+        .isEqualTo(expected);
   }
 
+  @Test
   public void testGetRepeatedFieldBuilderForExistingBuilder() {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     NestedMessage.Builder nestedMessageBuilder = NestedMessage.newBuilder().setBb(123);
@@ -195,59 +198,61 @@
     FieldDescriptor field =
         NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+    assertThat(
+            builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb())
+        .isEqualTo(expected);
 
     // Existing nestedMessageBuilder will also update builder.
     expected += 100;
     nestedMessageBuilder.setBb(expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+    assertThat(
+            builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb())
+        .isEqualTo(expected);
 
     // fieldBuilder still updates the builder.
     expected += 100;
     fieldBuilder.setField(field, expected);
-    assertEquals(
-        expected,
-        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+    assertThat(
+            builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb())
+        .isEqualTo(expected);
   }
 
+  @Test
   public void testGetExtensionFieldOutOfBound() {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     try {
       builder.getRepeatedField(UnittestProto.repeatedNestedMessageExtension.getDescriptor(), 0);
-      fail("Expected IndexOutOfBoundsException to be thrown");
+      assertWithMessage("Expected IndexOutOfBoundsException to be thrown").fail();
     } catch (IndexOutOfBoundsException expected) {
     }
     try {
       builder.getExtension(UnittestProto.repeatedNestedMessageExtension, 0);
-      fail("Expected IndexOutOfBoundsException to be thrown");
+      assertWithMessage("Expected IndexOutOfBoundsException to be thrown").fail();
     } catch (IndexOutOfBoundsException expected) {
     }
     TestAllExtensions extensionsMessage = builder.build();
     try {
       extensionsMessage.getRepeatedField(
           UnittestProto.repeatedNestedMessageExtension.getDescriptor(), 0);
-      fail("Expected IndexOutOfBoundsException to be thrown");
+      assertWithMessage("Expected IndexOutOfBoundsException to be thrown").fail();
     } catch (IndexOutOfBoundsException expected) {
     }
     try {
       extensionsMessage.getExtension(UnittestProto.repeatedNestedMessageExtension, 0);
-      fail("Expected IndexOutOfBoundsException to be thrown");
+      assertWithMessage("Expected IndexOutOfBoundsException to be thrown").fail();
     } catch (IndexOutOfBoundsException expected) {
     }
   }
 
+  @Test
   public void testDefaultInstance() throws Exception {
-    assertSame(
-        TestAllTypes.getDefaultInstance(),
-        TestAllTypes.getDefaultInstance().getDefaultInstanceForType());
-    assertSame(
-        TestAllTypes.getDefaultInstance(), TestAllTypes.newBuilder().getDefaultInstanceForType());
+    assertThat(TestAllTypes.getDefaultInstance())
+        .isSameInstanceAs(TestAllTypes.getDefaultInstance().getDefaultInstanceForType());
+    assertThat(TestAllTypes.getDefaultInstance())
+        .isSameInstanceAs(TestAllTypes.newBuilder().getDefaultInstanceForType());
   }
 
+  @Test
   public void testMessageOrBuilder() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
@@ -255,6 +260,7 @@
     TestUtil.assertAllFieldsSet(message);
   }
 
+  @Test
   public void testUsingBuilderMultipleTimes() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     // primitive field scalar and repeated
@@ -269,12 +275,12 @@
 
     TestAllTypes value1 = builder.build();
 
-    assertEquals(100, value1.getOptionalSfixed64());
-    assertEquals(100, value1.getRepeatedInt32(0));
-    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR, value1.getOptionalImportEnum());
-    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR, value1.getRepeatedImportEnum(0));
-    assertEquals(1, value1.getOptionalForeignMessage().getC());
-    assertEquals(1, value1.getRepeatedForeignMessage(0).getC());
+    assertThat(value1.getOptionalSfixed64()).isEqualTo(100);
+    assertThat(value1.getRepeatedInt32(0)).isEqualTo(100);
+    assertThat(value1.getOptionalImportEnum()).isEqualTo(UnittestImport.ImportEnum.IMPORT_BAR);
+    assertThat(value1.getRepeatedImportEnum(0)).isEqualTo(UnittestImport.ImportEnum.IMPORT_BAR);
+    assertThat(value1.getOptionalForeignMessage().getC()).isEqualTo(1);
+    assertThat(value1.getRepeatedForeignMessage(0).getC()).isEqualTo(1);
 
     // Make sure that builder didn't update previously created values
     builder.setOptionalSfixed64(200);
@@ -287,22 +293,23 @@
     TestAllTypes value2 = builder.build();
 
     // Make sure value1 didn't change.
-    assertEquals(100, value1.getOptionalSfixed64());
-    assertEquals(100, value1.getRepeatedInt32(0));
-    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR, value1.getOptionalImportEnum());
-    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR, value1.getRepeatedImportEnum(0));
-    assertEquals(1, value1.getOptionalForeignMessage().getC());
-    assertEquals(1, value1.getRepeatedForeignMessage(0).getC());
+    assertThat(value1.getOptionalSfixed64()).isEqualTo(100);
+    assertThat(value1.getRepeatedInt32(0)).isEqualTo(100);
+    assertThat(value1.getOptionalImportEnum()).isEqualTo(UnittestImport.ImportEnum.IMPORT_BAR);
+    assertThat(value1.getRepeatedImportEnum(0)).isEqualTo(UnittestImport.ImportEnum.IMPORT_BAR);
+    assertThat(value1.getOptionalForeignMessage().getC()).isEqualTo(1);
+    assertThat(value1.getRepeatedForeignMessage(0).getC()).isEqualTo(1);
 
     // Make sure value2 is correct
-    assertEquals(200, value2.getOptionalSfixed64());
-    assertEquals(200, value2.getRepeatedInt32(0));
-    assertEquals(UnittestImport.ImportEnum.IMPORT_FOO, value2.getOptionalImportEnum());
-    assertEquals(UnittestImport.ImportEnum.IMPORT_FOO, value2.getRepeatedImportEnum(0));
-    assertEquals(2, value2.getOptionalForeignMessage().getC());
-    assertEquals(2, value2.getRepeatedForeignMessage(0).getC());
+    assertThat(value2.getOptionalSfixed64()).isEqualTo(200);
+    assertThat(value2.getRepeatedInt32(0)).isEqualTo(200);
+    assertThat(value2.getOptionalImportEnum()).isEqualTo(UnittestImport.ImportEnum.IMPORT_FOO);
+    assertThat(value2.getRepeatedImportEnum(0)).isEqualTo(UnittestImport.ImportEnum.IMPORT_FOO);
+    assertThat(value2.getOptionalForeignMessage().getC()).isEqualTo(2);
+    assertThat(value2.getRepeatedForeignMessage(0).getC()).isEqualTo(2);
   }
 
+  @Test
   public void testProtosShareRepeatedArraysIfDidntChange() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     builder.addRepeatedInt32(100);
@@ -311,10 +318,12 @@
     TestAllTypes value1 = builder.build();
     TestAllTypes value2 = value1.toBuilder().build();
 
-    assertSame(value1.getRepeatedInt32List(), value2.getRepeatedInt32List());
-    assertSame(value1.getRepeatedForeignMessageList(), value2.getRepeatedForeignMessageList());
+    assertThat(value1.getRepeatedInt32List()).isSameInstanceAs(value2.getRepeatedInt32List());
+    assertThat(value1.getRepeatedForeignMessageList())
+        .isSameInstanceAs(value2.getRepeatedForeignMessageList());
   }
 
+  @Test
   public void testRepeatedArraysAreImmutable() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     builder.addRepeatedInt32(100);
@@ -332,6 +341,7 @@
     assertIsUnmodifiable(value.getRepeatedFloatList());
   }
 
+  @Test
   public void testParsedMessagesAreImmutable() throws Exception {
     TestAllTypes value = TestAllTypes.parser().parseFrom(TestUtil.getAllSet().toByteString());
     assertIsUnmodifiable(value.getRepeatedInt32List());
@@ -364,77 +374,79 @@
     } else {
       try {
         list.clear();
-        fail("List wasn't immutable");
+        assertWithMessage("List wasn't immutable").fail();
       } catch (UnsupportedOperationException e) {
         // good
       }
     }
   }
 
+  @Test
   public void testSettersRejectNull() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
       builder.setOptionalString(null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.setOptionalBytes(null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.setOptionalNestedMessage((TestAllTypes.NestedMessage) null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.setOptionalNestedMessage((TestAllTypes.NestedMessage.Builder) null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.setOptionalNestedEnum(null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.addRepeatedString(null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.addRepeatedBytes(null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.addRepeatedNestedMessage((TestAllTypes.NestedMessage) null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.addRepeatedNestedMessage((TestAllTypes.NestedMessage.Builder) null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.addRepeatedNestedEnum(null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
   }
 
+  @Test
   public void testRepeatedSetters() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
@@ -443,6 +455,7 @@
     TestUtil.assertRepeatedFieldsModified(message);
   }
 
+  @Test
   public void testRepeatedSettersRejectNull() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
 
@@ -450,7 +463,7 @@
     builder.addRepeatedString("two");
     try {
       builder.setRepeatedString(1, null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
@@ -459,7 +472,7 @@
     builder.addRepeatedBytes(TestUtil.toBytes("two"));
     try {
       builder.setRepeatedBytes(1, null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
@@ -468,13 +481,13 @@
     builder.addRepeatedNestedMessage(TestAllTypes.NestedMessage.newBuilder().setBb(456).build());
     try {
       builder.setRepeatedNestedMessage(1, (TestAllTypes.NestedMessage) null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
     try {
       builder.setRepeatedNestedMessage(1, (TestAllTypes.NestedMessage.Builder) null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
@@ -483,12 +496,13 @@
     builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAR);
     try {
       builder.setRepeatedNestedEnum(1, null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
   }
 
+  @Test
   public void testRepeatedAppend() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
 
@@ -499,45 +513,48 @@
     builder.addAllRepeatedForeignMessage(Arrays.asList(foreignMessage));
 
     TestAllTypes message = builder.build();
-    assertEquals(message.getRepeatedInt32List(), Arrays.asList(1, 2, 3, 4));
-    assertEquals(message.getRepeatedForeignEnumList(), Arrays.asList(ForeignEnum.FOREIGN_BAZ));
-    assertEquals(1, message.getRepeatedForeignMessageCount());
-    assertEquals(12, message.getRepeatedForeignMessage(0).getC());
+    assertThat(Arrays.asList(1, 2, 3, 4)).isEqualTo(message.getRepeatedInt32List());
+    assertThat(Arrays.asList(ForeignEnum.FOREIGN_BAZ))
+        .isEqualTo(message.getRepeatedForeignEnumList());
+    assertThat(message.getRepeatedForeignMessageCount()).isEqualTo(1);
+    assertThat(message.getRepeatedForeignMessage(0).getC()).isEqualTo(12);
   }
 
+  @Test
   public void testRepeatedAppendRejectsNull() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
 
     ForeignMessage foreignMessage = ForeignMessage.newBuilder().setC(12).build();
     try {
       builder.addAllRepeatedForeignMessage(Arrays.asList(foreignMessage, (ForeignMessage) null));
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
 
     try {
       builder.addAllRepeatedForeignEnum(Arrays.asList(ForeignEnum.FOREIGN_BAZ, null));
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
 
     try {
       builder.addAllRepeatedString(Arrays.asList("one", null));
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
 
     try {
       builder.addAllRepeatedBytes(Arrays.asList(TestUtil.toBytes("one"), null));
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
   }
 
+  @Test
   public void testRepeatedAppendIterateOnlyOnce() throws Exception {
     // Create a Iterable that can only be iterated once.
     Iterable<String> stringIterable =
@@ -555,29 +572,31 @@
         };
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     builder.addAllRepeatedString(stringIterable);
-    assertEquals(3, builder.getRepeatedStringCount());
-    assertEquals("one", builder.getRepeatedString(0));
-    assertEquals("two", builder.getRepeatedString(1));
-    assertEquals("three", builder.getRepeatedString(2));
+    assertThat(builder.getRepeatedStringCount()).isEqualTo(3);
+    assertThat(builder.getRepeatedString(0)).isEqualTo("one");
+    assertThat(builder.getRepeatedString(1)).isEqualTo("two");
+    assertThat(builder.getRepeatedString(2)).isEqualTo("three");
 
     try {
       builder.addAllRepeatedString(stringIterable);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (IllegalStateException e) {
       // We expect this exception.
     }
   }
 
+  @Test
   public void testMergeFromOtherRejectsNull() throws Exception {
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       builder.mergeFrom((TestAllTypes) null);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (NullPointerException e) {
       // We expect this exception.
     }
   }
 
+  @Test
   public void testSettingForeignMessageUsingBuilder() throws Exception {
     TestAllTypes message =
         TestAllTypes.newBuilder()
@@ -590,9 +609,10 @@
             .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(123).build())
             .build();
     // TODO(ngd): Upgrade to using real #equals method once implemented
-    assertEquals(expectedMessage.toString(), message.toString());
+    assertThat(message.toString()).isEqualTo(expectedMessage.toString());
   }
 
+  @Test
   public void testSettingRepeatedForeignMessageUsingBuilder() throws Exception {
     TestAllTypes message =
         TestAllTypes.newBuilder()
@@ -604,24 +624,26 @@
             // Create expected version passing foreign message instance explicitly.
             .addRepeatedForeignMessage(ForeignMessage.newBuilder().setC(456).build())
             .build();
-    assertEquals(expectedMessage.toString(), message.toString());
+    assertThat(message.toString()).isEqualTo(expectedMessage.toString());
   }
 
+  @Test
   public void testDefaults() throws Exception {
     TestUtil.assertClear(TestAllTypes.getDefaultInstance());
     TestUtil.assertClear(TestAllTypes.newBuilder().build());
 
     TestExtremeDefaultValues message = TestExtremeDefaultValues.getDefaultInstance();
-    assertEquals("\u1234", message.getUtf8String());
-    assertEquals(Double.POSITIVE_INFINITY, message.getInfDouble(), 0.0);
-    assertEquals(Double.NEGATIVE_INFINITY, message.getNegInfDouble(), 0.0);
-    assertTrue(Double.isNaN(message.getNanDouble()));
-    assertEquals(Float.POSITIVE_INFINITY, message.getInfFloat(), 0.0f);
-    assertEquals(Float.NEGATIVE_INFINITY, message.getNegInfFloat(), 0.0f);
-    assertTrue(Float.isNaN(message.getNanFloat()));
-    assertEquals("? ? ?? ?? ??? ??/ ??-", message.getCppTrigraph());
+    assertThat(message.getUtf8String()).isEqualTo("\u1234");
+    assertThat(message.getInfDouble()).isEqualTo(Double.POSITIVE_INFINITY);
+    assertThat(message.getNegInfDouble()).isEqualTo(Double.NEGATIVE_INFINITY);
+    assertThat(Double.isNaN(message.getNanDouble())).isTrue();
+    assertThat(message.getInfFloat()).isEqualTo(Float.POSITIVE_INFINITY);
+    assertThat(message.getNegInfFloat()).isEqualTo(Float.NEGATIVE_INFINITY);
+    assertThat(Float.isNaN(message.getNanFloat())).isTrue();
+    assertThat(message.getCppTrigraph()).isEqualTo("? ? ?? ?? ??? ??/ ??-");
   }
 
+  @Test
   public void testClear() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.assertClear(builder);
@@ -630,6 +652,7 @@
     TestUtil.assertClear(builder);
   }
 
+  @Test
   public void testReflectionGetters() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
@@ -639,6 +662,7 @@
     reflectionTester.assertAllFieldsSetViaReflection(message);
   }
 
+  @Test
   public void testReflectionSetters() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     reflectionTester.setAllFieldsViaReflection(builder);
@@ -648,11 +672,13 @@
     TestUtil.assertAllFieldsSet(message);
   }
 
+  @Test
   public void testReflectionSettersRejectNull() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     reflectionTester.assertReflectionSettersRejectNull(builder);
   }
 
+  @Test
   public void testReflectionRepeatedSetters() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     reflectionTester.setAllFieldsViaReflection(builder);
@@ -663,61 +689,69 @@
     TestUtil.assertRepeatedFieldsModified(message);
   }
 
+  @Test
   public void testReflectionRepeatedSettersRejectNull() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
   }
 
+  @Test
   public void testReflectionDefaults() throws Exception {
     reflectionTester.assertClearViaReflection(TestAllTypes.getDefaultInstance());
     reflectionTester.assertClearViaReflection(TestAllTypes.newBuilder().build());
   }
 
+  @Test
   public void testReflectionGetOneof() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     reflectionTester.setAllFieldsViaReflection(builder);
     Descriptors.OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0);
     Descriptors.FieldDescriptor field = TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
-    assertSame(field, builder.getOneofFieldDescriptor(oneof));
+    assertThat(field).isSameInstanceAs(builder.getOneofFieldDescriptor(oneof));
 
     TestAllTypes message = builder.build();
-    assertSame(field, message.getOneofFieldDescriptor(oneof));
+    assertThat(field).isSameInstanceAs(message.getOneofFieldDescriptor(oneof));
   }
 
+  @Test
   public void testReflectionClearOneof() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     reflectionTester.setAllFieldsViaReflection(builder);
     Descriptors.OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0);
     Descriptors.FieldDescriptor field = TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
 
-    assertTrue(builder.hasOneof(oneof));
-    assertTrue(builder.hasField(field));
+    assertThat(builder.hasOneof(oneof)).isTrue();
+    assertThat(builder.hasField(field)).isTrue();
     builder.clearOneof(oneof);
-    assertFalse(builder.hasOneof(oneof));
-    assertFalse(builder.hasField(field));
+    assertThat(builder.hasOneof(oneof)).isFalse();
+    assertThat(builder.hasField(field)).isFalse();
   }
 
+  @Test
   public void testEnumInterface() throws Exception {
-    assertTrue(
-        TestAllTypes.getDefaultInstance().getDefaultNestedEnum() instanceof ProtocolMessageEnum);
+    assertThat(TestAllTypes.getDefaultInstance().getDefaultNestedEnum())
+        .isInstanceOf(ProtocolMessageEnum.class);
   }
 
+  @Test
   public void testEnumMap() throws Exception {
     Internal.EnumLiteMap<ForeignEnum> map = ForeignEnum.internalGetValueMap();
 
     for (ForeignEnum value : ForeignEnum.values()) {
-      assertEquals(value, map.findValueByNumber(value.getNumber()));
+      assertThat(map.findValueByNumber(value.getNumber())).isEqualTo(value);
     }
 
-    assertTrue(map.findValueByNumber(12345) == null);
+    assertThat(map.findValueByNumber(12345) == null).isTrue();
   }
 
+  @Test
   public void testParsePackedToUnpacked() throws Exception {
     TestUnpackedTypes.Builder builder = TestUnpackedTypes.newBuilder();
     TestUnpackedTypes message = builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
     TestUtil.assertUnpackedFieldsSet(message);
   }
 
+  @Test
   public void testParseUnpackedToPacked() throws Exception {
     TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
     TestPackedTypes message = builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
@@ -731,6 +765,7 @@
       new TestUtil.ReflectionTester(
           TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry());
 
+  @Test
   public void testExtensionMessageOrBuilder() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TestUtil.setAllExtensions(builder);
@@ -738,6 +773,7 @@
     TestUtil.assertAllExtensionsSet(message);
   }
 
+  @Test
   public void testGetBuilderForExtensionField() {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     Message.Builder fieldBuilder =
@@ -746,21 +782,23 @@
     FieldDescriptor field =
         NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
     fieldBuilder.setField(field, expected);
-    assertEquals(expected, fieldBuilder.build().getField(field));
+    assertThat(fieldBuilder.build().getField(field)).isEqualTo(expected);
   }
 
 
+  @Test
   public void testGetBuilderForNonMessageExtensionField() {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     try {
       // This should throw an exception because the extension field is not a message.
       builder.newBuilderForField(UnittestProto.optionalInt32Extension.getDescriptor());
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // This exception is expected.
     }
   }
 
+  @Test
   public void testExtensionRepeatedSetters() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TestUtil.setAllExtensions(builder);
@@ -769,26 +807,29 @@
     TestUtil.assertRepeatedExtensionsModified(message);
   }
 
+  @Test
   public void testExtensionDefaults() throws Exception {
     TestUtil.assertExtensionsClear(TestAllExtensions.getDefaultInstance());
     TestUtil.assertExtensionsClear(TestAllExtensions.newBuilder().build());
   }
 
+  @Test
   public void testUnsetRepeatedExtensionGetField() {
     TestAllExtensions message = TestAllExtensions.getDefaultInstance();
     Object value;
 
     value = message.getField(UnittestProto.repeatedStringExtension.getDescriptor());
-    assertTrue(value instanceof List);
-    assertTrue(((List<?>) value).isEmpty());
+    assertThat(value instanceof List).isTrue();
+    assertThat(((List<?>) value).isEmpty()).isTrue();
     assertIsUnmodifiable((List<?>) value);
 
     value = message.getField(UnittestProto.repeatedNestedMessageExtension.getDescriptor());
-    assertTrue(value instanceof List);
-    assertTrue(((List<?>) value).isEmpty());
+    assertThat(value instanceof List).isTrue();
+    assertThat(((List<?>) value).isEmpty()).isTrue();
     assertIsUnmodifiable((List<?>) value);
   }
 
+  @Test
   public void testExtensionReflectionGetters() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TestUtil.setAllExtensions(builder);
@@ -798,6 +839,7 @@
     extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
   }
 
+  @Test
   public void testExtensionReflectionSetters() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     extensionsReflectionTester.setAllFieldsViaReflection(builder);
@@ -807,11 +849,13 @@
     TestUtil.assertAllExtensionsSet(message);
   }
 
+  @Test
   public void testExtensionReflectionSettersRejectNull() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
   }
 
+  @Test
   public void testExtensionReflectionRepeatedSetters() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     extensionsReflectionTester.setAllFieldsViaReflection(builder);
@@ -822,45 +866,51 @@
     TestUtil.assertRepeatedExtensionsModified(message);
   }
 
+  @Test
   public void testExtensionReflectionRepeatedSettersRejectNull() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     extensionsReflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
   }
 
+  @Test
   public void testExtensionReflectionDefaults() throws Exception {
     extensionsReflectionTester.assertClearViaReflection(TestAllExtensions.getDefaultInstance());
     extensionsReflectionTester.assertClearViaReflection(TestAllExtensions.newBuilder().build());
   }
 
+  @Test
   public void testClearExtension() throws Exception {
     // clearExtension() is not actually used in TestUtil, so try it manually.
-    assertFalse(
-        TestAllExtensions.newBuilder()
-            .setExtension(UnittestProto.optionalInt32Extension, 1)
-            .clearExtension(UnittestProto.optionalInt32Extension)
-            .hasExtension(UnittestProto.optionalInt32Extension));
-    assertEquals(
-        0,
-        TestAllExtensions.newBuilder()
-            .addExtension(UnittestProto.repeatedInt32Extension, 1)
-            .clearExtension(UnittestProto.repeatedInt32Extension)
-            .getExtensionCount(UnittestProto.repeatedInt32Extension));
+    assertThat(
+            TestAllExtensions.newBuilder()
+                .setExtension(UnittestProto.optionalInt32Extension, 1)
+                .clearExtension(UnittestProto.optionalInt32Extension)
+                .hasExtension(UnittestProto.optionalInt32Extension))
+        .isFalse();
+    assertThat(
+            TestAllExtensions.newBuilder()
+                .addExtension(UnittestProto.repeatedInt32Extension, 1)
+                .clearExtension(UnittestProto.repeatedInt32Extension)
+                .getExtensionCount(UnittestProto.repeatedInt32Extension))
+        .isEqualTo(0);
   }
 
+  @Test
   public void testExtensionCopy() throws Exception {
     TestAllExtensions original = TestUtil.getAllExtensionsSet();
     TestAllExtensions copy = TestAllExtensions.newBuilder(original).build();
     TestUtil.assertAllExtensionsSet(copy);
   }
 
+  @Test
   public void testExtensionMergeFrom() throws Exception {
     TestAllExtensions original =
         TestAllExtensions.newBuilder()
             .setExtension(UnittestProto.optionalInt32Extension, 1)
             .build();
     TestAllExtensions merged = TestAllExtensions.newBuilder().mergeFrom(original).build();
-    assertTrue(merged.hasExtension(UnittestProto.optionalInt32Extension));
-    assertEquals(1, (int) merged.getExtension(UnittestProto.optionalInt32Extension));
+    assertThat(merged.hasExtension(UnittestProto.optionalInt32Extension)).isTrue();
+    assertThat((int) merged.getExtension(UnittestProto.optionalInt32Extension)).isEqualTo(1);
   }
 
   // =================================================================
@@ -870,16 +920,18 @@
   // This test needs to be put before any other access to MultipleFilesTestProto
   // or messages defined in multiple_files_test.proto because the class loading
   // order affects initialization process of custom options.
+  @Test
   public void testEnumValueOptionsInMultipleFilesMode() throws Exception {
-    assertEquals(
-        12345,
-        EnumWithNoOuter.FOO
-            .getValueDescriptor()
-            .getOptions()
-            .getExtension(MultipleFilesTestProto.enumValueOption)
-            .intValue());
+    assertThat(
+            EnumWithNoOuter.FOO
+                .getValueDescriptor()
+                .getOptions()
+                .getExtension(MultipleFilesTestProto.enumValueOption)
+                .intValue())
+        .isEqualTo(12345);
   }
 
+  @Test
   public void testMultipleFilesOption() throws Exception {
     // We mostly just want to check that things compile.
     MessageWithNoOuter message =
@@ -889,56 +941,60 @@
             .setNestedEnum(MessageWithNoOuter.NestedEnum.BAZ)
             .setForeignEnum(EnumWithNoOuter.BAR)
             .build();
-    assertEquals(message, MessageWithNoOuter.parseFrom(message.toByteString()));
+    assertThat(MessageWithNoOuter.parseFrom(message.toByteString())).isEqualTo(message);
 
-    assertEquals(
-        MultipleFilesTestProto.getDescriptor(), MessageWithNoOuter.getDescriptor().getFile());
+    assertThat(MessageWithNoOuter.getDescriptor().getFile())
+        .isEqualTo(MultipleFilesTestProto.getDescriptor());
 
     Descriptors.FieldDescriptor field =
         MessageWithNoOuter.getDescriptor().findFieldByName("foreign_enum");
-    assertEquals(EnumWithNoOuter.BAR.getValueDescriptor(), message.getField(field));
+    assertThat(message.getField(field)).isEqualTo(EnumWithNoOuter.BAR.getValueDescriptor());
 
-    assertEquals(
-        MultipleFilesTestProto.getDescriptor(), ServiceWithNoOuter.getDescriptor().getFile());
+    assertThat(ServiceWithNoOuter.getDescriptor().getFile())
+        .isEqualTo(MultipleFilesTestProto.getDescriptor());
 
-    assertFalse(
-        TestAllExtensions.getDefaultInstance()
-            .hasExtension(MultipleFilesTestProto.extensionWithOuter));
+    assertThat(
+            TestAllExtensions.getDefaultInstance()
+                .hasExtension(MultipleFilesTestProto.extensionWithOuter))
+        .isFalse();
   }
 
+  @Test
   public void testOptionalFieldWithRequiredSubfieldsOptimizedForSize() throws Exception {
     TestOptionalOptimizedForSize message = TestOptionalOptimizedForSize.getDefaultInstance();
-    assertTrue(message.isInitialized());
+    assertThat(message.isInitialized()).isTrue();
 
     message =
         TestOptionalOptimizedForSize.newBuilder()
             .setO(TestRequiredOptimizedForSize.newBuilder().buildPartial())
             .buildPartial();
-    assertFalse(message.isInitialized());
+    assertThat(message.isInitialized()).isFalse();
 
     message =
         TestOptionalOptimizedForSize.newBuilder()
             .setO(TestRequiredOptimizedForSize.newBuilder().setX(5).buildPartial())
             .buildPartial();
-    assertTrue(message.isInitialized());
+    assertThat(message.isInitialized()).isTrue();
   }
 
+  @Test
   public void testUninitializedExtensionInOptimizedForSize() throws Exception {
     TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
     builder.setExtension(
         TestOptimizedForSize.testExtension2,
         TestRequiredOptimizedForSize.newBuilder().buildPartial());
-    assertFalse(builder.isInitialized());
-    assertFalse(builder.buildPartial().isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
+    assertThat(builder.buildPartial().isInitialized()).isFalse();
 
     builder = TestOptimizedForSize.newBuilder();
     builder.setExtension(
         TestOptimizedForSize.testExtension2,
         TestRequiredOptimizedForSize.newBuilder().setX(10).buildPartial());
-    assertTrue(builder.isInitialized());
-    assertTrue(builder.buildPartial().isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
+    assertThat(builder.buildPartial().isInitialized()).isTrue();
   }
 
+  @Test
   public void testToBuilder() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
@@ -947,39 +1003,43 @@
     TestUtil.assertAllFieldsSet(message.toBuilder().build());
   }
 
+  @Test
   public void testFieldConstantValues() throws Exception {
-    assertEquals(TestAllTypes.NestedMessage.BB_FIELD_NUMBER, 1);
-    assertEquals(TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER, 1);
-    assertEquals(TestAllTypes.OPTIONALGROUP_FIELD_NUMBER, 16);
-    assertEquals(TestAllTypes.OPTIONAL_NESTED_MESSAGE_FIELD_NUMBER, 18);
-    assertEquals(TestAllTypes.OPTIONAL_NESTED_ENUM_FIELD_NUMBER, 21);
-    assertEquals(TestAllTypes.REPEATED_INT32_FIELD_NUMBER, 31);
-    assertEquals(TestAllTypes.REPEATEDGROUP_FIELD_NUMBER, 46);
-    assertEquals(TestAllTypes.REPEATED_NESTED_MESSAGE_FIELD_NUMBER, 48);
-    assertEquals(TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER, 51);
+    assertThat(TestAllTypes.NestedMessage.BB_FIELD_NUMBER).isEqualTo(1);
+    assertThat(TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER).isEqualTo(1);
+    assertThat(TestAllTypes.OPTIONALGROUP_FIELD_NUMBER).isEqualTo(16);
+    assertThat(TestAllTypes.OPTIONAL_NESTED_MESSAGE_FIELD_NUMBER).isEqualTo(18);
+    assertThat(TestAllTypes.OPTIONAL_NESTED_ENUM_FIELD_NUMBER).isEqualTo(21);
+    assertThat(TestAllTypes.REPEATED_INT32_FIELD_NUMBER).isEqualTo(31);
+    assertThat(TestAllTypes.REPEATEDGROUP_FIELD_NUMBER).isEqualTo(46);
+    assertThat(TestAllTypes.REPEATED_NESTED_MESSAGE_FIELD_NUMBER).isEqualTo(48);
+    assertThat(TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER).isEqualTo(51);
   }
 
+  @Test
   public void testExtensionConstantValues() throws Exception {
-    assertEquals(UnittestProto.TestRequired.SINGLE_FIELD_NUMBER, 1000);
-    assertEquals(UnittestProto.TestRequired.MULTI_FIELD_NUMBER, 1001);
-    assertEquals(UnittestProto.OPTIONAL_INT32_EXTENSION_FIELD_NUMBER, 1);
-    assertEquals(UnittestProto.OPTIONALGROUP_EXTENSION_FIELD_NUMBER, 16);
-    assertEquals(UnittestProto.OPTIONAL_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 18);
-    assertEquals(UnittestProto.OPTIONAL_NESTED_ENUM_EXTENSION_FIELD_NUMBER, 21);
-    assertEquals(UnittestProto.REPEATED_INT32_EXTENSION_FIELD_NUMBER, 31);
-    assertEquals(UnittestProto.REPEATEDGROUP_EXTENSION_FIELD_NUMBER, 46);
-    assertEquals(UnittestProto.REPEATED_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 48);
-    assertEquals(UnittestProto.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER, 51);
+    assertThat(UnittestProto.TestRequired.SINGLE_FIELD_NUMBER).isEqualTo(1000);
+    assertThat(UnittestProto.TestRequired.MULTI_FIELD_NUMBER).isEqualTo(1001);
+    assertThat(UnittestProto.OPTIONAL_INT32_EXTENSION_FIELD_NUMBER).isEqualTo(1);
+    assertThat(UnittestProto.OPTIONALGROUP_EXTENSION_FIELD_NUMBER).isEqualTo(16);
+    assertThat(UnittestProto.OPTIONAL_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER).isEqualTo(18);
+    assertThat(UnittestProto.OPTIONAL_NESTED_ENUM_EXTENSION_FIELD_NUMBER).isEqualTo(21);
+    assertThat(UnittestProto.REPEATED_INT32_EXTENSION_FIELD_NUMBER).isEqualTo(31);
+    assertThat(UnittestProto.REPEATEDGROUP_EXTENSION_FIELD_NUMBER).isEqualTo(46);
+    assertThat(UnittestProto.REPEATED_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER).isEqualTo(48);
+    assertThat(UnittestProto.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER).isEqualTo(51);
   }
 
+  @Test
   public void testRecursiveMessageDefaultInstance() throws Exception {
     UnittestProto.TestRecursiveMessage message =
         UnittestProto.TestRecursiveMessage.getDefaultInstance();
-    assertTrue(message != null);
-    assertNotNull(message.getA());
-    assertTrue(message.getA().equals(message));
+    assertThat(message != null).isTrue();
+    assertThat(message.getA()).isNotNull();
+    assertThat(message.getA().equals(message)).isTrue();
   }
 
+  @Test
   public void testSerialize() throws Exception {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -994,9 +1054,10 @@
     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     ObjectInputStream in = new ObjectInputStream(bais);
     TestAllTypes actual = (TestAllTypes) in.readObject();
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
+  @Test
   public void testSerializePartial() throws Exception {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -1010,9 +1071,10 @@
     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     ObjectInputStream in = new ObjectInputStream(bais);
     TestAllTypes actual = (TestAllTypes) in.readObject();
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
+  @Test
   public void testDeserializeWithoutClassField() throws Exception {
     // serialized form for version <=3.6.0
     // just includes messageClassName and asBytes
@@ -1035,9 +1097,10 @@
     ByteArrayInputStream bais = new ByteArrayInputStream(int32ValueBytes);
     ObjectInputStream in = new ObjectInputStream(bais);
     Int32Value int32Value = (Int32Value) in.readObject();
-    assertEquals(123, int32Value.getValue());
+    assertThat(int32Value.getValue()).isEqualTo(123);
   }
 
+  @Test
   public void testDeserializeWithClassField() throws Exception {
     // serialized form for version > 3.6.0
     // includes messageClass, messageClassName (for compatibility), and asBytes
@@ -1071,31 +1134,36 @@
     ByteArrayInputStream bais = new ByteArrayInputStream(int32ValueBytes);
     ObjectInputStream in = new ObjectInputStream(bais);
     Int32Value int32Value = (Int32Value) in.readObject();
-    assertEquals(123, int32Value.getValue());
+    assertThat(int32Value.getValue()).isEqualTo(123);
   }
 
+  @Test
   public void testEnumValues() {
-    assertEquals(TestAllTypes.NestedEnum.BAR_VALUE, TestAllTypes.NestedEnum.BAR.getNumber());
-    assertEquals(TestAllTypes.NestedEnum.BAZ_VALUE, TestAllTypes.NestedEnum.BAZ.getNumber());
-    assertEquals(TestAllTypes.NestedEnum.FOO_VALUE, TestAllTypes.NestedEnum.FOO.getNumber());
+    assertThat(TestAllTypes.NestedEnum.BAR.getNumber())
+        .isEqualTo(TestAllTypes.NestedEnum.BAR_VALUE);
+    assertThat(TestAllTypes.NestedEnum.BAZ.getNumber())
+        .isEqualTo(TestAllTypes.NestedEnum.BAZ_VALUE);
+    assertThat(TestAllTypes.NestedEnum.FOO.getNumber())
+        .isEqualTo(TestAllTypes.NestedEnum.FOO_VALUE);
   }
 
+  @Test
   public void testNonNestedExtensionInitialization() {
-    assertTrue(
-        NonNestedExtension.nonNestedExtension.getMessageDefaultInstance()
-            instanceof MyNonNestedExtension);
-    assertEquals(
-        "nonNestedExtension", NonNestedExtension.nonNestedExtension.getDescriptor().getName());
+    assertThat(NonNestedExtension.nonNestedExtension.getMessageDefaultInstance())
+        .isInstanceOf(MyNonNestedExtension.class);
+    assertThat(NonNestedExtension.nonNestedExtension.getDescriptor().getName())
+        .isEqualTo("nonNestedExtension");
   }
 
+  @Test
   public void testNestedExtensionInitialization() {
-    assertTrue(
-        MyNestedExtension.recursiveExtension.getMessageDefaultInstance()
-            instanceof MessageToBeExtended);
-    assertEquals(
-        "recursiveExtension", MyNestedExtension.recursiveExtension.getDescriptor().getName());
+    assertThat(MyNestedExtension.recursiveExtension.getMessageDefaultInstance())
+        .isInstanceOf(MessageToBeExtended.class);
+    assertThat(MyNestedExtension.recursiveExtension.getDescriptor().getName())
+        .isEqualTo("recursiveExtension");
   }
 
+  @Test
   public void testInvalidations() throws Exception {
     GeneratedMessageV3.setAlwaysUseFieldBuildersForTesting(true);
     TestAllTypes.NestedMessage nestedMessage1 = TestAllTypes.NestedMessage.newBuilder().build();
@@ -1114,7 +1182,7 @@
     builder.addRepeatedInt32(1);
     builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAR);
     builder.addRepeatedNestedMessage(nestedMessage1);
-    assertEquals(0, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
 
     // Now tell it we want changes and make sure it's only fired once
     // And do this for each flavor
@@ -1123,39 +1191,40 @@
     builder.buildPartial();
     builder.setOptionalInt32(2);
     builder.setOptionalInt32(3);
-    assertEquals(1, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(1);
 
     // enum single
     builder.buildPartial();
     builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ);
     builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
-    assertEquals(2, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(2);
 
     // message single
     builder.buildPartial();
     builder.setOptionalNestedMessage(nestedMessage2);
     builder.setOptionalNestedMessage(nestedMessage1);
-    assertEquals(3, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(3);
 
     // primitive repeated
     builder.buildPartial();
     builder.addRepeatedInt32(2);
     builder.addRepeatedInt32(3);
-    assertEquals(4, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(4);
 
     // enum repeated
     builder.buildPartial();
     builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAZ);
     builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAZ);
-    assertEquals(5, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(5);
 
     // message repeated
     builder.buildPartial();
     builder.addRepeatedNestedMessage(nestedMessage2);
     builder.addRepeatedNestedMessage(nestedMessage1);
-    assertEquals(6, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(6);
   }
 
+  @Test
   public void testInvalidations_Extensions() throws Exception {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
 
@@ -1167,43 +1236,46 @@
     builder.addExtension(UnittestProto.repeatedInt32Extension, 1);
     builder.setExtension(UnittestProto.repeatedInt32Extension, 0, 2);
     builder.clearExtension(UnittestProto.repeatedInt32Extension);
-    assertEquals(0, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
 
     // Now tell it we want changes and make sure it's only fired once
     builder.buildPartial();
     builder.addExtension(UnittestProto.repeatedInt32Extension, 2);
     builder.addExtension(UnittestProto.repeatedInt32Extension, 3);
-    assertEquals(1, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(1);
 
     builder.buildPartial();
     builder.setExtension(UnittestProto.repeatedInt32Extension, 0, 4);
     builder.setExtension(UnittestProto.repeatedInt32Extension, 1, 5);
-    assertEquals(2, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(2);
 
     builder.buildPartial();
     builder.clearExtension(UnittestProto.repeatedInt32Extension);
     builder.clearExtension(UnittestProto.repeatedInt32Extension);
-    assertEquals(3, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(3);
   }
 
+  @Test
   public void testBaseMessageOrBuilder() {
     // Mostly just makes sure the base interface exists and has some methods.
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes message = builder.buildPartial();
     TestAllTypesOrBuilder messageAsInterface = (TestAllTypesOrBuilder) message;
 
-    assertEquals(messageAsInterface.getDefaultBool(), messageAsInterface.getDefaultBool());
-    assertEquals(
-        messageAsInterface.getOptionalDouble(), messageAsInterface.getOptionalDouble(), 0.0);
+    assertThat(messageAsInterface.getDefaultBool()).isEqualTo(messageAsInterface.getDefaultBool());
+    assertThat(messageAsInterface.getOptionalDouble())
+        .isEqualTo(messageAsInterface.getOptionalDouble());
   }
 
+  @Test
   public void testMessageOrBuilderGetters() {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
 
     // single fields
-    assertSame(ForeignMessage.getDefaultInstance(), builder.getOptionalForeignMessageOrBuilder());
+    assertThat(ForeignMessage.getDefaultInstance())
+        .isSameInstanceAs(builder.getOptionalForeignMessageOrBuilder());
     ForeignMessage.Builder subBuilder = builder.getOptionalForeignMessageBuilder();
-    assertSame(subBuilder, builder.getOptionalForeignMessageOrBuilder());
+    assertThat(subBuilder).isSameInstanceAs(builder.getOptionalForeignMessageOrBuilder());
 
     // repeated fields
     ForeignMessage m0 = ForeignMessage.newBuilder().buildPartial();
@@ -1212,22 +1284,23 @@
     builder.addRepeatedForeignMessage(m0);
     builder.addRepeatedForeignMessage(m1);
     builder.addRepeatedForeignMessage(m2);
-    assertSame(m0, builder.getRepeatedForeignMessageOrBuilder(0));
-    assertSame(m1, builder.getRepeatedForeignMessageOrBuilder(1));
-    assertSame(m2, builder.getRepeatedForeignMessageOrBuilder(2));
+    assertThat(m0).isSameInstanceAs(builder.getRepeatedForeignMessageOrBuilder(0));
+    assertThat(m1).isSameInstanceAs(builder.getRepeatedForeignMessageOrBuilder(1));
+    assertThat(m2).isSameInstanceAs(builder.getRepeatedForeignMessageOrBuilder(2));
     ForeignMessage.Builder b0 = builder.getRepeatedForeignMessageBuilder(0);
     ForeignMessage.Builder b1 = builder.getRepeatedForeignMessageBuilder(1);
-    assertSame(b0, builder.getRepeatedForeignMessageOrBuilder(0));
-    assertSame(b1, builder.getRepeatedForeignMessageOrBuilder(1));
-    assertSame(m2, builder.getRepeatedForeignMessageOrBuilder(2));
+    assertThat(b0).isSameInstanceAs(builder.getRepeatedForeignMessageOrBuilder(0));
+    assertThat(b1).isSameInstanceAs(builder.getRepeatedForeignMessageOrBuilder(1));
+    assertThat(m2).isSameInstanceAs(builder.getRepeatedForeignMessageOrBuilder(2));
 
     List<? extends ForeignMessageOrBuilder> messageOrBuilderList =
         builder.getRepeatedForeignMessageOrBuilderList();
-    assertSame(b0, messageOrBuilderList.get(0));
-    assertSame(b1, messageOrBuilderList.get(1));
-    assertSame(m2, messageOrBuilderList.get(2));
+    assertThat(b0).isSameInstanceAs(messageOrBuilderList.get(0));
+    assertThat(b1).isSameInstanceAs(messageOrBuilderList.get(1));
+    assertThat(m2).isSameInstanceAs(messageOrBuilderList.get(2));
   }
 
+  @Test
   public void testGetFieldBuilder() {
     Descriptor descriptor = TestAllTypes.getDescriptor();
 
@@ -1301,9 +1374,10 @@
     Message newMessage2 = builder2.build();
 
     // These two messages should be equal.
-    assertEquals(newMessage1, newMessage2);
+    assertThat(newMessage1).isEqualTo(newMessage2);
   }
 
+  @Test
   public void testGetFieldBuilderWithInitializedValue() {
     Descriptor descriptor = TestAllTypes.getDescriptor();
     FieldDescriptor fieldDescriptor = descriptor.findFieldByName("optional_nested_message");
@@ -1312,7 +1386,7 @@
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     NestedMessage.Builder fieldBuilder =
         (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
-    assertEquals(0, fieldBuilder.getBb());
+    assertThat(fieldBuilder.getBb()).isEqualTo(0);
 
     // Setting field value with new field builder instance.
     builder = TestAllTypes.newBuilder();
@@ -1321,41 +1395,42 @@
     // Then get the field builder instance by getFieldBuilder().
     fieldBuilder = (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
     // It should contain new value.
-    assertEquals(2, fieldBuilder.getBb());
+    assertThat(fieldBuilder.getBb()).isEqualTo(2);
     // These two builder should be equal.
-    assertSame(fieldBuilder, newFieldBuilder);
+    assertThat(fieldBuilder).isSameInstanceAs(newFieldBuilder);
   }
 
+  @Test
   public void testGetFieldBuilderNotSupportedException() {
     Descriptor descriptor = TestAllTypes.getDescriptor();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
       builder.getFieldBuilder(descriptor.findFieldByName("optional_int32"));
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
     try {
       builder.getFieldBuilder(descriptor.findFieldByName("optional_nested_enum"));
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
     try {
       builder.getFieldBuilder(descriptor.findFieldByName("repeated_int32"));
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
     try {
       builder.getFieldBuilder(descriptor.findFieldByName("repeated_nested_enum"));
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
     try {
       builder.getFieldBuilder(descriptor.findFieldByName("repeated_nested_message"));
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
@@ -1364,217 +1439,223 @@
   // Test that when the default outer class name conflicts with another type
   // defined in the proto the compiler will append a suffix to avoid the
   // conflict.
+  @Test
   public void testConflictingOuterClassName() {
     // We just need to make sure we can refer to the outer class with the
     // expected name. There is nothing else to test.
     OuterClassNameTestOuterClass.OuterClassNameTest message =
         OuterClassNameTestOuterClass.OuterClassNameTest.newBuilder().build();
-    assertTrue(
-        message.getDescriptorForType()
-            == OuterClassNameTestOuterClass.OuterClassNameTest.getDescriptor());
+    assertThat(message.getDescriptorForType())
+        .isSameInstanceAs(OuterClassNameTestOuterClass.OuterClassNameTest.getDescriptor());
 
     OuterClassNameTest2OuterClass.TestMessage2.NestedMessage.OuterClassNameTest2 message2 =
         OuterClassNameTest2OuterClass.TestMessage2.NestedMessage.OuterClassNameTest2.newBuilder()
             .build();
-    assertEquals(0, message2.getSerializedSize());
+    assertThat(message2.getSerializedSize()).isEqualTo(0);
 
     OuterClassNameTest3OuterClass.TestMessage3.NestedMessage.OuterClassNameTest3 enumValue =
         OuterClassNameTest3OuterClass.TestMessage3.NestedMessage.OuterClassNameTest3.DUMMY_VALUE;
-    assertEquals(1, enumValue.getNumber());
+    assertThat(enumValue.getNumber()).isEqualTo(1);
   }
 
   // =================================================================
   // oneof generated code test
+  @Test
   public void testOneofEnumCase() throws Exception {
     TestOneof2 message =
         TestOneof2.newBuilder().setFooInt(123).setFooString("foo").setFooCord("bar").build();
     TestUtil.assertAtMostOneFieldSetOneof(message);
   }
 
+  @Test
   public void testClearOneof() throws Exception {
     TestOneof2.Builder builder = TestOneof2.newBuilder().setFooInt(123);
-    assertEquals(TestOneof2.FooCase.FOO_INT, builder.getFooCase());
+    assertThat(builder.getFooCase()).isEqualTo(TestOneof2.FooCase.FOO_INT);
     builder.clearFoo();
-    assertEquals(TestOneof2.FooCase.FOO_NOT_SET, builder.getFooCase());
+    assertThat(builder.getFooCase()).isEqualTo(TestOneof2.FooCase.FOO_NOT_SET);
   }
 
+  @Test
   public void testSetOneofClearsOthers() throws Exception {
     TestOneof2.Builder builder = TestOneof2.newBuilder();
     TestOneof2 message = builder.setFooInt(123).setFooString("foo").buildPartial();
-    assertTrue(message.hasFooString());
+    assertThat(message.hasFooString()).isTrue();
     TestUtil.assertAtMostOneFieldSetOneof(message);
 
     message = builder.setFooCord("bar").buildPartial();
-    assertTrue(message.hasFooCord());
+    assertThat(message.hasFooCord()).isTrue();
     TestUtil.assertAtMostOneFieldSetOneof(message);
 
     message = builder.setFooStringPiece("baz").buildPartial();
-    assertTrue(message.hasFooStringPiece());
+    assertThat(message.hasFooStringPiece()).isTrue();
     TestUtil.assertAtMostOneFieldSetOneof(message);
 
     message = builder.setFooBytes(TestUtil.toBytes("qux")).buildPartial();
-    assertTrue(message.hasFooBytes());
+    assertThat(message.hasFooBytes()).isTrue();
     TestUtil.assertAtMostOneFieldSetOneof(message);
 
     message = builder.setFooEnum(TestOneof2.NestedEnum.FOO).buildPartial();
-    assertTrue(message.hasFooEnum());
+    assertThat(message.hasFooEnum()).isTrue();
     TestUtil.assertAtMostOneFieldSetOneof(message);
 
     message =
         builder
             .setFooMessage(TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build())
             .buildPartial();
-    assertTrue(message.hasFooMessage());
+    assertThat(message.hasFooMessage()).isTrue();
     TestUtil.assertAtMostOneFieldSetOneof(message);
 
     message = builder.setFooInt(123).buildPartial();
-    assertTrue(message.hasFooInt());
+    assertThat(message.hasFooInt()).isTrue();
     TestUtil.assertAtMostOneFieldSetOneof(message);
   }
 
+  @Test
   public void testOneofTypes() throws Exception {
     // Primitive
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooInt(), 0);
-      assertFalse(builder.hasFooInt());
-      assertTrue(builder.setFooInt(123).hasFooInt());
-      assertEquals(builder.getFooInt(), 123);
+      assertThat(builder.getFooInt()).isEqualTo(0);
+      assertThat(builder.hasFooInt()).isFalse();
+      assertThat(builder.setFooInt(123).hasFooInt()).isTrue();
+      assertThat(builder.getFooInt()).isEqualTo(123);
       TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooInt());
-      assertEquals(message.getFooInt(), 123);
+      assertThat(message.hasFooInt()).isTrue();
+      assertThat(123).isEqualTo(message.getFooInt());
 
-      assertFalse(builder.clearFooInt().hasFooInt());
+      assertThat(builder.clearFooInt().hasFooInt()).isFalse();
       TestOneof2 message2 = builder.build();
-      assertFalse(message2.hasFooInt());
-      assertEquals(0, message2.getFooInt());
+      assertThat(message2.hasFooInt()).isFalse();
+      assertThat(message2.getFooInt()).isEqualTo(0);
     }
 
     // Enum
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(TestOneof2.NestedEnum.FOO, builder.getFooEnum());
-      assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum());
-      assertEquals(TestOneof2.NestedEnum.BAR, builder.getFooEnum());
+      assertThat(builder.getFooEnum()).isEqualTo(TestOneof2.NestedEnum.FOO);
+      assertThat(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum()).isTrue();
+      assertThat(builder.getFooEnum()).isEqualTo(TestOneof2.NestedEnum.BAR);
       TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooEnum());
-      assertEquals(TestOneof2.NestedEnum.BAR, message.getFooEnum());
+      assertThat(message.hasFooEnum()).isTrue();
+      assertThat(message.getFooEnum()).isEqualTo(TestOneof2.NestedEnum.BAR);
 
-      assertFalse(builder.clearFooEnum().hasFooEnum());
+      assertThat(builder.clearFooEnum().hasFooEnum()).isFalse();
       TestOneof2 message2 = builder.build();
-      assertFalse(message2.hasFooEnum());
-      assertEquals(TestOneof2.NestedEnum.FOO, message2.getFooEnum());
+      assertThat(message2.hasFooEnum()).isFalse();
+      assertThat(message2.getFooEnum()).isEqualTo(TestOneof2.NestedEnum.FOO);
     }
 
     // String
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals("", builder.getFooString());
+      assertThat(builder.getFooString()).isEmpty();
       builder.setFooString("foo");
-      assertTrue(builder.hasFooString());
-      assertEquals("foo", builder.getFooString());
+      assertThat(builder.hasFooString()).isTrue();
+      assertThat(builder.getFooString()).isEqualTo("foo");
       TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooString());
-      assertEquals("foo", message.getFooString());
-      assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo"));
+      assertThat(message.hasFooString()).isTrue();
+      assertThat(message.getFooString()).isEqualTo("foo");
+      assertThat(TestUtil.toBytes("foo")).isEqualTo(message.getFooStringBytes());
 
-      assertFalse(builder.clearFooString().hasFooString());
+      assertThat(builder.clearFooString().hasFooString()).isFalse();
       TestOneof2 message2 = builder.buildPartial();
-      assertFalse(message2.hasFooString());
-      assertEquals("", message2.getFooString());
-      assertEquals(message2.getFooStringBytes(), TestUtil.toBytes(""));
+      assertThat(message2.hasFooString()).isFalse();
+      assertThat(message2.getFooString()).isEmpty();
+      assertThat(message2.getFooStringBytes()).isEqualTo(TestUtil.toBytes(""));
 
       // Get method should not change the oneof value.
       builder.setFooInt(123);
-      assertEquals("", builder.getFooString());
-      assertEquals(builder.getFooStringBytes(), TestUtil.toBytes(""));
-      assertEquals(123, builder.getFooInt());
+      assertThat(builder.getFooString()).isEmpty();
+      assertThat(builder.getFooStringBytes()).isEqualTo(TestUtil.toBytes(""));
+      assertThat(builder.getFooInt()).isEqualTo(123);
 
       message = builder.build();
-      assertEquals("", message.getFooString());
-      assertEquals(message.getFooStringBytes(), TestUtil.toBytes(""));
-      assertEquals(123, message.getFooInt());
+      assertThat(message.getFooString()).isEmpty();
+      assertThat(TestUtil.toBytes("")).isEqualTo(message.getFooStringBytes());
+      assertThat(message.getFooInt()).isEqualTo(123);
     }
 
     // Cord
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals("", builder.getFooCord());
+      assertThat(builder.getFooCord()).isEmpty();
       builder.setFooCord("foo");
-      assertTrue(builder.hasFooCord());
-      assertEquals("foo", builder.getFooCord());
+      assertThat(builder.hasFooCord()).isTrue();
+      assertThat(builder.getFooCord()).isEqualTo("foo");
       TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooCord());
-      assertEquals("foo", message.getFooCord());
-      assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo"));
+      assertThat(message.hasFooCord()).isTrue();
+      assertThat(message.getFooCord()).isEqualTo("foo");
+      assertThat(TestUtil.toBytes("foo")).isEqualTo(message.getFooCordBytes());
 
-      assertFalse(builder.clearFooCord().hasFooCord());
+      assertThat(builder.clearFooCord().hasFooCord()).isFalse();
       TestOneof2 message2 = builder.build();
-      assertFalse(message2.hasFooCord());
-      assertEquals("", message2.getFooCord());
-      assertEquals(message2.getFooCordBytes(), TestUtil.toBytes(""));
+      assertThat(message2.hasFooCord()).isFalse();
+      assertThat(message2.getFooCord()).isEmpty();
+      assertThat(message2.getFooCordBytes()).isEqualTo(TestUtil.toBytes(""));
     }
 
     // StringPiece
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals("", builder.getFooStringPiece());
+      assertThat(builder.getFooStringPiece()).isEmpty();
       builder.setFooStringPiece("foo");
-      assertTrue(builder.hasFooStringPiece());
-      assertEquals("foo", builder.getFooStringPiece());
+      assertThat(builder.hasFooStringPiece()).isTrue();
+      assertThat(builder.getFooStringPiece()).isEqualTo("foo");
       TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooStringPiece());
-      assertEquals("foo", message.getFooStringPiece());
-      assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo"));
+      assertThat(message.hasFooStringPiece()).isTrue();
+      assertThat(message.getFooStringPiece()).isEqualTo("foo");
+      assertThat(TestUtil.toBytes("foo")).isEqualTo(message.getFooStringPieceBytes());
 
-      assertFalse(builder.clearFooStringPiece().hasFooStringPiece());
+      assertThat(builder.clearFooStringPiece().hasFooStringPiece()).isFalse();
       TestOneof2 message2 = builder.build();
-      assertFalse(message2.hasFooStringPiece());
-      assertEquals("", message2.getFooStringPiece());
-      assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes(""));
+      assertThat(message2.hasFooStringPiece()).isFalse();
+      assertThat(message2.getFooStringPiece()).isEmpty();
+      assertThat(message2.getFooStringPieceBytes()).isEqualTo(TestUtil.toBytes(""));
     }
 
     // Message
     {
       // set
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(0, builder.getFooMessage().getQuxInt());
+      assertThat(builder.getFooMessage().getQuxInt()).isEqualTo(0);
       builder.setFooMessage(TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build());
-      assertTrue(builder.hasFooMessage());
-      assertEquals(234, builder.getFooMessage().getQuxInt());
+      assertThat(builder.hasFooMessage()).isTrue();
+      assertThat(builder.getFooMessage().getQuxInt()).isEqualTo(234);
       TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooMessage());
-      assertEquals(234, message.getFooMessage().getQuxInt());
+      assertThat(message.hasFooMessage()).isTrue();
+      assertThat(message.getFooMessage().getQuxInt()).isEqualTo(234);
 
       // clear
-      assertFalse(builder.clearFooMessage().hasFooString());
+      assertThat(builder.clearFooMessage().hasFooString()).isFalse();
       message = builder.build();
-      assertFalse(message.hasFooMessage());
-      assertEquals(0, message.getFooMessage().getQuxInt());
+      assertThat(message.hasFooMessage()).isFalse();
+      assertThat(message.getFooMessage().getQuxInt()).isEqualTo(0);
 
       // nested builder
       builder = TestOneof2.newBuilder();
-      assertSame(builder.getFooMessageOrBuilder(), TestOneof2.NestedMessage.getDefaultInstance());
-      assertFalse(builder.hasFooMessage());
+      assertThat(builder.getFooMessageOrBuilder())
+          .isSameInstanceAs(TestOneof2.NestedMessage.getDefaultInstance());
+      assertThat(builder.hasFooMessage()).isFalse();
       builder.getFooMessageBuilder().setQuxInt(123);
-      assertTrue(builder.hasFooMessage());
-      assertEquals(123, builder.getFooMessage().getQuxInt());
+      assertThat(builder.hasFooMessage()).isTrue();
+      assertThat(builder.getFooMessage().getQuxInt()).isEqualTo(123);
       message = builder.build();
-      assertTrue(message.hasFooMessage());
-      assertEquals(123, message.getFooMessage().getQuxInt());
+      assertThat(message.hasFooMessage()).isTrue();
+      assertThat(message.getFooMessage().getQuxInt()).isEqualTo(123);
     }
 
     // LazyMessage is tested in LazyMessageLiteTest.java
   }
 
+  @Test
   public void testOneofMerge() throws Exception {
     // Primitive Type
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
       TestOneof2 message = builder.setFooInt(123).build();
       TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
-      assertTrue(message2.hasFooInt());
-      assertEquals(123, message2.getFooInt());
+      assertThat(message2.hasFooInt()).isTrue();
+      assertThat(message2.getFooInt()).isEqualTo(123);
     }
 
     // String
@@ -1582,8 +1663,8 @@
       TestOneof2.Builder builder = TestOneof2.newBuilder();
       TestOneof2 message = builder.setFooString("foo").build();
       TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
-      assertTrue(message2.hasFooString());
-      assertEquals("foo", message2.getFooString());
+      assertThat(message2.hasFooString()).isTrue();
+      assertThat(message2.getFooString()).isEqualTo("foo");
     }
 
     // Enum
@@ -1591,8 +1672,8 @@
       TestOneof2.Builder builder = TestOneof2.newBuilder();
       TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
       TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
-      assertTrue(message2.hasFooEnum());
-      assertEquals(TestOneof2.NestedEnum.BAR, message2.getFooEnum());
+      assertThat(message2.hasFooEnum()).isTrue();
+      assertThat(message2.getFooEnum()).isEqualTo(TestOneof2.NestedEnum.BAR);
     }
 
     // Message
@@ -1603,11 +1684,12 @@
               .setFooMessage(TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build())
               .build();
       TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
-      assertTrue(message2.hasFooMessage());
-      assertEquals(234, message2.getFooMessage().getQuxInt());
+      assertThat(message2.hasFooMessage()).isTrue();
+      assertThat(message2.getFooMessage().getQuxInt()).isEqualTo(234);
     }
   }
 
+  @Test
   public void testOneofSerialization() throws Exception {
     // Primitive Type
     {
@@ -1615,8 +1697,8 @@
       TestOneof2 message = builder.setFooInt(123).build();
       ByteString serialized = message.toByteString();
       TestOneof2 message2 = TestOneof2.parseFrom(serialized);
-      assertTrue(message2.hasFooInt());
-      assertEquals(123, message2.getFooInt());
+      assertThat(message2.hasFooInt()).isTrue();
+      assertThat(message2.getFooInt()).isEqualTo(123);
     }
 
     // String
@@ -1625,8 +1707,8 @@
       TestOneof2 message = builder.setFooString("foo").build();
       ByteString serialized = message.toByteString();
       TestOneof2 message2 = TestOneof2.parseFrom(serialized);
-      assertTrue(message2.hasFooString());
-      assertEquals("foo", message2.getFooString());
+      assertThat(message2.hasFooString()).isTrue();
+      assertThat(message2.getFooString()).isEqualTo("foo");
     }
 
     // Enum
@@ -1635,8 +1717,8 @@
       TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
       ByteString serialized = message.toByteString();
       TestOneof2 message2 = TestOneof2.parseFrom(serialized);
-      assertTrue(message2.hasFooEnum());
-      assertEquals(TestOneof2.NestedEnum.BAR, message2.getFooEnum());
+      assertThat(message2.hasFooEnum()).isTrue();
+      assertThat(message2.getFooEnum()).isEqualTo(TestOneof2.NestedEnum.BAR);
     }
 
     // Message
@@ -1648,22 +1730,24 @@
               .build();
       ByteString serialized = message.toByteString();
       TestOneof2 message2 = TestOneof2.parseFrom(serialized);
-      assertTrue(message2.hasFooMessage());
-      assertEquals(234, message2.getFooMessage().getQuxInt());
+      assertThat(message2.hasFooMessage()).isTrue();
+      assertThat(message2.getFooMessage().getQuxInt()).isEqualTo(234);
     }
   }
 
+  @Test
   public void testOneofNestedBuilderOnChangePropagation() {
     NestedTestAllTypes.Builder parentBuilder = NestedTestAllTypes.newBuilder();
     TestAllTypes.Builder builder = parentBuilder.getPayloadBuilder();
     builder.getOneofNestedMessageBuilder();
-    assertTrue(builder.hasOneofNestedMessage());
-    assertTrue(parentBuilder.hasPayload());
+    assertThat(builder.hasOneofNestedMessage()).isTrue();
+    assertThat(parentBuilder.hasPayload()).isTrue();
     NestedTestAllTypes message = parentBuilder.build();
-    assertTrue(message.hasPayload());
-    assertTrue(message.getPayload().hasOneofNestedMessage());
+    assertThat(message.hasPayload()).isTrue();
+    assertThat(message.getPayload().hasOneofNestedMessage()).isTrue();
   }
 
+  @Test
   public void testGetRepeatedFieldBuilder() {
     Descriptor descriptor = TestAllTypes.getDescriptor();
 
@@ -1722,9 +1806,10 @@
     Message newMessage2 = builder2.build();
 
     // These two messages should be equal.
-    assertEquals(newMessage1, newMessage2);
+    assertThat(newMessage1).isEqualTo(newMessage2);
   }
 
+  @Test
   public void testGetRepeatedFieldBuilderWithInitializedValue() {
     Descriptor descriptor = TestAllTypes.getDescriptor();
     FieldDescriptor fieldDescriptor = descriptor.findFieldByName("repeated_nested_message");
@@ -1734,7 +1819,7 @@
     builder.addRepeatedNestedMessageBuilder();
     NestedMessage.Builder fieldBuilder =
         (NestedMessage.Builder) builder.getRepeatedFieldBuilder(fieldDescriptor, 0);
-    assertEquals(0, fieldBuilder.getBb());
+    assertThat(fieldBuilder.getBb()).isEqualTo(0);
 
     // Setting field value with new field builder instance.
     builder = TestAllTypes.newBuilder();
@@ -1743,41 +1828,42 @@
     // Then get the field builder instance by getRepeatedFieldBuilder().
     fieldBuilder = (NestedMessage.Builder) builder.getRepeatedFieldBuilder(fieldDescriptor, 0);
     // It should contain new value.
-    assertEquals(2, fieldBuilder.getBb());
+    assertThat(fieldBuilder.getBb()).isEqualTo(2);
     // These two builder should be equal.
-    assertSame(fieldBuilder, newFieldBuilder);
+    assertThat(fieldBuilder).isSameInstanceAs(newFieldBuilder);
   }
 
+  @Test
   public void testGetRepeatedFieldBuilderNotSupportedException() {
     Descriptor descriptor = TestAllTypes.getDescriptor();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
       builder.getRepeatedFieldBuilder(descriptor.findFieldByName("repeated_int32"), 0);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
     try {
       builder.getRepeatedFieldBuilder(descriptor.findFieldByName("repeated_nested_enum"), 0);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
     try {
       builder.getRepeatedFieldBuilder(descriptor.findFieldByName("optional_int32"), 0);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
     try {
       builder.getRepeatedFieldBuilder(descriptor.findFieldByName("optional_nested_enum"), 0);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
     try {
       builder.getRepeatedFieldBuilder(descriptor.findFieldByName("optional_nested_message"), 0);
-      fail("Exception was not thrown");
+      assertWithMessage("Exception was not thrown").fail();
     } catch (UnsupportedOperationException e) {
       // We expect this exception.
     }
diff --git a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
index 2ad94f8..15bbda9 100644
--- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -30,39 +30,44 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static java.util.Arrays.asList;
 
 import com.google.protobuf.Internal.IntList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests for {@link IntArrayList}.
- *
- * @author [email protected] (Daniel Weis)
- */
-public class IntArrayListTest extends TestCase {
+/** Tests for {@link IntArrayList}. */
+@RunWith(JUnit4.class)
+public class IntArrayListTest {
 
   private static final IntArrayList UNARY_LIST = newImmutableIntArrayList(1);
   private static final IntArrayList TERTIARY_LIST = newImmutableIntArrayList(1, 2, 3);
 
   private IntArrayList list;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     list = new IntArrayList();
   }
 
+  @Test
   public void testEmptyListReturnsSameInstance() {
-    assertSame(IntArrayList.emptyList(), IntArrayList.emptyList());
+    assertThat(IntArrayList.emptyList()).isSameInstanceAs(IntArrayList.emptyList());
   }
 
+  @Test
   public void testEmptyListIsImmutable() {
     assertImmutable(IntArrayList.emptyList());
   }
 
+  @Test
   public void testMakeImmutable() {
     list.addInt(3);
     list.addInt(4);
@@ -72,19 +77,20 @@
     assertImmutable(list);
   }
 
+  @Test
   public void testModificationWithIteration() {
     list.addAll(asList(1, 2, 3, 4));
     Iterator<Integer> iterator = list.iterator();
-    assertEquals(4, list.size());
-    assertEquals(1, (int) list.get(0));
-    assertEquals(1, (int) iterator.next());
+    assertThat(list).hasSize(4);
+    assertThat((int) list.get(0)).isEqualTo(1);
+    assertThat((int) iterator.next()).isEqualTo(1);
     list.set(0, 1);
-    assertEquals(2, (int) iterator.next());
+    assertThat((int) iterator.next()).isEqualTo(2);
 
     list.remove(0);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
@@ -93,191 +99,211 @@
     list.add(0, 0);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
   }
 
+  @Test
   public void testGet() {
-    assertEquals(1, (int) TERTIARY_LIST.get(0));
-    assertEquals(2, (int) TERTIARY_LIST.get(1));
-    assertEquals(3, (int) TERTIARY_LIST.get(2));
+    assertThat((int) TERTIARY_LIST.get(0)).isEqualTo(1);
+    assertThat((int) TERTIARY_LIST.get(1)).isEqualTo(2);
+    assertThat((int) TERTIARY_LIST.get(2)).isEqualTo(3);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testGetInt() {
-    assertEquals(1, TERTIARY_LIST.getInt(0));
-    assertEquals(2, TERTIARY_LIST.getInt(1));
-    assertEquals(3, TERTIARY_LIST.getInt(2));
+    assertThat(TERTIARY_LIST.getInt(0)).isEqualTo(1);
+    assertThat(TERTIARY_LIST.getInt(1)).isEqualTo(2);
+    assertThat(TERTIARY_LIST.getInt(2)).isEqualTo(3);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testIndexOf_nullElement() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(null));
+    assertThat(TERTIARY_LIST.indexOf(null)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_incompatibleElementType() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(new Object()));
+    assertThat(TERTIARY_LIST.indexOf(new Object())).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInList() {
-    assertEquals(-1, UNARY_LIST.indexOf(2));
+    assertThat(UNARY_LIST.indexOf(2)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInListWithDuplicates() {
     IntArrayList listWithDupes = newImmutableIntArrayList(1, 1);
-    assertEquals(-1, listWithDupes.indexOf(2));
+    assertThat(listWithDupes.indexOf(2)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_inList() {
-    assertEquals(1, TERTIARY_LIST.indexOf(2));
+    assertThat(TERTIARY_LIST.indexOf(2)).isEqualTo(1);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchAtHead() {
     IntArrayList listWithDupes = newImmutableIntArrayList(1, 1, 2);
-    assertEquals(0, listWithDupes.indexOf(1));
+    assertThat(listWithDupes.indexOf(1)).isEqualTo(0);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchMidList() {
     IntArrayList listWithDupes = newImmutableIntArrayList(2, 1, 1, 2);
-    assertEquals(1, listWithDupes.indexOf(1));
+    assertThat(listWithDupes.indexOf(1)).isEqualTo(1);
   }
 
+  @Test
   public void testContains_nullElement() {
-    assertEquals(false, TERTIARY_LIST.contains(null));
+    assertThat(TERTIARY_LIST).doesNotContain(null);
   }
 
+  @Test
   public void testContains_incompatibleElementType() {
-    assertEquals(false, TERTIARY_LIST.contains(new Object()));
+    assertThat(TERTIARY_LIST).doesNotContain(new Object());
   }
 
+  @Test
   public void testContains_notInList() {
-    assertEquals(false, UNARY_LIST.contains(2));
+    assertThat(UNARY_LIST).doesNotContain(2);
   }
 
+  @Test
   public void testContains_notInListWithDuplicates() {
     IntArrayList listWithDupes = newImmutableIntArrayList(1, 1);
-    assertEquals(false, listWithDupes.contains(2));
+    assertThat(listWithDupes).doesNotContain(2);
   }
 
+  @Test
   public void testContains_inList() {
-    assertEquals(true, TERTIARY_LIST.contains(2));
+    assertThat(TERTIARY_LIST).contains(2);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchAtHead() {
     IntArrayList listWithDupes = newImmutableIntArrayList(1, 1, 2);
-    assertEquals(true, listWithDupes.contains(1));
+    assertThat(listWithDupes).contains(1);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchMidList() {
     IntArrayList listWithDupes = newImmutableIntArrayList(2, 1, 1, 2);
-    assertEquals(true, listWithDupes.contains(1));
+    assertThat(listWithDupes).contains(1);
   }
 
+  @Test
   public void testSize() {
-    assertEquals(0, IntArrayList.emptyList().size());
-    assertEquals(1, UNARY_LIST.size());
-    assertEquals(3, TERTIARY_LIST.size());
+    assertThat(IntArrayList.emptyList()).isEmpty();
+    assertThat(UNARY_LIST).hasSize(1);
+    assertThat(TERTIARY_LIST).hasSize(3);
 
     list.addInt(3);
     list.addInt(4);
     list.addInt(6);
     list.addInt(8);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
 
     list.remove(0);
-    assertEquals(3, list.size());
+    assertThat(list).hasSize(3);
 
     list.add(17);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
   }
 
+  @Test
   public void testSet() {
     list.addInt(2);
     list.addInt(4);
 
-    assertEquals(2, (int) list.set(0, 3));
-    assertEquals(3, list.getInt(0));
+    assertThat((int) list.set(0, 3)).isEqualTo(2);
+    assertThat(list.getInt(0)).isEqualTo(3);
 
-    assertEquals(4, (int) list.set(1, 0));
-    assertEquals(0, list.getInt(1));
+    assertThat((int) list.set(1, 0)).isEqualTo(4);
+    assertThat(list.getInt(1)).isEqualTo(0);
 
     try {
       list.set(-1, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.set(2, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testSetInt() {
     list.addInt(1);
     list.addInt(3);
 
-    assertEquals(1, list.setInt(0, 0));
-    assertEquals(0, list.getInt(0));
+    assertThat(list.setInt(0, 0)).isEqualTo(1);
+    assertThat(list.getInt(0)).isEqualTo(0);
 
-    assertEquals(3, list.setInt(1, 0));
-    assertEquals(0, list.getInt(1));
+    assertThat(list.setInt(1, 0)).isEqualTo(3);
+    assertThat(list.getInt(1)).isEqualTo(0);
 
     try {
       list.setInt(-1, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.setInt(2, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testAdd() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.add(2));
-    assertEquals(asList(2), list);
+    assertThat(list.add(2)).isTrue();
+    assertThat(list).containsExactly(2);
 
-    assertTrue(list.add(3));
+    assertThat(list.add(3)).isTrue();
     list.add(0, 4);
-    assertEquals(asList(4, 2, 3), list);
+    assertThat(list).containsExactly(4, 2, 3).inOrder();
 
     list.add(0, 1);
     list.add(0, 0);
@@ -285,7 +311,7 @@
     for (int i = 0; i < 6; i++) {
       list.add(Integer.valueOf(5 + i));
     }
-    assertEquals(asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10), list);
+    assertThat(list).containsExactly(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10).inOrder();
 
     try {
       list.add(-1, 5);
@@ -300,90 +326,98 @@
     }
   }
 
+  @Test
   public void testAddInt() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
     list.addInt(2);
-    assertEquals(asList(2), list);
+    assertThat(list).containsExactly(2);
 
     list.addInt(3);
-    assertEquals(asList(2, 3), list);
+    assertThat(list).containsExactly(2, 3).inOrder();
   }
 
+  @Test
   public void testAddAll() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.addAll(Collections.singleton(1)));
-    assertEquals(1, list.size());
-    assertEquals(1, (int) list.get(0));
-    assertEquals(1, list.getInt(0));
+    assertThat(list.addAll(Collections.singleton(1))).isTrue();
+    assertThat(list).hasSize(1);
+    assertThat((int) list.get(0)).isEqualTo(1);
+    assertThat(list.getInt(0)).isEqualTo(1);
 
-    assertTrue(list.addAll(asList(2, 3, 4, 5, 6)));
-    assertEquals(asList(1, 2, 3, 4, 5, 6), list);
+    assertThat(list.addAll(asList(2, 3, 4, 5, 6))).isTrue();
+    assertThat(list).containsExactly(1, 2, 3, 4, 5, 6).inOrder();
 
-    assertTrue(list.addAll(TERTIARY_LIST));
-    assertEquals(asList(1, 2, 3, 4, 5, 6, 1, 2, 3), list);
+    assertThat(list.addAll(TERTIARY_LIST)).isTrue();
+    assertThat(list).containsExactly(1, 2, 3, 4, 5, 6, 1, 2, 3).inOrder();
 
-    assertFalse(list.addAll(Collections.<Integer>emptyList()));
-    assertFalse(list.addAll(IntArrayList.emptyList()));
+    assertThat(list.addAll(Collections.<Integer>emptyList())).isFalse();
+    assertThat(list.addAll(IntArrayList.emptyList())).isFalse();
   }
 
+  @Test
   public void testEquals() {
     IntArrayList list1 = new IntArrayList();
     IntArrayList list2 = new IntArrayList();
 
-    assertEquals(list1, list2);
+    assertThat(list1).isEqualTo(list2);
   }
 
+  @Test
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
-    assertEquals(1, (int) list.remove(0));
-    assertEquals(asList(2, 3), list);
+    assertThat((int) list.remove(0)).isEqualTo(1);
+    assertThat(list).containsExactly(2, 3).inOrder();
 
-    assertTrue(list.remove(Integer.valueOf(3)));
-    assertEquals(asList(2), list);
+    assertThat(list.remove(Integer.valueOf(3))).isTrue();
+    assertThat(list).containsExactly(2);
 
-    assertFalse(list.remove(Integer.valueOf(3)));
-    assertEquals(asList(2), list);
+    assertThat(list.remove(Integer.valueOf(3))).isFalse();
+    assertThat(list).containsExactly(2);
 
-    assertEquals(2, (int) list.remove(0));
-    assertEquals(asList(), list);
+    assertThat((int) list.remove(0)).isEqualTo(2);
+    assertThat(list).isEmpty();
 
     try {
       list.remove(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.remove(0);
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testRemoveEnd_listAtCapacity() {
     IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addInt(3);
     toRemove.remove(0);
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
+  @Test
   public void testRemove_listAtCapacity() {
     IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(2);
     toRemove.addInt(3);
     toRemove.addInt(4);
     toRemove.remove(0);
-    assertEquals(1, toRemove.size());
-    assertEquals(4, (int) toRemove.get(0));
+    assertThat(toRemove).hasSize(1);
+    assertThat((int) toRemove.get(0)).isEqualTo(4);
   }
 
+  @Test
   public void testSublistRemoveEndOfCapacity() {
     IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addInt(3);
     toRemove.subList(0, 1).clear();
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
   private void assertImmutable(IntList list) {
@@ -393,147 +427,147 @@
 
     try {
       list.add(1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.add(0, 1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.<Integer>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.singletonList(1));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(new IntArrayList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.singleton(1));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.<Integer>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addInt(0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.clear();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.<Integer>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.singleton(1));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(Collections.<Integer>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(Collections.singleton(1));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.set(0, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.setInt(0, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
index 6a737f1..bbbe2cd 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
 import static com.google.protobuf.IsValidUtf8TestUtil.DIRECT_NIO_FACTORY;
 import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT;
 import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT;
@@ -39,7 +40,9 @@
 
 import com.google.protobuf.IsValidUtf8TestUtil.ByteStringFactory;
 import com.google.protobuf.IsValidUtf8TestUtil.Shard;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Tests cases for {@link ByteString#isValidUtf8()}. This includes three brute force tests that
@@ -49,12 +52,11 @@
  * sequence that will round trip when converted to a String and then back to bytes and will return
  * false for any sequence that will not round trip. See also {@link IsValidUtf8FourByteTest}. It
  * also includes some other more targeted tests.
- *
- * @author [email protected] (Jon Perlow)
- * @author [email protected] (Martin Buchholz)
  */
-public class IsValidUtf8Test extends TestCase {
+@RunWith(JUnit4.class)
+public class IsValidUtf8Test {
   /** Tests that round tripping of all two byte permutations work. */
+  @Test
   public void testIsValidUtf8_1Byte() {
     testBytes(LITERAL_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
     testBytes(HEAP_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
@@ -62,6 +64,7 @@
   }
 
   /** Tests that round tripping of all two byte permutations work. */
+  @Test
   public void testIsValidUtf8_2Bytes() {
     testBytes(LITERAL_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
     testBytes(HEAP_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
@@ -69,6 +72,7 @@
   }
 
   /** Tests that round tripping of all three byte permutations work. */
+  @Test
   public void testIsValidUtf8_3Bytes() {
     // Travis' OOM killer doesn't like this test
     if (System.getenv("TRAVIS") == null) {
@@ -83,6 +87,7 @@
    * prohibitively expensive to test for automated runs; {@link IsValidUtf8FourByteTest} is used for
    * full coverage. This method tests specific four-byte cases.
    */
+  @Test
   public void testIsValidUtf8_4BytesSamples() {
     // Valid 4 byte.
     assertValidUtf8(0xF0, 0xA4, 0xAD, 0xA2);
@@ -97,29 +102,40 @@
   }
 
   /** Tests some hard-coded test cases. */
+  @Test
   public void testSomeSequences() {
     // Empty
-    assertTrue(asBytes("").isValidUtf8());
+    assertThat(asBytes("").isValidUtf8()).isTrue();
 
     // One-byte characters, including control characters
-    assertTrue(asBytes("\u0000abc\u007f").isValidUtf8());
+    assertThat(asBytes("\u0000abc\u007f").isValidUtf8()).isTrue();
 
     // Two-byte characters
-    assertTrue(asBytes("\u00a2\u00a2").isValidUtf8());
+    assertThat(asBytes("\u00a2\u00a2").isValidUtf8()).isTrue();
 
     // Three-byte characters
-    assertTrue(asBytes("\u020ac\u020ac").isValidUtf8());
+    assertThat(asBytes("\u020ac\u020ac").isValidUtf8()).isTrue();
 
     // Four-byte characters
-    assertTrue(asBytes("\u024B62\u024B62").isValidUtf8());
+    assertThat(asBytes("\u024B62\u024B62").isValidUtf8()).isTrue();
 
     // Mixed string
-    assertTrue(asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62").isValidUtf8());
+    assertThat(asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62").isValidUtf8()).isTrue();
 
     // Not a valid string
     assertInvalidUtf8(-1, 0, -1, 0);
   }
 
+  @Test
+  public void testShardsHaveExpectedRoundTrippables() {
+    // A sanity check.
+    int actual = 0;
+    for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
+      actual = (int) (actual + shard.expected);
+    }
+    assertThat(actual).isEqualTo(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT);
+  }
+
   private byte[] toByteArray(int... bytes) {
     byte[] realBytes = new byte[bytes.length];
     for (int i = 0; i < bytes.length; i++) {
@@ -130,12 +146,12 @@
 
   private void assertValidUtf8(ByteStringFactory factory, int[] bytes, boolean not) {
     byte[] realBytes = toByteArray(bytes);
-    assertTrue(not ^ Utf8.isValidUtf8(realBytes));
-    assertTrue(not ^ Utf8.isValidUtf8(realBytes, 0, bytes.length));
+    assertThat(not ^ Utf8.isValidUtf8(realBytes)).isTrue();
+    assertThat(not ^ Utf8.isValidUtf8(realBytes, 0, bytes.length)).isTrue();
     ByteString leaf = factory.newByteString(realBytes);
     ByteString sub = leaf.substring(0, bytes.length);
-    assertTrue(not ^ leaf.isValidUtf8());
-    assertTrue(not ^ sub.isValidUtf8());
+    assertThat(not ^ leaf.isValidUtf8()).isTrue();
+    assertThat(not ^ sub.isValidUtf8()).isTrue();
     ByteString[] ropes = {
       RopeByteString.newInstanceForTest(ByteString.EMPTY, leaf),
       RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
@@ -144,7 +160,7 @@
       RopeByteString.newInstanceForTest(sub, leaf)
     };
     for (ByteString rope : ropes) {
-      assertTrue(not ^ rope.isValidUtf8());
+      assertThat(not ^ rope.isValidUtf8()).isTrue();
     }
   }
 
@@ -163,13 +179,4 @@
   private static ByteString asBytes(String s) {
     return ByteString.copyFromUtf8(s);
   }
-
-  public void testShardsHaveExpectedRoundTrippables() {
-    // A sanity check.
-    int actual = 0;
-    for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
-      actual = (int) (actual + shard.expected);
-    }
-    assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT, actual);
-  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
index 67d2f59..94a9ffb 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
@@ -30,11 +30,8 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import java.lang.ref.SoftReference;
 import java.nio.ByteBuffer;
@@ -56,7 +53,7 @@
  * @author [email protected] (Martin Buchholz)
  */
 final class IsValidUtf8TestUtil {
-  private static Logger logger = Logger.getLogger(IsValidUtf8TestUtil.class.getName());
+  private static final Logger logger = Logger.getLogger(IsValidUtf8TestUtil.class.getName());
 
   private IsValidUtf8TestUtil() {}
 
@@ -80,8 +77,7 @@
         }
       };
 
-  private static ThreadLocal<SoftReference<ByteBuffer>> directBuffer =
-      new ThreadLocal<SoftReference<ByteBuffer>>();
+  private static final ThreadLocal<SoftReference<ByteBuffer>> directBuffer = new ThreadLocal<>();
 
   /**
    * Factory for direct {@link ByteBuffer} instances. To reduce direct memory usage, this uses a
@@ -171,7 +167,7 @@
     final long expected;
 
     public Shard(long index, long start, long lim, long expected) {
-      assertTrue(start < lim);
+      assertThat(start).isLessThan(lim);
       this.index = index;
       this.start = start;
       this.lim = lim;
@@ -216,11 +212,11 @@
       generateFourByteShards(128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
 
   private static List<Shard> generateFourByteShards(int numShards, long[] expected) {
-    assertEquals(numShards, expected.length);
-    List<Shard> shards = new ArrayList<Shard>(numShards);
+    assertThat(expected).hasLength(numShards);
+    List<Shard> shards = new ArrayList<>(numShards);
     long lim = 1L << 32;
     long increment = lim / numShards;
-    assertTrue(lim % numShards == 0);
+    assertThat(lim % numShards).isEqualTo(0);
     for (int i = 0; i < numShards; i++) {
       shards.add(new Shard(i, increment * i, increment * (i + 1), expected[i]));
     }
@@ -276,11 +272,11 @@
       }
 
       // Check agreement with static Utf8 methods.
-      assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes));
-      assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes, 0, numBytes));
+      assertThat(Utf8.isValidUtf8(bytes)).isEqualTo(isRoundTrippable);
+      assertThat(Utf8.isValidUtf8(bytes, 0, numBytes)).isEqualTo(isRoundTrippable);
 
       try {
-        assertEquals(s, Utf8.decodeUtf8(bytes, 0, numBytes));
+        assertThat(Utf8.decodeUtf8(bytes, 0, numBytes)).isEqualTo(s);
       } catch (InvalidProtocolBufferException e) {
         if (isRoundTrippable) {
           System.out.println("Could not decode utf-8");
@@ -304,31 +300,32 @@
         System.out.printf("state=%04x %04x %04x i=%d j=%d%n", state1, state2, state3, i, j);
         outputFailure(byteChar, bytes, bytesReencoded);
       }
-      assertEquals(isRoundTrippable, (state3 == Utf8.COMPLETE));
+      assertThat((state3 == Utf8.COMPLETE)).isEqualTo(isRoundTrippable);
 
       // Test ropes built out of small partial sequences
       ByteString rope =
           RopeByteString.newInstanceForTest(
               bs.substring(0, i),
               RopeByteString.newInstanceForTest(bs.substring(i, j), bs.substring(j, numBytes)));
-      assertSame(RopeByteString.class, rope.getClass());
+      assertThat(rope.getClass()).isSameInstanceAs(RopeByteString.class);
 
       ByteString[] byteStrings = {bs, bs.substring(0, numBytes), rope};
       for (ByteString x : byteStrings) {
-        assertEquals(isRoundTrippable, x.isValidUtf8());
-        assertEquals(state3, x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes));
+        assertThat(x.isValidUtf8()).isEqualTo(isRoundTrippable);
+        assertThat(x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes)).isEqualTo(state3);
 
-        assertEquals(state1, x.partialIsValidUtf8(Utf8.COMPLETE, 0, i));
-        assertEquals(state1, x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i));
-        assertEquals(state2, x.partialIsValidUtf8(state1, i, j - i));
-        assertEquals(state2, x.substring(i, j).partialIsValidUtf8(state1, 0, j - i));
-        assertEquals(state3, x.partialIsValidUtf8(state2, j, numBytes - j));
-        assertEquals(state3, x.substring(j, numBytes).partialIsValidUtf8(state2, 0, numBytes - j));
+        assertThat(x.partialIsValidUtf8(Utf8.COMPLETE, 0, i)).isEqualTo(state1);
+        assertThat(x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i)).isEqualTo(state1);
+        assertThat(x.partialIsValidUtf8(state1, i, j - i)).isEqualTo(state2);
+        assertThat(x.substring(i, j).partialIsValidUtf8(state1, 0, j - i)).isEqualTo(state2);
+        assertThat(x.partialIsValidUtf8(state2, j, numBytes - j)).isEqualTo(state3);
+        assertThat(x.substring(j, numBytes).partialIsValidUtf8(state2, 0, numBytes - j))
+            .isEqualTo(state3);
       }
 
       // ByteString reduplication should not affect its UTF-8 validity.
       ByteString ropeADope = RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
-      assertEquals(isRoundTrippable, ropeADope.isValidUtf8());
+      assertThat(ropeADope.isValidUtf8()).isEqualTo(isRoundTrippable);
 
       if (isRoundTrippable) {
         countRoundTripped++;
@@ -339,7 +336,7 @@
       }
     }
     logger.info("Round tripped " + countRoundTripped + " of " + count);
-    assertEquals(expectedCount, countRoundTripped);
+    assertThat(countRoundTripped).isEqualTo(expectedCount);
   }
 
   /**
@@ -397,17 +394,17 @@
       }
       boolean isRoundTrippable = factory.newByteString(bytes).isValidUtf8();
       CoderResult result = decoder.decode(bb, cb, true);
-      assertFalse(result.isError());
+      assertThat(result.isError()).isFalse();
       result = decoder.flush(cb);
-      assertFalse(result.isError());
+      assertThat(result.isError()).isFalse();
 
       int charLen = cb.position();
       cb.rewind();
       cb.limit(charLen);
       result = encoder.encode(cb, bbReencoded, true);
-      assertFalse(result.isError());
+      assertThat(result.isError()).isFalse();
       result = encoder.flush(bbReencoded);
-      assertFalse(result.isError());
+      assertThat(result.isError()).isFalse();
 
       boolean bytesEqual = true;
       int bytesLen = bbReencoded.position();
@@ -434,7 +431,7 @@
       }
     }
     logger.info("Round tripped " + countRoundTripped + " of " + count);
-    assertEquals(expectedCount, countRoundTripped);
+    assertThat(countRoundTripped).isEqualTo(expectedCount);
   }
 
   private static void outputFailure(long byteChar, byte[] bytes, byte[] after) {
@@ -442,10 +439,8 @@
   }
 
   private static void outputFailure(long byteChar, byte[] bytes, byte[] after, int len) {
-    fail(
-        String.format(
-            "Failure: (%s) %s => %s",
-            Long.toHexString(byteChar), toHexString(bytes), toHexString(after, len)));
+    assertWithMessage("Failure: (%s) %s => %s",
+            Long.toHexString(byteChar), toHexString(bytes), toHexString(after, len)).fail();
   }
 
   private static String toHexString(byte[] b) {
diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
index 8c13aca..98cee80 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
@@ -30,36 +30,39 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
 import static protobuf_unittest.UnittestProto.optionalInt32Extension;
 
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import java.io.IOException;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Unit test for {@link LazyFieldLite}.
- *
- * @author [email protected] (Xiang Li)
- */
-public class LazyFieldLiteTest extends TestCase {
+/** Unit test for {@link LazyFieldLite}. */
+@RunWith(JUnit4.class)
+public class LazyFieldLiteTest {
 
+  @Test
   public void testGetValue() {
     MessageLite message = TestUtil.getAllSet();
     LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+    assertThat(message).isEqualTo(lazyField.getValue(TestAllTypes.getDefaultInstance()));
     changeValue(lazyField);
     assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
   }
 
+  @Test
   public void testGetValueEx() throws Exception {
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+    assertThat(message).isEqualTo(lazyField.getValue(TestAllExtensions.getDefaultInstance()));
     changeValue(lazyField);
     assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
   }
 
+  @Test
   public void testSetValue() {
     MessageLite message = TestUtil.getAllSet();
     LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
@@ -67,9 +70,10 @@
     assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
     message = lazyField.getValue(TestAllTypes.getDefaultInstance());
     changeValue(lazyField);
-    assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+    assertThat(message).isEqualTo(lazyField.getValue(TestAllTypes.getDefaultInstance()));
   }
 
+  @Test
   public void testSetValueEx() throws Exception {
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
@@ -77,41 +81,46 @@
     assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
     MessageLite value = lazyField.getValue(TestAllExtensions.getDefaultInstance());
     changeValue(lazyField);
-    assertEquals(value, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+    assertThat(value).isEqualTo(lazyField.getValue(TestAllExtensions.getDefaultInstance()));
   }
 
+  @Test
   public void testGetSerializedSize() {
     MessageLite message = TestUtil.getAllSet();
     LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(lazyField.getSerializedSize());
     changeValue(lazyField);
     assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
   }
 
+  @Test
   public void testGetSerializedSizeEx() throws Exception {
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(lazyField.getSerializedSize());
     changeValue(lazyField);
     assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
   }
 
+  @Test
   public void testGetByteString() {
     MessageLite message = TestUtil.getAllSet();
     LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message.toByteString(), lazyField.toByteString());
+    assertThat(message.toByteString()).isEqualTo(lazyField.toByteString());
     changeValue(lazyField);
     assertNotEqual(message.toByteString(), lazyField.toByteString());
   }
 
+  @Test
   public void testGetByteStringEx() throws Exception {
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message.toByteString(), lazyField.toByteString());
+    assertThat(message.toByteString()).isEqualTo(lazyField.toByteString());
     changeValue(lazyField);
     assertNotEqual(message.toByteString(), lazyField.toByteString());
   }
 
+  @Test
   public void testMergeExtensions() throws Exception {
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     LazyFieldLite original = createLazyFieldLiteFromMessage(message);
@@ -119,25 +128,29 @@
     merged.merge(original);
     TestAllExtensions value =
         (TestAllExtensions) merged.getValue(TestAllExtensions.getDefaultInstance());
-    assertEquals(message, value);
+    assertThat(message).isEqualTo(value);
   }
 
+  @Test
   public void testEmptyLazyField() throws Exception {
     LazyFieldLite field = new LazyFieldLite();
-    assertEquals(0, field.getSerializedSize());
-    assertEquals(ByteString.EMPTY, field.toByteString());
+    assertThat(field.getSerializedSize()).isEqualTo(0);
+    assertThat(field.toByteString()).isEqualTo(ByteString.EMPTY);
   }
 
+  @Test
   public void testInvalidProto() throws Exception {
     // Silently fails and uses the default instance.
     LazyFieldLite field =
         new LazyFieldLite(TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
-    assertEquals(
-        TestAllTypes.getDefaultInstance(), field.getValue(TestAllTypes.getDefaultInstance()));
-    assertEquals(0, field.getSerializedSize());
-    assertEquals(ByteString.EMPTY, field.toByteString());
+    assertThat(
+        field.getValue(TestAllTypes.getDefaultInstance()))
+            .isEqualTo(TestAllTypes.getDefaultInstance());
+    assertThat(field.getSerializedSize()).isEqualTo(0);
+    assertThat(field.toByteString()).isEqualTo(ByteString.EMPTY);
   }
 
+  @Test
   public void testMergeBeforeParsing() throws Exception {
     TestAllTypes message1 = TestAllTypes.newBuilder().setOptionalInt32(1).build();
     LazyFieldLite field1 = createLazyFieldLiteFromMessage(message1);
@@ -147,9 +160,10 @@
     field1.merge(field2);
     TestAllTypes expected =
         TestAllTypes.newBuilder().setOptionalInt32(1).setOptionalInt64(2).build();
-    assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+    assertThat(field1.getValue(TestAllTypes.getDefaultInstance())).isEqualTo(expected);
   }
 
+  @Test
   public void testMergeOneNotParsed() throws Exception {
     // Test a few different paths that involve one message that was not parsed.
     TestAllTypes message1 = TestAllTypes.newBuilder().setOptionalInt32(1).build();
@@ -161,16 +175,17 @@
     field1.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
     LazyFieldLite field2 = createLazyFieldLiteFromMessage(message2);
     field1.merge(field2);
-    assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+    assertThat(field1.getValue(TestAllTypes.getDefaultInstance())).isEqualTo(expected);
 
     // Now reverse which one is parsed first.
     field1 = LazyFieldLite.fromValue(message1);
     field2 = createLazyFieldLiteFromMessage(message2);
     field2.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
     field1.merge(field2);
-    assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+    assertThat(field1.getValue(TestAllTypes.getDefaultInstance())).isEqualTo(expected);
   }
 
+  @Test
   public void testMergeInvalid() throws Exception {
     // Test a few different paths that involve one message that was not parsed.
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(1).build();
@@ -180,9 +195,10 @@
     invalid.merge(valid);
 
     // We swallow the exception and just use the set field.
-    assertEquals(message, invalid.getValue(TestAllTypes.getDefaultInstance()));
+    assertThat(invalid.getValue(TestAllTypes.getDefaultInstance())).isEqualTo(message);
   }
 
+  @Test
   public void testMergeKeepsExtensionsWhenPossible() throws Exception {
     // In this test we attempt to only use the empty registry, which will strip out all extensions
     // when serializing and then parsing. We verify that each code path will attempt to not
@@ -190,32 +206,36 @@
     // extensionRegistry.
     TestAllExtensions messageWithExtensions =
         TestAllExtensions.newBuilder().setExtension(optionalInt32Extension, 42).build();
-    TestAllExtensions emptyMessage = TestAllExtensions.newBuilder().build();
+    TestAllExtensions emptyMessage = TestAllExtensions.getDefaultInstance();
 
     ExtensionRegistryLite emptyRegistry = ExtensionRegistryLite.getEmptyRegistry();
 
     LazyFieldLite field = LazyFieldLite.fromValue(messageWithExtensions);
     field.merge(createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage));
-    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+    assertThat(field.getValue(TestAllExtensions.getDefaultInstance()))
+        .isEqualTo(messageWithExtensions);
 
     // Now reverse the order of the merging.
     field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
     field.merge(LazyFieldLite.fromValue(messageWithExtensions));
-    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+    assertThat(field.getValue(TestAllExtensions.getDefaultInstance()))
+        .isEqualTo(messageWithExtensions);
 
     // Now try parsing the empty field first.
     field = LazyFieldLite.fromValue(messageWithExtensions);
     LazyFieldLite other = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
     other.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
     field.merge(other);
-    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+    assertThat(field.getValue(TestAllExtensions.getDefaultInstance()))
+        .isEqualTo(messageWithExtensions);
 
     // And again reverse.
     field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
     field.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
     other = LazyFieldLite.fromValue(messageWithExtensions);
     field.merge(other);
-    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+    assertThat(field.getValue(TestAllExtensions.getDefaultInstance()))
+        .isEqualTo(messageWithExtensions);
   }
 
 
@@ -239,7 +259,8 @@
   }
 
   private void assertNotEqual(Object unexpected, Object actual) {
-    assertFalse(unexpected == actual || (unexpected != null && unexpected.equals(actual)));
+    assertThat(unexpected).isNotSameInstanceAs(actual);
+    assertThat((unexpected != null && unexpected.equals(actual))).isFalse();
   }
 
 }
diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
index a3901e9..dbda3bd 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
@@ -30,71 +30,79 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Unit test for {@link LazyField}.
- *
- * @author [email protected] (Xiang Li)
- */
-public class LazyFieldTest extends TestCase {
+/** Unit test for {@link LazyField}. */
+@RunWith(JUnit4.class)
+public class LazyFieldTest {
+
+  @Test
   public void testHashCode() {
     MessageLite message = TestUtil.getAllSet();
     LazyField lazyField = createLazyFieldFromMessage(message);
-    assertEquals(message.hashCode(), lazyField.hashCode());
+    assertThat(message.hashCode()).isEqualTo(lazyField.hashCode());
     lazyField.getValue();
-    assertEquals(message.hashCode(), lazyField.hashCode());
+    assertThat(message.hashCode()).isEqualTo(lazyField.hashCode());
     changeValue(lazyField);
     // make sure two messages have different hash code
     assertNotEqual(message.hashCode(), lazyField.hashCode());
   }
 
+  @Test
   public void testHashCodeEx() throws Exception {
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     LazyField lazyField = createLazyFieldFromMessage(message);
-    assertEquals(message.hashCode(), lazyField.hashCode());
+    assertThat(message.hashCode()).isEqualTo(lazyField.hashCode());
     lazyField.getValue();
-    assertEquals(message.hashCode(), lazyField.hashCode());
+    assertThat(message.hashCode()).isEqualTo(lazyField.hashCode());
     changeValue(lazyField);
     // make sure two messages have different hash code
     assertNotEqual(message.hashCode(), lazyField.hashCode());
   }
 
+  @Test
   public void testGetValue() {
     MessageLite message = TestUtil.getAllSet();
     LazyField lazyField = createLazyFieldFromMessage(message);
-    assertEquals(message, lazyField.getValue());
+    assertThat(message).isEqualTo(lazyField.getValue());
     changeValue(lazyField);
     assertNotEqual(message, lazyField.getValue());
   }
 
+  @Test
   public void testGetValueEx() throws Exception {
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     LazyField lazyField = createLazyFieldFromMessage(message);
-    assertEquals(message, lazyField.getValue());
+    assertThat(message).isEqualTo(lazyField.getValue());
     changeValue(lazyField);
     assertNotEqual(message, lazyField.getValue());
   }
 
+  @Test
   public void testEqualsObject() {
     MessageLite message = TestUtil.getAllSet();
     LazyField lazyField = createLazyFieldFromMessage(message);
-    assertTrue(lazyField.equals(message));
+    assertThat(lazyField).isEqualTo(message);
     changeValue(lazyField);
-    assertFalse(lazyField.equals(message));
-    assertFalse(message.equals(lazyField.getValue()));
+    assertThat(lazyField).isNotEqualTo(message);
+    assertThat(message).isNotEqualTo(lazyField.getValue());
   }
 
-  @SuppressWarnings("EqualsIncompatibleType") // LazyField.equals() is not symmetric
+  @Test
+  @SuppressWarnings("TruthIncompatibleType") // LazyField.equals() is not symmetric
   public void testEqualsObjectEx() throws Exception {
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     LazyField lazyField = createLazyFieldFromMessage(message);
-    assertTrue(lazyField.equals(message));
+    assertThat(lazyField).isEqualTo(message);
     changeValue(lazyField);
-    assertFalse(lazyField.equals(message));
-    assertFalse(message.equals(lazyField.getValue()));
+    assertThat(lazyField).isNotEqualTo(message);
+    assertThat(message).isNotEqualTo(lazyField.getValue());
   }
 
   // Help methods.
@@ -113,6 +121,7 @@
   }
 
   private void assertNotEqual(Object unexpected, Object actual) {
-    assertFalse(unexpected == actual || (unexpected != null && unexpected.equals(actual)));
+    assertThat(unexpected).isNotSameInstanceAs(actual);
+    assertThat((unexpected != null && unexpected.equals(actual))).isFalse();
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
index c5880d5..576feea 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
@@ -30,30 +30,23 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import protobuf_unittest.LazyFieldsLite.LazyExtension;
 import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite;
 import protobuf_unittest.LazyFieldsLite.LazyMessageLite;
 import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite;
 import java.util.ArrayList;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Unit test for messages with lazy fields.
- *
- * @author [email protected] (Naoki Iwasaki)
- */
-public class LazyMessageLiteTest extends TestCase {
+/** Unit test for messages with lazy fields. */
+@RunWith(JUnit4.class)
+public class LazyMessageLiteTest {
 
-  @Override
-  protected void setUp() throws Exception {
-    super.setUp();
-  }
-
-  @Override
-  protected void tearDown() throws Exception {
-    super.tearDown();
-  }
-
+  @Test
   public void testSetValues() {
     LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder().setNum(3).build();
     LazyInnerMessageLite inner =
@@ -66,24 +59,28 @@
             .setOneofInner(inner)
             .build();
 
-    assertEquals(1, outer.getNum());
-    assertEquals(421, outer.getNumWithDefault());
+    assertThat(outer.getNum()).isEqualTo(1);
+    assertThat(outer.getNumWithDefault()).isEqualTo(421);
 
-    assertEquals(2, outer.getInner().getNum());
-    assertEquals(42, outer.getInner().getNumWithDefault());
+    assertThat(outer.getInner().getNum()).isEqualTo(2);
+    assertThat(outer.getInner().getNumWithDefault()).isEqualTo(42);
 
-    assertEquals(3, outer.getInner().getNested().getNum());
-    assertEquals(4, outer.getInner().getNested().getNumWithDefault());
+    assertThat(outer.getInner().getNum()).isEqualTo(2);
+    assertThat(outer.getInner().getNumWithDefault()).isEqualTo(42);
 
-    assertFalse(outer.hasOneofNum());
-    assertTrue(outer.hasOneofInner());
+    assertThat(outer.getInner().getNested().getNum()).isEqualTo(3);
+    assertThat(outer.getInner().getNested().getNumWithDefault()).isEqualTo(4);
 
-    assertEquals(2, outer.getOneofInner().getNum());
-    assertEquals(42, outer.getOneofInner().getNumWithDefault());
-    assertEquals(3, outer.getOneofInner().getNested().getNum());
-    assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
+    assertThat(outer.hasOneofNum()).isFalse();
+    assertThat(outer.hasOneofInner()).isTrue();
+
+    assertThat(outer.getOneofInner().getNum()).isEqualTo(2);
+    assertThat(outer.getOneofInner().getNumWithDefault()).isEqualTo(42);
+    assertThat(outer.getOneofInner().getNested().getNum()).isEqualTo(3);
+    assertThat(outer.getOneofInner().getNested().getNumWithDefault()).isEqualTo(4);
   }
 
+  @Test
   public void testSetRepeatedValues() {
     LazyMessageLite outer =
         LazyMessageLite.newBuilder()
@@ -92,12 +89,13 @@
             .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
             .build();
 
-    assertEquals(1, outer.getNum());
-    assertEquals(2, outer.getRepeatedInnerCount());
-    assertEquals(119, outer.getRepeatedInner(0).getNum());
-    assertEquals(122, outer.getRepeatedInner(1).getNum());
+    assertThat(outer.getNum()).isEqualTo(1);
+    assertThat(outer.getRepeatedInnerCount()).isEqualTo(2);
+    assertThat(outer.getRepeatedInner(0).getNum()).isEqualTo(119);
+    assertThat(outer.getRepeatedInner(1).getNum()).isEqualTo(122);
   }
 
+  @Test
   public void testRepeatedMutability() throws Exception {
     LazyMessageLite outer =
         LazyMessageLite.newBuilder()
@@ -105,14 +103,17 @@
             .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
             .build();
 
-    outer = LazyMessageLite.parseFrom(outer.toByteArray());
+    outer =
+        LazyMessageLite.parseFrom(outer.toByteArray(),
+            ExtensionRegistryLite.getEmptyRegistry());
     try {
       outer.getRepeatedInnerList().set(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException expected) {
     }
   }
 
+  @Test
   public void testAddAll() {
     ArrayList<LazyInnerMessageLite> inners = new ArrayList<>();
     int count = 4;
@@ -122,51 +123,53 @@
     }
 
     LazyMessageLite outer = LazyMessageLite.newBuilder().addAllRepeatedInner(inners).build();
-    assertEquals(count, outer.getRepeatedInnerCount());
+    assertThat(outer.getRepeatedInnerCount()).isEqualTo(count);
     for (int i = 0; i < count; i++) {
-      assertEquals(i, outer.getRepeatedInner(i).getNum());
+      assertThat(outer.getRepeatedInner(i).getNum()).isEqualTo(i);
     }
   }
 
+  @Test
   public void testGetDefaultValues() {
     LazyMessageLite outer = LazyMessageLite.getDefaultInstance();
 
-    assertEquals(0, outer.getNum());
-    assertEquals(421, outer.getNumWithDefault());
+    assertThat(outer.getNum()).isEqualTo(0);
+    assertThat(outer.getNumWithDefault()).isEqualTo(421);
 
-    assertEquals(0, outer.getInner().getNum());
-    assertEquals(42, outer.getInner().getNumWithDefault());
+    assertThat(outer.getInner().getNum()).isEqualTo(0);
+    assertThat(outer.getInner().getNumWithDefault()).isEqualTo(42);
 
-    assertEquals(0, outer.getInner().getNested().getNum());
-    assertEquals(4, outer.getInner().getNested().getNumWithDefault());
+    assertThat(outer.getInner().getNested().getNum()).isEqualTo(0);
+    assertThat(outer.getInner().getNested().getNumWithDefault()).isEqualTo(4);
 
-    assertEquals(0, outer.getOneofNum());
+    assertThat(outer.getOneofNum()).isEqualTo(0);
 
-    assertEquals(0, outer.getOneofInner().getNum());
-    assertEquals(42, outer.getOneofInner().getNumWithDefault());
-    assertEquals(0, outer.getOneofInner().getNested().getNum());
-    assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
+    assertThat(outer.getOneofInner().getNum()).isEqualTo(0);
+    assertThat(outer.getOneofInner().getNumWithDefault()).isEqualTo(42);
+    assertThat(outer.getOneofInner().getNested().getNum()).isEqualTo(0);
+    assertThat(outer.getOneofInner().getNested().getNumWithDefault()).isEqualTo(4);
   }
 
+  @Test
   public void testClearValues() {
     LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder().setNum(115).build();
 
     LazyMessageLite.Builder outerBuilder = LazyMessageLite.newBuilder();
 
-    assertEquals(0, outerBuilder.build().getNum());
+    assertThat(outerBuilder.build().getNum()).isEqualTo(0);
 
     // Set/Clear num
     outerBuilder.setNum(100);
 
-    assertEquals(100, outerBuilder.build().getNum());
-    assertEquals(421, outerBuilder.build().getNumWithDefault());
-    assertFalse(outerBuilder.build().hasInner());
+    assertThat(outerBuilder.build().getNum()).isEqualTo(100);
+    assertThat(outerBuilder.build().getNumWithDefault()).isEqualTo(421);
+    assertThat(outerBuilder.build().hasInner()).isFalse();
 
     outerBuilder.clearNum();
 
-    assertEquals(0, outerBuilder.build().getNum());
-    assertEquals(421, outerBuilder.build().getNumWithDefault());
-    assertFalse(outerBuilder.build().hasInner());
+    assertThat(outerBuilder.build().getNum()).isEqualTo(0);
+    assertThat(outerBuilder.build().getNumWithDefault()).isEqualTo(421);
+    assertThat(outerBuilder.build().hasInner()).isFalse();
 
     // Set/Clear all
     outerBuilder
@@ -177,28 +180,29 @@
         .setOneofInner(LazyInnerMessageLite.newBuilder().setNum(123));
 
     LazyMessageLite outer = outerBuilder.build();
-    assertEquals(100, outer.getNum());
-    assertEquals(421, outer.getNumWithDefault());
-    assertTrue(outer.hasInner());
-    assertEquals(115, outer.getInner().getNum());
-    assertEquals(2, outer.getRepeatedInnerCount());
-    assertEquals(119, outer.getRepeatedInner(0).getNum());
-    assertEquals(122, outer.getRepeatedInner(1).getNum());
-    assertTrue(outer.hasOneofInner());
-    assertEquals(123, outer.getOneofInner().getNum());
+    assertThat(outer.getNum()).isEqualTo(100);
+    assertThat(outer.getNumWithDefault()).isEqualTo(421);
+    assertThat(outer.hasInner()).isTrue();
+    assertThat(outer.getInner().getNum()).isEqualTo(115);
+    assertThat(outer.getRepeatedInnerCount()).isEqualTo(2);
+    assertThat(outer.getRepeatedInner(0).getNum()).isEqualTo(119);
+    assertThat(outer.getRepeatedInner(1).getNum()).isEqualTo(122);
+    assertThat(outer.hasOneofInner()).isTrue();
+    assertThat(outer.getOneofInner().getNum()).isEqualTo(123);
 
     outerBuilder.clear();
 
     outer = outerBuilder.build();
 
-    assertEquals(0, outer.getNum());
-    assertEquals(421, outer.getNumWithDefault());
-    assertFalse(outer.hasInner());
-    assertEquals(0, outer.getRepeatedInnerCount());
-    assertFalse(outer.hasOneofInner());
-    assertEquals(0, outer.getOneofInner().getNum());
+    assertThat(outer.getNum()).isEqualTo(0);
+    assertThat(outer.getNumWithDefault()).isEqualTo(421);
+    assertThat(outer.hasInner()).isFalse();
+    assertThat(outer.getRepeatedInnerCount()).isEqualTo(0);
+    assertThat(outer.hasOneofInner()).isFalse();
+    assertThat(outer.getOneofInner().getNum()).isEqualTo(0);
   }
 
+  @Test
   public void testMergeValues() {
     LazyMessageLite outerBase = LazyMessageLite.newBuilder().setNumWithDefault(122).build();
 
@@ -211,14 +215,15 @@
             .build();
 
     LazyMessageLite merged = LazyMessageLite.newBuilder(outerBase).mergeFrom(outerMerging).build();
-    assertEquals(119, merged.getNum());
-    assertEquals(122, merged.getNumWithDefault());
-    assertEquals(115, merged.getInner().getNum());
-    assertEquals(42, merged.getInner().getNumWithDefault());
-    assertEquals(115, merged.getOneofInner().getNum());
-    assertEquals(42, merged.getOneofInner().getNumWithDefault());
+    assertThat(merged.getNum()).isEqualTo(119);
+    assertThat(merged.getNumWithDefault()).isEqualTo(122);
+    assertThat(merged.getInner().getNum()).isEqualTo(115);
+    assertThat(merged.getInner().getNumWithDefault()).isEqualTo(42);
+    assertThat(merged.getOneofInner().getNum()).isEqualTo(115);
+    assertThat(merged.getOneofInner().getNumWithDefault()).isEqualTo(42);
   }
 
+  @Test
   public void testMergeDefaultValues() {
     LazyInnerMessageLite innerBase = LazyInnerMessageLite.newBuilder().setNum(115).build();
     LazyMessageLite outerBase =
@@ -233,15 +238,16 @@
 
     LazyMessageLite merged = LazyMessageLite.newBuilder(outerBase).mergeFrom(outerMerging).build();
     // Merging default-instance shouldn't overwrite values in the base message.
-    assertEquals(119, merged.getNum());
-    assertEquals(122, merged.getNumWithDefault());
-    assertEquals(115, merged.getInner().getNum());
-    assertEquals(42, merged.getInner().getNumWithDefault());
-    assertEquals(115, merged.getOneofInner().getNum());
-    assertEquals(42, merged.getOneofInner().getNumWithDefault());
+    assertThat(merged.getNum()).isEqualTo(119);
+    assertThat(merged.getNumWithDefault()).isEqualTo(122);
+    assertThat(merged.getInner().getNum()).isEqualTo(115);
+    assertThat(merged.getInner().getNumWithDefault()).isEqualTo(42);
+    assertThat(merged.getOneofInner().getNum()).isEqualTo(115);
+    assertThat(merged.getOneofInner().getNumWithDefault()).isEqualTo(42);
   }
 
   // Regression test for b/28198805.
+  @Test
   public void testMergeOneofMessages() throws Exception {
     LazyInnerMessageLite inner = LazyInnerMessageLite.getDefaultInstance();
     LazyMessageLite outer = LazyMessageLite.newBuilder().setOneofInner(inner).build();
@@ -254,10 +260,11 @@
 
     // Check that the 'outer' stays the same.
     ByteString data2 = outer.toByteString();
-    assertEquals(data1, data2);
-    assertEquals(0, outer.getOneofInner().getNum());
+    assertThat(data1).isEqualTo(data2);
+    assertThat(outer.getOneofInner().getNum()).isEqualTo(0);
   }
 
+  @Test
   public void testSerialize() throws InvalidProtocolBufferException {
     LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder().setNum(3).build();
     LazyInnerMessageLite inner =
@@ -266,40 +273,42 @@
         LazyMessageLite.newBuilder().setNum(1).setInner(inner).setOneofInner(inner).build();
 
     ByteString bytes = outer.toByteString();
-    assertEquals(bytes.size(), outer.getSerializedSize());
+    assertThat(bytes.size()).isEqualTo(outer.getSerializedSize());
 
-    LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes);
+    LazyMessageLite deserialized =
+        LazyMessageLite.parseFrom(bytes, ExtensionRegistryLite.getEmptyRegistry());
 
-    assertEquals(1, deserialized.getNum());
-    assertEquals(421, deserialized.getNumWithDefault());
+    assertThat(deserialized.getNum()).isEqualTo(1);
+    assertThat(deserialized.getNumWithDefault()).isEqualTo(421);
 
-    assertEquals(2, deserialized.getInner().getNum());
-    assertEquals(42, deserialized.getInner().getNumWithDefault());
+    assertThat(deserialized.getInner().getNum()).isEqualTo(2);
+    assertThat(deserialized.getInner().getNumWithDefault()).isEqualTo(42);
 
-    assertEquals(3, deserialized.getInner().getNested().getNum());
-    assertEquals(4, deserialized.getInner().getNested().getNumWithDefault());
+    assertThat(deserialized.getInner().getNested().getNum()).isEqualTo(3);
+    assertThat(deserialized.getInner().getNested().getNumWithDefault()).isEqualTo(4);
 
-    assertEquals(2, deserialized.getOneofInner().getNum());
-    assertEquals(42, deserialized.getOneofInner().getNumWithDefault());
-    assertEquals(3, deserialized.getOneofInner().getNested().getNum());
-    assertEquals(4, deserialized.getOneofInner().getNested().getNumWithDefault());
+    assertThat(deserialized.getOneofInner().getNum()).isEqualTo(2);
+    assertThat(deserialized.getOneofInner().getNumWithDefault()).isEqualTo(42);
+    assertThat(deserialized.getOneofInner().getNested().getNum()).isEqualTo(3);
+    assertThat(deserialized.getOneofInner().getNested().getNumWithDefault()).isEqualTo(4);
 
-    assertEquals(bytes, deserialized.toByteString());
+    assertThat(deserialized.toByteString()).isEqualTo(bytes);
   }
 
+  @Test
   public void testExtensions() throws Exception {
     LazyInnerMessageLite.Builder innerBuilder = LazyInnerMessageLite.newBuilder();
     innerBuilder.setExtension(
         LazyExtension.extension, LazyExtension.newBuilder().setName("name").build());
-    assertTrue(innerBuilder.hasExtension(LazyExtension.extension));
-    assertEquals("name", innerBuilder.getExtension(LazyExtension.extension).getName());
+    assertThat(innerBuilder.hasExtension(LazyExtension.extension)).isTrue();
+    assertThat(innerBuilder.getExtension(LazyExtension.extension).getName()).isEqualTo("name");
 
     LazyInnerMessageLite innerMessage = innerBuilder.build();
-    assertTrue(innerMessage.hasExtension(LazyExtension.extension));
-    assertEquals("name", innerMessage.getExtension(LazyExtension.extension).getName());
+    assertThat(innerMessage.hasExtension(LazyExtension.extension)).isTrue();
+    assertThat(innerMessage.getExtension(LazyExtension.extension).getName()).isEqualTo("name");
 
     LazyMessageLite lite = LazyMessageLite.newBuilder().setInner(innerMessage).build();
-    assertTrue(lite.getInner().hasExtension(LazyExtension.extension));
-    assertEquals("name", lite.getInner().getExtension(LazyExtension.extension).getName());
+    assertThat(lite.getInner().hasExtension(LazyExtension.extension)).isTrue();
+    assertThat(lite.getInner().getExtension(LazyExtension.extension).getName()).isEqualTo("name");
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
index 24d0038..1ef03ce 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static java.util.Arrays.asList;
 
 import java.util.ArrayList;
@@ -37,14 +39,13 @@
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests for {@link LazyStringArrayList}.
- *
- * @author [email protected] (Jon Perlow)
- */
-public class LazyStringArrayListTest extends TestCase {
+/** Tests for {@link LazyStringArrayList}. */
+@RunWith(JUnit4.class)
+public class LazyStringArrayListTest {
 
   private static final String STRING_A = "A";
   private static final String STRING_B = "B";
@@ -54,53 +55,56 @@
   private static final ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
   private static final ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
 
+  @Test
   public void testJustStrings() {
     LazyStringArrayList list = new LazyStringArrayList();
     list.add(STRING_A);
     list.add(STRING_B);
     list.add(STRING_C);
 
-    assertEquals(3, list.size());
-    assertSame(STRING_A, list.get(0));
-    assertSame(STRING_B, list.get(1));
-    assertSame(STRING_C, list.get(2));
+    assertThat(list).hasSize(3);
+    assertThat(list.get(0)).isSameInstanceAs(STRING_A);
+    assertThat(list.get(1)).isSameInstanceAs(STRING_B);
+    assertThat(list.get(2)).isSameInstanceAs(STRING_C);
 
     list.set(1, STRING_C);
-    assertSame(STRING_C, list.get(1));
+    assertThat(list.get(1)).isSameInstanceAs(STRING_C);
 
     list.remove(1);
-    assertSame(STRING_A, list.get(0));
-    assertSame(STRING_C, list.get(1));
+    assertThat(list.get(0)).isSameInstanceAs(STRING_A);
+    assertThat(list.get(1)).isSameInstanceAs(STRING_C);
 
     List<ByteString> byteStringList = list.asByteStringList();
-    assertEquals(BYTE_STRING_A, byteStringList.get(0));
-    assertEquals(BYTE_STRING_C, byteStringList.get(1));
+    assertThat(byteStringList.get(0)).isEqualTo(BYTE_STRING_A);
+    assertThat(byteStringList.get(1)).isEqualTo(BYTE_STRING_C);
 
     // Underlying list should be transformed.
-    assertSame(byteStringList.get(0), list.getByteString(0));
-    assertSame(byteStringList.get(1), list.getByteString(1));
+    assertThat(byteStringList.get(0)).isSameInstanceAs(list.getByteString(0));
+    assertThat(byteStringList.get(1)).isSameInstanceAs(list.getByteString(1));
   }
 
+  @Test
   public void testJustByteString() {
     LazyStringArrayList list = new LazyStringArrayList();
     list.add(BYTE_STRING_A);
     list.add(BYTE_STRING_B);
     list.add(BYTE_STRING_C);
 
-    assertEquals(3, list.size());
-    assertSame(BYTE_STRING_A, list.getByteString(0));
-    assertSame(BYTE_STRING_B, list.getByteString(1));
-    assertSame(BYTE_STRING_C, list.getByteString(2));
+    assertThat(list).hasSize(3);
+    assertThat(list.getByteString(0)).isSameInstanceAs(BYTE_STRING_A);
+    assertThat(list.getByteString(1)).isSameInstanceAs(BYTE_STRING_B);
+    assertThat(list.getByteString(2)).isSameInstanceAs(BYTE_STRING_C);
 
     list.remove(1);
-    assertSame(BYTE_STRING_A, list.getByteString(0));
-    assertSame(BYTE_STRING_C, list.getByteString(1));
+    assertThat(list.getByteString(0)).isSameInstanceAs(BYTE_STRING_A);
+    assertThat(list.getByteString(1)).isSameInstanceAs(BYTE_STRING_C);
 
     List<ByteString> byteStringList = list.asByteStringList();
-    assertSame(BYTE_STRING_A, byteStringList.get(0));
-    assertSame(BYTE_STRING_C, byteStringList.get(1));
+    assertThat(byteStringList.get(0)).isSameInstanceAs(BYTE_STRING_A);
+    assertThat(byteStringList.get(1)).isSameInstanceAs(BYTE_STRING_C);
   }
 
+  @Test
   public void testConversionBackAndForth() {
     LazyStringArrayList list = new LazyStringArrayList();
     list.add(STRING_A);
@@ -108,33 +112,34 @@
     list.add(BYTE_STRING_C);
 
     // String a should be the same because it was originally a string
-    assertSame(STRING_A, list.get(0));
+    assertThat(list.get(0)).isSameInstanceAs(STRING_A);
 
     // String b and c should be different because the string has to be computed
     // from the ByteString
     String bPrime = list.get(1);
-    assertNotSame(STRING_B, bPrime);
-    assertEquals(STRING_B, bPrime);
+    assertThat(bPrime).isNotSameInstanceAs(STRING_B);
+    assertThat(bPrime).isEqualTo(STRING_B);
     String cPrime = list.get(2);
-    assertNotSame(STRING_C, cPrime);
-    assertEquals(STRING_C, cPrime);
+    assertThat(cPrime).isNotSameInstanceAs(STRING_C);
+    assertThat(cPrime).isEqualTo(STRING_C);
 
     // String c and c should stay the same once cached.
-    assertSame(bPrime, list.get(1));
-    assertSame(cPrime, list.get(2));
+    assertThat(list.get(1)).isSameInstanceAs(bPrime);
+    assertThat(list.get(2)).isSameInstanceAs(cPrime);
 
     // ByteString needs to be computed from string for both a and b
     ByteString aPrimeByteString = list.getByteString(0);
-    assertEquals(BYTE_STRING_A, aPrimeByteString);
+    assertThat(aPrimeByteString).isEqualTo(BYTE_STRING_A);
     ByteString bPrimeByteString = list.getByteString(1);
-    assertNotSame(BYTE_STRING_B, bPrimeByteString);
-    assertEquals(BYTE_STRING_B, list.getByteString(1));
+    assertThat(bPrimeByteString).isNotSameInstanceAs(BYTE_STRING_B);
+    assertThat(list.getByteString(1)).isEqualTo(BYTE_STRING_B);
 
     // Once cached, ByteString should stay cached.
-    assertSame(aPrimeByteString, list.getByteString(0));
-    assertSame(bPrimeByteString, list.getByteString(1));
+    assertThat(list.getByteString(0)).isSameInstanceAs(aPrimeByteString);
+    assertThat(list.getByteString(1)).isSameInstanceAs(bPrimeByteString);
   }
 
+  @Test
   public void testCopyConstructorCopiesByReference() {
     LazyStringArrayList list1 = new LazyStringArrayList();
     list1.add(STRING_A);
@@ -142,25 +147,27 @@
     list1.add(BYTE_STRING_C);
 
     LazyStringArrayList list2 = new LazyStringArrayList(list1);
-    assertEquals(3, list2.size());
-    assertSame(STRING_A, list2.get(0));
-    assertSame(BYTE_STRING_B, list2.getByteString(1));
-    assertSame(BYTE_STRING_C, list2.getByteString(2));
+    assertThat(list2).hasSize(3);
+    assertThat(list2.get(0)).isSameInstanceAs(STRING_A);
+    assertThat(list2.getByteString(1)).isSameInstanceAs(BYTE_STRING_B);
+    assertThat(list2.getByteString(2)).isSameInstanceAs(BYTE_STRING_C);
   }
 
+  @Test
   public void testListCopyConstructor() {
-    List<String> list1 = new ArrayList<String>();
+    List<String> list1 = new ArrayList<>();
     list1.add(STRING_A);
     list1.add(STRING_B);
     list1.add(STRING_C);
 
     LazyStringArrayList list2 = new LazyStringArrayList(list1);
-    assertEquals(3, list2.size());
-    assertSame(STRING_A, list2.get(0));
-    assertSame(STRING_B, list2.get(1));
-    assertSame(STRING_C, list2.get(2));
+    assertThat(list2).hasSize(3);
+    assertThat(list2.get(0)).isSameInstanceAs(STRING_A);
+    assertThat(list2.get(1)).isSameInstanceAs(STRING_B);
+    assertThat(list2.get(2)).isSameInstanceAs(STRING_C);
   }
 
+  @Test
   public void testAddAllCopiesByReferenceIfPossible() {
     LazyStringArrayList list1 = new LazyStringArrayList();
     list1.add(STRING_A);
@@ -170,19 +177,20 @@
     LazyStringArrayList list2 = new LazyStringArrayList();
     list2.addAll(list1);
 
-    assertEquals(3, list2.size());
-    assertSame(STRING_A, list2.get(0));
-    assertSame(BYTE_STRING_B, list2.getByteString(1));
-    assertSame(BYTE_STRING_C, list2.getByteString(2));
+    assertThat(list2).hasSize(3);
+    assertThat(list2.get(0)).isSameInstanceAs(STRING_A);
+    assertThat(list2.getByteString(1)).isSameInstanceAs(BYTE_STRING_B);
+    assertThat(list2.getByteString(2)).isSameInstanceAs(BYTE_STRING_C);
   }
 
+  @Test
   public void testModificationWithIteration() {
     LazyStringArrayList list = new LazyStringArrayList();
     list.addAll(asList(STRING_A, STRING_B, STRING_C));
     Iterator<String> iterator = list.iterator();
-    assertEquals(3, list.size());
-    assertEquals(STRING_A, list.get(0));
-    assertEquals(STRING_A, iterator.next());
+    assertThat(list).hasSize(3);
+    assertThat(list.get(0)).isEqualTo(STRING_A);
+    assertThat(iterator.next()).isSameInstanceAs(STRING_A);
 
     // Does not structurally modify.
     iterator = list.iterator();
@@ -192,7 +200,7 @@
     list.remove(0);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (ConcurrentModificationException e) {
       // expected
     }
@@ -201,12 +209,13 @@
     list.add(0, STRING_C);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (ConcurrentModificationException e) {
       // expected
     }
   }
 
+  @Test
   public void testMakeImmutable() {
     LazyStringArrayList list = new LazyStringArrayList();
     list.add(STRING_A);
@@ -220,54 +229,55 @@
 
     try {
       list.add(BYTE_STRING_A.toByteArray());
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.add(BYTE_STRING_A);
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAllByteArray(Collections.singletonList(BYTE_STRING_A.toByteArray()));
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAllByteString(asList(BYTE_STRING_A));
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.mergeFrom(new LazyStringArrayList());
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.set(0, BYTE_STRING_A.toByteArray());
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.set(0, BYTE_STRING_A);
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
   }
 
+  @Test
   public void testImmutabilityPropagation() {
     LazyStringArrayList list = new LazyStringArrayList();
     list.add(STRING_A);
@@ -281,81 +291,80 @@
     assertGenericListImmutable(byteArrayList, byteArrayList.get(0));
   }
 
-  @SuppressWarnings("unchecked")
   private static <T> void assertGenericListImmutable(List<T> list, T value) {
     try {
       list.add(value);
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.add(0, value);
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(asList(value));
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, asList(value));
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.clear();
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(0);
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(value);
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(asList(value));
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(asList());
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(asList());
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.set(0, value);
-      fail();
+      assertWithMessage("expected exception").fail();;
     } catch (UnsupportedOperationException e) {
       // expected
     }
diff --git a/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java b/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
index 18c9c74..006ba38 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
@@ -30,16 +30,21 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import protobuf_unittest.UnittestProto;
 import java.io.IOException;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
- * Tests to make sure the lazy conversion of UTF8-encoded byte arrays to strings works correctly.
- *
- * @author [email protected] (Jon Perlow)
+ * Tests to make sure the lazy conversion of UTF8-encoded byte arrays to strings works
+ * correctly.
  */
-public class LazyStringEndToEndTest extends TestCase {
+@RunWith(JUnit4.class)
+public class LazyStringEndToEndTest {
 
   private static final ByteString TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8 =
       ByteString.copyFrom(
@@ -50,9 +55,8 @@
 
   private ByteString encodedTestAllTypes;
 
-  @Override
-  protected void setUp() throws Exception {
-    super.setUp();
+  @Before
+  public void setUp() throws Exception {
     this.encodedTestAllTypes =
         UnittestProto.TestAllTypes.newBuilder()
             .setOptionalString("foo")
@@ -63,27 +67,34 @@
   }
 
   /** Tests that an invalid UTF8 string will roundtrip through a parse and serialization. */
+  @Test
   public void testParseAndSerialize() throws InvalidProtocolBufferException {
     UnittestProto.TestAllTypes tV2 =
-        UnittestProto.TestAllTypes.parseFrom(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
+        UnittestProto.TestAllTypes.parseFrom(
+            TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8,
+            ExtensionRegistryLite.getEmptyRegistry());
     ByteString bytes = tV2.toByteString();
-    assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
+    assertThat(bytes).isEqualTo(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
 
     tV2.getOptionalString();
     bytes = tV2.toByteString();
-    assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
+    assertThat(bytes).isEqualTo(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
   }
 
+  @Test
   public void testParseAndWrite() throws IOException {
     UnittestProto.TestAllTypes tV2 =
-        UnittestProto.TestAllTypes.parseFrom(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
+        UnittestProto.TestAllTypes.parseFrom(
+            TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8,
+            ExtensionRegistryLite.getEmptyRegistry());
     byte[] sink = new byte[TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8.size()];
     CodedOutputStream outputStream = CodedOutputStream.newInstance(sink);
     tV2.writeTo(outputStream);
     outputStream.flush();
-    assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, ByteString.copyFrom(sink));
+    assertThat(ByteString.copyFrom(sink)).isEqualTo(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
   }
 
+  @Test
   public void testCaching() {
     String a = "a";
     String b = "b";
@@ -96,30 +107,33 @@
             .build();
 
     // String should be the one we passed it.
-    assertSame(a, proto.getOptionalString());
-    assertSame(b, proto.getRepeatedString(0));
-    assertSame(c, proto.getRepeatedString(1));
+    assertThat(proto.getOptionalString()).isSameInstanceAs(a);
+    assertThat(proto.getRepeatedString(0)).isSameInstanceAs(b);
+    assertThat(proto.getRepeatedString(1)).isSameInstanceAs(c);
 
     // Ensure serialization keeps strings cached.
     proto.toByteString();
 
     // And now the string should stay cached.
-    assertSame(a, proto.getOptionalString());
-    assertSame(b, proto.getRepeatedString(0));
-    assertSame(c, proto.getRepeatedString(1));
+    assertThat(proto.getOptionalString()).isSameInstanceAs(a);
+    assertThat(proto.getRepeatedString(0)).isSameInstanceAs(b);
+    assertThat(proto.getRepeatedString(1)).isSameInstanceAs(c);
   }
 
+  @Test
   public void testNoStringCachingIfOnlyBytesAccessed() throws Exception {
-    UnittestProto.TestAllTypes proto = UnittestProto.TestAllTypes.parseFrom(encodedTestAllTypes);
+    UnittestProto.TestAllTypes proto =
+        UnittestProto.TestAllTypes.parseFrom(
+            encodedTestAllTypes, ExtensionRegistryLite.getEmptyRegistry());
     ByteString optional = proto.getOptionalStringBytes();
-    assertSame(optional, proto.getOptionalStringBytes());
-    assertSame(optional, proto.toBuilder().getOptionalStringBytes());
+    assertThat(proto.getOptionalStringBytes()).isSameInstanceAs(optional);
+    assertThat(proto.toBuilder().getOptionalStringBytes()).isSameInstanceAs(optional);
 
     ByteString repeated0 = proto.getRepeatedStringBytes(0);
     ByteString repeated1 = proto.getRepeatedStringBytes(1);
-    assertSame(repeated0, proto.getRepeatedStringBytes(0));
-    assertSame(repeated1, proto.getRepeatedStringBytes(1));
-    assertSame(repeated0, proto.toBuilder().getRepeatedStringBytes(0));
-    assertSame(repeated1, proto.toBuilder().getRepeatedStringBytes(1));
+    assertThat(proto.getRepeatedStringBytes(0)).isSameInstanceAs(repeated0);
+    assertThat(proto.getRepeatedStringBytes(1)).isSameInstanceAs(repeated1);
+    assertThat(proto.toBuilder().getRepeatedStringBytes(0)).isSameInstanceAs(repeated0);
+    assertThat(proto.toBuilder().getRepeatedStringBytes(1)).isSameInstanceAs(repeated1);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
index 4177a47..5ec4a93 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -31,6 +31,7 @@
 package com.google.protobuf;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -45,16 +46,18 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Test {@code LiteralByteString} by setting up a reference string in {@link #setUp()}. This class
  * is designed to be extended for testing extensions of {@code LiteralByteString} such as {@code
  * BoundedByteString}, see {@link BoundedByteStringTest}.
- *
- * @author [email protected] (Carl Haverl)
  */
-public class LiteralByteStringTest extends TestCase {
+@RunWith(JUnit4.class)
+public class LiteralByteStringTest {
   protected static final String UTF_8 = "UTF-8";
 
   protected String classUnderTest;
@@ -62,48 +65,56 @@
   protected ByteString stringUnderTest;
   protected int expectedHashCode;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     classUnderTest = "LiteralByteString";
     referenceBytes = ByteStringTest.getTestBytes(1234, 11337766L);
     stringUnderTest = ByteString.copyFrom(referenceBytes);
     expectedHashCode = 331161852;
   }
 
+  @Test
   public void testExpectedType() {
     String actualClassName = getActualClassName(stringUnderTest);
-    assertEquals(classUnderTest + " should match type exactly", classUnderTest, actualClassName);
+    assertWithMessage("%s should match type exactly", classUnderTest)
+        .that(classUnderTest)
+        .isEqualTo(actualClassName);
   }
 
   protected String getActualClassName(Object object) {
     return object.getClass().getSimpleName();
   }
 
+  @Test
   public void testByteAt() {
     boolean stillEqual = true;
     for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
       stillEqual = (referenceBytes[i] == stringUnderTest.byteAt(i));
     }
-    assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
+    assertWithMessage("%s must capture the right bytes", classUnderTest).that(stillEqual).isTrue();
   }
 
+  @Test
   public void testByteIterator() {
     boolean stillEqual = true;
     ByteString.ByteIterator iter = stringUnderTest.iterator();
     for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
       stillEqual = (iter.hasNext() && referenceBytes[i] == iter.nextByte());
     }
-    assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
-    assertFalse(classUnderTest + " must have exhausted the iterator", iter.hasNext());
+    assertWithMessage("%s must capture the right bytes", classUnderTest).that(stillEqual).isTrue();
+    assertWithMessage("%s must have exhausted the iterator", classUnderTest)
+        .that(iter.hasNext())
+        .isFalse();
 
     try {
       iter.nextByte();
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NoSuchElementException e) {
       // This is success
     }
   }
 
+  @Test
   public void testByteIterable() {
     boolean stillEqual = true;
     int j = 0;
@@ -111,25 +122,36 @@
       stillEqual = (referenceBytes[j] == quantum);
       ++j;
     }
-    assertTrue(classUnderTest + " must capture the right bytes as Bytes", stillEqual);
-    assertEquals(classUnderTest + " iterable character count", referenceBytes.length, j);
+    assertWithMessage("%s must capture the right bytes as Bytes", classUnderTest)
+        .that(stillEqual)
+        .isTrue();
+    assertWithMessage("%s iterable character count", classUnderTest)
+        .that(referenceBytes)
+        .hasLength(j);
   }
 
+  @Test
   public void testSize() {
-    assertEquals(
-        classUnderTest + " must have the expected size",
-        referenceBytes.length,
-        stringUnderTest.size());
+    assertWithMessage("%s must have the expected size", classUnderTest)
+        .that(referenceBytes.length)
+        .isEqualTo(stringUnderTest.size());
   }
 
+  @Test
   public void testGetTreeDepth() {
-    assertEquals(classUnderTest + " must have depth 0", 0, stringUnderTest.getTreeDepth());
+    assertWithMessage("%s must have depth 0", classUnderTest)
+        .that(stringUnderTest.getTreeDepth())
+        .isEqualTo(0);
   }
 
+  @Test
   public void testIsBalanced() {
-    assertTrue(classUnderTest + " is technically balanced", stringUnderTest.isBalanced());
+    assertWithMessage("%s is technically balanced", classUnderTest)
+        .that(stringUnderTest.isBalanced())
+        .isTrue();
   }
 
+  @Test
   public void testCopyTo_ByteArrayOffsetLength() {
     int destinationOffset = 50;
     int length = 100;
@@ -140,9 +162,12 @@
     for (int i = 0; stillEqual && i < length; ++i) {
       stillEqual = referenceBytes[i + sourceOffset] == destination[i + destinationOffset];
     }
-    assertTrue(classUnderTest + ".copyTo(4 arg) must give the expected bytes", stillEqual);
+    assertWithMessage("%s.copyTo(4 arg) must give the expected bytes", classUnderTest)
+        .that(stillEqual)
+        .isTrue();
   }
 
+  @Test
   public void testCopyTo_ByteArrayOffsetLengthErrors() {
     int destinationOffset = 50;
     int length = 100;
@@ -152,7 +177,9 @@
       // Copy one too many bytes
       stringUnderTest.copyTo(
           destination, stringUnderTest.size() + 1 - length, destinationOffset, length);
-      fail("Should have thrown an exception when copying too many bytes of a " + classUnderTest);
+      assertWithMessage(
+              "Should have thrown an exception when copying too many bytes of a %s", classUnderTest)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -160,9 +187,10 @@
     try {
       // Copy with illegal negative sourceOffset
       stringUnderTest.copyTo(destination, -1, destinationOffset, length);
-      fail(
-          "Should have thrown an exception when given a negative sourceOffset in "
-              + classUnderTest);
+      assertWithMessage(
+              "Should have thrown an exception when given a negative sourceOffset in %s",
+              classUnderTest)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -170,9 +198,10 @@
     try {
       // Copy with illegal negative destinationOffset
       stringUnderTest.copyTo(destination, 0, -1, length);
-      fail(
-          "Should have thrown an exception when given a negative destinationOffset in "
-              + classUnderTest);
+      assertWithMessage(
+              "Should have thrown an exception when given a negative destinationOffset in %s",
+              classUnderTest)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -180,7 +209,9 @@
     try {
       // Copy with illegal negative size
       stringUnderTest.copyTo(destination, 0, 0, -1);
-      fail("Should have thrown an exception when given a negative size in " + classUnderTest);
+      assertWithMessage(
+              "Should have thrown an exception when given a negative size in %s", classUnderTest)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -188,9 +219,10 @@
     try {
       // Copy with illegal too-large sourceOffset
       stringUnderTest.copyTo(destination, 2 * stringUnderTest.size(), 0, length);
-      fail(
-          "Should have thrown an exception when the destinationOffset is too large in "
-              + classUnderTest);
+      assertWithMessage(
+              "Should have thrown an exception when the destinationOffset is too large in %s",
+              classUnderTest)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -198,27 +230,33 @@
     try {
       // Copy with illegal too-large destinationOffset
       stringUnderTest.copyTo(destination, 0, 2 * destination.length, length);
-      fail(
-          "Should have thrown an exception when the destinationOffset is too large in "
-              + classUnderTest);
+      assertWithMessage(
+              "Should have thrown an exception when the destinationOffset is too large in %s",
+              classUnderTest)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
   }
 
+  @Test
   public void testCopyTo_ByteBuffer() {
     ByteBuffer myBuffer = ByteBuffer.allocate(referenceBytes.length);
     stringUnderTest.copyTo(myBuffer);
-    assertTrue(
-        classUnderTest + ".copyTo(ByteBuffer) must give back the same bytes",
-        Arrays.equals(referenceBytes, myBuffer.array()));
+    assertWithMessage("%s.copyTo(ByteBuffer) must give back the same bytes", classUnderTest)
+        .that(Arrays.equals(referenceBytes, myBuffer.array()))
+        .isTrue();
   }
 
+  @Test
   public void testMarkSupported() {
     InputStream stream = stringUnderTest.newInput();
-    assertTrue(classUnderTest + ".newInput() must support marking", stream.markSupported());
+    assertWithMessage("%s.newInput() must support marking", classUnderTest)
+        .that(stream.markSupported())
+        .isTrue();
   }
 
+  @Test
   public void testMarkAndReset() throws IOException {
     int fraction = stringUnderTest.size() / 3;
 
@@ -227,16 +265,17 @@
 
     skipFully(stream, fraction); // Skip a large fraction, but not all.
     int available = stream.available();
-    assertTrue(
-        classUnderTest + ": after skipping to the 'middle', half the bytes are available",
-        (stringUnderTest.size() - fraction) == available);
+    assertWithMessage(
+            "%s: after skipping to the 'middle', half the bytes are available", classUnderTest)
+        .that((stringUnderTest.size() - fraction) == available)
+        .isTrue();
     stream.reset();
 
     skipFully(stream, stringUnderTest.size()); // Skip to the end.
     available = stream.available();
-    assertTrue(
-        classUnderTest + ": after skipping to the end, no more bytes are available",
-        0 == available);
+    assertWithMessage("%s: after skipping to the end, no more bytes are available", classUnderTest)
+        .that(0 == available)
+        .isTrue();
   }
 
   /**
@@ -272,50 +311,55 @@
     }
   }
 
+  @Test
   public void testAsReadOnlyByteBuffer() {
     ByteBuffer byteBuffer = stringUnderTest.asReadOnlyByteBuffer();
     byte[] roundTripBytes = new byte[referenceBytes.length];
-    assertTrue(byteBuffer.remaining() == referenceBytes.length);
-    assertTrue(byteBuffer.isReadOnly());
+    assertThat(byteBuffer.remaining() == referenceBytes.length).isTrue();
+    assertThat(byteBuffer.isReadOnly()).isTrue();
     byteBuffer.get(roundTripBytes);
-    assertTrue(
-        classUnderTest + ".asReadOnlyByteBuffer() must give back the same bytes",
-        Arrays.equals(referenceBytes, roundTripBytes));
+    assertWithMessage("%s.asReadOnlyByteBuffer() must give back the same bytes", classUnderTest)
+        .that(Arrays.equals(referenceBytes, roundTripBytes))
+        .isTrue();
   }
 
+  @Test
   public void testAsReadOnlyByteBufferList() {
     List<ByteBuffer> byteBuffers = stringUnderTest.asReadOnlyByteBufferList();
     int bytesSeen = 0;
     byte[] roundTripBytes = new byte[referenceBytes.length];
     for (ByteBuffer byteBuffer : byteBuffers) {
       int thisLength = byteBuffer.remaining();
-      assertTrue(byteBuffer.isReadOnly());
-      assertTrue(bytesSeen + thisLength <= referenceBytes.length);
+      assertThat(byteBuffer.isReadOnly()).isTrue();
+      assertThat(bytesSeen + thisLength <= referenceBytes.length).isTrue();
       byteBuffer.get(roundTripBytes, bytesSeen, thisLength);
       bytesSeen += thisLength;
     }
-    assertTrue(bytesSeen == referenceBytes.length);
-    assertTrue(
-        classUnderTest + ".asReadOnlyByteBufferTest() must give back the same bytes",
-        Arrays.equals(referenceBytes, roundTripBytes));
+    assertThat(bytesSeen == referenceBytes.length).isTrue();
+    assertWithMessage("%s.asReadOnlyByteBufferTest() must give back the same bytes", classUnderTest)
+        .that(Arrays.equals(referenceBytes, roundTripBytes))
+        .isTrue();
   }
 
+  @Test
   public void testToByteArray() {
     byte[] roundTripBytes = stringUnderTest.toByteArray();
-    assertTrue(
-        classUnderTest + ".toByteArray() must give back the same bytes",
-        Arrays.equals(referenceBytes, roundTripBytes));
+    assertWithMessage("%s.toByteArray() must give back the same bytes", classUnderTest)
+        .that(Arrays.equals(referenceBytes, roundTripBytes))
+        .isTrue();
   }
 
+  @Test
   public void testWriteTo() throws IOException {
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
     stringUnderTest.writeTo(bos);
     byte[] roundTripBytes = bos.toByteArray();
-    assertTrue(
-        classUnderTest + ".writeTo() must give back the same bytes",
-        Arrays.equals(referenceBytes, roundTripBytes));
+    assertWithMessage("%s.writeTo() must give back the same bytes", classUnderTest)
+        .that(Arrays.equals(referenceBytes, roundTripBytes))
+        .isTrue();
   }
 
+  @Test
   public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException {
     OutputStream os =
         new OutputStream() {
@@ -331,11 +375,12 @@
         };
 
     stringUnderTest.writeTo(os);
-    assertTrue(
-        classUnderTest + ".writeTo() must not grant access to underlying array",
-        Arrays.equals(referenceBytes, stringUnderTest.toByteArray()));
+    assertWithMessage("%s.writeTo() must not grant access to underlying array", classUnderTest)
+        .that(Arrays.equals(referenceBytes, stringUnderTest.toByteArray()))
+        .isTrue();
   }
 
+  @Test
   public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException {
     OutputStream os =
         new OutputStream() {
@@ -352,11 +397,12 @@
 
     stringUnderTest.writeToInternal(os, 0, stringUnderTest.size());
     byte[] allZeros = new byte[stringUnderTest.size()];
-    assertTrue(
-        classUnderTest + ".writeToInternal() must grant access to underlying array",
-        Arrays.equals(allZeros, stringUnderTest.toByteArray()));
+    assertWithMessage("%s.writeToInternal() must grant access to underlying array", classUnderTest)
+        .that(Arrays.equals(allZeros, stringUnderTest.toByteArray()))
+        .isTrue();
   }
 
+  @Test
   public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException {
     ByteOutput out =
         new ByteOutput() {
@@ -388,197 +434,240 @@
 
     stringUnderTest.writeTo(out);
     byte[] allZeros = new byte[stringUnderTest.size()];
-    assertTrue(
-        classUnderTest + ".writeToInternal() must grant access to underlying array",
-        Arrays.equals(allZeros, stringUnderTest.toByteArray()));
+    assertWithMessage("%s.writeToInternal() must grant access to underlying array", classUnderTest)
+        .that(Arrays.equals(allZeros, stringUnderTest.toByteArray()))
+        .isTrue();
   }
 
+  @Test
   public void testNewOutput() throws IOException {
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
     ByteString.Output output = ByteString.newOutput();
     stringUnderTest.writeTo(output);
-    assertEquals("Output Size returns correct result", output.size(), stringUnderTest.size());
+    assertWithMessage("Output Size returns correct result")
+        .that(output.size())
+        .isEqualTo(stringUnderTest.size());
     output.writeTo(bos);
-    assertTrue(
-        "Output.writeTo() must give back the same bytes",
-        Arrays.equals(referenceBytes, bos.toByteArray()));
+    assertWithMessage("Output.writeTo() must give back the same bytes")
+        .that(Arrays.equals(referenceBytes, bos.toByteArray()))
+        .isTrue();
 
     // write the output stream to itself! This should cause it to double
     output.writeTo(output);
-    assertEquals(
-        "Writing an output stream to itself is successful",
-        stringUnderTest.concat(stringUnderTest),
-        output.toByteString());
+    assertWithMessage("Writing an output stream to itself is successful")
+        .that(stringUnderTest.concat(stringUnderTest))
+        .isEqualTo(output.toByteString());
 
     output.reset();
-    assertEquals("Output.reset() resets the output", 0, output.size());
-    assertEquals("Output.reset() resets the output", ByteString.EMPTY, output.toByteString());
+    assertWithMessage("Output.reset() resets the output").that(output.size()).isEqualTo(0);
+    assertWithMessage("Output.reset() resets the output")
+        .that(output.toByteString())
+        .isEqualTo(ByteString.EMPTY);
   }
 
+  @Test
   public void testToString() throws UnsupportedEncodingException {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
     String roundTripString = unicode.toString(UTF_8);
-    assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
+    assertWithMessage("%s unicode must match", classUnderTest)
+        .that(testString)
+        .isEqualTo(roundTripString);
   }
 
+  @Test
   public void testCharsetToString() {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
     String roundTripString = unicode.toString(Internal.UTF_8);
-    assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
+    assertWithMessage("%s unicode must match", classUnderTest)
+        .that(testString)
+        .isEqualTo(roundTripString);
   }
 
+  @Test
   public void testToString_returnsCanonicalEmptyString() {
-    assertSame(
-        classUnderTest + " must be the same string references",
-        ByteString.EMPTY.toString(Internal.UTF_8),
-        ByteString.wrap(new byte[] {}).toString(Internal.UTF_8));
+    assertWithMessage("%s must be the same string references", classUnderTest)
+        .that(ByteString.EMPTY.toString(Internal.UTF_8))
+        .isSameInstanceAs(ByteString.wrap(new byte[] {}).toString(Internal.UTF_8));
   }
 
+  @Test
   public void testToString_raisesException() {
     try {
       ByteString.EMPTY.toString("invalid");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (UnsupportedEncodingException expected) {
       // This is success
     }
 
     try {
       ByteString.wrap(referenceBytes).toString("invalid");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (UnsupportedEncodingException expected) {
       // This is success
     }
   }
 
+  @Test
+  @SuppressWarnings("SelfEquals")
   public void testEquals() {
-    assertEquals(classUnderTest + " must not equal null", false, stringUnderTest.equals(null));
-    assertEquals(classUnderTest + " must equal self", stringUnderTest, stringUnderTest);
-    assertFalse(
-        classUnderTest + " must not equal the empty string",
-        stringUnderTest.equals(ByteString.EMPTY));
-    assertEquals(
-        classUnderTest + " empty strings must be equal",
-        ByteString.wrap(new byte[] {}),
-        stringUnderTest.substring(55, 55));
-    assertEquals(
-        classUnderTest + " must equal another string with the same value",
-        stringUnderTest,
-        ByteString.wrap(referenceBytes));
+    assertWithMessage("%s must not equal null", classUnderTest)
+        .that(stringUnderTest)
+        .isNotEqualTo(null);
+    assertWithMessage("%s must equal self", classUnderTest)
+        .that(stringUnderTest.equals(stringUnderTest))
+        .isTrue();
+    assertWithMessage("%s must not equal the empty string", classUnderTest)
+        .that(stringUnderTest)
+        .isNotEqualTo(ByteString.EMPTY);
+    assertWithMessage("%s empty strings must be equal", classUnderTest)
+        .that(ByteString.wrap(new byte[] {}))
+        .isEqualTo(stringUnderTest.substring(55, 55));
+    assertWithMessage("%s must equal another string with the same value", classUnderTest)
+        .that(stringUnderTest)
+        .isEqualTo(ByteString.wrap(referenceBytes));
 
     byte[] mungedBytes = new byte[referenceBytes.length];
     System.arraycopy(referenceBytes, 0, mungedBytes, 0, referenceBytes.length);
     mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF);
-    assertFalse(
-        classUnderTest + " must not equal every string with the same length",
-        stringUnderTest.equals(ByteString.wrap(mungedBytes)));
+    assertWithMessage("%s must not equal every string with the same length", classUnderTest)
+        .that(stringUnderTest)
+        .isNotEqualTo(ByteString.wrap(mungedBytes));
   }
 
+  @Test
   public void testHashCode() {
     int hash = stringUnderTest.hashCode();
-    assertEquals(classUnderTest + " must have expected hashCode", expectedHashCode, hash);
+    assertWithMessage("%s must have expected hashCode", classUnderTest)
+        .that(hash)
+        .isEqualTo(expectedHashCode);
   }
 
+  @Test
   public void testPeekCachedHashCode() {
-    assertEquals(
-        classUnderTest + ".peekCachedHashCode() should return zero at first",
-        0,
-        stringUnderTest.peekCachedHashCode());
-    stringUnderTest.hashCode();
-    assertEquals(
-        classUnderTest + ".peekCachedHashCode should return zero at first",
-        expectedHashCode,
-        stringUnderTest.peekCachedHashCode());
+    assertWithMessage("%s.peekCachedHashCode() should return zero at first", classUnderTest)
+        .that(stringUnderTest.peekCachedHashCode())
+        .isEqualTo(0);
+    int unused = stringUnderTest.hashCode();
+    assertWithMessage("%s.peekCachedHashCode should return zero at first", classUnderTest)
+        .that(stringUnderTest.peekCachedHashCode())
+        .isEqualTo(expectedHashCode);
   }
 
+  @Test
   public void testPartialHash() {
     // partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
     // This test would fail if the expected hash were 1.  It's not.
     int hash = stringUnderTest.partialHash(stringUnderTest.size(), 0, stringUnderTest.size());
-    assertEquals(
-        classUnderTest + ".partialHash() must yield expected hashCode", expectedHashCode, hash);
+    assertWithMessage("%s.partialHash() must yield expected hashCode", classUnderTest)
+        .that(hash)
+        .isEqualTo(expectedHashCode);
   }
 
+  @Test
   public void testNewInput() throws IOException {
     InputStream input = stringUnderTest.newInput();
-    assertEquals(
-        "InputStream.available() returns correct value", stringUnderTest.size(), input.available());
+    assertWithMessage("InputStream.available() returns correct value")
+        .that(stringUnderTest.size())
+        .isEqualTo(input.available());
     boolean stillEqual = true;
     for (byte referenceByte : referenceBytes) {
       int expectedInt = (referenceByte & 0xFF);
       stillEqual = (expectedInt == input.read());
     }
-    assertEquals("InputStream.available() returns correct value", 0, input.available());
-    assertTrue(classUnderTest + " must give the same bytes from the InputStream", stillEqual);
-    assertEquals(classUnderTest + " InputStream must now be exhausted", -1, input.read());
+    assertWithMessage("InputStream.available() returns correct value")
+        .that(input.available())
+        .isEqualTo(0);
+    assertWithMessage("%s must give the same bytes from the InputStream", classUnderTest)
+        .that(stillEqual)
+        .isTrue();
+    assertWithMessage("%s InputStream must now be exhausted", classUnderTest)
+        .that(input.read())
+        .isEqualTo(-1);
   }
 
+  @Test
   public void testNewInput_readZeroBytes() throws IOException {
     InputStream input = stringUnderTest.newInput();
-    assertEquals(
-        classUnderTest + " InputStream.read() returns 0 when told to read 0 bytes and not at EOF",
-        0,
-        input.read(new byte[0]));
+    assertWithMessage(
+            "%s InputStream.read() returns 0 when told to read 0 bytes and not at EOF",
+            classUnderTest)
+        .that(input.read(new byte[0]))
+        .isEqualTo(0);
 
     input.skip(input.available());
-    assertEquals(
-        classUnderTest + " InputStream.read() returns -1 when told to read 0 bytes at EOF",
-        -1,
-        input.read(new byte[0]));
+    assertWithMessage(
+            "%s InputStream.read() returns -1 when told to read 0 bytes at EOF", classUnderTest)
+        .that(input.read(new byte[0]))
+        .isEqualTo(-1);
   }
 
+  @Test
   public void testNewInput_skip() throws IOException {
     InputStream input = stringUnderTest.newInput();
     int stringSize = stringUnderTest.size();
     int nearEndIndex = stringSize * 2 / 3;
 
     long skipped1 = input.skip(nearEndIndex);
-    assertEquals("InputStream.skip()", skipped1, nearEndIndex);
-    assertEquals("InputStream.available()", stringSize - skipped1, input.available());
-    assertTrue("InputStream.mark() is available", input.markSupported());
+    assertWithMessage("InputStream.skip()").that(skipped1).isEqualTo(nearEndIndex);
+    assertWithMessage("InputStream.available()")
+        .that(input.available())
+        .isEqualTo(stringSize - skipped1);
+    assertWithMessage("InputStream.mark() is available").that(input.markSupported()).isTrue();
     input.mark(0);
-    assertEquals(
-        "InputStream.skip(), read()", stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
-    assertEquals("InputStream.available()", stringSize - skipped1 - 1, input.available());
+    assertWithMessage("InputStream.skip(), read()")
+        .that(stringUnderTest.byteAt(nearEndIndex) & 0xFF)
+        .isEqualTo(input.read());
+    assertWithMessage("InputStream.available()")
+        .that(input.available())
+        .isEqualTo(stringSize - skipped1 - 1);
 
     long skipped2 = input.skip(stringSize);
-    assertEquals("InputStream.skip() incomplete", skipped2, stringSize - skipped1 - 1);
-    assertEquals("InputStream.skip(), no more input", 0, input.available());
-    assertEquals("InputStream.skip(), no more input", -1, input.read());
+    assertWithMessage("InputStream.skip() incomplete")
+        .that(skipped2)
+        .isEqualTo(stringSize - skipped1 - 1);
+    assertWithMessage("InputStream.skip(), no more input").that(input.available()).isEqualTo(0);
+    assertWithMessage("InputStream.skip(), no more input").that(input.read()).isEqualTo(-1);
     assertThat(input.skip(1)).isEqualTo(0);
     assertThat(input.read(new byte[1], /* off= */ 0, /*len=*/ 0)).isEqualTo(-1);
 
     input.reset();
-    assertEquals("InputStream.reset() succeeded", stringSize - skipped1, input.available());
-    assertEquals(
-        "InputStream.reset(), read()", stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
+    assertWithMessage("InputStream.reset() succeeded")
+        .that(input.available())
+        .isEqualTo(stringSize - skipped1);
+    assertWithMessage("InputStream.reset(), read()")
+        .that(input.read())
+        .isEqualTo(stringUnderTest.byteAt(nearEndIndex) & 0xFF);
   }
 
+  @Test
   public void testNewCodedInput() throws IOException {
     CodedInputStream cis = stringUnderTest.newCodedInput();
     byte[] roundTripBytes = cis.readRawBytes(referenceBytes.length);
-    assertTrue(
-        classUnderTest + " must give the same bytes back from the CodedInputStream",
-        Arrays.equals(referenceBytes, roundTripBytes));
-    assertTrue(classUnderTest + " CodedInputStream must now be exhausted", cis.isAtEnd());
+    assertWithMessage("%s must give the same bytes back from the CodedInputStream", classUnderTest)
+        .that(Arrays.equals(referenceBytes, roundTripBytes))
+        .isTrue();
+    assertWithMessage(" %s CodedInputStream must now be exhausted", classUnderTest)
+        .that(cis.isAtEnd())
+        .isTrue();
   }
 
   /**
    * Make sure we keep things simple when concatenating with empty. See also {@link
    * ByteStringTest#testConcat_empty()}.
    */
+  @Test
   public void testConcat_empty() {
-    assertSame(
-        classUnderTest + " concatenated with empty must give " + classUnderTest,
-        stringUnderTest.concat(ByteString.EMPTY),
-        stringUnderTest);
-    assertSame(
-        "empty concatenated with " + classUnderTest + " must give " + classUnderTest,
-        ByteString.EMPTY.concat(stringUnderTest),
-        stringUnderTest);
+    assertWithMessage("%s concatenated with empty must give %s ", classUnderTest, classUnderTest)
+        .that(stringUnderTest.concat(ByteString.EMPTY))
+        .isSameInstanceAs(stringUnderTest);
+    assertWithMessage("empty concatenated with %s must give %s", classUnderTest, classUnderTest)
+        .that(ByteString.EMPTY.concat(stringUnderTest))
+        .isSameInstanceAs(stringUnderTest);
   }
 
+  @Test
   public void testJavaSerialization() throws Exception {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(out);
@@ -588,7 +677,7 @@
     InputStream in = new ByteArrayInputStream(pickled);
     ObjectInputStream ois = new ObjectInputStream(in);
     Object o = ois.readObject();
-    assertTrue("Didn't get a ByteString back", o instanceof ByteString);
-    assertEquals("Should get an equal ByteString back", stringUnderTest, o);
+    assertWithMessage("Didn't get a ByteString back").that(o).isInstanceOf(ByteString.class);
+    assertWithMessage("Should get an equal ByteString back").that(o).isEqualTo(stringUnderTest);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
index d6fbaf9..2982e0c 100644
--- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -30,39 +30,44 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static java.util.Arrays.asList;
 
 import com.google.protobuf.Internal.LongList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests for {@link LongArrayList}.
- *
- * @author [email protected] (Daniel Weis)
- */
-public class LongArrayListTest extends TestCase {
+/** Tests for {@link LongArrayList}. */
+@RunWith(JUnit4.class)
+public class LongArrayListTest {
 
   private static final LongArrayList UNARY_LIST = newImmutableLongArrayList(1);
   private static final LongArrayList TERTIARY_LIST = newImmutableLongArrayList(1, 2, 3);
 
   private LongArrayList list;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     list = new LongArrayList();
   }
 
+  @Test
   public void testEmptyListReturnsSameInstance() {
-    assertSame(LongArrayList.emptyList(), LongArrayList.emptyList());
+    assertThat(LongArrayList.emptyList()).isSameInstanceAs(LongArrayList.emptyList());
   }
 
+  @Test
   public void testEmptyListIsImmutable() {
     assertImmutable(LongArrayList.emptyList());
   }
 
+  @Test
   public void testMakeImmutable() {
     list.addLong(3);
     list.addLong(4);
@@ -72,19 +77,20 @@
     assertImmutable(list);
   }
 
+  @Test
   public void testModificationWithIteration() {
     list.addAll(asList(1L, 2L, 3L, 4L));
     Iterator<Long> iterator = list.iterator();
-    assertEquals(4, list.size());
-    assertEquals(1L, (long) list.get(0));
-    assertEquals(1L, (long) iterator.next());
+    assertThat(list).hasSize(4);
+    assertThat((long) list.get(0)).isEqualTo(1L);
+    assertThat((long) iterator.next()).isEqualTo(1L);
     list.set(0, 1L);
-    assertEquals(2L, (long) iterator.next());
+    assertThat((long) iterator.next()).isEqualTo(2L);
 
     list.remove(0);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
@@ -93,191 +99,211 @@
     list.add(0, 0L);
     try {
       iterator.next();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (ConcurrentModificationException e) {
       // expected
     }
   }
 
+  @Test
   public void testGet() {
-    assertEquals(1L, (long) TERTIARY_LIST.get(0));
-    assertEquals(2L, (long) TERTIARY_LIST.get(1));
-    assertEquals(3L, (long) TERTIARY_LIST.get(2));
+    assertThat((long) TERTIARY_LIST.get(0)).isEqualTo(1L);
+    assertThat((long) TERTIARY_LIST.get(1)).isEqualTo(2L);
+    assertThat((long) TERTIARY_LIST.get(2)).isEqualTo(3L);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testGetLong() {
-    assertEquals(1L, TERTIARY_LIST.getLong(0));
-    assertEquals(2L, TERTIARY_LIST.getLong(1));
-    assertEquals(3L, TERTIARY_LIST.getLong(2));
+    assertThat(TERTIARY_LIST.getLong(0)).isEqualTo(1L);
+    assertThat(TERTIARY_LIST.getLong(1)).isEqualTo(2L);
+    assertThat(TERTIARY_LIST.getLong(2)).isEqualTo(3L);
 
     try {
       TERTIARY_LIST.get(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       TERTIARY_LIST.get(3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testIndexOf_nullElement() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(null));
+    assertThat(TERTIARY_LIST.indexOf(null)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_incompatibleElementType() {
-    assertEquals(-1, TERTIARY_LIST.indexOf(new Object()));
+    assertThat(TERTIARY_LIST.indexOf(new Object())).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInList() {
-    assertEquals(-1, UNARY_LIST.indexOf(2L));
+    assertThat(UNARY_LIST.indexOf(2L)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_notInListWithDuplicates() {
     LongArrayList listWithDupes = newImmutableLongArrayList(1L, 1L);
-    assertEquals(-1, listWithDupes.indexOf(2L));
+    assertThat(listWithDupes.indexOf(2L)).isEqualTo(-1);
   }
 
+  @Test
   public void testIndexOf_inList() {
-    assertEquals(1, TERTIARY_LIST.indexOf(2L));
+    assertThat(TERTIARY_LIST.indexOf(2L)).isEqualTo(1);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchAtHead() {
     LongArrayList listWithDupes = newImmutableLongArrayList(1L, 1L, 2L);
-    assertEquals(0, listWithDupes.indexOf(1L));
+    assertThat(listWithDupes.indexOf(1L)).isEqualTo(0);
   }
 
+  @Test
   public void testIndexOf_inListWithDuplicates_matchMidList() {
     LongArrayList listWithDupes = newImmutableLongArrayList(2L, 1L, 1L, 2L);
-    assertEquals(1, listWithDupes.indexOf(1L));
+    assertThat(listWithDupes.indexOf(1L)).isEqualTo(1);
   }
 
+  @Test
   public void testContains_nullElement() {
-    assertEquals(false, TERTIARY_LIST.contains(null));
+    assertThat(TERTIARY_LIST).doesNotContain(null);
   }
 
+  @Test
   public void testContains_incompatibleElementType() {
-    assertEquals(false, TERTIARY_LIST.contains(new Object()));
+    assertThat(TERTIARY_LIST).doesNotContain(new Object());
   }
 
+  @Test
   public void testContains_notInList() {
-    assertEquals(false, UNARY_LIST.contains(2L));
+    assertThat(UNARY_LIST).doesNotContain(2L);
   }
 
+  @Test
   public void testContains_notInListWithDuplicates() {
     LongArrayList listWithDupes = newImmutableLongArrayList(1L, 1L);
-    assertEquals(false, listWithDupes.contains(2L));
+    assertThat(listWithDupes).doesNotContain(2L);
   }
 
+  @Test
   public void testContains_inList() {
-    assertEquals(true, TERTIARY_LIST.contains(2L));
+    assertThat(TERTIARY_LIST).contains(2L);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchAtHead() {
     LongArrayList listWithDupes = newImmutableLongArrayList(1L, 1L, 2L);
-    assertEquals(true, listWithDupes.contains(1L));
+    assertThat(listWithDupes).contains(1L);
   }
 
+  @Test
   public void testContains_inListWithDuplicates_matchMidList() {
     LongArrayList listWithDupes = newImmutableLongArrayList(2L, 1L, 1L, 2L);
-    assertEquals(true, listWithDupes.contains(1L));
+    assertThat(listWithDupes).contains(1L);
   }
 
+  @Test
   public void testSize() {
-    assertEquals(0, LongArrayList.emptyList().size());
-    assertEquals(1, UNARY_LIST.size());
-    assertEquals(3, TERTIARY_LIST.size());
+    assertThat(LongArrayList.emptyList()).isEmpty();
+    assertThat(UNARY_LIST).hasSize(1);
+    assertThat(TERTIARY_LIST).hasSize(3);
 
     list.addLong(3);
     list.addLong(4);
     list.addLong(6);
     list.addLong(8);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
 
     list.remove(0);
-    assertEquals(3, list.size());
+    assertThat(list).hasSize(3);
 
     list.add(17L);
-    assertEquals(4, list.size());
+    assertThat(list).hasSize(4);
   }
 
+  @Test
   public void testSet() {
     list.addLong(2);
     list.addLong(4);
 
-    assertEquals(2L, (long) list.set(0, 3L));
-    assertEquals(3L, list.getLong(0));
+    assertThat((long) list.set(0, 3L)).isEqualTo(2L);
+    assertThat(list.getLong(0)).isEqualTo(3L);
 
-    assertEquals(4L, (long) list.set(1, 0L));
-    assertEquals(0L, list.getLong(1));
+    assertThat((long) list.set(1, 0L)).isEqualTo(4L);
+    assertThat(list.getLong(1)).isEqualTo(0L);
 
     try {
       list.set(-1, 0L);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.set(2, 0L);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testSetLong() {
     list.addLong(1);
     list.addLong(3);
 
-    assertEquals(1L, list.setLong(0, 0));
-    assertEquals(0L, list.getLong(0));
+    assertThat(list.setLong(0, 0)).isEqualTo(1L);
+    assertThat(list.getLong(0)).isEqualTo(0L);
 
-    assertEquals(3L, list.setLong(1, 0));
-    assertEquals(0L, list.getLong(1));
+    assertThat(list.setLong(1, 0)).isEqualTo(3L);
+    assertThat(list.getLong(1)).isEqualTo(0L);
 
     try {
       list.setLong(-1, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.setLong(2, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testAdd() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.add(2L));
-    assertEquals(asList(2L), list);
+    assertThat(list.add(2L)).isTrue();
+    assertThat(list).containsExactly(2L);
 
-    assertTrue(list.add(3L));
+    assertThat(list.add(3L)).isTrue();
     list.add(0, 4L);
-    assertEquals(asList(4L, 2L, 3L), list);
+    assertThat(list).containsExactly(4L, 2L, 3L).inOrder();
 
     list.add(0, 1L);
     list.add(0, 0L);
@@ -285,7 +311,7 @@
     for (int i = 0; i < 6; i++) {
       list.add(Long.valueOf(5 + i));
     }
-    assertEquals(asList(0L, 1L, 4L, 2L, 3L, 5L, 6L, 7L, 8L, 9L, 10L), list);
+    assertThat(list).containsExactly(0L, 1L, 4L, 2L, 3L, 5L, 6L, 7L, 8L, 9L, 10L).inOrder();
 
     try {
       list.add(-1, 5L);
@@ -300,90 +326,98 @@
     }
   }
 
+  @Test
   public void testAddLong() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
     list.addLong(2);
-    assertEquals(asList(2L), list);
+    assertThat(list).containsExactly(2L);
 
     list.addLong(3);
-    assertEquals(asList(2L, 3L), list);
+    assertThat(list).containsExactly(2L, 3L).inOrder();
   }
 
+  @Test
   public void testAddAll() {
-    assertEquals(0, list.size());
+    assertThat(list).isEmpty();
 
-    assertTrue(list.addAll(Collections.singleton(1L)));
-    assertEquals(1, list.size());
-    assertEquals(1L, (long) list.get(0));
-    assertEquals(1L, list.getLong(0));
+    assertThat(list.addAll(Collections.singleton(1L))).isTrue();
+    assertThat(list).hasSize(1);
+    assertThat((long) list.get(0)).isEqualTo(1L);
+    assertThat(list.getLong(0)).isEqualTo(1L);
 
-    assertTrue(list.addAll(asList(2L, 3L, 4L, 5L, 6L)));
-    assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L), list);
+    assertThat(list.addAll(asList(2L, 3L, 4L, 5L, 6L))).isTrue();
+    assertThat(list).containsExactly(1L, 2L, 3L, 4L, 5L, 6L).inOrder();
 
-    assertTrue(list.addAll(TERTIARY_LIST));
-    assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L), list);
+    assertThat(list.addAll(TERTIARY_LIST)).isTrue();
+    assertThat(list).containsExactly(1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L).inOrder();
 
-    assertFalse(list.addAll(Collections.<Long>emptyList()));
-    assertFalse(list.addAll(LongArrayList.emptyList()));
+    assertThat(list.addAll(Collections.<Long>emptyList())).isFalse();
+    assertThat(list.addAll(LongArrayList.emptyList())).isFalse();
   }
 
+  @Test
   public void testEquals() {
     LongArrayList list1 = new LongArrayList();
     LongArrayList list2 = new LongArrayList();
 
-    assertEquals(list1, list2);
+    assertThat(list1).isEqualTo(list2);
   }
 
+  @Test
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
-    assertEquals(1L, (long) list.remove(0));
-    assertEquals(asList(2L, 3L), list);
+    assertThat((long) list.remove(0)).isEqualTo(1L);
+    assertThat(list).containsExactly(2L, 3L).inOrder();
 
-    assertTrue(list.remove(Long.valueOf(3)));
-    assertEquals(asList(2L), list);
+    assertThat(list.remove(Long.valueOf(3))).isTrue();
+    assertThat(list).containsExactly(2L);
 
-    assertFalse(list.remove(Long.valueOf(3)));
-    assertEquals(asList(2L), list);
+    assertThat(list.remove(Long.valueOf(3))).isFalse();
+    assertThat(list).containsExactly(2L);
 
-    assertEquals(2L, (long) list.remove(0));
-    assertEquals(asList(), list);
+    assertThat((long) list.remove(0)).isEqualTo(2L);
+    assertThat(list).isEmpty();
 
     try {
       list.remove(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
 
     try {
       list.remove(0);
+      assertWithMessage("expected exception").fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
 
+  @Test
   public void testRemoveEnd_listAtCapacity() {
     LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addLong(3);
     toRemove.remove(0);
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
+  @Test
   public void testRemove_listAtCapacity() {
     LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(2);
     toRemove.addLong(3);
     toRemove.addLong(4);
     toRemove.remove(0);
-    assertEquals(1, toRemove.size());
-    assertEquals(4L, (long) toRemove.get(0));
+    assertThat(toRemove).hasSize(1);
+    assertThat((long) toRemove.get(0)).isEqualTo(4L);
   }
 
+  @Test
   public void testSublistRemoveEndOfCapacity() {
     LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addLong(3);
     toRemove.subList(0, 1).clear();
-    assertEquals(0, toRemove.size());
+    assertThat(toRemove).isEmpty();
   }
 
   private void assertImmutable(LongList list) {
@@ -393,147 +427,147 @@
 
     try {
       list.add(1L);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.add(0, 1L);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.<Long>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(Collections.singletonList(1L));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(new LongArrayList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.singleton(1L));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addAll(0, Collections.<Long>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.addLong(0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.clear();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.<Long>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(Collections.singleton(1L));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.removeAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(Collections.<Long>emptyList());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(Collections.singleton(1L));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.retainAll(UNARY_LIST);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.set(0, 0L);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
 
     try {
       list.setLong(0, 0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
index 4de09cd..b143dce 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import map_lite_test.MapForProto2TestProto.BizarroTestMap;
 import map_lite_test.MapForProto2TestProto.TestMap;
 import map_lite_test.MapForProto2TestProto.TestMap.MessageValue;
@@ -38,13 +41,15 @@
 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;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Unit tests for map fields. */
-public final class MapForProto2LiteTest extends TestCase {
+@RunWith(JUnit4.class)
+public final class MapForProto2LiteTest {
 
   private void setMapValues(TestMap.Builder builder) {
     builder
@@ -68,6 +73,7 @@
         .putStringToInt32Field("3", 33);
   }
 
+  @Test
   public void testSetMapValues() {
     TestMap.Builder mapBuilder = TestMap.newBuilder();
     setMapValues(mapBuilder);
@@ -86,35 +92,35 @@
   }
 
   private void assertMapValuesSet(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32FieldMap().size());
-    assertEquals(11, message.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(22, message.getInt32ToInt32FieldMap().get(2).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
+    assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
+    assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(11);
+    assertThat(message.getInt32ToInt32FieldMap().get(2).intValue()).isEqualTo(22);
+    assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
 
-    assertEquals(3, message.getInt32ToStringFieldMap().size());
-    assertEquals("11", message.getInt32ToStringFieldMap().get(1));
-    assertEquals("22", message.getInt32ToStringFieldMap().get(2));
-    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
+    assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "11");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(2, "22");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
 
-    assertEquals(3, message.getInt32ToBytesFieldMap().size());
-    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesFieldMap().get(1));
-    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesFieldMap().get(2));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
+    assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("11"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(2, TestUtil.toBytes("22"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
 
-    assertEquals(3, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(2));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.FOO);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
 
-    assertEquals(3, message.getInt32ToMessageFieldMap().size());
-    assertEquals(11, message.getInt32ToMessageFieldMap().get(1).getValue());
-    assertEquals(22, message.getInt32ToMessageFieldMap().get(2).getValue());
-    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
+    assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(11);
+    assertThat(message.getInt32ToMessageFieldMap().get(2).getValue()).isEqualTo(22);
+    assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
 
-    assertEquals(3, message.getStringToInt32FieldMap().size());
-    assertEquals(11, message.getStringToInt32FieldMap().get("1").intValue());
-    assertEquals(22, message.getStringToInt32FieldMap().get("2").intValue());
-    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
+    assertThat(message.getStringToInt32FieldMap()).hasSize(3);
+    assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(11);
+    assertThat(message.getStringToInt32FieldMap().get("2").intValue()).isEqualTo(22);
+    assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
   }
 
   private void updateMapValues(TestMap.Builder builder) {
@@ -139,6 +145,7 @@
         .putStringToInt32Field("4", 44);
   }
 
+  @Test
   public void testUpdateMapValues() {
     TestMap.Builder mapBuilder = TestMap.newBuilder();
     setMapValues(mapBuilder);
@@ -152,52 +159,53 @@
   }
 
   private void assertMapValuesUpdated(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32FieldMap().size());
-    assertEquals(111, message.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
-    assertEquals(44, message.getInt32ToInt32FieldMap().get(4).intValue());
+    assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
+    assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(111);
+    assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
+    assertThat(message.getInt32ToInt32FieldMap().get(4).intValue()).isEqualTo(44);
 
-    assertEquals(3, message.getInt32ToStringFieldMap().size());
-    assertEquals("111", message.getInt32ToStringFieldMap().get(1));
-    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
-    assertEquals("44", message.getInt32ToStringFieldMap().get(4));
+    assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "111");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(4, "44");
 
-    assertEquals(3, message.getInt32ToBytesFieldMap().size());
-    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesFieldMap().get(1));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
-    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesFieldMap().get(4));
+    assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("111"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(4, TestUtil.toBytes("44"));
 
-    assertEquals(3, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
-    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumFieldMap().get(4));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(4, TestMap.EnumValue.QUX);
 
-    assertEquals(3, message.getInt32ToMessageFieldMap().size());
-    assertEquals(111, message.getInt32ToMessageFieldMap().get(1).getValue());
-    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
-    assertEquals(44, message.getInt32ToMessageFieldMap().get(4).getValue());
+    assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(111);
+    assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
+    assertThat(message.getInt32ToMessageFieldMap().get(4).getValue()).isEqualTo(44);
 
-    assertEquals(3, message.getStringToInt32FieldMap().size());
-    assertEquals(111, message.getStringToInt32FieldMap().get("1").intValue());
-    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
-    assertEquals(44, message.getStringToInt32FieldMap().get("4").intValue());
+    assertThat(message.getStringToInt32FieldMap()).hasSize(3);
+    assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(111);
+    assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
+    assertThat(message.getStringToInt32FieldMap().get("4").intValue()).isEqualTo(44);
   }
 
   private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
-    assertEquals(0, testMapOrBuilder.getStringToInt32FieldMap().size());
-    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToStringFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getStringToInt32FieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(0);
   }
 
+  @Test
   public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
     // Since builders are implemented as a thin wrapper around a message
     // instance, we attempt to verify that we can't cause the builder to modify
@@ -206,15 +214,16 @@
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     builder.putInt32ToInt32Field(1, 2);
-    assertTrue(message.getInt32ToInt32FieldMap().isEmpty());
+    assertThat(message.getInt32ToInt32FieldMap()).isEmpty();
     message = builder.build();
-    assertEquals(newMap(1, 2), message.getInt32ToInt32FieldMap());
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32FieldMap());
+    assertThat(message.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2));
+    assertThat(builder.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2));
     builder.putInt32ToInt32Field(2, 3);
-    assertEquals(newMap(1, 2), message.getInt32ToInt32FieldMap());
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32FieldMap());
+    assertThat(message.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2));
+    assertThat(builder.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2, 2, 3));
   }
 
+  @Test
   public void testGetMapIsImmutable() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapsAreImmutable(builder);
@@ -238,57 +247,58 @@
   private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
     try {
       map.put(key, value);
-      fail();
+      assertWithMessage("Expected UnsupportedOperationException").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     if (!map.isEmpty()) {
       try {
         map.entrySet().remove(map.entrySet().iterator().next());
-        fail();
+        assertWithMessage("Expected UnsupportedOperationException").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
     }
   }
 
+  @Test
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder().putInt32ToInt32Field(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32FieldMap());
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32FieldMap());
+    assertThat(builder.build().getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2));
+    assertThat(builder.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2));
     builder.putInt32ToInt32Field(2, 3);
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32FieldMap());
+    assertThat(builder.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2, 2, 3));
 
     builder.putInt32ToEnumField(1, TestMap.EnumValue.BAR);
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumFieldMap());
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumFieldMap());
+    assertThat(builder.build().getInt32ToEnumFieldMap())
+        .isEqualTo(newMap(1, TestMap.EnumValue.BAR));
+    assertThat(builder.getInt32ToEnumFieldMap()).isEqualTo(newMap(1, TestMap.EnumValue.BAR));
     builder.putInt32ToEnumField(2, TestMap.EnumValue.FOO);
-    assertEquals(
-        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
-        builder.getInt32ToEnumFieldMap());
+    assertThat(builder.getInt32ToEnumFieldMap())
+        .isEqualTo(newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO));
 
     builder.putInt32ToStringField(1, "1");
-    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringFieldMap());
-    assertEquals(newMap(1, "1"), builder.getInt32ToStringFieldMap());
+    assertThat(builder.build().getInt32ToStringFieldMap()).isEqualTo(newMap(1, "1"));
+    assertThat(builder.getInt32ToStringFieldMap()).isEqualTo(newMap(1, "1"));
     builder.putInt32ToStringField(2, "2");
-    assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringFieldMap());
+    assertThat(builder.getInt32ToStringFieldMap()).isEqualTo(newMap(1, "1", 2, "2"));
 
     builder.putInt32ToMessageField(1, TestMap.MessageValue.getDefaultInstance());
-    assertEquals(
-        newMap(1, TestMap.MessageValue.getDefaultInstance()),
-        builder.build().getInt32ToMessageFieldMap());
-    assertEquals(
-        newMap(1, TestMap.MessageValue.getDefaultInstance()), builder.getInt32ToMessageFieldMap());
+    assertThat(builder.build().getInt32ToMessageFieldMap())
+        .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance()));
+    assertThat(builder.getInt32ToMessageFieldMap())
+        .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance()));
     builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
-    assertEquals(
-        newMap(
-            1,
-            TestMap.MessageValue.getDefaultInstance(),
-            2,
-            TestMap.MessageValue.getDefaultInstance()),
-        builder.getInt32ToMessageFieldMap());
+    assertThat(builder.getInt32ToMessageFieldMap())
+        .isEqualTo(
+            newMap(
+                1,
+                TestMap.MessageValue.getDefaultInstance(),
+                2,
+                TestMap.MessageValue.getDefaultInstance()));
   }
 
+  @Test
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
@@ -311,6 +321,7 @@
     assertMapValuesCleared(message);
   }
 
+  @Test
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
     setMapValues(sourceBuilder);
@@ -322,64 +333,66 @@
     assertMapValuesSet(destination.build());
   }
 
+  @Test
   public void testPutChecksNullKeysAndValues() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
 
     try {
       builder.putInt32ToStringField(1, null);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToBytesField(1, null);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToEnumField(1, null);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToMessageField(1, null);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putStringToInt32Field(null, 1);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();;
     } catch (NullPointerException e) {
       // expected.
     }
   }
 
+  @Test
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
     updateMapValues(builder);
     message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
 
     builder = message.toBuilder();
     builder.clear();
     message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
   }
@@ -392,39 +405,41 @@
     return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
   }
 
+  @Test
   public void testParseError() throws Exception {
     ByteString bytes = TestUtil.toBytes("SOME BYTES");
     String stringKey = "a string key";
 
     TestMap map =
         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build());
-    assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
+    assertThat(map.getInt32ToInt32FieldOrDefault(5, -1)).isEqualTo(0);
 
     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build());
-    assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
+    assertThat(map.getInt32ToStringFieldOrDefault(0, null)).isEmpty();
 
     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build());
-    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+    assertThat(ByteString.EMPTY).isEqualTo(map.getInt32ToBytesFieldOrDefault(0, null));
 
     map =
         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build());
-    assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
+    assertThat(map.getInt32ToEnumFieldOrDefault(0, null)).isEqualTo(TestMap.EnumValue.FOO);
 
     try {
       tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build());
-      fail();
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
     } catch (InvalidProtocolBufferException expected) {
-      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      assertThat(expected.getUnfinishedMessage()).isInstanceOf(TestMap.class);
       map = (TestMap) expected.getUnfinishedMessage();
-      assertTrue(map.getInt32ToMessageFieldMap().isEmpty());
+      assertThat(map.getInt32ToMessageFieldMap()).isEmpty();
     }
 
     map =
         tryParseTestMap(
             BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build());
-    assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
+    assertThat(map.getStringToInt32FieldOrDefault(stringKey, -1)).isEqualTo(0);
   }
 
+  @Test
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
@@ -435,6 +450,7 @@
     assertMapValuesSet(other.build());
   }
 
+  @Test
   public void testEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
@@ -455,17 +471,18 @@
             .putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
 
-    assertEquals(m1, m2);
-    assertEquals(m1.hashCode(), m2.hashCode());
+    assertThat(m2).isEqualTo(m1);
+    assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
 
     // Make sure we did compare map fields.
     b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
-    assertFalse(m1.equals(m2));
+    assertThat(m1.equals(m2)).isFalse();
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
   }
 
+  @Test
   public void testUnknownEnumValues() throws Exception {
     ByteString data =
         TestUnknownEnumValue.newBuilder()
@@ -474,27 +491,30 @@
             .build()
             .toByteString();
 
-    TestMap message = TestMap.parseFrom(data);
+    TestMap message = TestMap.parseFrom(data, ExtensionRegistryLite.getEmptyRegistry());
     // Entries with unknown enum values will be stored into UnknownFieldSet so
     // there is only one entry in the map.
-    assertEquals(1, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(1);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
     // Serializing and parsing should preserve the unknown entry.
     data = message.toByteString();
-    TestUnknownEnumValue messageWithUnknownEnums = TestUnknownEnumValue.parseFrom(data);
-    assertEquals(2, messageWithUnknownEnums.getInt32ToInt32FieldMap().size());
-    assertEquals(1, messageWithUnknownEnums.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32FieldMap().get(2).intValue());
+    TestUnknownEnumValue messageWithUnknownEnums =
+        TestUnknownEnumValue.parseFrom(data, ExtensionRegistryLite.getEmptyRegistry());
+    assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap()).hasSize(2);
+    assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(1);
+    assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap().get(2).intValue())
+        .isEqualTo(54321);
   }
 
+  @Test
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
 
-    assertEquals(
-        Arrays.asList("1", "2", "3"),
-        new ArrayList<String>(message.getStringToInt32FieldMap().keySet()));
+    assertThat(new ArrayList<String>(message.getStringToInt32FieldMap().keySet()))
+        .containsExactly("1", "2", "3")
+        .inOrder();
   }
 
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
@@ -510,16 +530,18 @@
     return map;
   }
 
+  @Test
   public void testGetMap() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
-    assertEquals(message.getStringToInt32FieldMap(), message.getStringToInt32FieldMap());
-    assertEquals(message.getInt32ToBytesFieldMap(), message.getInt32ToBytesFieldMap());
-    assertEquals(message.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
-    assertEquals(message.getInt32ToMessageFieldMap(), message.getInt32ToMessageFieldMap());
+    assertThat(message.getStringToInt32FieldMap()).isEqualTo(message.getStringToInt32FieldMap());
+    assertThat(message.getInt32ToBytesFieldMap()).isEqualTo(message.getInt32ToBytesFieldMap());
+    assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message.getInt32ToEnumFieldMap());
+    assertThat(message.getInt32ToMessageFieldMap()).isEqualTo(message.getInt32ToMessageFieldMap());
   }
 
+  @Test
   public void testContains() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
@@ -528,37 +550,38 @@
   }
 
   private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
-    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToStringField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
-    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+    assertThat(testMapOrBuilder.containsStringToInt32Field("1")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("2")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("3")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("-1")).isFalse();
   }
 
+  @Test
   public void testCount() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -570,23 +593,24 @@
     assertMapCounts(3, message);
 
     builder = message.toBuilder().putInt32ToInt32Field(4, 44);
-    assertEquals(4, builder.getInt32ToInt32FieldCount());
-    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+    assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
+    assertThat(builder.build().getInt32ToInt32FieldCount()).isEqualTo(4);
 
     // already present - should be unchanged
     builder.putInt32ToInt32Field(4, 44);
-    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
   }
 
   private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToInt32FieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToStringFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToBytesFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToEnumFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToMessageFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getStringToInt32FieldCount());
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(expectedCount);
   }
 
+  @Test
   public void testGetOrDefault() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -596,34 +620,38 @@
   }
 
   public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
-    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)).isEqualTo(11);
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)).isEqualTo(-11);
 
-    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
-    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")).isEqualTo("11");
+    assertWithMessage("-11")
+        .that(testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null))
+        .isNull();
 
-    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null))
+        .isEqualTo(TestUtil.toBytes("11"));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null))
+        .isEqualTo(TestMap.EnumValue.FOO);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(
-        MessageValue.newBuilder().setValue(11).build(),
-        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null))
+        .isEqualTo(MessageValue.newBuilder().setValue(11).build());
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
-    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)).isEqualTo(11);
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)).isEqualTo(-11);
 
     try {
       testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
+  @Test
   public void testGetOrThrow() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -633,100 +661,100 @@
   }
 
   public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
     try {
       testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
-      fail();
+      assertWithMessage("Expected IllegalArgumentException").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
 
     try {
       testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
-      fail();
+      assertWithMessage("Expected IllegalArgumentException").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
 
     try {
       testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
-      fail();
+      assertWithMessage("Expected IllegalArgumentException").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     try {
       testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
-      fail();
+      assertWithMessage("Expected IllegalArgumentException").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(
-        MessageValue.newBuilder().setValue(11).build(),
-        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrThrow(1))
+        .isEqualTo(MessageValue.newBuilder().setValue(11).build());
     try {
       testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
-      fail();
+      assertWithMessage("Expected IllegalArgumentException").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
     try {
       testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
-      fail();
+      assertWithMessage("Expected IllegalArgumentException").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
     try {
       testMapOrBuilder.getStringToInt32FieldOrThrow(null);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
+  @Test
   public void testPut() {
     TestMap.Builder builder = TestMap.newBuilder();
     builder.putInt32ToInt32Field(1, 11);
-    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
 
     builder.putInt32ToStringField(1, "a");
-    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("a");
     try {
       builder.putInt32ToStringField(1, null);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
-    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
     try {
       builder.putInt32ToBytesField(1, null);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
-    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     try {
       builder.putInt32ToEnumField(1, null);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putStringToInt32Field("a", 1);
-    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    assertThat(builder.getStringToInt32FieldOrThrow("a")).isEqualTo(1);
     try {
       builder.putStringToInt32Field(null, -1);
     } catch (NullPointerException e) {
@@ -734,42 +762,43 @@
     }
   }
 
+  @Test
   public void testRemove() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
-    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToInt32Field(1);
-      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+      assertThat(builder.getInt32ToInt32FieldOrDefault(1, -1)).isEqualTo(-1);
     }
 
-    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToStringField(1);
-      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToStringFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToBytesField(1);
-      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToBytesFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToEnumField(1);
-      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToEnumFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    assertThat(builder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
     for (int times = 0; times < 2; times++) {
       builder.removeStringToInt32Field("1");
-      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+      assertThat(builder.getStringToInt32FieldOrDefault("1", -1)).isEqualTo(-1);
     }
 
     try {
       builder.removeStringToInt32Field(null);
-      fail();
+      assertWithMessage("Expected NullPointerException").fail();
     } catch (NullPointerException e) {
       // expected
     }
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
index 25c5625..821b93c 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import map_test.MapForProto2TestProto.BizarroTestMap;
 import map_test.MapForProto2TestProto.ReservedAsMapField;
@@ -40,17 +43,21 @@
 import map_test.MapForProto2TestProto.TestMapOrBuilder;
 import map_test.MapForProto2TestProto.TestRecursiveMap;
 import map_test.MapForProto2TestProto.TestUnknownEnumValue;
+import map_test.Message1;
+import map_test.RedactAllTypes;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Unit tests for map fields in proto2 protos. */
-public class MapForProto2Test extends TestCase {
+@RunWith(JUnit4.class)
+public class MapForProto2Test {
 
   private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 11);
@@ -103,6 +110,7 @@
         .putStringToInt32Field("3", 33);
   }
 
+  @Test
   public void testSetMapValues() {
     TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
     setMapValuesUsingMutableMap(usingMutableMapBuilder);
@@ -114,7 +122,7 @@
     TestMap usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesSet(usingAccessors);
 
-    assertEquals(usingAccessors, usingMutableMap);
+    assertThat(usingAccessors).isEqualTo(usingMutableMap);
   }
 
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
@@ -128,35 +136,35 @@
   }
 
   private void assertMapValuesSet(TestMapOrBuilder message) {
-    assertEquals(3, message.getInt32ToInt32FieldMap().size());
-    assertEquals(11, message.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(22, message.getInt32ToInt32FieldMap().get(2).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
+    assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
+    assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(11);
+    assertThat(message.getInt32ToInt32FieldMap().get(2).intValue()).isEqualTo(22);
+    assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
 
-    assertEquals(3, message.getInt32ToStringFieldMap().size());
-    assertEquals("11", message.getInt32ToStringFieldMap().get(1));
-    assertEquals("22", message.getInt32ToStringFieldMap().get(2));
-    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
+    assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "11");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(2, "22");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
 
-    assertEquals(3, message.getInt32ToBytesFieldMap().size());
-    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesFieldMap().get(1));
-    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesFieldMap().get(2));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
+    assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("11"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(2, TestUtil.toBytes("22"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
 
-    assertEquals(3, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(2));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.FOO);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
 
-    assertEquals(3, message.getInt32ToMessageFieldMap().size());
-    assertEquals(11, message.getInt32ToMessageFieldMap().get(1).getValue());
-    assertEquals(22, message.getInt32ToMessageFieldMap().get(2).getValue());
-    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
+    assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(11);
+    assertThat(message.getInt32ToMessageFieldMap().get(2).getValue()).isEqualTo(22);
+    assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
 
-    assertEquals(3, message.getStringToInt32FieldMap().size());
-    assertEquals(11, message.getStringToInt32FieldMap().get("1").intValue());
-    assertEquals(22, message.getStringToInt32FieldMap().get("2").intValue());
-    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
+    assertThat(message.getStringToInt32FieldMap()).hasSize(3);
+    assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(11);
+    assertThat(message.getStringToInt32FieldMap().get("2").intValue()).isEqualTo(22);
+    assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
   }
 
   private void updateMapValuesUsingMutableMap(TestMap.Builder builder) {
@@ -209,6 +217,7 @@
         .putStringToInt32Field("4", 44);
   }
 
+  @Test
   public void testUpdateMapValues() {
     TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
     setMapValuesUsingMutableMap(usingMutableMapBuilder);
@@ -220,7 +229,7 @@
     TestMap usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesSet(usingAccessors);
 
-    assertEquals(usingAccessors, usingMutableMap);
+    assertThat(usingAccessors).isEqualTo(usingMutableMap);
     //
     usingMutableMapBuilder = usingMutableMap.toBuilder();
     updateMapValuesUsingMutableMap(usingMutableMapBuilder);
@@ -232,56 +241,57 @@
     usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesUpdated(usingAccessors);
 
-    assertEquals(usingAccessors, usingMutableMap);
+    assertThat(usingAccessors).isEqualTo(usingMutableMap);
   }
 
   private void assertMapValuesUpdated(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32FieldMap().size());
-    assertEquals(111, message.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
-    assertEquals(44, message.getInt32ToInt32FieldMap().get(4).intValue());
+    assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
+    assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(111);
+    assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
+    assertThat(message.getInt32ToInt32FieldMap().get(4).intValue()).isEqualTo(44);
 
-    assertEquals(3, message.getInt32ToStringFieldMap().size());
-    assertEquals("111", message.getInt32ToStringFieldMap().get(1));
-    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
-    assertEquals("44", message.getInt32ToStringFieldMap().get(4));
+    assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "111");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(4, "44");
 
-    assertEquals(3, message.getInt32ToBytesFieldMap().size());
-    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesFieldMap().get(1));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
-    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesFieldMap().get(4));
+    assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("111"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(4, TestUtil.toBytes("44"));
 
-    assertEquals(3, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
-    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumFieldMap().get(4));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(4, TestMap.EnumValue.QUX);
 
-    assertEquals(3, message.getInt32ToMessageFieldMap().size());
-    assertEquals(111, message.getInt32ToMessageFieldMap().get(1).getValue());
-    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
-    assertEquals(44, message.getInt32ToMessageFieldMap().get(4).getValue());
+    assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(111);
+    assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
+    assertThat(message.getInt32ToMessageFieldMap().get(4).getValue()).isEqualTo(44);
 
-    assertEquals(3, message.getStringToInt32FieldMap().size());
-    assertEquals(111, message.getStringToInt32FieldMap().get("1").intValue());
-    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
-    assertEquals(44, message.getStringToInt32FieldMap().get("4").intValue());
+    assertThat(message.getStringToInt32FieldMap()).hasSize(3);
+    assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(111);
+    assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
+    assertThat(message.getStringToInt32FieldMap().get("4").intValue()).isEqualTo(44);
   }
 
   private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
-    assertEquals(0, testMapOrBuilder.getStringToInt32FieldMap().size());
-    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToStringFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getStringToInt32FieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(0);
   }
 
+  @Test
   public void testGetMapIsImmutable() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapsAreImmutable(builder);
@@ -305,120 +315,119 @@
   private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
     try {
       map.put(key, value);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
   }
 
+  @Test
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
     intMap.put(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
     try {
       intMap.put(2, 3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
     builder.getMutableInt32ToInt32Field().put(2, 3);
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+    assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2, 2, 3));
   //
     Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
     enumMap.put(1, TestMap.EnumValue.BAR);
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
+    assertThat(builder.build().getInt32ToEnumField())
+        .isEqualTo(newMap(1, TestMap.EnumValue.BAR));
     try {
       enumMap.put(2, TestMap.EnumValue.FOO);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    assertThat(builder.getInt32ToEnumField()).isEqualTo(newMap(1, TestMap.EnumValue.BAR));
     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
-    assertEquals(
-        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
-        builder.getInt32ToEnumField());
+    assertThat(builder.getInt32ToEnumField())
+            .isEqualTo(newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO));
   //
     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
     stringMap.put(1, "1");
-    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
+    assertThat(builder.build().getInt32ToStringField()).isEqualTo(newMap(1, "1"));
     try {
       stringMap.put(2, "2");
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    assertThat(builder.getInt32ToStringField()).isEqualTo(newMap(1, "1"));
     builder.getMutableInt32ToStringField().put(2, "2");
-    assertEquals(
-        newMap(1, "1", 2, "2"),
-        builder.getInt32ToStringField());
+    assertThat(builder.getInt32ToStringField()).isEqualTo(newMap(1, "1", 2, "2"));
   //
     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
-    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
-        builder.build().getInt32ToMessageField());
+    assertThat(builder.build().getInt32ToMessageField())
+        .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance()));
     try {
       messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
-        builder.getInt32ToMessageField());
+    assertThat(builder.getInt32ToMessageField())
+        .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance()));
     builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
-    assertEquals(
+    assertThat(builder.getInt32ToMessageField()).isEqualTo(
         newMap(1, TestMap.MessageValue.getDefaultInstance(),
-            2, TestMap.MessageValue.getDefaultInstance()),
-        builder.getInt32ToMessageField());
+            2, TestMap.MessageValue.getDefaultInstance()));
   }
   //
+  @Test
   public void testMutableMapLifecycle_collections() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
     intMap.put(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
     try {
       intMap.remove(2);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.entrySet().remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.entrySet().iterator().remove();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.keySet().remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.values().remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.values().iterator().remove();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, 2), intMap);
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    assertThat(intMap).isEqualTo(newMap(1, 2));
+    assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
+    assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
   }
   //
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
@@ -434,6 +443,7 @@
     return map;
   }
 
+  @Test
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
@@ -456,6 +466,7 @@
     assertMapValuesCleared(message);
   }
 
+  @Test
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
     setMapValuesUsingAccessors(sourceBuilder);
@@ -466,67 +477,69 @@
     copyMapValues(source, destination);
     assertMapValuesSet(destination.build());
 
-    assertEquals(3, destination.getInt32ToEnumFieldCount());
+    assertThat(destination.getInt32ToEnumFieldCount()).isEqualTo(3);
   }
 
+  @Test
   public void testPutChecksNullKeysAndValues() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
 
     try {
       builder.putInt32ToStringField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToBytesField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToEnumField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToMessageField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putStringToInt32Field(null, 1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
   }
 
+  @Test
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
     updateMapValuesUsingAccessors(builder);
     message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
 
     builder = message.toBuilder();
     builder.clear();
     message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
   }
@@ -539,39 +552,41 @@
     return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
   }
 
+  @Test
   public void testParseError() throws Exception {
     ByteString bytes = TestUtil.toBytes("SOME BYTES");
     String stringKey = "a string key";
 
     TestMap map =
         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build());
-    assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
+    assertThat(map.getInt32ToInt32FieldOrDefault(5, -1)).isEqualTo(0);
 
     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build());
-    assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
+    assertThat(map.getInt32ToStringFieldOrDefault(0, null)).isEmpty();
 
     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build());
-    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+    assertThat(ByteString.EMPTY).isEqualTo(map.getInt32ToBytesFieldOrDefault(0, null));
 
     map =
         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build());
-    assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
+    assertThat(map.getInt32ToEnumFieldOrDefault(0, null)).isEqualTo(TestMap.EnumValue.FOO);
 
     try {
       tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
-      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      assertThat(expected.getUnfinishedMessage()).isInstanceOf(TestMap.class);
       map = (TestMap) expected.getUnfinishedMessage();
-      assertTrue(map.getInt32ToMessageFieldMap().isEmpty());
+      assertThat(map.getInt32ToMessageFieldMap()).isEmpty();
     }
 
     map =
         tryParseTestMap(
             BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build());
-    assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
+    assertThat(map.getStringToInt32FieldOrDefault(stringKey, -1)).isEqualTo(0);
   }
 
+  @Test
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
@@ -582,6 +597,7 @@
     assertMapValuesSet(other.build());
   }
 
+  @Test
   public void testEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
@@ -600,13 +616,13 @@
     b2.putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
 
-    assertEquals(m1, m2);
-    assertEquals(m1.hashCode(), m2.hashCode());
+    assertThat(m2).isEqualTo(m1);
+    assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
 
     // Make sure we did compare map fields.
     b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
-    assertFalse(m1.equals(m2));
+    assertThat(m1.equals(m2)).isFalse();
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
   }
@@ -636,16 +652,16 @@
       Message mapEntry = (Message) entry;
       Object key = getFieldValue(mapEntry, "key");
       Object value = getFieldValue(mapEntry, "value");
-      assertTrue(values.containsKey(key));
-      assertEquals(value, values.get(key));
+      assertThat(values.containsKey(key)).isTrue();
+      assertThat(values.get(key)).isEqualTo(value);
     }
-    assertEquals(values.size(), message.getRepeatedFieldCount(field));
+    assertThat(message.getRepeatedFieldCount(field)).isEqualTo(values.size());
     for (int i = 0; i < message.getRepeatedFieldCount(field); i++) {
       Message mapEntry = (Message) message.getRepeatedField(field, i);
       Object key = getFieldValue(mapEntry, "key");
       Object value = getFieldValue(mapEntry, "value");
-      assertTrue(values.containsKey(key));
-      assertEquals(value, values.get(key));
+      assertThat(values.containsKey(key)).isTrue();
+      assertThat(values.get(key)).isEqualTo(value);
     }
   }
 
@@ -660,7 +676,7 @@
   }
 
   private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
-    List<Message> entryList = new ArrayList<Message>();
+    List<Message> entryList = new ArrayList<>();
     for (Map.Entry<?, ?> entry : values.entrySet()) {
       entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue()));
     }
@@ -669,12 +685,13 @@
   }
 
   private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) {
-    Map<K, V> map = new HashMap<K, V>();
+    Map<K, V> map = new HashMap<>();
     map.put(key1, value1);
     map.put(key2, value2);
     return map;
   }
 
+  @Test
   public void testReflectionApi() throws Exception {
     // In reflection API, map fields are just repeated message fields.
     TestMap.Builder builder =
@@ -698,8 +715,8 @@
     builder.clearField(f("int32_to_int32_field"));
     builder.clearField(f("int32_to_message_field"));
     message = builder.build();
-    assertEquals(0, message.getInt32ToInt32FieldMap().size());
-    assertEquals(0, message.getInt32ToMessageFieldMap().size());
+    assertThat(message.getInt32ToInt32FieldMap()).isEmpty();
+    assertThat(message.getInt32ToMessageFieldMap()).isEmpty();
 
     // Test setField()
     setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44));
@@ -710,10 +727,10 @@
             111, MessageValue.newBuilder().setValue(222).build(),
             333, MessageValue.newBuilder().setValue(444).build()));
     message = builder.build();
-    assertEquals(22, message.getInt32ToInt32FieldMap().get(11).intValue());
-    assertEquals(44, message.getInt32ToInt32FieldMap().get(33).intValue());
-    assertEquals(222, message.getInt32ToMessageFieldMap().get(111).getValue());
-    assertEquals(444, message.getInt32ToMessageFieldMap().get(333).getValue());
+    assertThat(message.getInt32ToInt32FieldMap().get(11).intValue()).isEqualTo(22);
+    assertThat(message.getInt32ToInt32FieldMap().get(33).intValue()).isEqualTo(44);
+    assertThat(message.getInt32ToMessageFieldMap().get(111).getValue()).isEqualTo(222);
+    assertThat(message.getInt32ToMessageFieldMap().get(333).getValue()).isEqualTo(444);
 
     // Test addRepeatedField
     builder.addRepeatedField(
@@ -726,8 +743,8 @@
             555,
             MessageValue.newBuilder().setValue(666).build()));
     message = builder.build();
-    assertEquals(66, message.getInt32ToInt32FieldMap().get(55).intValue());
-    assertEquals(666, message.getInt32ToMessageFieldMap().get(555).getValue());
+    assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(66);
+    assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(666);
 
     // Test addRepeatedField (overriding existing values)
     builder.addRepeatedField(
@@ -740,8 +757,8 @@
             555,
             MessageValue.newBuilder().setValue(555).build()));
     message = builder.build();
-    assertEquals(55, message.getInt32ToInt32FieldMap().get(55).intValue());
-    assertEquals(555, message.getInt32ToMessageFieldMap().get(555).getValue());
+    assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55);
+    assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(555);
 
     // Test setRepeatedField
     for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
@@ -755,12 +772,13 @@
       builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build());
     }
     message = builder.build();
-    assertEquals(11, message.getInt32ToInt32FieldMap().get(22).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(44).intValue());
-    assertEquals(55, message.getInt32ToInt32FieldMap().get(55).intValue());
+    assertThat(message.getInt32ToInt32FieldMap().get(22).intValue()).isEqualTo(11);
+    assertThat(message.getInt32ToInt32FieldMap().get(44).intValue()).isEqualTo(33);
+    assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55);
   }
 
   // See additional coverage in TextFormatTest.java.
+  @Test
   public void testTextFormat() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
@@ -775,6 +793,7 @@
     assertMapValuesSet(message);
   }
 
+  @Test
   public void testDynamicMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
@@ -782,14 +801,18 @@
 
     Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
     Message dynamicMessage =
-        dynamicDefaultInstance.newBuilderForType().mergeFrom(message.toByteString()).build();
+        dynamicDefaultInstance
+            .newBuilderForType()
+            .mergeFrom(message.toByteString(), ExtensionRegistry.getEmptyRegistry())
+            .build();
 
-    assertEquals(message, dynamicMessage);
-    assertEquals(message.hashCode(), dynamicMessage.hashCode());
+    assertThat(dynamicMessage).isEqualTo(message);
+    assertThat(dynamicMessage.hashCode()).isEqualTo(message.hashCode());
   }
 
   // Check that DynamicMessage handles map field serialization the same way as generated code
   // regarding unset key and value field in a map entry.
+  @Test
   public void testDynamicMessageUnsetKeyAndValue() throws Exception {
     FieldDescriptor field = f("int32_to_int32_field");
 
@@ -800,11 +823,12 @@
     Message message = builder.build();
     ByteString bytes = message.toByteString();
     // Parse it back to the same generated type.
-    Message generatedMessage = TestMap.parseFrom(bytes);
+    Message generatedMessage = TestMap.parseFrom(bytes, ExtensionRegistry.getEmptyRegistry());
     // Assert the serialized bytes are equivalent.
-    assertEquals(generatedMessage.toByteString(), bytes);
+    assertThat(bytes).isEqualTo(generatedMessage.toByteString());
   }
 
+  @Test
   public void testReflectionEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
@@ -825,69 +849,80 @@
     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4));
     Message m2 = b2.build();
 
-    assertEquals(m1, m2);
-    assertEquals(m1.hashCode(), m2.hashCode());
+    assertThat(m2).isEqualTo(m1);
+    assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
 
     // Make sure we did compare map fields.
     b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0));
     m2 = b2.build();
-    assertFalse(m1.equals(m2));
+    assertThat(m1.equals(m2)).isFalse();
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
   }
 
+  @Test
   public void testUnknownEnumValues() throws Exception {
-    TestUnknownEnumValue.Builder builder =
-        TestUnknownEnumValue.newBuilder().putInt32ToInt32Field(1, 1).putInt32ToInt32Field(2, 54321);
-    ByteString data = builder.build().toByteString();
+    TestUnknownEnumValue builder =
+        TestUnknownEnumValue.newBuilder()
+            .putInt32ToInt32Field(1, 1)
+            .putInt32ToInt32Field(2, 54321)
+            .build();
+    ByteString data = builder.toByteString();
 
-    TestMap message = TestMap.parseFrom(data);
+    TestMap message = TestMap.parseFrom(data, ExtensionRegistry.getEmptyRegistry());
     // Entries with unknown enum values will be stored into UnknownFieldSet so
     // there is only one entry in the map.
-    assertEquals(1, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(1);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
     // UnknownFieldSet should not be empty.
-    assertFalse(message.getUnknownFields().asMap().isEmpty());
+    assertThat(message.getUnknownFields().asMap()).isNotEmpty();
     // Serializing and parsing should preserve the unknown entry.
     data = message.toByteString();
-    TestUnknownEnumValue messageWithUnknownEnums = TestUnknownEnumValue.parseFrom(data);
-    assertEquals(2, messageWithUnknownEnums.getInt32ToInt32FieldMap().size());
-    assertEquals(1, messageWithUnknownEnums.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32FieldMap().get(2).intValue());
+    TestUnknownEnumValue messageWithUnknownEnums =
+        TestUnknownEnumValue.parseFrom(data, ExtensionRegistry.getEmptyRegistry());
+    assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap()).hasSize(2);
+    assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(1);
+    assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap().get(2).intValue())
+        .isEqualTo(54321);
   }
 
+  @Test
   public void testRequiredMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().buildPartial());
     TestMap message = builder.buildPartial();
-    assertFalse(message.isInitialized());
+    assertThat(message.isInitialized()).isFalse();
 
     builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().setValue(1).build());
     message = builder.build();
-    assertTrue(message.isInitialized());
+    assertThat(message.isInitialized()).isTrue();
   }
 
+  @Test
   public void testRecursiveMap() throws Exception {
     TestRecursiveMap.Builder builder = TestRecursiveMap.newBuilder();
     builder.putRecursiveMapField(1, TestRecursiveMap.newBuilder().setValue(2).build());
     builder.putRecursiveMapField(3, TestRecursiveMap.newBuilder().setValue(4).build());
     ByteString data = builder.build().toByteString();
 
-    TestRecursiveMap message = TestRecursiveMap.parseFrom(data);
-    assertEquals(2, message.getRecursiveMapFieldMap().get(1).getValue());
-    assertEquals(4, message.getRecursiveMapFieldMap().get(3).getValue());
+    TestRecursiveMap message =
+        TestRecursiveMap.parseFrom(data, ExtensionRegistry.getEmptyRegistry());
+    assertThat(message.getRecursiveMapFieldMap().get(1).getValue()).isEqualTo(2);
+    assertThat(message.getRecursiveMapFieldMap().get(3).getValue()).isEqualTo(4);
   }
 
+  @Test
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
-    assertEquals(
-        Arrays.asList("1", "2", "3"),
-        new ArrayList<String>(message.getStringToInt32FieldMap().keySet()));
+    assertThat(new ArrayList<String>(message.getStringToInt32FieldMap().keySet()))
+        .containsExactly("1", "2", "3")
+        .inOrder();
   }
 
+  @Test
   public void testContains() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
@@ -896,37 +931,38 @@
   }
 
   private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
-    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToStringField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
-    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+    assertThat(testMapOrBuilder.containsStringToInt32Field("1")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("2")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("3")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("-1")).isFalse();
   }
 
+  @Test
   public void testCount() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -938,23 +974,24 @@
     assertMapCounts(3, message);
 
     builder = message.toBuilder().putInt32ToInt32Field(4, 44);
-    assertEquals(4, builder.getInt32ToInt32FieldCount());
-    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+    assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
+    assertThat(builder.build().getInt32ToInt32FieldCount()).isEqualTo(4);
 
     // already present - should be unchanged
     builder.putInt32ToInt32Field(4, 44);
-    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
   }
 
   private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToInt32FieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToStringFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToBytesFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToEnumFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToMessageFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getStringToInt32FieldCount());
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(expectedCount);
   }
 
+  @Test
   public void testGetOrDefault() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -964,34 +1001,38 @@
   }
 
   public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
-    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)).isEqualTo(11);
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)).isEqualTo(-11);
 
-    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
-    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")).isEqualTo("11");
+    assertWithMessage("-11")
+        .that(testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null))
+        .isNull();
 
-    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null))
+        .isEqualTo(TestUtil.toBytes("11"));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null))
+        .isEqualTo(TestMap.EnumValue.FOO);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(
-        MessageValue.newBuilder().setValue(11).build(),
-        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null))
+        .isEqualTo(MessageValue.newBuilder().setValue(11).build());
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
-    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)).isEqualTo(11);
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)).isEqualTo(-11);
 
     try {
       testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
+  @Test
   public void testGetOrThrow() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -1001,100 +1042,100 @@
   }
 
   public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
     try {
       testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
 
     try {
       testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
 
     try {
       testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     try {
       testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(
-        MessageValue.newBuilder().setValue(11).build(),
-        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrThrow(1))
+        .isEqualTo(MessageValue.newBuilder().setValue(11).build());
     try {
       testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
     try {
       testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
     try {
       testMapOrBuilder.getStringToInt32FieldOrThrow(null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
+  @Test
   public void testPut() {
     TestMap.Builder builder = TestMap.newBuilder();
     builder.putInt32ToInt32Field(1, 11);
-    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
 
     builder.putInt32ToStringField(1, "a");
-    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("a");
     try {
       builder.putInt32ToStringField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
-    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
     try {
       builder.putInt32ToBytesField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
-    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     try {
       builder.putInt32ToEnumField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putStringToInt32Field("a", 1);
-    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    assertThat(builder.getStringToInt32FieldOrThrow("a")).isEqualTo(1);
     try {
       builder.putStringToInt32Field(null, -1);
     } catch (NullPointerException e) {
@@ -1102,79 +1143,79 @@
     }
   }
 
+  @Test
   public void testRemove() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
-    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToInt32Field(1);
-      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+      assertThat(builder.getInt32ToInt32FieldOrDefault(1, -1)).isEqualTo(-1);
     }
 
-    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToStringField(1);
-      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToStringFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToBytesField(1);
-      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToBytesFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToEnumField(1);
-      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToEnumFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    assertThat(builder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
     for (int times = 0; times < 2; times++) {
       builder.removeStringToInt32Field("1");
-      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+      assertThat(builder.getStringToInt32FieldOrDefault("1", -1)).isEqualTo(-1);
     }
 
     try {
       builder.removeStringToInt32Field(null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
   // Regression test for b/20494788
+  @Test
   public void testMapInitializationOrder() throws Exception {
-    assertEquals(
-        "RedactAllTypes",
-        map_test.RedactAllTypes.getDefaultInstance()
-            .getDescriptorForType()
-            .getName());
+    assertThat(RedactAllTypes.getDefaultInstance().getDescriptorForType().getName())
+        .isEqualTo("RedactAllTypes");
 
-    map_test.Message1.Builder builder =
-        map_test.Message1.newBuilder();
+    Message1.Builder builder = Message1.newBuilder();
     builder.putMapField("key", true);
-    map_test.Message1 message = builder.build();
+    Message1 message = builder.build();
     Message mapEntry =
         (Message)
             message.getRepeatedField(
                 message.getDescriptorForType().findFieldByName("map_field"), 0);
-    assertEquals(2, mapEntry.getAllFields().size());
+    assertThat(mapEntry.getAllFields()).hasSize(2);
   }
 
+  @Test
   public void testReservedWordsFieldNames() {
-    ReservedAsMapField unused1 = ReservedAsMapField.newBuilder().build();
-    ReservedAsMapFieldWithEnumValue unused2 = ReservedAsMapFieldWithEnumValue.newBuilder().build();
+    ReservedAsMapField unused1 = ReservedAsMapField.getDefaultInstance();
+    ReservedAsMapFieldWithEnumValue unused2 = ReservedAsMapFieldWithEnumValue.getDefaultInstance();
   }
 
+  @Test
   public void testGetMap() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
     assertMapValuesSet(builder);
     TestMap message = builder.build();
-    assertEquals(message.getStringToInt32FieldMap(), message.getStringToInt32FieldMap());
-    assertEquals(message.getInt32ToBytesFieldMap(), message.getInt32ToBytesFieldMap());
-    assertEquals(message.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
-    assertEquals(message.getInt32ToMessageFieldMap(), message.getInt32ToMessageFieldMap());
+    assertThat(message.getStringToInt32FieldMap()).isEqualTo(message.getStringToInt32FieldMap());
+    assertThat(message.getInt32ToBytesFieldMap()).isEqualTo(message.getInt32ToBytesFieldMap());
+    assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message.getInt32ToEnumFieldMap());
+    assertThat(message.getInt32ToMessageFieldMap()).isEqualTo(message.getInt32ToMessageFieldMap());
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/MapLiteTest.java b/java/core/src/test/java/com/google/protobuf/MapLiteTest.java
index 33282ad..5f39893 100644
--- a/java/core/src/test/java/com/google/protobuf/MapLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapLiteTest.java
@@ -30,7 +30,8 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertArrayEquals;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import map_lite_test.MapTestProto.BizarroTestMap;
 import map_lite_test.MapTestProto.TestMap;
@@ -39,13 +40,15 @@
 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;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Unit tests for map fields. */
-public final class MapLiteTest extends TestCase {
+@RunWith(JUnit4.class)
+public final class MapLiteTest {
 
   private void setMapValues(TestMap.Builder builder) {
     builder
@@ -69,6 +72,7 @@
         .putStringToInt32Field("3", 33);
   }
 
+  @Test
   public void testSetMapValues() {
     TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
     setMapValues(usingMutableMapBuilder);
@@ -79,7 +83,7 @@
     setMapValues(usingAccessorsBuilder);
     TestMap usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesSet(usingAccessors);
-    assertEquals(usingAccessors, usingMutableMap);
+    assertThat(usingMutableMap).isEqualTo(usingAccessors);
   }
 
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
@@ -93,35 +97,35 @@
   }
 
   private void assertMapValuesSet(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32FieldMap().size());
-    assertEquals(11, message.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(22, message.getInt32ToInt32FieldMap().get(2).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
+    assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
+    assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(11);
+    assertThat(message.getInt32ToInt32FieldMap().get(2).intValue()).isEqualTo(22);
+    assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
 
-    assertEquals(3, message.getInt32ToStringFieldMap().size());
-    assertEquals("11", message.getInt32ToStringFieldMap().get(1));
-    assertEquals("22", message.getInt32ToStringFieldMap().get(2));
-    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
+    assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "11");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(2, "22");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
 
-    assertEquals(3, message.getInt32ToBytesFieldMap().size());
-    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesFieldMap().get(1));
-    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesFieldMap().get(2));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
+    assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("11"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(2, TestUtil.toBytes("22"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
 
-    assertEquals(3, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(2));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.FOO);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
 
-    assertEquals(3, message.getInt32ToMessageFieldMap().size());
-    assertEquals(11, message.getInt32ToMessageFieldMap().get(1).getValue());
-    assertEquals(22, message.getInt32ToMessageFieldMap().get(2).getValue());
-    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
+    assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(11);
+    assertThat(message.getInt32ToMessageFieldMap().get(2).getValue()).isEqualTo(22);
+    assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
 
-    assertEquals(3, message.getStringToInt32FieldMap().size());
-    assertEquals(11, message.getStringToInt32FieldMap().get("1").intValue());
-    assertEquals(22, message.getStringToInt32FieldMap().get("2").intValue());
-    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
+    assertThat(message.getStringToInt32FieldMap()).hasSize(3);
+    assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(11);
+    assertThat(message.getStringToInt32FieldMap().get("2").intValue()).isEqualTo(22);
+    assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
   }
 
   private void updateMapValues(TestMap.Builder builder) {
@@ -146,6 +150,7 @@
         .putStringToInt32Field("4", 44);
   }
 
+  @Test
   public void testUpdateMapValues() {
     TestMap.Builder mapBuilder = TestMap.newBuilder();
     setMapValues(mapBuilder);
@@ -159,52 +164,53 @@
   }
 
   private void assertMapValuesUpdated(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32FieldMap().size());
-    assertEquals(111, message.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
-    assertEquals(44, message.getInt32ToInt32FieldMap().get(4).intValue());
+    assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
+    assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(111);
+    assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
+    assertThat(message.getInt32ToInt32FieldMap().get(4).intValue()).isEqualTo(44);
 
-    assertEquals(3, message.getInt32ToStringFieldMap().size());
-    assertEquals("111", message.getInt32ToStringFieldMap().get(1));
-    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
-    assertEquals("44", message.getInt32ToStringFieldMap().get(4));
+    assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "111");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(4, "44");
 
-    assertEquals(3, message.getInt32ToBytesFieldMap().size());
-    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesFieldMap().get(1));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
-    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesFieldMap().get(4));
+    assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("111"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(4, TestUtil.toBytes("44"));
 
-    assertEquals(3, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
-    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumFieldMap().get(4));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(4, TestMap.EnumValue.QUX);
 
-    assertEquals(3, message.getInt32ToMessageFieldMap().size());
-    assertEquals(111, message.getInt32ToMessageFieldMap().get(1).getValue());
-    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
-    assertEquals(44, message.getInt32ToMessageFieldMap().get(4).getValue());
+    assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(111);
+    assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
+    assertThat(message.getInt32ToMessageFieldMap().get(4).getValue()).isEqualTo(44);
 
-    assertEquals(3, message.getStringToInt32FieldMap().size());
-    assertEquals(111, message.getStringToInt32FieldMap().get("1").intValue());
-    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
-    assertEquals(44, message.getStringToInt32FieldMap().get("4").intValue());
+    assertThat(message.getStringToInt32FieldMap()).hasSize(3);
+    assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(111);
+    assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
+    assertThat(message.getStringToInt32FieldMap().get("4").intValue()).isEqualTo(44);
   }
 
   private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
-    assertEquals(0, testMapOrBuilder.getStringToInt32FieldMap().size());
-    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToStringFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getStringToInt32FieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(0);
   }
 
+  @Test
   public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
     // Since builders are implemented as a thin wrapper around a message
     // instance, we attempt to verify that we can't cause the builder to modify
@@ -213,14 +219,15 @@
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     builder.putInt32ToInt32Field(1, 2);
-    assertTrue(message.getInt32ToInt32FieldMap().isEmpty());
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32FieldMap());
+    assertThat(message.getInt32ToInt32FieldMap()).isEmpty();
+    assertThat(builder.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2));
     message = builder.build();
     builder.putInt32ToInt32Field(2, 3);
-    assertEquals(newMap(1, 2), message.getInt32ToInt32FieldMap());
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32FieldMap());
+    assertThat(message.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2));
+    assertThat(builder.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2, 2, 3));
   }
 
+  @Test
   public void testGetMapIsImmutable() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapsAreImmutable(builder);
@@ -244,63 +251,65 @@
   private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
     try {
       map.put(key, value);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     if (!map.isEmpty()) {
       try {
         map.entrySet().remove(map.entrySet().iterator().next());
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
     }
   }
 
+  @Test
   public void testMapFieldClear() {
     TestMap.Builder builder = TestMap.newBuilder().putInt32ToInt32Field(1, 2);
     builder.clearInt32ToInt32Field();
-    assertEquals(0, builder.getInt32ToInt32FieldCount());
+    assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(0);
   }
 
+  @Test
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder().putInt32ToInt32Field(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32FieldMap());
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32FieldMap());
+    assertThat(builder.build().getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2));
+    assertThat(builder.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2));
     builder.putInt32ToInt32Field(2, 3);
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32FieldMap());
+    assertThat(builder.getInt32ToInt32FieldMap()).isEqualTo(newMap(1, 2, 2, 3));
 
     builder.putInt32ToEnumField(1, TestMap.EnumValue.BAR);
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumFieldMap());
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumFieldMap());
+    assertThat(builder.build().getInt32ToEnumFieldMap())
+        .isEqualTo(newMap(1, TestMap.EnumValue.BAR));
+    assertThat(builder.getInt32ToEnumFieldMap()).isEqualTo(newMap(1, TestMap.EnumValue.BAR));
     builder.putInt32ToEnumField(2, TestMap.EnumValue.FOO);
-    assertEquals(
-        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
-        builder.getInt32ToEnumFieldMap());
+    assertThat(builder.getInt32ToEnumFieldMap())
+        .isEqualTo(newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO));
 
     builder.putInt32ToStringField(1, "1");
-    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringFieldMap());
-    assertEquals(newMap(1, "1"), builder.getInt32ToStringFieldMap());
+    assertThat(builder.build().getInt32ToStringFieldMap()).isEqualTo(newMap(1, "1"));
+    assertThat(builder.getInt32ToStringFieldMap()).isEqualTo(newMap(1, "1"));
     builder.putInt32ToStringField(2, "2");
-    assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringFieldMap());
+    assertThat(builder.getInt32ToStringFieldMap()).isEqualTo(newMap(1, "1", 2, "2"));
 
     builder.putInt32ToMessageField(1, TestMap.MessageValue.getDefaultInstance());
-    assertEquals(
-        newMap(1, TestMap.MessageValue.getDefaultInstance()),
-        builder.build().getInt32ToMessageFieldMap());
-    assertEquals(
-        newMap(1, TestMap.MessageValue.getDefaultInstance()), builder.getInt32ToMessageFieldMap());
+    assertThat(builder.build().getInt32ToMessageFieldMap())
+        .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance()));
+    assertThat(builder.getInt32ToMessageFieldMap())
+        .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance()));
     builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
-    assertEquals(
-        newMap(
-            1,
-            TestMap.MessageValue.getDefaultInstance(),
-            2,
-            TestMap.MessageValue.getDefaultInstance()),
-        builder.getInt32ToMessageFieldMap());
+    assertThat(builder.getInt32ToMessageFieldMap())
+        .isEqualTo(
+            newMap(
+                1,
+                TestMap.MessageValue.getDefaultInstance(),
+                2,
+                TestMap.MessageValue.getDefaultInstance()));
   }
 
+  @Test
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
@@ -323,6 +332,7 @@
     assertMapValuesCleared(message);
   }
 
+  @Test
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
     setMapValues(sourceBuilder);
@@ -334,6 +344,7 @@
     assertMapValuesSet(destination.build());
   }
 
+  @Test
   public void testPutAllForUnknownEnumValues() throws Exception {
     TestMap.Builder sourceBuilder =
         TestMap.newBuilder()
@@ -346,84 +357,88 @@
     destinationBuilder.putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValueMap());
     TestMap destination = destinationBuilder.build();
 
-    assertEquals(0, destination.getInt32ToEnumFieldValueMap().get(0).intValue());
-    assertEquals(1, destination.getInt32ToEnumFieldValueMap().get(1).intValue());
-    assertEquals(1000, destination.getInt32ToEnumFieldValueMap().get(2).intValue());
-    assertEquals(3, destination.getInt32ToEnumFieldCount());
+    assertThat(destination.getInt32ToEnumFieldValueMap().get(0).intValue()).isEqualTo(0);
+    assertThat(destination.getInt32ToEnumFieldValueMap().get(1).intValue()).isEqualTo(1);
+    assertThat(destination.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
+    assertThat(destination.getInt32ToEnumFieldCount()).isEqualTo(3);
   }
 
+  @Test
   public void testPutForUnknownEnumValues() throws Exception {
-    TestMap.Builder builder =
+    TestMap builder =
         TestMap.newBuilder()
             .putInt32ToEnumFieldValue(0, 0)
             .putInt32ToEnumFieldValue(1, 1)
-            .putInt32ToEnumFieldValue(2, 1000); // unknown value.
-    TestMap message = builder.build();
+            .putInt32ToEnumFieldValue(2, 1000)
+            .build(); // unknown value.
+    TestMap message = builder;
 
-    assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0));
-    assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1));
-    assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2));
-    assertEquals(3, message.getInt32ToEnumFieldCount());
+    assertThat(message.getInt32ToEnumFieldValueOrThrow(0)).isEqualTo(0);
+    assertThat(message.getInt32ToEnumFieldValueOrThrow(1)).isEqualTo(1);
+    assertThat(message.getInt32ToEnumFieldValueOrThrow(2)).isEqualTo(1000);
+    assertThat(message.getInt32ToEnumFieldCount()).isEqualTo(3);
   }
 
+  @Test
   public void testPutChecksNullKeysAndValues() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
 
     try {
       builder.putInt32ToStringField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToBytesField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToEnumField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToMessageField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putStringToInt32Field(null, 1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
   }
 
+  @Test
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
     updateMapValues(builder);
     message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
 
     builder = message.toBuilder();
     builder.clear();
     message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
   }
@@ -436,39 +451,41 @@
     return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
   }
 
+  @Test
   public void testParseError() throws Exception {
     ByteString bytes = TestUtil.toBytes("SOME BYTES");
     String stringKey = "a string key";
 
     TestMap map =
         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build());
-    assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
+    assertThat(map.getInt32ToInt32FieldOrDefault(5, -1)).isEqualTo(0);
 
     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build());
-    assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
+    assertThat(map.getInt32ToStringFieldOrDefault(0, null)).isEmpty();
 
     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build());
-    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+    assertThat(ByteString.EMPTY).isEqualTo(map.getInt32ToBytesFieldOrDefault(0, null));
 
     map =
         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build());
-    assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
+    assertThat(map.getInt32ToEnumFieldOrDefault(0, null)).isEqualTo(TestMap.EnumValue.FOO);
 
     try {
       tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
-      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      assertThat(expected.getUnfinishedMessage()).isInstanceOf(TestMap.class);
       map = (TestMap) expected.getUnfinishedMessage();
-      assertTrue(map.getInt32ToMessageFieldMap().isEmpty());
+      assertThat(map.getInt32ToMessageFieldMap()).isEmpty();
     }
 
     map =
         tryParseTestMap(
             BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build());
-    assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
+    assertThat(map.getStringToInt32FieldOrDefault(stringKey, -1)).isEqualTo(0);
   }
 
+  @Test
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
@@ -479,18 +496,20 @@
     assertMapValuesSet(other.build());
   }
 
+  @Test
   public void testEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
 
     // We can't control the order of elements in a HashMap. The best we can do
     // here is to add elements in different order.
-    TestMap.Builder b1 =
+    TestMap b1 =
         TestMap.newBuilder()
             .putInt32ToInt32Field(1, 2)
             .putInt32ToInt32Field(3, 4)
-            .putInt32ToInt32Field(5, 6);
-    TestMap m1 = b1.build();
+            .putInt32ToInt32Field(5, 6)
+            .build();
+    TestMap m1 = b1;
 
     TestMap.Builder b2 =
         TestMap.newBuilder()
@@ -499,13 +518,13 @@
             .putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
 
-    assertEquals(m1, m2);
-    assertEquals(m1.hashCode(), m2.hashCode());
+    assertThat(m2).isEqualTo(m1);
+    assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
 
     // Make sure we did compare map fields.
     b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
-    assertFalse(m1.equals(m2));
+    assertThat(m1.equals(m2)).isFalse();
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
 
@@ -513,10 +532,11 @@
     // equals() should return false.
     b2.removeInt32ToInt32Field(1);
     m2 = b2.build();
-    assertFalse(m1.equals(m2));
-    assertFalse(m2.equals(m1));
+    assertThat(m1.equals(m2)).isFalse();
+    assertThat(m2.equals(m1)).isFalse();
   }
 
+  @Test
   public void testUnknownEnumValues() throws Exception {
     TestMap.Builder builder =
         TestMap.newBuilder()
@@ -525,55 +545,60 @@
             .putInt32ToEnumFieldValue(2, 1000); // unknown value.
     TestMap message = builder.build();
 
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(0));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumFieldMap().get(2));
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(0, TestMap.EnumValue.FOO);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.UNRECOGNIZED);
 
     builder.putAllInt32ToEnumFieldValue(newMap(2, 1000)); // unknown value.
     message = builder.build();
-    assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumFieldMap().get(2));
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.UNRECOGNIZED);
 
     // Unknown enum values should be preserved after:
     //   1. Serialization and parsing.
     //   2. toBuild().
     //   3. mergeFrom().
-    message = TestMap.parseFrom(message.toByteString());
-    assertEquals(1000, message.getInt32ToEnumFieldValueMap().get(2).intValue());
+    message = TestMap.parseFrom(message.toByteString(), ExtensionRegistryLite.getEmptyRegistry());
+    assertThat(message.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
     builder = message.toBuilder();
-    assertEquals(1000, builder.getInt32ToEnumFieldValueMap().get(2).intValue());
+    assertThat(builder.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
     builder = TestMap.newBuilder().mergeFrom(message);
-    assertEquals(1000, builder.getInt32ToEnumFieldValueMap().get(2).intValue());
+    assertThat(builder.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
 
     // hashCode()/equals() should take unknown enum values into account.
     builder.putAllInt32ToEnumFieldValue(newMap(2, 1001));
     TestMap message2 = builder.build();
-    assertFalse(message.hashCode() == message2.hashCode());
-    assertFalse(message.equals(message2));
+    assertThat(message.hashCode()).isNotEqualTo(message2.hashCode());
+    assertThat(message.equals(message2)).isFalse();
     // Unknown values will be converted to UNRECOGNIZED so the resulted enum map
     // should be the same.
-    assertEquals(message2.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
+    assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message2.getInt32ToEnumFieldMap());
   }
 
+  @Test
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
 
-    assertEquals(
-        Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32FieldMap().keySet()));
+    assertThat(new ArrayList<>(message.getStringToInt32FieldMap().keySet()))
+        .containsExactly("1", "2", "3")
+        .inOrder();
   }
 
+  @Test
   public void testGetMap() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
-    assertEquals(message.getStringToInt32FieldMap(), message.getStringToInt32FieldMap());
-    assertEquals(message.getInt32ToBytesFieldMap(), message.getInt32ToBytesFieldMap());
-    assertEquals(message.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
-    assertEquals(message.getInt32ToEnumFieldValueMap(), message.getInt32ToEnumFieldValueMap());
-    assertEquals(message.getInt32ToMessageFieldMap(), message.getInt32ToMessageFieldMap());
+    assertThat(message.getStringToInt32FieldMap()).isEqualTo(message.getStringToInt32FieldMap());
+    assertThat(message.getInt32ToBytesFieldMap()).isEqualTo(message.getInt32ToBytesFieldMap());
+    assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message.getInt32ToEnumFieldMap());
+    assertThat(message.getInt32ToEnumFieldValueMap())
+        .isEqualTo(message.getInt32ToEnumFieldValueMap());
+    assertThat(message.getInt32ToMessageFieldMap()).isEqualTo(message.getInt32ToMessageFieldMap());
   }
 
+  @Test
   public void testContains() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
@@ -582,37 +607,38 @@
   }
 
   private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
-    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToStringField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
-    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+    assertThat(testMapOrBuilder.containsStringToInt32Field("1")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("2")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("3")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("-1")).isFalse();
   }
 
+  @Test
   public void testCount() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -624,23 +650,24 @@
     assertMapCounts(3, message);
 
     builder = message.toBuilder().putInt32ToInt32Field(4, 44);
-    assertEquals(4, builder.getInt32ToInt32FieldCount());
-    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+    assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
+    assertThat(builder.build().getInt32ToInt32FieldCount()).isEqualTo(4);
 
     // already present - should be unchanged
     builder.putInt32ToInt32Field(4, 44);
-    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
   }
 
   private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToInt32FieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToStringFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToBytesFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToEnumFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToMessageFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getStringToInt32FieldCount());
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(expectedCount);
   }
 
+  @Test
   public void testGetOrDefault() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -650,39 +677,42 @@
   }
 
   public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
-    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)).isEqualTo(11);
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)).isEqualTo(-11);
 
-    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
-    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")).isEqualTo("11");
+    assertWithMessage("-11")
+        .that(testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null))
+        .isNull();
 
-    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null))
+        .isEqualTo(TestUtil.toBytes("11"));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null))
+        .isEqualTo(TestMap.EnumValue.FOO);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(
-        TestMap.EnumValue.BAR.getNumber(),
-        testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1));
-    assertEquals(-1, testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1))
+        .isEqualTo(TestMap.EnumValue.BAR.getNumber());
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1)).isEqualTo(-1);
 
-    assertEquals(
-        MessageValue.newBuilder().setValue(11).build(),
-        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null))
+        .isEqualTo(MessageValue.newBuilder().setValue(11).build());
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
-    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)).isEqualTo(11);
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)).isEqualTo(-11);
 
     try {
       testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
+  @Test
   public void testGetOrThrow() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -692,109 +722,109 @@
   }
 
   public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
     try {
       testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
 
     try {
       testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
 
     try {
       testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     try {
       testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(
-        TestMap.EnumValue.BAR.getNumber(), testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2))
+        .isEqualTo(TestMap.EnumValue.BAR.getNumber());
     try {
       testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(
-        MessageValue.newBuilder().setValue(11).build(),
-        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrThrow(1))
+        .isEqualTo(MessageValue.newBuilder().setValue(11).build());
     try {
       testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
     try {
       testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
     try {
       testMapOrBuilder.getStringToInt32FieldOrThrow(null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
+  @Test
   public void testPut() {
     TestMap.Builder builder = TestMap.newBuilder();
     builder.putInt32ToInt32Field(1, 11);
-    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
 
     builder.putInt32ToStringField(1, "a");
-    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("a");
     try {
       builder.putInt32ToStringField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
-    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
     try {
       builder.putInt32ToBytesField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
-    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     try {
       builder.putInt32ToEnumField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putStringToInt32Field("a", 1);
-    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    assertThat(builder.getStringToInt32FieldOrThrow("a")).isEqualTo(1);
     try {
       builder.putStringToInt32Field(null, -1);
     } catch (NullPointerException e) {
@@ -802,42 +832,43 @@
     }
   }
 
+  @Test
   public void testRemove() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
-    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToInt32Field(1);
-      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+      assertThat(builder.getInt32ToInt32FieldOrDefault(1, -1)).isEqualTo(-1);
     }
 
-    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToStringField(1);
-      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToStringFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToBytesField(1);
-      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToBytesFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToEnumField(1);
-      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToEnumFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    assertThat(builder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
     for (int times = 0; times < 2; times++) {
       builder.removeStringToInt32Field("1");
-      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+      assertThat(builder.getStringToInt32FieldOrDefault("1", -1)).isEqualTo(-1);
     }
 
     try {
       builder.removeStringToInt32Field(null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
@@ -856,40 +887,41 @@
     return map;
   }
 
+  @Test
   public void testMap_withNulls() {
     TestMap.Builder builder = TestMap.newBuilder();
 
     try {
       builder.putStringToInt32Field(null, 3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
     try {
       builder.putAllStringToInt32Field(newMap(null, 3, "hi", 4));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
     try {
       builder.putInt32ToMessageField(3, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
     try {
       builder.putAllInt32ToMessageField(
           MapLiteTest.<Integer, MessageValue>newMap(4, null, 5, null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
     try {
       builder.putAllInt32ToMessageField(null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
-    assertArrayEquals(new byte[0], builder.build().toByteArray());
+    assertThat(builder.build().toByteArray()).isEqualTo(new byte[0]);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/MapTest.java b/java/core/src/test/java/com/google/protobuf/MapTest.java
index c3b1fa3..cc7a121 100644
--- a/java/core/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -30,7 +30,8 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertArrayEquals;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.EnumDescriptor;
@@ -46,14 +47,16 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Unit tests for map fields. */
-public class MapTest extends TestCase {
+@RunWith(JUnit4.class)
+public class MapTest {
 
   private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 11);
@@ -106,6 +109,7 @@
         .putStringToInt32Field("3", 33);
   }
 
+  @Test
   public void testSetMapValues() {
     TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
     setMapValuesUsingMutableMap(usingMutableMapBuilder);
@@ -117,7 +121,7 @@
     TestMap usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesSet(usingAccessors);
 
-    assertEquals(usingAccessors, usingMutableMap);
+    assertThat(usingAccessors).isEqualTo(usingMutableMap);
   }
 
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
@@ -131,35 +135,35 @@
   }
 
   private void assertMapValuesSet(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32FieldMap().size());
-    assertEquals(11, message.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(22, message.getInt32ToInt32FieldMap().get(2).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
+    assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
+    assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(11);
+    assertThat(message.getInt32ToInt32FieldMap().get(2).intValue()).isEqualTo(22);
+    assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
 
-    assertEquals(3, message.getInt32ToStringFieldMap().size());
-    assertEquals("11", message.getInt32ToStringFieldMap().get(1));
-    assertEquals("22", message.getInt32ToStringFieldMap().get(2));
-    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
+    assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "11");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(2, "22");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
 
-    assertEquals(3, message.getInt32ToBytesFieldMap().size());
-    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesFieldMap().get(1));
-    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesFieldMap().get(2));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
+    assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("11"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(2, TestUtil.toBytes("22"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
 
-    assertEquals(3, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(2));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.FOO);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
 
-    assertEquals(3, message.getInt32ToMessageFieldMap().size());
-    assertEquals(11, message.getInt32ToMessageFieldMap().get(1).getValue());
-    assertEquals(22, message.getInt32ToMessageFieldMap().get(2).getValue());
-    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
+    assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(11);
+    assertThat(message.getInt32ToMessageFieldMap().get(2).getValue()).isEqualTo(22);
+    assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
 
-    assertEquals(3, message.getStringToInt32FieldMap().size());
-    assertEquals(11, message.getStringToInt32FieldMap().get("1").intValue());
-    assertEquals(22, message.getStringToInt32FieldMap().get("2").intValue());
-    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
+    assertThat(message.getStringToInt32FieldMap()).hasSize(3);
+    assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(11);
+    assertThat(message.getStringToInt32FieldMap().get("2").intValue()).isEqualTo(22);
+    assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
   }
 
   private void updateMapValuesUsingMutableMap(TestMap.Builder builder) {
@@ -212,6 +216,7 @@
         .putStringToInt32Field("4", 44);
   }
 
+  @Test
   public void testUpdateMapValues() {
     TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
     setMapValuesUsingMutableMap(usingMutableMapBuilder);
@@ -223,7 +228,7 @@
     TestMap usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesSet(usingAccessors);
 
-    assertEquals(usingAccessors, usingMutableMap);
+    assertThat(usingAccessors).isEqualTo(usingMutableMap);
     //
     usingMutableMapBuilder = usingMutableMap.toBuilder();
     updateMapValuesUsingMutableMap(usingMutableMapBuilder);
@@ -235,56 +240,57 @@
     usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesUpdated(usingAccessors);
 
-    assertEquals(usingAccessors, usingMutableMap);
+    assertThat(usingAccessors).isEqualTo(usingMutableMap);
   }
 
   private void assertMapValuesUpdated(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32FieldMap().size());
-    assertEquals(111, message.getInt32ToInt32FieldMap().get(1).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
-    assertEquals(44, message.getInt32ToInt32FieldMap().get(4).intValue());
+    assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
+    assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(111);
+    assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
+    assertThat(message.getInt32ToInt32FieldMap().get(4).intValue()).isEqualTo(44);
 
-    assertEquals(3, message.getInt32ToStringFieldMap().size());
-    assertEquals("111", message.getInt32ToStringFieldMap().get(1));
-    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
-    assertEquals("44", message.getInt32ToStringFieldMap().get(4));
+    assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "111");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
+    assertThat(message.getInt32ToStringFieldMap()).containsEntry(4, "44");
 
-    assertEquals(3, message.getInt32ToBytesFieldMap().size());
-    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesFieldMap().get(1));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
-    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesFieldMap().get(4));
+    assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("111"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
+    assertThat(message.getInt32ToBytesFieldMap()).containsEntry(4, TestUtil.toBytes("44"));
 
-    assertEquals(3, message.getInt32ToEnumFieldMap().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
-    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumFieldMap().get(4));
+    assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(4, TestMap.EnumValue.QUX);
 
-    assertEquals(3, message.getInt32ToMessageFieldMap().size());
-    assertEquals(111, message.getInt32ToMessageFieldMap().get(1).getValue());
-    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
-    assertEquals(44, message.getInt32ToMessageFieldMap().get(4).getValue());
+    assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
+    assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(111);
+    assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
+    assertThat(message.getInt32ToMessageFieldMap().get(4).getValue()).isEqualTo(44);
 
-    assertEquals(3, message.getStringToInt32FieldMap().size());
-    assertEquals(111, message.getStringToInt32FieldMap().get("1").intValue());
-    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
-    assertEquals(44, message.getStringToInt32FieldMap().get("4").intValue());
+    assertThat(message.getStringToInt32FieldMap()).hasSize(3);
+    assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(111);
+    assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
+    assertThat(message.getStringToInt32FieldMap().get("4").intValue()).isEqualTo(44);
   }
 
   private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
-    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldMap().size());
-    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
-    assertEquals(0, testMapOrBuilder.getStringToInt32FieldMap().size());
-    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToStringFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(0);
+    assertThat(testMapOrBuilder.getStringToInt32FieldMap()).isEmpty();
+    assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(0);
   }
 
+  @Test
   public void testGetMapIsImmutable() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapsAreImmutable(builder);
@@ -308,122 +314,122 @@
   private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
     try {
       map.put(key, value);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
   }
 
+  @Test
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
     intMap.put(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
     try {
       intMap.put(2, 3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
     builder.getMutableInt32ToInt32Field().put(2, 3);
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+    assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2, 2, 3));
   //
     Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
     enumMap.put(1, TestMap.EnumValue.BAR);
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
+    assertThat(builder.build().getInt32ToEnumField())
+        .isEqualTo(newMap(1, TestMap.EnumValue.BAR));
     try {
       enumMap.put(2, TestMap.EnumValue.FOO);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    assertThat(builder.getInt32ToEnumField()).isEqualTo(newMap(1, TestMap.EnumValue.BAR));
     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
-    assertEquals(
-        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
-        builder.getInt32ToEnumField());
+    assertThat(builder.getInt32ToEnumField()).isEqualTo(
+        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO));
   //
     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
     stringMap.put(1, "1");
-    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
+    assertThat(builder.build().getInt32ToStringField()).isEqualTo(newMap(1, "1"));
     try {
       stringMap.put(2, "2");
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    assertThat(builder.getInt32ToStringField()).isEqualTo(newMap(1, "1"));
     builder.putInt32ToStringField(2, "2");
-    assertEquals(
-        newMap(1, "1", 2, "2"),
-        builder.getInt32ToStringField());
+    assertThat(builder.getInt32ToStringField()).isEqualTo(newMap(1, "1", 2, "2"));
   //
     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
-    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
-        builder.build().getInt32ToMessageField());
+    assertThat( builder.build().getInt32ToMessageField())
+        .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance()));
     try {
       messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
-        builder.getInt32ToMessageField());
+    assertThat(builder.getInt32ToMessageField())
+        .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance()));
     builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
-    assertEquals(
+    assertThat(builder.getInt32ToMessageField()).isEqualTo(
         newMap(1, TestMap.MessageValue.getDefaultInstance(),
-            2, TestMap.MessageValue.getDefaultInstance()),
-        builder.getInt32ToMessageField());
+            2, TestMap.MessageValue.getDefaultInstance()));
   }
   //
+  @Test
   public void testMutableMapLifecycle_collections() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
     intMap.put(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
     try {
       intMap.remove(2);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.entrySet().remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.entrySet().iterator().remove();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.keySet().remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.values().remove(new Object());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
     try {
       intMap.values().iterator().remove();
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(newMap(1, 2), intMap);
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    assertThat(intMap).isEqualTo(newMap(1, 2));
+    assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
+    assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
   }
 
+  @Test
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
@@ -446,6 +452,7 @@
     assertMapValuesCleared(message);
   }
 
+  @Test
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
     setMapValuesUsingAccessors(sourceBuilder);
@@ -457,6 +464,7 @@
     assertMapValuesSet(destination.build());
   }
 
+  @Test
   public void testPutAllForUnknownEnumValues() throws Exception {
     TestMap source =
         TestMap.newBuilder()
@@ -472,12 +480,13 @@
             .putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValueMap())
             .build();
 
-    assertEquals(0, destination.getInt32ToEnumFieldValueMap().get(0).intValue());
-    assertEquals(1, destination.getInt32ToEnumFieldValueMap().get(1).intValue());
-    assertEquals(1000, destination.getInt32ToEnumFieldValueMap().get(2).intValue());
-    assertEquals(3, destination.getInt32ToEnumFieldCount());
+    assertThat(destination.getInt32ToEnumFieldValueMap().get(0).intValue()).isEqualTo(0);
+    assertThat(destination.getInt32ToEnumFieldValueMap().get(1).intValue()).isEqualTo(1);
+    assertThat(destination.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
+    assertThat(destination.getInt32ToEnumFieldCount()).isEqualTo(3);
   }
 
+  @Test
   public void testPutForUnknownEnumValues() throws Exception {
     TestMap message =
         TestMap.newBuilder()
@@ -485,70 +494,72 @@
             .putInt32ToEnumFieldValue(1, 1)
             .putInt32ToEnumFieldValue(2, 1000) // unknown value.
             .build();
-    assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0));
-    assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1));
-    assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2));
-    assertEquals(3, message.getInt32ToEnumFieldCount());
+    assertThat(message.getInt32ToEnumFieldValueOrThrow(0)).isEqualTo(0);
+    assertThat(message.getInt32ToEnumFieldValueOrThrow(1)).isEqualTo(1);
+    assertThat(message.getInt32ToEnumFieldValueOrThrow(2)).isEqualTo(1000);
+    assertThat(message.getInt32ToEnumFieldCount()).isEqualTo(3);
   }
 
+  @Test
   public void testPutChecksNullKeysAndValues() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
 
     try {
       builder.putInt32ToStringField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToBytesField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToEnumField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putInt32ToMessageField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
 
     try {
       builder.putStringToInt32Field(null, 1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
   }
 
+  @Test
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
     updateMapValuesUsingAccessors(builder);
     message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
 
     builder = message.toBuilder();
     builder.clear();
     message = builder.build();
-    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
   }
@@ -561,39 +572,41 @@
     return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
   }
 
+  @Test
   public void testParseError() throws Exception {
     ByteString bytes = TestUtil.toBytes("SOME BYTES");
     String stringKey = "a string key";
 
     TestMap map =
         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build());
-    assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
+    assertThat(map.getInt32ToInt32FieldOrDefault(5, -1)).isEqualTo(0);
 
     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build());
-    assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
+    assertThat(map.getInt32ToStringFieldOrDefault(0, null)).isEmpty();
 
     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build());
-    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+    assertThat(ByteString.EMPTY).isEqualTo(map.getInt32ToBytesFieldOrDefault(0, null));
 
     map =
         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build());
-    assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
+    assertThat(map.getInt32ToEnumFieldOrDefault(0, null)).isEqualTo(TestMap.EnumValue.FOO);
 
     try {
       tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build());
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
-      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      assertThat(expected.getUnfinishedMessage()).isInstanceOf(TestMap.class);
       map = (TestMap) expected.getUnfinishedMessage();
-      assertTrue(map.getInt32ToMessageFieldMap().isEmpty());
+      assertThat(map.getInt32ToMessageFieldMap()).isEmpty();
     }
 
     map =
         tryParseTestMap(
             BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build());
-    assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
+    assertThat(map.getStringToInt32FieldOrDefault(stringKey, -1)).isEqualTo(0);
   }
 
+  @Test
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
@@ -604,6 +617,7 @@
     assertMapValuesSet(other.build());
   }
 
+  @Test
   public void testEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
@@ -624,13 +638,13 @@
             .putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
 
-    assertEquals(m1, m2);
-    assertEquals(m1.hashCode(), m2.hashCode());
+    assertThat(m2).isEqualTo(m1);
+    assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
 
     // Make sure we did compare map fields.
     b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
-    assertFalse(m1.equals(m2));
+    assertThat(m1.equals(m2)).isFalse();
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
 
@@ -638,22 +652,25 @@
     // equals() should return false.
     b2.removeInt32ToInt32Field(1);
     m2 = b2.build();
-    assertFalse(m1.equals(m2));
-    assertFalse(m2.equals(m1));
+    assertThat(m1.equals(m2)).isFalse();
+    assertThat(m2.equals(m1)).isFalse();
   }
 
+  @Test
   public void testNestedBuilderOnChangeEventPropagation() {
     TestOnChangeEventPropagation.Builder parent = TestOnChangeEventPropagation.newBuilder();
     parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 2);
     TestOnChangeEventPropagation message = parent.build();
-    assertEquals(2, message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue());
+    assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue())
+        .isEqualTo(2);
 
     // Make a change using nested builder.
     parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 3);
 
     // Should be able to observe the change.
     message = parent.build();
-    assertEquals(3, message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue());
+    assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue())
+        .isEqualTo(3);
 
     // Make another change using mergeFrom()
     TestMap other = TestMap.newBuilder().putInt32ToInt32Field(1, 4).build();
@@ -661,16 +678,18 @@
 
     // Should be able to observe the change.
     message = parent.build();
-    assertEquals(4, message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue());
+    assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue())
+        .isEqualTo(4);
 
     // Make yet another change by clearing the nested builder.
     parent.getOptionalMessageBuilder().clear();
 
     // Should be able to observe the change.
     message = parent.build();
-    assertEquals(0, message.getOptionalMessage().getInt32ToInt32FieldMap().size());
+    assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap()).isEmpty();
   }
 
+  @Test
   public void testNestedBuilderOnChangeEventPropagationReflection() {
     FieldDescriptor intMapField = f("int32_to_int32_field");
     // Create an outer message builder with nested builder.
@@ -685,7 +704,7 @@
 
     // Should be able to observe the change.
     TestOnChangeEventPropagation message = parentBuilder.build();
-    assertEquals(1, message.getOptionalMessage().getInt32ToInt32FieldMap().size());
+    assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap()).hasSize(1);
 
     // Change the entry value.
     entryBuilder.putInt32ToInt32Field(1, 4);
@@ -694,7 +713,8 @@
 
     // Should be able to observe the change.
     message = parentBuilder.build();
-    assertEquals(4, message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue());
+    assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue())
+        .isEqualTo(4);
 
     // Clear the nested builder.
     testMapBuilder = parentBuilder.getOptionalMessageBuilder();
@@ -702,7 +722,7 @@
 
     // Should be able to observe the change.
     message = parentBuilder.build();
-    assertEquals(0, message.getOptionalMessage().getInt32ToInt32FieldMap().size());
+    assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap()).isEmpty();
   }
 
   // The following methods are used to test reflection API.
@@ -729,16 +749,16 @@
       Message mapEntry = (Message) entry;
       Object key = getFieldValue(mapEntry, "key");
       Object value = getFieldValue(mapEntry, "value");
-      assertTrue(values.containsKey(key));
-      assertEquals(value, values.get(key));
+      assertThat(values.containsKey(key)).isTrue();
+      assertThat(values.get(key)).isEqualTo(value);
     }
-    assertEquals(values.size(), message.getRepeatedFieldCount(field));
+    assertThat(message.getRepeatedFieldCount(field)).isEqualTo(values.size());
     for (int i = 0; i < message.getRepeatedFieldCount(field); i++) {
       Message mapEntry = (Message) message.getRepeatedField(field, i);
       Object key = getFieldValue(mapEntry, "key");
       Object value = getFieldValue(mapEntry, "value");
-      assertTrue(values.containsKey(key));
-      assertEquals(value, values.get(key));
+      assertThat(values.containsKey(key)).isTrue();
+      assertThat(values.get(key)).isEqualTo(value);
     }
   }
 
@@ -768,6 +788,7 @@
     return map;
   }
 
+  @Test
   public void testReflectionApi() throws Exception {
     // In reflection API, map fields are just repeated message fields.
     TestMap.Builder builder =
@@ -791,8 +812,8 @@
     builder.clearField(f("int32_to_int32_field"));
     builder.clearField(f("int32_to_message_field"));
     message = builder.build();
-    assertEquals(0, message.getInt32ToInt32FieldMap().size());
-    assertEquals(0, message.getInt32ToMessageFieldMap().size());
+    assertThat(message.getInt32ToInt32FieldMap()).isEmpty();
+    assertThat(message.getInt32ToMessageFieldMap()).isEmpty();
 
     // Test setField()
     setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44));
@@ -803,10 +824,10 @@
             111, MessageValue.newBuilder().setValue(222).build(),
             333, MessageValue.newBuilder().setValue(444).build()));
     message = builder.build();
-    assertEquals(22, message.getInt32ToInt32FieldMap().get(11).intValue());
-    assertEquals(44, message.getInt32ToInt32FieldMap().get(33).intValue());
-    assertEquals(222, message.getInt32ToMessageFieldMap().get(111).getValue());
-    assertEquals(444, message.getInt32ToMessageFieldMap().get(333).getValue());
+    assertThat(message.getInt32ToInt32FieldMap().get(11).intValue()).isEqualTo(22);
+    assertThat(message.getInt32ToInt32FieldMap().get(33).intValue()).isEqualTo(44);
+    assertThat(message.getInt32ToMessageFieldMap().get(111).getValue()).isEqualTo(222);
+    assertThat(message.getInt32ToMessageFieldMap().get(333).getValue()).isEqualTo(444);
 
     // Test addRepeatedField
     builder.addRepeatedField(
@@ -819,8 +840,8 @@
             555,
             MessageValue.newBuilder().setValue(666).build()));
     message = builder.build();
-    assertEquals(66, message.getInt32ToInt32FieldMap().get(55).intValue());
-    assertEquals(666, message.getInt32ToMessageFieldMap().get(555).getValue());
+    assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(66);
+    assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(666);
 
     // Test addRepeatedField (overriding existing values)
     builder.addRepeatedField(
@@ -833,8 +854,8 @@
             555,
             MessageValue.newBuilder().setValue(555).build()));
     message = builder.build();
-    assertEquals(55, message.getInt32ToInt32FieldMap().get(55).intValue());
-    assertEquals(555, message.getInt32ToMessageFieldMap().get(555).getValue());
+    assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55);
+    assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(555);
 
     // Test setRepeatedField
     for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
@@ -848,12 +869,13 @@
       builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build());
     }
     message = builder.build();
-    assertEquals(11, message.getInt32ToInt32FieldMap().get(22).intValue());
-    assertEquals(33, message.getInt32ToInt32FieldMap().get(44).intValue());
-    assertEquals(55, message.getInt32ToInt32FieldMap().get(55).intValue());
+    assertThat(message.getInt32ToInt32FieldMap().get(22).intValue()).isEqualTo(11);
+    assertThat(message.getInt32ToInt32FieldMap().get(44).intValue()).isEqualTo(33);
+    assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55);
   }
 
   // See additional coverage in TextFormatTest.java.
+  @Test
   public void testTextFormat() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
@@ -868,6 +890,7 @@
     assertMapValuesSet(message);
   }
 
+  @Test
   public void testDynamicMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
@@ -875,14 +898,18 @@
 
     Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
     Message dynamicMessage =
-        dynamicDefaultInstance.newBuilderForType().mergeFrom(message.toByteString()).build();
+        dynamicDefaultInstance
+            .newBuilderForType()
+            .mergeFrom(message.toByteString(), ExtensionRegistry.getEmptyRegistry())
+            .build();
 
-    assertEquals(message, dynamicMessage);
-    assertEquals(message.hashCode(), dynamicMessage.hashCode());
+    assertThat(dynamicMessage).isEqualTo(message);
+    assertThat(dynamicMessage.hashCode()).isEqualTo(message.hashCode());
   }
 
   // Check that DynamicMessage handles map field serialization the same way as generated code
   // regarding unset key and value field in a map entry.
+  @Test
   public void testDynamicMessageUnsetKeyAndValue() throws Exception {
     FieldDescriptor field = f("int32_to_int32_field");
 
@@ -893,11 +920,12 @@
     Message message = builder.build();
     ByteString bytes = message.toByteString();
     // Parse it back to the same generated type.
-    Message generatedMessage = TestMap.parseFrom(bytes);
+    Message generatedMessage = TestMap.parseFrom(bytes, ExtensionRegistry.getEmptyRegistry());
     // Assert the serialized bytes are equivalent.
-    assertEquals(generatedMessage.toByteString(), bytes);
+    assertThat(bytes).isEqualTo(generatedMessage.toByteString());
   }
 
+  @Test
   public void testReflectionEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
@@ -918,17 +946,18 @@
     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4));
     Message m2 = b2.build();
 
-    assertEquals(m1, m2);
-    assertEquals(m1.hashCode(), m2.hashCode());
+    assertThat(m2).isEqualTo(m1);
+    assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
 
     // Make sure we did compare map fields.
     b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0));
     m2 = b2.build();
-    assertFalse(m1.equals(m2));
+    assertThat(m1).isNotEqualTo(m2);
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
   }
 
+  @Test
   public void testUnknownEnumValues() throws Exception {
     TestMap.Builder builder =
         TestMap.newBuilder()
@@ -939,32 +968,33 @@
                     2, 1000)); // unknown value.
     TestMap message = builder.build();
 
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(0));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
-    assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumFieldMap().get(2));
-    assertEquals(1000, message.getInt32ToEnumFieldValueMap().get(2).intValue());
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(0, TestMap.EnumValue.FOO);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
+    assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.UNRECOGNIZED);
+    assertThat(message.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
 
     // Unknown enum values should be preserved after:
     //   1. Serialization and parsing.
     //   2. toBuild().
     //   3. mergeFrom().
-    message = TestMap.parseFrom(message.toByteString());
-    assertEquals(1000, message.getInt32ToEnumFieldValueMap().get(2).intValue());
+    message = TestMap.parseFrom(message.toByteString(), ExtensionRegistry.getEmptyRegistry());
+    assertThat(message.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
     builder = message.toBuilder();
-    assertEquals(1000, builder.getInt32ToEnumFieldValueMap().get(2).intValue());
+    assertThat(builder.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
     builder = TestMap.newBuilder().mergeFrom(message);
-    assertEquals(1000, builder.getInt32ToEnumFieldValueMap().get(2).intValue());
+    assertThat(builder.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
 
     // hashCode()/equals() should take unknown enum values into account.
     builder.putAllInt32ToEnumFieldValue(newMap(2, 1001));
     TestMap message2 = builder.build();
-    assertFalse(message.hashCode() == message2.hashCode());
-    assertFalse(message.equals(message2));
+    assertThat(message.hashCode()).isNotEqualTo(message2.hashCode());
+    assertThat(message.equals(message2)).isFalse();
     // Unknown values will be converted to UNRECOGNIZED so the resulted enum map
     // should be the same.
-    assertEquals(message2.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
+    assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message2.getInt32ToEnumFieldMap());
   }
 
+  @Test
   public void testUnknownEnumValuesInReflectionApi() throws Exception {
     Descriptor descriptor = TestMap.getDescriptor();
     EnumDescriptor enumDescriptor = TestMap.EnumValue.getDescriptor();
@@ -983,7 +1013,7 @@
       Message mapEntry = (Message) builder.getRepeatedField(field, i);
       int key = ((Integer) getFieldValue(mapEntry, "key")).intValue();
       int value = ((EnumValueDescriptor) getFieldValue(mapEntry, "value")).getNumber();
-      assertEquals(data.get(key).intValue(), value);
+      assertThat(value).isEqualTo(data.get(key).intValue());
       Message.Builder mapEntryBuilder = mapEntry.toBuilder();
       // Increase the value by 1.
       setFieldValue(
@@ -994,30 +1024,35 @@
     // Verify that enum values have been successfully updated.
     TestMap message = builder.build();
     for (Map.Entry<Integer, Integer> entry : message.getInt32ToEnumFieldValueMap().entrySet()) {
-      assertEquals(data.get(entry.getKey()) + 1, entry.getValue().intValue());
+      assertThat(entry.getValue().intValue()).isEqualTo(data.get(entry.getKey()) + 1);
     }
   }
 
+  @Test
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
-    assertEquals(
-        Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32FieldMap().keySet()));
+    assertThat(new ArrayList<>(message.getStringToInt32FieldMap().keySet()))
+        .containsExactly("1", "2", "3")
+        .inOrder();
   }
 
+  @Test
   public void testGetMap() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
-    assertEquals(message.getStringToInt32FieldMap(), message.getStringToInt32FieldMap());
-    assertEquals(message.getInt32ToBytesFieldMap(), message.getInt32ToBytesFieldMap());
-    assertEquals(message.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
-    assertEquals(message.getInt32ToEnumFieldValueMap(), message.getInt32ToEnumFieldValueMap());
-    assertEquals(message.getInt32ToMessageFieldMap(), message.getInt32ToMessageFieldMap());
+    assertThat(message.getStringToInt32FieldMap()).isEqualTo(message.getStringToInt32FieldMap());
+    assertThat(message.getInt32ToBytesFieldMap()).isEqualTo(message.getInt32ToBytesFieldMap());
+    assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message.getInt32ToEnumFieldMap());
+    assertThat(message.getInt32ToEnumFieldValueMap())
+        .isEqualTo(message.getInt32ToEnumFieldValueMap());
+    assertThat(message.getInt32ToMessageFieldMap()).isEqualTo(message.getInt32ToMessageFieldMap());
   }
 
+  @Test
   public void testContains() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
@@ -1026,37 +1061,38 @@
   }
 
   private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
-    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
-    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToInt32Field(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToStringField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToStringField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToBytesField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToEnumField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
-    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
-    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(1)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(2)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(3)).isTrue();
+    assertThat(testMapOrBuilder.containsInt32ToMessageField(-1)).isFalse();
 
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
-    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
-    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+    assertThat(testMapOrBuilder.containsStringToInt32Field("1")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("2")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("3")).isTrue();
+    assertThat(testMapOrBuilder.containsStringToInt32Field("-1")).isFalse();
   }
 
+  @Test
   public void testCount() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -1068,23 +1104,24 @@
     assertMapCounts(3, message);
 
     builder = message.toBuilder().putInt32ToInt32Field(4, 44);
-    assertEquals(4, builder.getInt32ToInt32FieldCount());
-    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+    assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
+    assertThat(builder.build().getInt32ToInt32FieldCount()).isEqualTo(4);
 
     // already present - should be unchanged
     builder.putInt32ToInt32Field(4, 44);
-    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
   }
 
   private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToInt32FieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToStringFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToBytesFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToEnumFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getInt32ToMessageFieldCount());
-    assertEquals(expectedCount, testMapOrBuilder.getStringToInt32FieldCount());
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(expectedCount);
+    assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(expectedCount);
   }
 
+  @Test
   public void testGetOrDefault() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -1094,39 +1131,42 @@
   }
 
   public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
-    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)).isEqualTo(11);
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)).isEqualTo(-11);
 
-    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
-    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")).isEqualTo("11");
+    assertWithMessage("-11")
+        .that(testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null))
+        .isNull();
 
-    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null))
+        .isEqualTo(TestUtil.toBytes("11"));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null))
+        .isEqualTo(TestMap.EnumValue.FOO);
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(
-        TestMap.EnumValue.BAR.getNumber(),
-        testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1));
-    assertEquals(-1, testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1))
+        .isEqualTo(TestMap.EnumValue.BAR.getNumber());
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1)).isEqualTo(-1);
 
-    assertEquals(
-        MessageValue.newBuilder().setValue(11).build(),
-        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
-    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null))
+        .isEqualTo(MessageValue.newBuilder().setValue(11).build());
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)).isNull();
 
-    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
-    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)).isEqualTo(11);
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)).isEqualTo(-11);
 
     try {
       testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
+  @Test
   public void testGetOrThrow() {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
@@ -1136,115 +1176,116 @@
   }
 
   public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
-    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
     try {
       testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
 
     try {
       testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
 
     try {
       testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     try {
       testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(
-        TestMap.EnumValue.BAR.getNumber(), testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2));
+    assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2))
+        .isEqualTo(TestMap.EnumValue.BAR.getNumber());
     try {
       testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(
-        MessageValue.newBuilder().setValue(11).build(),
-        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    assertThat(testMapOrBuilder.getInt32ToMessageFieldOrThrow(1))
+        .isEqualTo(MessageValue.newBuilder().setValue(11).build());
     try {
       testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
-    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    assertThat(testMapOrBuilder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
     try {
       testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IllegalArgumentException e) {
       // expected
     }
 
     try {
       testMapOrBuilder.getStringToInt32FieldOrThrow(null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
+  @Test
   public void testPut() {
     TestMap.Builder builder = TestMap.newBuilder();
     builder.putInt32ToInt32Field(1, 11);
-    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
 
     builder.putInt32ToStringField(1, "a");
-    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("a");
     try {
       builder.putInt32ToStringField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
-    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
     try {
       builder.putInt32ToBytesField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
-    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     try {
       builder.putInt32ToEnumField(1, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
 
     builder.putInt32ToEnumFieldValue(1, TestMap.EnumValue.BAR.getNumber());
-    assertEquals(TestMap.EnumValue.BAR.getNumber(), builder.getInt32ToEnumFieldValueOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldValueOrThrow(1))
+        .isEqualTo(TestMap.EnumValue.BAR.getNumber());
     builder.putInt32ToEnumFieldValue(1, -1);
-    assertEquals(-1, builder.getInt32ToEnumFieldValueOrThrow(1));
-    assertEquals(TestMap.EnumValue.UNRECOGNIZED, builder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldValueOrThrow(1)).isEqualTo(-1);
+    assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.UNRECOGNIZED);
 
     builder.putStringToInt32Field("a", 1);
-    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    assertThat(builder.getStringToInt32FieldOrThrow("a")).isEqualTo(1);
     try {
       builder.putStringToInt32Field(null, -1);
     } catch (NullPointerException e) {
@@ -1252,53 +1293,56 @@
     }
   }
 
+  @Test
   public void testRemove() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
-    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToInt32Field(1);
-      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+      assertThat(builder.getInt32ToInt32FieldOrDefault(1, -1)).isEqualTo(-1);
     }
 
-    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToStringField(1);
-      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToStringFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToBytesField(1);
-      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToBytesFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToEnumField(1);
-      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+      assertThat(builder.getInt32ToEnumFieldOrDefault(1, null)).isNull();
     }
 
-    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    assertThat(builder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
     for (int times = 0; times < 2; times++) {
       builder.removeStringToInt32Field("1");
-      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+      assertThat(builder.getStringToInt32FieldOrDefault("1", -1)).isEqualTo(-1);
     }
 
     try {
       builder.removeStringToInt32Field(null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected
     }
   }
 
+  @Test
   public void testReservedWordsFieldNames() {
-    ReservedAsMapField unused1 = ReservedAsMapField.newBuilder().build();
-    ReservedAsMapFieldWithEnumValue unused2 = ReservedAsMapFieldWithEnumValue.newBuilder().build();
+    ReservedAsMapField unused1 = ReservedAsMapField.getDefaultInstance();
+    ReservedAsMapFieldWithEnumValue unused2 = ReservedAsMapFieldWithEnumValue.getDefaultInstance();
   }
 
-  public void testDeterministicSerialziation() throws Exception {
+  @Test
+  public void testDeterministicSerialization() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     // int32->int32
     builder.putInt32ToInt32Field(5, 1);
@@ -1363,16 +1407,17 @@
           int64Keys.add(readMapLongKey(input));
           break;
         default:
-          fail("Unexpected fields.");
+          assertWithMessage("Unexpected fields.").fail();
       }
       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);
+    assertThat(int32Keys).containsExactly(-2, 0, 1, 4, 5).inOrder();
+    assertThat(uint32Keys).containsExactly(-2, 0, 1, 4, 5).inOrder();
+    assertThat(int64Keys).containsExactly(-2L, 0L, 1L, 4L, 5L).inOrder();
+    assertThat(stringKeys).containsExactly("", "bar", "baz", "foo", "hello", "world").inOrder();
   }
 
+  @Test
   public void testInitFromPartialDynamicMessage() {
     FieldDescriptor fieldDescriptor =
         TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER);
@@ -1389,11 +1434,11 @@
                     .build())
             .build();
     TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build();
-    assertEquals(
-        TestMap.MessageValue.newBuilder().setValue(10).build(),
-        message.getInt32ToMessageFieldMap().get(10));
+    assertThat(message.getInt32ToMessageFieldMap())
+        .containsEntry(10, TestMap.MessageValue.newBuilder().setValue(10).build());
   }
 
+  @Test
   public void testInitFromFullyDynamicMessage() {
     FieldDescriptor fieldDescriptor =
         TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER);
@@ -1415,38 +1460,37 @@
                     .build())
             .build();
     TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build();
-    assertEquals(
-        TestMap.MessageValue.newBuilder().setValue(10).build(),
-        message.getInt32ToMessageFieldMap().get(10));
+    assertThat(message.getInt32ToMessageFieldMap())
+        .containsEntry(10, TestMap.MessageValue.newBuilder().setValue(10).build());
   }
 
   private int readMapIntegerKey(CodedInputStream input) throws IOException {
     int tag = input.readTag();
-    assertEquals(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT), tag);
+    assertThat(tag).isEqualTo(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
     int ret = input.readInt32();
     // skip the value field.
     input.skipField(input.readTag());
-    assertTrue(input.isAtEnd());
+    assertThat(input.isAtEnd()).isTrue();
     return ret;
   }
 
   private long readMapLongKey(CodedInputStream input) throws IOException {
     int tag = input.readTag();
-    assertEquals(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT), tag);
+    assertThat(tag).isEqualTo(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
     long ret = input.readInt64();
     // skip the value field.
     input.skipField(input.readTag());
-    assertTrue(input.isAtEnd());
+    assertThat(input.isAtEnd()).isTrue();
     return ret;
   }
 
   private String readMapStringKey(CodedInputStream input) throws IOException {
     int tag = input.readTag();
-    assertEquals(WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED), tag);
+    assertThat(tag).isEqualTo(WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED));
     String ret = input.readString();
     // skip the value field.
     input.skipField(input.readTag());
-    assertTrue(input.isAtEnd());
+    assertThat(input.isAtEnd()).isTrue();
     return ret;
   }
 
@@ -1471,39 +1515,40 @@
     return map;
   }
 
+  @Test
   public void testMap_withNulls() {
     TestMap.Builder builder = TestMap.newBuilder();
 
     try {
       builder.putStringToInt32Field(null, 3);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
     try {
       builder.putAllStringToInt32Field(newMap(null, 3, "hi", 4));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
     try {
       builder.putInt32ToMessageField(3, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
     try {
       builder.putAllInt32ToMessageField(MapTest.<Integer, MessageValue>newMap(4, null, 5, null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
     try {
       builder.putAllInt32ToMessageField(null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
 
-    assertArrayEquals(new byte[0], builder.build().toByteArray());
+    assertThat(builder.build().toByteArray()).isEqualTo(new byte[0]);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/MessageTest.java b/java/core/src/test/java/com/google/protobuf/MessageTest.java
index 760511b..9c34161 100644
--- a/java/core/src/test/java/com/google/protobuf/MessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MessageTest.java
@@ -30,20 +30,22 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import protobuf_unittest.UnittestProto.ForeignMessage;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto.TestRequiredForeign;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Misc. unit tests for message operations that apply to both generated and dynamic messages.
- *
- * @author [email protected] Kenton Varda
- */
-public class MessageTest extends TestCase {
+/** Misc. unit tests for message operations that apply to both generated and dynamic messages. */
+@RunWith(JUnit4.class)
+public class MessageTest {
   // =================================================================
   // Message-merging tests.
 
@@ -74,41 +76,45 @@
           + "repeated_string: \"qux\"\n"
           + "repeated_string: \"bar\"\n";
 
+  @Test
   public void testParsingWithNullExtensionRegistry() throws Exception {
     try {
       TestAllTypes.parseFrom(new byte[] {}, null);
-      fail();
+      assertWithMessage("Expected exception").fail();
     } catch (NullPointerException expected) {
     }
   }
 
+  @Test
   public void testMergeFrom() throws Exception {
     TestAllTypes result = TestAllTypes.newBuilder(MERGE_DEST).mergeFrom(MERGE_SOURCE).build();
 
-    assertEquals(MERGE_RESULT_TEXT, result.toString());
+    assertThat(result.toString()).isEqualTo(MERGE_RESULT_TEXT);
   }
 
   /**
    * Test merging a DynamicMessage into a GeneratedMessage. As long as they have the same
    * descriptor, this should work, but it is an entirely different code path.
    */
+  @Test
   public void testMergeFromDynamic() throws Exception {
     TestAllTypes result =
         TestAllTypes.newBuilder(MERGE_DEST)
             .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
             .build();
 
-    assertEquals(MERGE_RESULT_TEXT, result.toString());
+    assertThat(result.toString()).isEqualTo(MERGE_RESULT_TEXT);
   }
 
   /** Test merging two DynamicMessages. */
+  @Test
   public void testDynamicMergeFrom() throws Exception {
     DynamicMessage result =
         DynamicMessage.newBuilder(MERGE_DEST)
             .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
             .build();
 
-    assertEquals(MERGE_RESULT_TEXT, result.toString());
+    assertThat(result.toString()).isEqualTo(MERGE_RESULT_TEXT);
   }
 
   // =================================================================
@@ -118,103 +124,111 @@
   private static final TestRequired TEST_REQUIRED_INITIALIZED =
       TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
 
+  @Test
   public void testRequired() throws Exception {
     TestRequired.Builder builder = TestRequired.newBuilder();
 
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
     builder.setA(1);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
     builder.setB(1);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
     builder.setC(1);
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
   }
 
+  @Test
   public void testRequiredForeign() throws Exception {
     TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
 
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
 
     builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
 
     builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
 
     builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
 
     builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
   }
 
+  @Test
   public void testRequiredExtension() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
 
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
 
     builder.setExtension(TestRequired.single, TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
 
     builder.setExtension(TestRequired.single, TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
 
     builder.addExtension(TestRequired.multi, TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
 
     builder.setExtension(TestRequired.multi, 0, TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
   }
 
+  @Test
   public void testRequiredDynamic() throws Exception {
     Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
     DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
 
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
     builder.setField(descriptor.findFieldByName("a"), 1);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
     builder.setField(descriptor.findFieldByName("b"), 1);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
     builder.setField(descriptor.findFieldByName("c"), 1);
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
   }
 
+  @Test
   public void testRequiredDynamicForeign() throws Exception {
     Descriptors.Descriptor descriptor = TestRequiredForeign.getDescriptor();
     DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
 
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
 
     builder.setField(descriptor.findFieldByName("optional_message"), TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
 
     builder.setField(descriptor.findFieldByName("optional_message"), TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
 
     builder.addRepeatedField(
         descriptor.findFieldByName("repeated_message"), TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
+    assertThat(builder.isInitialized()).isFalse();
 
     builder.setRepeatedField(
         descriptor.findFieldByName("repeated_message"), 0, TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
+    assertThat(builder.isInitialized()).isTrue();
   }
 
+  @Test
   public void testUninitializedException() throws Exception {
     try {
       TestRequired.newBuilder().build();
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (UninitializedMessageException e) {
-      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: a, b, c");
     }
   }
 
+  @Test
   public void testBuildPartial() throws Exception {
     // We're mostly testing that no exception is thrown.
     TestRequired message = TestRequired.newBuilder().buildPartial();
-    assertFalse(message.isInitialized());
+    assertThat(message.isInitialized()).isFalse();
   }
 
+  @Test
   public void testNestedUninitializedException() throws Exception {
     try {
       TestRequiredForeign.newBuilder()
@@ -222,23 +236,25 @@
           .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
           .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
           .build();
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (UninitializedMessageException e) {
-      assertEquals(
-          "Message missing required fields: "
-              + "optional_message.a, "
-              + "optional_message.b, "
-              + "optional_message.c, "
-              + "repeated_message[0].a, "
-              + "repeated_message[0].b, "
-              + "repeated_message[0].c, "
-              + "repeated_message[1].a, "
-              + "repeated_message[1].b, "
-              + "repeated_message[1].c",
-          e.getMessage());
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo(
+              "Message missing required fields: "
+                  + "optional_message.a, "
+                  + "optional_message.b, "
+                  + "optional_message.c, "
+                  + "repeated_message[0].a, "
+                  + "repeated_message[0].b, "
+                  + "repeated_message[0].c, "
+                  + "repeated_message[1].a, "
+                  + "repeated_message[1].b, "
+                  + "repeated_message[1].c");
     }
   }
 
+  @Test
   public void testBuildNestedPartial() throws Exception {
     // We're mostly testing that no exception is thrown.
     TestRequiredForeign message =
@@ -247,18 +263,20 @@
             .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
             .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
             .buildPartial();
-    assertFalse(message.isInitialized());
+    assertThat(message.isInitialized()).isFalse();
   }
 
+  @Test
   public void testParseUnititialized() throws Exception {
     try {
       TestRequired.parseFrom(ByteString.EMPTY);
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (InvalidProtocolBufferException e) {
-      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: a, b, c");
     }
   }
 
+  @Test
   public void testParseNestedUnititialized() throws Exception {
     ByteString data =
         TestRequiredForeign.newBuilder()
@@ -270,49 +288,54 @@
 
     try {
       TestRequiredForeign.parseFrom(data);
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (InvalidProtocolBufferException e) {
-      assertEquals(
-          "Message missing required fields: "
-              + "optional_message.a, "
-              + "optional_message.b, "
-              + "optional_message.c, "
-              + "repeated_message[0].a, "
-              + "repeated_message[0].b, "
-              + "repeated_message[0].c, "
-              + "repeated_message[1].a, "
-              + "repeated_message[1].b, "
-              + "repeated_message[1].c",
-          e.getMessage());
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo(
+              "Message missing required fields: "
+                  + "optional_message.a, "
+                  + "optional_message.b, "
+                  + "optional_message.c, "
+                  + "repeated_message[0].a, "
+                  + "repeated_message[0].b, "
+                  + "repeated_message[0].c, "
+                  + "repeated_message[1].a, "
+                  + "repeated_message[1].b, "
+                  + "repeated_message[1].c");
     }
   }
 
+  @Test
   public void testDynamicUninitializedException() throws Exception {
     try {
       DynamicMessage.newBuilder(TestRequired.getDescriptor()).build();
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (UninitializedMessageException e) {
-      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: a, b, c");
     }
   }
 
+  @Test
   public void testDynamicBuildPartial() throws Exception {
     // We're mostly testing that no exception is thrown.
     DynamicMessage message = DynamicMessage.newBuilder(TestRequired.getDescriptor()).buildPartial();
-    assertFalse(message.isInitialized());
+    assertThat(message.isInitialized()).isFalse();
   }
 
+  @Test
   public void testDynamicParseUnititialized() throws Exception {
     try {
       Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
       DynamicMessage.parseFrom(descriptor, ByteString.EMPTY);
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (InvalidProtocolBufferException e) {
-      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: a, b, c");
     }
   }
 
   /** Test reading unset repeated message from DynamicMessage. */
+  @Test
   public void testDynamicRepeatedMessageNull() throws Exception {
     TestRequired.getDescriptor();
     DynamicMessage result =
@@ -320,16 +343,18 @@
             .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
             .build();
 
-    assertTrue(
-        result.getField(result.getDescriptorForType().findFieldByName("repeated_foreign_message"))
-            instanceof List<?>);
-    assertEquals(
-        0,
-        result.getRepeatedFieldCount(
-            result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
+    assertThat(
+            result.getField(
+                result.getDescriptorForType().findFieldByName("repeated_foreign_message")))
+        .isInstanceOf(List.class);
+    assertThat(
+            result.getRepeatedFieldCount(
+                result.getDescriptorForType().findFieldByName("repeated_foreign_message")))
+        .isEqualTo(0);
   }
 
   /** Test reading repeated message from DynamicMessage. */
+  @Test
   public void testDynamicRepeatedMessageNotNull() throws Exception {
     TestAllTypes repeatedNested =
         TestAllTypes.newBuilder()
@@ -346,12 +371,13 @@
             .mergeFrom(DynamicMessage.newBuilder(repeatedNested).build())
             .build();
 
-    assertTrue(
-        result.getField(result.getDescriptorForType().findFieldByName("repeated_foreign_message"))
-            instanceof List<?>);
-    assertEquals(
-        2,
-        result.getRepeatedFieldCount(
-            result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
+    assertThat(
+            result.getField(
+                result.getDescriptorForType().findFieldByName("repeated_foreign_message")))
+        .isInstanceOf(List.class);
+    assertThat(
+            result.getRepeatedFieldCount(
+                result.getDescriptorForType().findFieldByName("repeated_foreign_message")))
+        .isEqualTo(2);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
index 1af3f93..961c0b5 100644
--- a/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
+++ b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
@@ -30,21 +30,25 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import protobuf_unittest.Engine;
 import protobuf_unittest.Vehicle;
 import protobuf_unittest.Wheel;
 import java.util.ArrayList;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Test cases that exercise end-to-end use cases involving {@link SingleFieldBuilder} and {@link
  * RepeatedFieldBuilder}.
- *
- * @author [email protected] (Jon Perlow)
  */
-public class NestedBuildersTest extends TestCase {
+@RunWith(JUnit4.class)
+public class NestedBuildersTest {
 
+  @Test
   public void testMessagesAndBuilders() {
     Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
     vehicleBuilder.addWheelBuilder().setRadius(4).setWidth(1);
@@ -54,13 +58,13 @@
     vehicleBuilder.getEngineBuilder().setLiters(10);
 
     Vehicle vehicle = vehicleBuilder.build();
-    assertEquals(4, vehicle.getWheelCount());
+    assertThat(vehicle.getWheelCount()).isEqualTo(4);
     for (int i = 0; i < 4; i++) {
       Wheel wheel = vehicle.getWheel(i);
-      assertEquals(4, wheel.getRadius());
-      assertEquals(i + 1, wheel.getWidth());
+      assertThat(wheel.getRadius()).isEqualTo(4);
+      assertThat(wheel.getWidth()).isEqualTo(i + 1);
     }
-    assertEquals(10, vehicle.getEngine().getLiters());
+    assertThat(vehicle.getEngine().getLiters()).isEqualTo(10);
 
     for (int i = 0; i < 4; i++) {
       vehicleBuilder.getWheelBuilder(i).setRadius(5).setWidth(i + 10);
@@ -70,16 +74,17 @@
     vehicle = vehicleBuilder.build();
     for (int i = 0; i < 4; i++) {
       Wheel wheel = vehicle.getWheel(i);
-      assertEquals(5, wheel.getRadius());
-      assertEquals(i + 10, wheel.getWidth());
+      assertThat(wheel.getRadius()).isEqualTo(5);
+      assertThat(wheel.getWidth()).isEqualTo(i + 10);
     }
-    assertEquals(20, vehicle.getEngine().getLiters());
-    assertTrue(vehicle.hasEngine());
+    assertThat(vehicle.getEngine().getLiters()).isEqualTo(20);
+    assertThat(vehicle.hasEngine()).isTrue();
 
     engineBuilder.setLiters(50);
-    assertEquals(50, vehicleBuilder.getEngine().getLiters());
+    assertThat(vehicleBuilder.getEngine().getLiters()).isEqualTo(50);
   }
 
+  @Test
   public void testMessagesAreCached() {
     Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
     vehicleBuilder.addWheelBuilder().setRadius(1).setWidth(2);
@@ -90,7 +95,7 @@
     // Make sure messages are cached.
     List<Wheel> wheels = new ArrayList<Wheel>(vehicleBuilder.getWheelList());
     for (int i = 0; i < wheels.size(); i++) {
-      assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
+      assertThat(wheels.get(i)).isSameInstanceAs(vehicleBuilder.getWheel(i));
     }
 
     // Now get builders and check they didn't change.
@@ -98,7 +103,7 @@
       vehicleBuilder.getWheel(i);
     }
     for (int i = 0; i < wheels.size(); i++) {
-      assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
+      assertThat(wheels.get(i)).isSameInstanceAs(vehicleBuilder.getWheel(i));
     }
 
     // Change just one
@@ -107,33 +112,36 @@
     // Now get wheels and check that only that one changed
     for (int i = 0; i < wheels.size(); i++) {
       if (i < 3) {
-        assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
+        assertThat(wheels.get(i)).isSameInstanceAs(vehicleBuilder.getWheel(i));
       } else {
-        assertNotSame(wheels.get(i), vehicleBuilder.getWheel(i));
+        assertThat(wheels.get(i)).isNotSameInstanceAs(vehicleBuilder.getWheel(i));
       }
     }
   }
 
+  @Test
   public void testRemove_WithNestedBuilders() {
     Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
     vehicleBuilder.addWheelBuilder().setRadius(1).setWidth(1);
     vehicleBuilder.addWheelBuilder().setRadius(2).setWidth(2);
     vehicleBuilder.removeWheel(0);
 
-    assertEquals(1, vehicleBuilder.getWheelCount());
-    assertEquals(2, vehicleBuilder.getWheel(0).getRadius());
+    assertThat(vehicleBuilder.getWheelCount()).isEqualTo(1);
+    assertThat(vehicleBuilder.getWheel(0).getRadius()).isEqualTo(2);
   }
 
+  @Test
   public void testRemove_WithNestedMessages() {
     Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
     vehicleBuilder.addWheel(Wheel.newBuilder().setRadius(1).setWidth(1));
     vehicleBuilder.addWheel(Wheel.newBuilder().setRadius(2).setWidth(2));
     vehicleBuilder.removeWheel(0);
 
-    assertEquals(1, vehicleBuilder.getWheelCount());
-    assertEquals(2, vehicleBuilder.getWheel(0).getRadius());
+    assertThat(vehicleBuilder.getWheelCount()).isEqualTo(1);
+    assertThat(vehicleBuilder.getWheel(0).getRadius()).isEqualTo(2);
   }
 
+  @Test
   public void testMerge() {
     Vehicle vehicle1 =
         Vehicle.newBuilder()
@@ -143,16 +151,17 @@
 
     Vehicle vehicle2 = Vehicle.newBuilder().mergeFrom(vehicle1).build();
     // List should be the same -- no allocation
-    assertSame(vehicle1.getWheelList(), vehicle2.getWheelList());
+    assertThat(vehicle1.getWheelList()).isSameInstanceAs(vehicle2.getWheelList());
 
     Vehicle vehicle3 = vehicle1.toBuilder().build();
-    assertSame(vehicle1.getWheelList(), vehicle3.getWheelList());
+    assertThat(vehicle1.getWheelList()).isSameInstanceAs(vehicle3.getWheelList());
   }
 
+  @Test
   public void testGettingBuilderMarksFieldAsHaving() {
     Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
     vehicleBuilder.getEngineBuilder();
     Vehicle vehicle = vehicleBuilder.buildPartial();
-    assertTrue(vehicle.hasEngine());
+    assertThat(vehicle.hasEngine()).isTrue();
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
index 489bb7c..1f14271 100644
--- a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static com.google.protobuf.Internal.UTF_8;
 
 import java.io.ByteArrayInputStream;
@@ -46,10 +48,13 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Tests for {@link NioByteString}. */
-public class NioByteStringTest extends TestCase {
+@RunWith(JUnit4.class)
+public class NioByteStringTest {
   private static final ByteString EMPTY = new NioByteString(ByteBuffer.wrap(new byte[0]));
   private static final String CLASSNAME = NioByteString.class.getSimpleName();
   private static final byte[] BYTES = ByteStringTest.getTestBytes(1234, 11337766L);
@@ -58,9 +63,12 @@
   private final ByteBuffer backingBuffer = ByteBuffer.wrap(BYTES.clone());
   private final ByteString testString = new NioByteString(backingBuffer);
 
+  @Test
   public void testExpectedType() {
     String actualClassName = getActualClassName(testString);
-    assertEquals(CLASSNAME + " should match type exactly", CLASSNAME, actualClassName);
+    assertWithMessage("%s should match type exactly", CLASSNAME)
+        .that(CLASSNAME)
+        .isEqualTo(actualClassName);
   }
 
   protected String getActualClassName(Object object) {
@@ -69,31 +77,36 @@
     return actualClassName;
   }
 
+  @Test
   public void testByteAt() {
     boolean stillEqual = true;
     for (int i = 0; stillEqual && i < BYTES.length; ++i) {
       stillEqual = (BYTES[i] == testString.byteAt(i));
     }
-    assertTrue(CLASSNAME + " must capture the right bytes", stillEqual);
+    assertWithMessage("%s must capture the right bytes", CLASSNAME).that(stillEqual).isTrue();
   }
 
+  @Test
   public void testByteIterator() {
     boolean stillEqual = true;
     ByteString.ByteIterator iter = testString.iterator();
     for (int i = 0; stillEqual && i < BYTES.length; ++i) {
       stillEqual = (iter.hasNext() && BYTES[i] == iter.nextByte());
     }
-    assertTrue(CLASSNAME + " must capture the right bytes", stillEqual);
-    assertFalse(CLASSNAME + " must have exhausted the iterator", iter.hasNext());
+    assertWithMessage("%s must capture the right bytes", CLASSNAME).that(stillEqual).isTrue();
+    assertWithMessage("%s must have exhausted the iterator", CLASSNAME)
+        .that(iter.hasNext())
+        .isFalse();
 
     try {
       iter.nextByte();
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NoSuchElementException e) {
       // This is success
     }
   }
 
+  @Test
   public void testByteIterable() {
     boolean stillEqual = true;
     int j = 0;
@@ -101,22 +114,34 @@
       stillEqual = (BYTES[j] == quantum);
       ++j;
     }
-    assertTrue(CLASSNAME + " must capture the right bytes as Bytes", stillEqual);
-    assertEquals(CLASSNAME + " iterable character count", BYTES.length, j);
+    assertWithMessage("%s must capture the right bytes as Bytes", CLASSNAME)
+        .that(stillEqual)
+        .isTrue();
+    assertWithMessage("%s iterable character count", CLASSNAME).that(BYTES).hasLength(j);
   }
 
+  @Test
   public void testSize() {
-    assertEquals(CLASSNAME + " must have the expected size", BYTES.length, testString.size());
+    assertWithMessage("%s must have the expected size", CLASSNAME)
+        .that(BYTES)
+        .hasLength(testString.size());
   }
 
+  @Test
   public void testGetTreeDepth() {
-    assertEquals(CLASSNAME + " must have depth 0", 0, testString.getTreeDepth());
+    assertWithMessage("%s must have depth 0", CLASSNAME)
+        .that(testString.getTreeDepth())
+        .isEqualTo(0);
   }
 
+  @Test
   public void testIsBalanced() {
-    assertTrue(CLASSNAME + " is technically balanced", testString.isBalanced());
+    assertWithMessage("%s is technically balanced", CLASSNAME)
+        .that(testString.isBalanced())
+        .isTrue();
   }
 
+  @Test
   public void testCopyTo_ByteArrayOffsetLength() {
     int destinationOffset = 50;
     int length = 100;
@@ -127,9 +152,12 @@
     for (int i = 0; stillEqual && i < length; ++i) {
       stillEqual = BYTES[i + sourceOffset] == destination[i + destinationOffset];
     }
-    assertTrue(CLASSNAME + ".copyTo(4 arg) must give the expected bytes", stillEqual);
+    assertWithMessage("%s.copyTo(4 arg) must give the expected bytes", CLASSNAME)
+        .that(stillEqual)
+        .isTrue();
   }
 
+  @Test
   public void testCopyTo_ByteArrayOffsetLengthErrors() {
     int destinationOffset = 50;
     int length = 100;
@@ -138,7 +166,9 @@
     try {
       // Copy one too many bytes
       testString.copyTo(destination, testString.size() + 1 - length, destinationOffset, length);
-      fail("Should have thrown an exception when copying too many bytes of a " + CLASSNAME);
+      assertWithMessage(
+              "Should have thrown an exception when copying too many bytes of a %s", CLASSNAME)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -146,7 +176,10 @@
     try {
       // Copy with illegal negative sourceOffset
       testString.copyTo(destination, -1, destinationOffset, length);
-      fail("Should have thrown an exception when given a negative sourceOffset in " + CLASSNAME);
+      assertWithMessage(
+              "Should have thrown an exception when given a negative sourceOffset in %s ",
+              CLASSNAME)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -154,9 +187,10 @@
     try {
       // Copy with illegal negative destinationOffset
       testString.copyTo(destination, 0, -1, length);
-      fail(
-          "Should have thrown an exception when given a negative destinationOffset in "
-              + CLASSNAME);
+      assertWithMessage(
+              "Should have thrown an exception when given a negative destinationOffset in %s",
+              CLASSNAME)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -164,7 +198,9 @@
     try {
       // Copy with illegal negative size
       testString.copyTo(destination, 0, 0, -1);
-      fail("Should have thrown an exception when given a negative size in " + CLASSNAME);
+      assertWithMessage(
+              "Should have thrown an exception when given a negative size in %s", CLASSNAME)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -172,9 +208,10 @@
     try {
       // Copy with illegal too-large sourceOffset
       testString.copyTo(destination, 2 * testString.size(), 0, length);
-      fail(
-          "Should have thrown an exception when the destinationOffset is too large in "
-              + CLASSNAME);
+      assertWithMessage(
+              "Should have thrown an exception when the destinationOffset is too large in %s",
+              CLASSNAME)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
@@ -182,33 +219,38 @@
     try {
       // Copy with illegal too-large destinationOffset
       testString.copyTo(destination, 0, 2 * destination.length, length);
-      fail(
-          "Should have thrown an exception when the destinationOffset is too large in "
-              + CLASSNAME);
+      assertWithMessage(
+              "Should have thrown an exception when the destinationOffset is too large in %s",
+              CLASSNAME)
+          .fail();
     } catch (IndexOutOfBoundsException expected) {
       // This is success
     }
   }
 
+  @Test
   public void testCopyTo_ByteBuffer() {
     // Same length.
     ByteBuffer myBuffer = ByteBuffer.allocate(BYTES.length);
     testString.copyTo(myBuffer);
     myBuffer.flip();
-    assertEquals(
-        CLASSNAME + ".copyTo(ByteBuffer) must give back the same bytes", backingBuffer, myBuffer);
+    assertWithMessage("%s.copyTo(ByteBuffer) must give back the same bytes", CLASSNAME)
+        .that(backingBuffer)
+        .isEqualTo(myBuffer);
 
     // Target buffer bigger than required.
     myBuffer = ByteBuffer.allocate(testString.size() + 1);
     testString.copyTo(myBuffer);
     myBuffer.flip();
-    assertEquals(backingBuffer, myBuffer);
+    assertThat(backingBuffer).isEqualTo(myBuffer);
 
     // Target buffer has no space.
     myBuffer = ByteBuffer.allocate(0);
     try {
       testString.copyTo(myBuffer);
-      fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
+      assertWithMessage(
+              "Should have thrown an exception when target ByteBuffer has insufficient capacity")
+          .fail();
     } catch (BufferOverflowException e) {
       // Expected.
     }
@@ -217,17 +259,23 @@
     myBuffer = ByteBuffer.allocate(1);
     try {
       testString.copyTo(myBuffer);
-      fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
+      assertWithMessage(
+              "Should have thrown an exception when target ByteBuffer has insufficient capacity")
+          .fail();
     } catch (BufferOverflowException e) {
       // Expected.
     }
   }
 
+  @Test
   public void testMarkSupported() {
     InputStream stream = testString.newInput();
-    assertTrue(CLASSNAME + ".newInput() must support marking", stream.markSupported());
+    assertWithMessage("%s.newInput() must support marking", CLASSNAME)
+        .that(stream.markSupported())
+        .isTrue();
   }
 
+  @Test
   public void testMarkAndReset() throws IOException {
     int fraction = testString.size() / 3;
 
@@ -235,21 +283,18 @@
     stream.mark(testString.size()); // First, mark() the end.
 
     skipFully(stream, fraction); // Skip a large fraction, but not all.
-    assertEquals(
-        CLASSNAME + ": after skipping to the 'middle', half the bytes are available",
-        (testString.size() - fraction),
-        stream.available());
+    assertWithMessage("%s: after skipping to the 'middle', half the bytes are available", CLASSNAME)
+        .that((testString.size() - fraction))
+        .isEqualTo(stream.available());
     stream.reset();
-    assertEquals(
-        CLASSNAME + ": after resetting, all bytes are available",
-        testString.size(),
-        stream.available());
+    assertWithMessage("%s: after resetting, all bytes are available", CLASSNAME)
+        .that(testString.size())
+        .isEqualTo(stream.available());
 
     skipFully(stream, testString.size()); // Skip to the end.
-    assertEquals(
-        CLASSNAME + ": after skipping to the end, no more bytes are available",
-        0,
-        stream.available());
+    assertWithMessage("%s: after skipping to the end, no more bytes are available", CLASSNAME)
+        .that(stream.available())
+        .isEqualTo(0);
   }
 
   /**
@@ -285,50 +330,55 @@
     }
   }
 
+  @Test
   public void testAsReadOnlyByteBuffer() {
     ByteBuffer byteBuffer = testString.asReadOnlyByteBuffer();
     byte[] roundTripBytes = new byte[BYTES.length];
-    assertTrue(byteBuffer.remaining() == BYTES.length);
-    assertTrue(byteBuffer.isReadOnly());
+    assertThat(byteBuffer.remaining() == BYTES.length).isTrue();
+    assertThat(byteBuffer.isReadOnly()).isTrue();
     byteBuffer.get(roundTripBytes);
-    assertTrue(
-        CLASSNAME + ".asReadOnlyByteBuffer() must give back the same bytes",
-        Arrays.equals(BYTES, roundTripBytes));
+    assertWithMessage("%s.asReadOnlyByteBuffer() must give back the same bytes", CLASSNAME)
+        .that(Arrays.equals(BYTES, roundTripBytes))
+        .isTrue();
   }
 
+  @Test
   public void testAsReadOnlyByteBufferList() {
     List<ByteBuffer> byteBuffers = testString.asReadOnlyByteBufferList();
     int bytesSeen = 0;
     byte[] roundTripBytes = new byte[BYTES.length];
     for (ByteBuffer byteBuffer : byteBuffers) {
       int thisLength = byteBuffer.remaining();
-      assertTrue(byteBuffer.isReadOnly());
-      assertTrue(bytesSeen + thisLength <= BYTES.length);
+      assertThat(byteBuffer.isReadOnly()).isTrue();
+      assertThat(bytesSeen + thisLength <= BYTES.length).isTrue();
       byteBuffer.get(roundTripBytes, bytesSeen, thisLength);
       bytesSeen += thisLength;
     }
-    assertTrue(bytesSeen == BYTES.length);
-    assertTrue(
-        CLASSNAME + ".asReadOnlyByteBufferTest() must give back the same bytes",
-        Arrays.equals(BYTES, roundTripBytes));
+    assertThat(BYTES).hasLength(bytesSeen);
+    assertWithMessage("%s.asReadOnlyByteBufferTest() must give back the same bytes", CLASSNAME)
+        .that(Arrays.equals(BYTES, roundTripBytes))
+        .isTrue();
   }
 
+  @Test
   public void testToByteArray() {
     byte[] roundTripBytes = testString.toByteArray();
-    assertTrue(
-        CLASSNAME + ".toByteArray() must give back the same bytes",
-        Arrays.equals(BYTES, roundTripBytes));
+    assertWithMessage("%s.toByteArray() must give back the same bytes", CLASSNAME)
+        .that(Arrays.equals(BYTES, roundTripBytes))
+        .isTrue();
   }
 
+  @Test
   public void testWriteTo() throws IOException {
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
     testString.writeTo(bos);
     byte[] roundTripBytes = bos.toByteArray();
-    assertTrue(
-        CLASSNAME + ".writeTo() must give back the same bytes",
-        Arrays.equals(BYTES, roundTripBytes));
+    assertWithMessage("%s.writeTo() must give back the same bytes", CLASSNAME)
+        .that(Arrays.equals(BYTES, roundTripBytes))
+        .isTrue();
   }
 
+  @Test
   public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException {
     OutputStream os =
         new OutputStream() {
@@ -345,11 +395,12 @@
 
     byte[] original = Arrays.copyOf(BYTES, BYTES.length);
     testString.writeTo(os);
-    assertTrue(
-        CLASSNAME + ".writeTo() must NOT grant access to underlying buffer",
-        Arrays.equals(original, BYTES));
+    assertWithMessage("%s.writeTo() must NOT grant access to underlying buffer", CLASSNAME)
+        .that(Arrays.equals(original, BYTES))
+        .isTrue();
   }
 
+  @Test
   public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException {
     OutputStream os =
         new OutputStream() {
@@ -366,11 +417,12 @@
 
     testString.writeToInternal(os, 0, testString.size());
     byte[] allZeros = new byte[testString.size()];
-    assertTrue(
-        CLASSNAME + ".writeToInternal() must grant access to underlying buffer",
-        Arrays.equals(allZeros, backingBuffer.array()));
+    assertWithMessage("%s.writeToInternal() must grant access to underlying buffer", CLASSNAME)
+        .that(Arrays.equals(allZeros, backingBuffer.array()))
+        .isTrue();
   }
 
+  @Test
   public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException {
     ByteOutput out =
         new ByteOutput() {
@@ -403,128 +455,157 @@
 
     testString.writeTo(out);
     byte[] allZeros = new byte[testString.size()];
-    assertTrue(
-        CLASSNAME + ".writeTo() must grant access to underlying buffer",
-        Arrays.equals(allZeros, backingBuffer.array()));
+    assertWithMessage("%s.writeTo() must grant access to underlying buffer", CLASSNAME)
+        .that(Arrays.equals(allZeros, backingBuffer.array()))
+        .isTrue();
   }
 
+  @Test
   public void testNewOutput() throws IOException {
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
     ByteString.Output output = ByteString.newOutput();
     testString.writeTo(output);
-    assertEquals("Output Size returns correct result", output.size(), testString.size());
+    assertWithMessage("Output Size returns correct result")
+        .that(output.size())
+        .isEqualTo(testString.size());
     output.writeTo(bos);
-    assertTrue(
-        "Output.writeTo() must give back the same bytes", Arrays.equals(BYTES, bos.toByteArray()));
+    assertWithMessage("Output.writeTo() must give back the same bytes")
+        .that(Arrays.equals(BYTES, bos.toByteArray()))
+        .isTrue();
 
     // write the output stream to itself! This should cause it to double
     output.writeTo(output);
-    assertEquals(
-        "Writing an output stream to itself is successful",
-        testString.concat(testString),
-        output.toByteString());
+    assertWithMessage("Writing an output stream to itself is successful")
+        .that(testString.concat(testString))
+        .isEqualTo(output.toByteString());
 
     output.reset();
-    assertEquals("Output.reset() resets the output", 0, output.size());
-    assertEquals("Output.reset() resets the output", EMPTY, output.toByteString());
+    assertWithMessage("Output.reset() resets the output").that(output.size()).isEqualTo(0);
+    assertWithMessage("Output.reset() resets the output")
+        .that(output.toByteString())
+        .isEqualTo(EMPTY);
   }
 
+  @Test
   public void testToString() {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString unicode = forString(testString);
     String roundTripString = unicode.toString(UTF_8);
-    assertEquals(CLASSNAME + " unicode must match", testString, roundTripString);
+    assertWithMessage("%s unicode must match", CLASSNAME)
+        .that(testString)
+        .isEqualTo(roundTripString);
   }
 
+  @Test
   public void testCharsetToString() {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString unicode = forString(testString);
     String roundTripString = unicode.toString(UTF_8);
-    assertEquals(CLASSNAME + " unicode must match", testString, roundTripString);
+    assertWithMessage("%s unicode must match", CLASSNAME)
+        .that(testString)
+        .isEqualTo(roundTripString);
   }
 
+  @Test
   public void testToString_returnsCanonicalEmptyString() {
-    assertSame(
-        CLASSNAME + " must be the same string references",
-        EMPTY.toString(UTF_8),
-        new NioByteString(ByteBuffer.wrap(new byte[0])).toString(UTF_8));
+    assertWithMessage("%s must be the same string references", CLASSNAME)
+        .that(EMPTY.toString(UTF_8))
+        .isSameInstanceAs(new NioByteString(ByteBuffer.wrap(new byte[0])).toString(UTF_8));
   }
 
+  @Test
   public void testToString_raisesException() {
     try {
       EMPTY.toString("invalid");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (UnsupportedEncodingException expected) {
       // This is success
     }
 
     try {
       testString.toString("invalid");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (UnsupportedEncodingException expected) {
       // This is success
     }
   }
 
+  @Test
+  @SuppressWarnings("TruthSelfEquals")
   public void testEquals() {
-    assertEquals(CLASSNAME + " must not equal null", false, testString.equals(null));
-    assertEquals(CLASSNAME + " must equal self", testString, testString);
-    assertFalse(CLASSNAME + " must not equal the empty string", testString.equals(EMPTY));
-    assertEquals(CLASSNAME + " empty strings must be equal", EMPTY, testString.substring(55, 55));
-    assertEquals(
-        CLASSNAME + " must equal another string with the same value",
-        testString,
-        new NioByteString(backingBuffer));
+    assertWithMessage("%s must not equal null", CLASSNAME).that(testString).isNotEqualTo(null);
+    assertWithMessage("%s must equal self", CLASSNAME).that(testString).isEqualTo(testString);
+    assertWithMessage("%s must not equal the empty string", CLASSNAME)
+        .that(testString)
+        .isNotEqualTo(EMPTY);
+    assertWithMessage("%s empty strings must be equal", CLASSNAME)
+        .that(EMPTY)
+        .isEqualTo(testString.substring(55, 55));
+    assertWithMessage("%s must equal another string with the same value", CLASSNAME)
+        .that(testString)
+        .isEqualTo(new NioByteString(backingBuffer));
 
     byte[] mungedBytes = mungedBytes();
-    assertFalse(
-        CLASSNAME + " must not equal every string with the same length",
-        testString.equals(new NioByteString(ByteBuffer.wrap(mungedBytes))));
+    assertWithMessage("%s must not equal every string with the same length", CLASSNAME)
+        .that(testString.equals(new NioByteString(ByteBuffer.wrap(mungedBytes))))
+        .isFalse();
   }
 
+  @Test
   public void testEqualsLiteralByteString() {
     ByteString literal = ByteString.copyFrom(BYTES);
-    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", literal, testString);
-    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", testString, literal);
-    assertFalse(
-        CLASSNAME + " must not equal the empty string", testString.equals(ByteString.EMPTY));
-    assertEquals(
-        CLASSNAME + " empty strings must be equal", ByteString.EMPTY, testString.substring(55, 55));
+    assertWithMessage("%s must equal LiteralByteString with same value", CLASSNAME)
+        .that(literal)
+        .isEqualTo(testString);
+    assertWithMessage("%s must equal LiteralByteString with same value", CLASSNAME)
+        .that(testString)
+        .isEqualTo(literal);
+    assertWithMessage("%s must not equal the empty string", CLASSNAME)
+        .that(testString)
+        .isNotEqualTo(ByteString.EMPTY);
+    assertWithMessage("%s empty strings must be equal", CLASSNAME)
+        .that(ByteString.EMPTY)
+        .isEqualTo(testString.substring(55, 55));
 
     literal = ByteString.copyFrom(mungedBytes());
-    assertFalse(
-        CLASSNAME + " must not equal every LiteralByteString with the same length",
-        testString.equals(literal));
-    assertFalse(
-        CLASSNAME + " must not equal every LiteralByteString with the same length",
-        literal.equals(testString));
+    assertWithMessage("%s must not equal every LiteralByteString with the same length", CLASSNAME)
+        .that(testString)
+        .isNotEqualTo(literal);
+    assertWithMessage("%s must not equal every LiteralByteString with the same length", CLASSNAME)
+        .that(literal)
+        .isNotEqualTo(testString);
   }
 
+  @Test
   public void testEqualsRopeByteString() {
     ByteString p1 = ByteString.copyFrom(BYTES, 0, 5);
     ByteString p2 = ByteString.copyFrom(BYTES, 5, BYTES.length - 5);
     ByteString rope = p1.concat(p2);
 
-    assertEquals(CLASSNAME + " must equal RopeByteString with same value", rope, testString);
-    assertEquals(CLASSNAME + " must equal RopeByteString with same value", testString, rope);
-    assertFalse(
-        CLASSNAME + " must not equal the empty string",
-        testString.equals(ByteString.EMPTY.concat(ByteString.EMPTY)));
-    assertEquals(
-        CLASSNAME + " empty strings must be equal",
-        ByteString.EMPTY.concat(ByteString.EMPTY),
-        testString.substring(55, 55));
+    assertWithMessage("%s must equal RopeByteString with same value", CLASSNAME)
+        .that(rope)
+        .isEqualTo(testString);
+    assertWithMessage("%s must equal RopeByteString with same value", CLASSNAME)
+        .that(testString)
+        .isEqualTo(rope);
+    assertWithMessage("%s must not equal the empty string", CLASSNAME)
+        .that(testString)
+        .isNotEqualTo(ByteString.EMPTY.concat(ByteString.EMPTY));
+    assertWithMessage("%s empty strings must be equal", CLASSNAME)
+        .that(ByteString.EMPTY.concat(ByteString.EMPTY))
+        .isEqualTo(testString.substring(55, 55));
 
     byte[] mungedBytes = mungedBytes();
     p1 = ByteString.copyFrom(mungedBytes, 0, 5);
     p2 = ByteString.copyFrom(mungedBytes, 5, mungedBytes.length - 5);
     rope = p1.concat(p2);
-    assertFalse(
-        CLASSNAME + " must not equal every RopeByteString with the same length",
-        testString.equals(rope));
-    assertFalse(
-        CLASSNAME + " must not equal every RopeByteString with the same length",
-        rope.equals(testString));
+    assertWithMessage("%s must not equal every RopeByteString with the same length", CLASSNAME)
+        .that(testString)
+        .isNotEqualTo(rope);
+
+    assertWithMessage("%s must not equal every RopeByteString with the same length", CLASSNAME)
+        .that(rope)
+        .isNotEqualTo(testString);
   }
 
   private byte[] mungedBytes() {
@@ -534,91 +615,118 @@
     return mungedBytes;
   }
 
+  @Test
   public void testHashCode() {
     int hash = testString.hashCode();
-    assertEquals(CLASSNAME + " must have expected hashCode", EXPECTED_HASH, hash);
+    assertWithMessage("%s must have expected hashCode", CLASSNAME)
+        .that(hash)
+        .isEqualTo(EXPECTED_HASH);
   }
 
+  @Test
   public void testPeekCachedHashCode() {
     ByteString newString = new NioByteString(backingBuffer);
-    assertEquals(
-        CLASSNAME + ".peekCachedHashCode() should return zero at first",
-        0,
-        newString.peekCachedHashCode());
-    newString.hashCode();
-    assertEquals(
-        CLASSNAME + ".peekCachedHashCode should return zero at first",
-        EXPECTED_HASH,
-        newString.peekCachedHashCode());
+    assertWithMessage("%s.peekCachedHashCode() should return zero at first", CLASSNAME)
+        .that(newString.peekCachedHashCode())
+        .isEqualTo(0);
+    int unused = newString.hashCode();
+    assertWithMessage("%s.peekCachedHashCode should return zero at first", CLASSNAME)
+        .that(newString.peekCachedHashCode())
+        .isEqualTo(EXPECTED_HASH);
   }
 
+  @Test
   public void testPartialHash() {
     // partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
     // This test would fail if the expected hash were 1.  It's not.
     int hash = testString.partialHash(testString.size(), 0, testString.size());
-    assertEquals(CLASSNAME + ".partialHash() must yield expected hashCode", EXPECTED_HASH, hash);
+    assertWithMessage("%s.partialHash() must yield expected hashCode", CLASSNAME)
+        .that(hash)
+        .isEqualTo(EXPECTED_HASH);
   }
 
+  @Test
   public void testNewInput() throws IOException {
     InputStream input = testString.newInput();
-    assertEquals(
-        "InputStream.available() returns correct value", testString.size(), input.available());
+    assertWithMessage("InputStream.available() returns correct value")
+        .that(testString.size())
+        .isEqualTo(input.available());
     boolean stillEqual = true;
     for (byte referenceByte : BYTES) {
       int expectedInt = (referenceByte & 0xFF);
       stillEqual = (expectedInt == input.read());
     }
-    assertEquals("InputStream.available() returns correct value", 0, input.available());
-    assertTrue(CLASSNAME + " must give the same bytes from the InputStream", stillEqual);
-    assertEquals(CLASSNAME + " InputStream must now be exhausted", -1, input.read());
+    assertWithMessage("InputStream.available() returns correct value")
+        .that(input.available())
+        .isEqualTo(0);
+    assertWithMessage("%s must give the same bytes from the InputStream", CLASSNAME)
+        .that(stillEqual)
+        .isTrue();
+    assertWithMessage("%s InputStream must now be exhausted", CLASSNAME)
+        .that(input.read())
+        .isEqualTo(-1);
   }
 
+  @Test
   public void testNewInput_skip() throws IOException {
     InputStream input = testString.newInput();
     int stringSize = testString.size();
     int nearEndIndex = stringSize * 2 / 3;
     long skipped1 = input.skip(nearEndIndex);
-    assertEquals("InputStream.skip()", skipped1, nearEndIndex);
-    assertEquals("InputStream.available()", stringSize - skipped1, input.available());
-    assertTrue("InputStream.mark() is available", input.markSupported());
+    assertWithMessage("InputStream.skip()").that(skipped1).isEqualTo(nearEndIndex);
+    assertWithMessage("InputStream.available()")
+        .that(input.available())
+        .isEqualTo(stringSize - skipped1);
+    assertWithMessage("InputStream.mark() is available").that(input.markSupported()).isTrue();
     input.mark(0);
-    assertEquals(
-        "InputStream.skip(), read()", testString.byteAt(nearEndIndex) & 0xFF, input.read());
-    assertEquals("InputStream.available()", stringSize - skipped1 - 1, input.available());
+    assertWithMessage("InputStream.skip(), read()")
+        .that(input.read())
+        .isEqualTo(testString.byteAt(nearEndIndex) & 0xFF);
+    assertWithMessage("InputStream.available()")
+        .that(input.available())
+        .isEqualTo(stringSize - skipped1 - 1);
     long skipped2 = input.skip(stringSize);
-    assertEquals("InputStream.skip() incomplete", skipped2, stringSize - skipped1 - 1);
-    assertEquals("InputStream.skip(), no more input", 0, input.available());
-    assertEquals("InputStream.skip(), no more input", -1, input.read());
+    assertWithMessage("InputStream.skip() incomplete")
+        .that(skipped2)
+        .isEqualTo(stringSize - skipped1 - 1);
+    assertWithMessage("InputStream.skip(), no more input").that(input.available()).isEqualTo(0);
+    assertWithMessage("InputStream.skip(), no more input").that(input.read()).isEqualTo(-1);
     input.reset();
-    assertEquals("InputStream.reset() succeeded", stringSize - skipped1, input.available());
-    assertEquals(
-        "InputStream.reset(), read()", testString.byteAt(nearEndIndex) & 0xFF, input.read());
+    assertWithMessage("InputStream.reset() succeeded")
+        .that(input.available())
+        .isEqualTo(stringSize - skipped1);
+    assertWithMessage("InputStream.reset(), read()")
+        .that(input.read())
+        .isEqualTo(testString.byteAt(nearEndIndex) & 0xFF);
   }
 
+  @Test
   public void testNewCodedInput() throws IOException {
     CodedInputStream cis = testString.newCodedInput();
     byte[] roundTripBytes = cis.readRawBytes(BYTES.length);
-    assertTrue(
-        CLASSNAME + " must give the same bytes back from the CodedInputStream",
-        Arrays.equals(BYTES, roundTripBytes));
-    assertTrue(CLASSNAME + " CodedInputStream must now be exhausted", cis.isAtEnd());
+    assertWithMessage("%s must give the same bytes back from the CodedInputStream", CLASSNAME)
+        .that(Arrays.equals(BYTES, roundTripBytes))
+        .isTrue();
+    assertWithMessage("%s CodedInputStream must now be exhausted", CLASSNAME)
+        .that(cis.isAtEnd())
+        .isTrue();
   }
 
   /**
    * Make sure we keep things simple when concatenating with empty. See also {@link
    * ByteStringTest#testConcat_empty()}.
    */
+  @Test
   public void testConcat_empty() {
-    assertSame(
-        CLASSNAME + " concatenated with empty must give " + CLASSNAME,
-        testString.concat(EMPTY),
-        testString);
-    assertSame(
-        "empty concatenated with " + CLASSNAME + " must give " + CLASSNAME,
-        EMPTY.concat(testString),
-        testString);
+    assertWithMessage("%s concatenated with empty must give %s", CLASSNAME, CLASSNAME)
+        .that(testString.concat(EMPTY))
+        .isSameInstanceAs(testString);
+    assertWithMessage("empty concatenated with %s must give %s", CLASSNAME, CLASSNAME)
+        .that(EMPTY.concat(testString))
+        .isSameInstanceAs(testString);
   }
 
+  @Test
   public void testJavaSerialization() throws Exception {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(out);
@@ -628,8 +736,8 @@
     InputStream in = new ByteArrayInputStream(pickled);
     ObjectInputStream ois = new ObjectInputStream(in);
     Object o = ois.readObject();
-    assertTrue("Didn't get a ByteString back", o instanceof ByteString);
-    assertEquals("Should get an equal ByteString back", testString, o);
+    assertWithMessage("Didn't get a ByteString back").that(o).isInstanceOf(ByteString.class);
+    assertWithMessage("Should get an equal ByteString back").that(o).isEqualTo(testString);
   }
 
   private static ByteString forString(String str) {
diff --git a/java/core/src/test/java/com/google/protobuf/PackedFieldTest.java b/java/core/src/test/java/com/google/protobuf/PackedFieldTest.java
index 2397d2e..ce77baa 100644
--- a/java/core/src/test/java/com/google/protobuf/PackedFieldTest.java
+++ b/java/core/src/test/java/com/google/protobuf/PackedFieldTest.java
@@ -30,13 +30,18 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.protobuf.PackedFieldTestProto.TestAllTypes;
 import com.google.protobuf.PackedFieldTestProto.TestAllTypes.NestedEnum;
 import com.google.protobuf.PackedFieldTestProto.TestUnpackedTypes;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Tests primitive repeated fields in proto3 are packed in wire format. */
-public class PackedFieldTest extends TestCase {
+@RunWith(JUnit4.class)
+public class PackedFieldTest {
   static final ByteString expectedPackedRawBytes =
       ByteString.copyFrom(
           new byte[] {
@@ -191,29 +196,34 @@
             0x01, // repeated nested enum
           });
 
+  @Test
   public void testPackedGeneratedMessage() throws Exception {
     TestAllTypes message = TestAllTypes.parseFrom(expectedPackedRawBytes);
-    assertEquals(expectedPackedRawBytes, message.toByteString());
+    assertThat(message.toByteString()).isEqualTo(expectedPackedRawBytes);
   }
 
+  @Test
   public void testPackedDynamicMessageSerialize() throws Exception {
     DynamicMessage message =
         DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), expectedPackedRawBytes);
-    assertEquals(expectedPackedRawBytes, message.toByteString());
+    assertThat(message.toByteString()).isEqualTo(expectedPackedRawBytes);
   }
 
+  @Test
   public void testUnpackedGeneratedMessage() throws Exception {
     TestUnpackedTypes message = TestUnpackedTypes.parseFrom(expectedUnpackedRawBytes);
-    assertEquals(expectedUnpackedRawBytes, message.toByteString());
+    assertThat(message.toByteString()).isEqualTo(expectedUnpackedRawBytes);
   }
 
+  @Test
   public void testUnPackedDynamicMessageSerialize() throws Exception {
     DynamicMessage message =
         DynamicMessage.parseFrom(TestUnpackedTypes.getDescriptor(), expectedUnpackedRawBytes);
-    assertEquals(expectedUnpackedRawBytes, message.toByteString());
+    assertThat(message.toByteString()).isEqualTo(expectedUnpackedRawBytes);
   }
 
   // Make sure we haven't screwed up the code generation for packing fields by default.
+  @Test
   public void testPackedSerialization() throws Exception {
     TestAllTypes message =
         TestAllTypes.newBuilder()
@@ -225,7 +235,7 @@
 
     while (!in.isAtEnd()) {
       int tag = in.readTag();
-      assertEquals(WireFormat.WIRETYPE_LENGTH_DELIMITED, WireFormat.getTagWireType(tag));
+      assertThat(WireFormat.getTagWireType(tag)).isEqualTo(WireFormat.WIRETYPE_LENGTH_DELIMITED);
       in.skipField(tag);
     }
   }
diff --git a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
index 4e63ee7..c1660a8 100644
--- a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
@@ -30,9 +30,7 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
 import static org.junit.Assert.fail;
 
 import com.google.protobuf.DescriptorProtos.DescriptorProto;
@@ -250,9 +248,8 @@
   private void verifyExceptions(ParseTester parseTester) {
     // No exception
     try {
-      assertEquals(
-          DescriptorProto.getDescriptor().toProto(),
-          parseTester.parse(new ByteArrayInputStream(serializedProto)));
+      assertThat(parseTester.parse(new ByteArrayInputStream(serializedProto)))
+          .isEqualTo(DescriptorProto.getDescriptor().toProto());
     } catch (IOException e) {
       fail("No exception expected: " + e);
     }
@@ -263,7 +260,7 @@
       parseTester.parse(broken(new ByteArrayInputStream(serializedProto)));
       fail("IOException expected but not thrown");
     } catch (IOException e) {
-      assertFalse(e instanceof InvalidProtocolBufferException);
+      assertThat(e).isNotInstanceOf(InvalidProtocolBufferException.class);
     }
 
     // InvalidProtocolBufferException
@@ -275,7 +272,7 @@
       parseTester.parse(new ByteArrayInputStream(serializedProto));
       fail("InvalidProtocolBufferException expected but not thrown");
     } catch (IOException e) {
-      assertTrue(e instanceof InvalidProtocolBufferException);
+      assertThat(e).isInstanceOf(InvalidProtocolBufferException.class);
     }
   }
 
diff --git a/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java b/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java
index eb2dc3d..fd0bf45 100644
--- a/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java
@@ -30,15 +30,21 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.protobuf.UnittestLite.TestAllTypesLite;
 import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
 import com.google.protobuf.UnittestLite.TestParsingMergeLite;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class ParserLiteTest extends TestCase {
+@RunWith(JUnit4.class)
+public class ParserLiteTest {
+
   private void assertRoundTripEquals(MessageLite message, ExtensionRegistryLite registry)
       throws Exception {
     final byte[] data = message.toByteArray();
@@ -46,15 +52,16 @@
     final int length = data.length;
     final int padding = 30;
     Parser<? extends MessageLite> parser = message.getParserForType();
-    assertEquals(message, parser.parseFrom(data, registry));
-    assertEquals(
-        message,
-        parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length, registry));
-    assertEquals(message, parser.parseFrom(message.toByteString(), registry));
-    assertEquals(message, parser.parseFrom(new ByteArrayInputStream(data), registry));
-    assertEquals(message, parser.parseFrom(CodedInputStream.newInstance(data), registry));
-    assertEquals(
-        message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry));
+    assertThat(message).isEqualTo(parser.parseFrom(data, registry));
+    assertThat(message)
+        .isEqualTo(
+            parser.parseFrom(
+                generatePaddingArray(data, offset, padding), offset, length, registry));
+    assertThat(message).isEqualTo(parser.parseFrom(message.toByteString(), registry));
+    assertThat(message).isEqualTo(parser.parseFrom(new ByteArrayInputStream(data), registry));
+    assertThat(message).isEqualTo(parser.parseFrom(CodedInputStream.newInstance(data), registry));
+    assertThat(message)
+        .isEqualTo(parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry));
   }
 
   @SuppressWarnings("unchecked")
@@ -65,13 +72,13 @@
     final int padding = 30;
 
     Parser<MessageLite> parser = (Parser<MessageLite>) message.getParserForType();
-    assertEquals(message, parser.parseFrom(data));
-    assertEquals(
-        message, parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length));
-    assertEquals(message, parser.parseFrom(message.toByteString()));
-    assertEquals(message, parser.parseFrom(new ByteArrayInputStream(data)));
-    assertEquals(message, parser.parseFrom(CodedInputStream.newInstance(data)));
-    assertEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer()));
+    assertThat(message).isEqualTo(parser.parseFrom(data));
+    assertThat(message)
+        .isEqualTo(parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length));
+    assertThat(message).isEqualTo(parser.parseFrom(message.toByteString()));
+    assertThat(message).isEqualTo(parser.parseFrom(new ByteArrayInputStream(data)));
+    assertThat(message).isEqualTo(parser.parseFrom(CodedInputStream.newInstance(data)));
+    assertThat(message).isEqualTo(parser.parseFrom(message.toByteString().asReadOnlyByteBuffer()));
   }
 
   private byte[] generatePaddingArray(byte[] data, int offset, int padding) {
@@ -80,21 +87,25 @@
     return result;
   }
 
+  @Test
   public void testParseExtensionsLite() throws Exception {
     assertRoundTripEquals(
         TestUtilLite.getAllLiteExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
   }
 
+  @Test
   public void testParsePacked() throws Exception {
     assertRoundTripEquals(TestUtil.getPackedSet());
     assertRoundTripEquals(TestUtil.getPackedExtensionsSet(), TestUtil.getExtensionRegistry());
   }
 
+  @Test
   public void testParsePackedLite() throws Exception {
     assertRoundTripEquals(
         TestUtilLite.getLitePackedExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
   }
 
+  @Test
   public void testParseDelimitedToLite() throws Exception {
     // Write MessageLite with packed extension fields.
     TestPackedExtensionsLite packedMessage = TestUtilLite.getLitePackedExtensionsSet();
@@ -103,25 +114,26 @@
     packedMessage.writeDelimitedTo(output);
 
     InputStream input = new ByteArrayInputStream(output.toByteArray());
-    assertEquals(
-        packedMessage,
-        packedMessage
-            .getParserForType()
-            .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite()));
-    assertEquals(
-        packedMessage,
-        packedMessage
-            .getParserForType()
-            .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite()));
+    assertThat(packedMessage)
+        .isEqualTo(
+            packedMessage
+                .getParserForType()
+                .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite()));
+    assertThat(packedMessage)
+        .isEqualTo(
+            packedMessage
+                .getParserForType()
+                .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite()));
   }
 
   /** Helper method for {@link #testParsingMergeLite()}. */
   private void assertMessageMerged(TestAllTypesLite allTypes) throws Exception {
-    assertEquals(3, allTypes.getOptionalInt32());
-    assertEquals(2, allTypes.getOptionalInt64());
-    assertEquals("hello", allTypes.getOptionalString());
+    assertThat(allTypes.getOptionalInt32()).isEqualTo(3);
+    assertThat(allTypes.getOptionalInt64()).isEqualTo(2);
+    assertThat(allTypes.getOptionalString()).isEqualTo("hello");
   }
 
+  @Test
   public void testParsingMergeLite() throws Exception {
     // Build messages.
     TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
@@ -184,8 +196,8 @@
     assertMessageMerged(parsingMerge.getExtension(TestParsingMergeLite.optionalExt));
 
     // Repeated fields should not be merged.
-    assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
-    assertEquals(3, parsingMerge.getRepeatedGroupCount());
-    assertEquals(3, parsingMerge.getExtensionCount(TestParsingMergeLite.repeatedExt));
+    assertThat(parsingMerge.getRepeatedAllTypesCount()).isEqualTo(3);
+    assertThat(parsingMerge.getRepeatedGroupCount()).isEqualTo(3);
+    assertThat(parsingMerge.getExtensionCount(TestParsingMergeLite.repeatedExt)).isEqualTo(3);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/ParserTest.java b/java/core/src/test/java/com/google/protobuf/ParserTest.java
index 983caec..e78c671 100644
--- a/java/core/src/test/java/com/google/protobuf/ParserTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import protobuf_unittest.UnittestOptimizeFor;
 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
 import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
@@ -44,17 +47,18 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InterruptedIOException;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Unit test for {@link Parser}.
- *
- * @author [email protected] (Pherl Liu)
- */
-public class ParserTest extends TestCase {
+/** Unit test for {@link Parser}. */
+@RunWith(JUnit4.class)
+public class ParserTest {
+
+  @Test
   public void testGeneratedMessageParserSingleton() throws Exception {
     for (int i = 0; i < 10; i++) {
-      assertEquals(TestAllTypes.parser(), TestUtil.getAllSet().getParserForType());
+      assertThat(TestUtil.getAllSet().getParserForType()).isEqualTo(TestAllTypes.parser());
     }
   }
 
@@ -95,9 +99,9 @@
 
   private void assertMessageEquals(MessageLite expected, MessageLite actual) throws Exception {
     if (expected instanceof Message) {
-      assertEquals(expected, actual);
+      assertThat(actual).isEqualTo(expected);
     } else {
-      assertEquals(expected.toByteString(), actual.toByteString());
+      assertThat(actual.toByteString()).isEqualTo(expected.toByteString());
     }
   }
 
@@ -107,11 +111,13 @@
     return result;
   }
 
+  @Test
   public void testNormalMessage() throws Exception {
     assertRoundTripEquals(TestUtil.getAllSet());
   }
 
 
+  @Test
   public void testParsePartial() throws Exception {
     assertParsePartial(TestRequired.parser(), TestRequired.newBuilder().setA(1).buildPartial());
   }
@@ -122,15 +128,16 @@
 
     // parsePartialFrom should pass.
     byte[] data = partialMessage.toByteArray();
-    assertEquals(partialMessage, parser.parsePartialFrom(data));
-    assertEquals(partialMessage, parser.parsePartialFrom(partialMessage.toByteString()));
-    assertEquals(partialMessage, parser.parsePartialFrom(new ByteArrayInputStream(data)));
-    assertEquals(partialMessage, parser.parsePartialFrom(CodedInputStream.newInstance(data)));
+    assertThat(parser.parsePartialFrom(data)).isEqualTo(partialMessage);
+    assertThat(parser.parsePartialFrom(partialMessage.toByteString())).isEqualTo(partialMessage);
+    assertThat(parser.parsePartialFrom(new ByteArrayInputStream(data))).isEqualTo(partialMessage);
+    assertThat(parser.parsePartialFrom(CodedInputStream.newInstance(data)))
+        .isEqualTo(partialMessage);
 
     // parseFrom(ByteArray)
     try {
       parser.parseFrom(partialMessage.toByteArray());
-      fail(errorString);
+      assertWithMessage(errorString).fail();
     } catch (InvalidProtocolBufferException e) {
       // pass.
     }
@@ -138,7 +145,7 @@
     // parseFrom(ByteString)
     try {
       parser.parseFrom(partialMessage.toByteString());
-      fail(errorString);
+      assertWithMessage(errorString).fail();
     } catch (InvalidProtocolBufferException e) {
       // pass.
     }
@@ -146,7 +153,7 @@
     // parseFrom(InputStream)
     try {
       parser.parseFrom(new ByteArrayInputStream(partialMessage.toByteArray()));
-      fail(errorString);
+      assertWithMessage(errorString).fail();
     } catch (IOException e) {
       // pass.
     }
@@ -154,21 +161,24 @@
     // parseFrom(CodedInputStream)
     try {
       parser.parseFrom(CodedInputStream.newInstance(partialMessage.toByteArray()));
-      fail(errorString);
+      assertWithMessage(errorString).fail();
     } catch (IOException e) {
       // pass.
     }
   }
 
+  @Test
   public void testParseExtensions() throws Exception {
     assertRoundTripEquals(TestUtil.getAllExtensionsSet(), TestUtil.getExtensionRegistry());
   }
 
+  @Test
   public void testParsePacked() throws Exception {
     assertRoundTripEquals(TestUtil.getPackedSet());
     assertRoundTripEquals(TestUtil.getPackedExtensionsSet(), TestUtil.getExtensionRegistry());
   }
 
+  @Test
   public void testParseDelimitedTo() throws Exception {
     // Write normal Message.
     TestAllTypes normalMessage = TestUtil.getAllSet();
@@ -181,14 +191,16 @@
     assertMessageEquals(normalMessage, normalMessage.getParserForType().parseDelimitedFrom(input));
   }
 
+  @Test
   public void testParseUnknownFields() throws Exception {
     // All fields will be treated as unknown fields in emptyMessage.
     TestEmptyMessage emptyMessage =
         TestEmptyMessage.parser().parseFrom(TestUtil.getAllSet().toByteString());
-    assertEquals(TestUtil.getAllSet().toByteString(), emptyMessage.toByteString());
+    assertThat(emptyMessage.toByteString()).isEqualTo(TestUtil.getAllSet().toByteString());
   }
 
 
+  @Test
   public void testOptimizeForSize() throws Exception {
     TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
     builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());
@@ -206,11 +218,12 @@
 
   /** Helper method for {@link #testParsingMerge()}. */
   private void assertMessageMerged(TestAllTypes allTypes) throws Exception {
-    assertEquals(3, allTypes.getOptionalInt32());
-    assertEquals(2, allTypes.getOptionalInt64());
-    assertEquals("hello", allTypes.getOptionalString());
+    assertThat(allTypes.getOptionalInt32()).isEqualTo(3);
+    assertThat(allTypes.getOptionalInt64()).isEqualTo(2);
+    assertThat(allTypes.getOptionalString()).isEqualTo("hello");
   }
 
+  @Test
   public void testParsingMerge() throws Exception {
     // Build messages.
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -273,11 +286,12 @@
     assertMessageMerged(parsingMerge.getExtension(TestParsingMerge.optionalExt));
 
     // Repeated fields should not be merged.
-    assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
-    assertEquals(3, parsingMerge.getRepeatedGroupCount());
-    assertEquals(3, parsingMerge.getExtensionCount(TestParsingMerge.repeatedExt));
+    assertThat(parsingMerge.getRepeatedAllTypesCount()).isEqualTo(3);
+    assertThat(parsingMerge.getRepeatedGroupCount()).isEqualTo(3);
+    assertThat(parsingMerge.getExtensionCount(TestParsingMerge.repeatedExt)).isEqualTo(3);
   }
 
+  @Test
   public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() {
     try {
       TestAllTypes.parseDelimitedFrom(
@@ -287,12 +301,13 @@
               throw new InterruptedIOException();
             }
           });
-      fail("Expected InterruptedIOException");
+      assertWithMessage("Expected InterruptedIOException").fail();
     } catch (Exception e) {
-      assertEquals(InterruptedIOException.class, e.getClass());
+      assertThat(e.getClass()).isEqualTo(InterruptedIOException.class);
     }
   }
 
+  @Test
   public void testParseDelimitedFrom_secondByteInterrupted_preservesCause() {
     try {
       TestAllTypes.parseDelimitedFrom(
@@ -311,9 +326,9 @@
               }
             }
           });
-      fail("Expected InterruptedIOException");
+      assertWithMessage("Expected InterruptedIOException").fail();
     } catch (Exception e) {
-      assertEquals(InterruptedIOException.class, e.getClass());
+      assertThat(e.getClass()).isEqualTo(InterruptedIOException.class);
     }
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java b/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java
index dfda4b3..07864a9 100644
--- a/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java
+++ b/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java
@@ -30,9 +30,8 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import com.google.protobuf.testing.Proto2Testing;
 import com.google.protobuf.testing.Proto2Testing.Proto2Message;
@@ -67,14 +66,14 @@
     Proto2MessageWithExtensions message =
         ExperimentalSerializationUtil.fromByteArray(
             data, Proto2MessageWithExtensions.class, extensionRegistry);
-    assertEquals(base, message);
+    assertThat(message).isEqualTo(base);
 
     Proto2MessageWithExtensions roundtripMessage =
         ExperimentalSerializationUtil.fromByteArray(
             ExperimentalSerializationUtil.toByteArray(message),
             Proto2MessageWithExtensions.class,
             extensionRegistry);
-    assertEquals(base, roundtripMessage);
+    assertThat(roundtripMessage).isEqualTo(base);
   }
 
   @Test
@@ -82,7 +81,7 @@
     // Use unknown fields to hold invalid enum values.
     UnknownFieldSetLite unknowns = UnknownFieldSetLite.newInstance();
     final int outOfRange = 1000;
-    assertNull(TestEnum.forNumber(outOfRange));
+    assertThat(TestEnum.forNumber(outOfRange)).isNull();
     unknowns.storeField(
         WireFormat.makeTag(Proto2Message.FIELD_ENUM_13_FIELD_NUMBER, WireFormat.WIRETYPE_VARINT),
         (long) outOfRange);
@@ -125,17 +124,17 @@
     Proto2MessageWithExtensions parsed =
         ExperimentalSerializationUtil.fromByteArray(
             output, Proto2MessageWithExtensions.class, extensionRegistry);
-    assertFalse(
-        "out-of-range singular enum should not be in message",
-        parsed.hasExtension(Proto2Testing.fieldEnum13));
+    assertWithMessage("out-of-range singular enum should not be in message")
+        .that(parsed.hasExtension(Proto2Testing.fieldEnum13))
+        .isFalse();
     {
       List<Long> singularEnum =
           parsed
               .getUnknownFields()
               .getField(Proto2Message.FIELD_ENUM_13_FIELD_NUMBER)
               .getVarintList();
-      assertEquals(1, singularEnum.size());
-      assertEquals((Long) (long) outOfRange, singularEnum.get(0));
+      assertThat(singularEnum).hasSize(1);
+      assertThat(singularEnum.get(0)).isEqualTo((Long) (long) outOfRange);
     }
     {
       List<Long> repeatedEnum =
@@ -143,8 +142,8 @@
               .getUnknownFields()
               .getField(Proto2Message.FIELD_ENUM_LIST_30_FIELD_NUMBER)
               .getVarintList();
-      assertEquals(1, repeatedEnum.size());
-      assertEquals((Long) (long) outOfRange, repeatedEnum.get(0));
+      assertThat(repeatedEnum).hasSize(1);
+      assertThat(repeatedEnum.get(0)).isEqualTo((Long) (long) outOfRange);
     }
     {
       List<Long> packedRepeatedEnum =
@@ -152,20 +151,18 @@
               .getUnknownFields()
               .getField(Proto2Message.FIELD_ENUM_LIST_PACKED_44_FIELD_NUMBER)
               .getVarintList();
-      assertEquals(1, packedRepeatedEnum.size());
-      assertEquals((Long) (long) outOfRange, packedRepeatedEnum.get(0));
+      assertThat(packedRepeatedEnum).hasSize(1);
+      assertThat(packedRepeatedEnum.get(0)).isEqualTo((Long) (long) outOfRange);
     }
-    assertEquals(
-        "out-of-range repeated enum should not be in message",
-        2,
-        parsed.getExtension(Proto2Testing.fieldEnumList30).size());
-    assertEquals(TestEnum.ONE, parsed.getExtension(Proto2Testing.fieldEnumList30, 0));
-    assertEquals(TestEnum.TWO, parsed.getExtension(Proto2Testing.fieldEnumList30, 1));
-    assertEquals(
-        "out-of-range packed repeated enum should not be in message",
-        2,
-        parsed.getExtension(Proto2Testing.fieldEnumListPacked44).size());
-    assertEquals(TestEnum.ONE, parsed.getExtension(Proto2Testing.fieldEnumListPacked44, 0));
-    assertEquals(TestEnum.TWO, parsed.getExtension(Proto2Testing.fieldEnumListPacked44, 1));
+    assertWithMessage("out-of-range repeated enum should not be in message")
+        .that(parsed.getExtension(Proto2Testing.fieldEnumList30).size())
+        .isEqualTo(2);
+    assertThat(parsed.getExtension(Proto2Testing.fieldEnumList30, 0)).isEqualTo(TestEnum.ONE);
+    assertThat(parsed.getExtension(Proto2Testing.fieldEnumList30, 1)).isEqualTo(TestEnum.TWO);
+    assertWithMessage("out-of-range packed repeated enum should not be in message")
+        .that(parsed.getExtension(Proto2Testing.fieldEnumListPacked44).size())
+        .isEqualTo(2);
+    assertThat(parsed.getExtension(Proto2Testing.fieldEnumListPacked44, 0)).isEqualTo(TestEnum.ONE);
+    assertThat(parsed.getExtension(Proto2Testing.fieldEnumListPacked44, 1)).isEqualTo(TestEnum.TWO);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java b/java/core/src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java
index 57ac069..d1e4a90 100644
--- a/java/core/src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java
+++ b/java/core/src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java
@@ -30,14 +30,19 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import protobuf_unittest.UnittestProto;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Unit tests for proto2 that treats unknown enum values as unknown fields. */
-public class Proto2UnknownEnumValueTest extends TestCase {
+@RunWith(JUnit4.class)
+public class Proto2UnknownEnumValueTest {
   FieldDescriptor singularField =
       TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
   FieldDescriptor repeatedField =
@@ -64,48 +69,47 @@
     return builder.build().toByteArray();
   }
 
+  @Test
   public void testUnknownEnumValues() throws Exception {
     TestAllTypes message = TestAllTypes.parseFrom(payload);
 
     // Known enum values should be preserved.
-    assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
-    assertEquals(2, message.getRepeatedNestedEnumList().size());
-    assertEquals(TestAllTypes.NestedEnum.FOO, message.getRepeatedNestedEnum(0));
-    assertEquals(TestAllTypes.NestedEnum.BAZ, message.getRepeatedNestedEnum(1));
+    assertThat(message.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.BAR);
+    assertThat(message.getRepeatedNestedEnumList().size()).isEqualTo(2);
+    assertThat(message.getRepeatedNestedEnum(0)).isEqualTo(TestAllTypes.NestedEnum.FOO);
+    assertThat(message.getRepeatedNestedEnum(1)).isEqualTo(TestAllTypes.NestedEnum.BAZ);
 
     // Unknown enum values should be found in UnknownFieldSet.
     UnknownFieldSet unknown = message.getUnknownFields();
-    assertEquals(
-        1901, unknown.getField(singularField.getNumber()).getVarintList().get(0).longValue());
-    assertEquals(
-        1902, unknown.getField(repeatedField.getNumber()).getVarintList().get(0).longValue());
-    assertEquals(
-        1903, unknown.getField(repeatedField.getNumber()).getVarintList().get(1).longValue());
+    assertThat(unknown.getField(singularField.getNumber()).getVarintList().get(0).longValue())
+        .isEqualTo(1901);
+    assertThat(unknown.getField(repeatedField.getNumber()).getVarintList().get(0).longValue())
+        .isEqualTo(1902);
+    assertThat(unknown.getField(repeatedField.getNumber()).getVarintList().get(1).longValue())
+        .isEqualTo(1903);
   }
 
+  @Test
   public void testExtensionUnknownEnumValues() throws Exception {
     ExtensionRegistry registry = ExtensionRegistry.newInstance();
     UnittestProto.registerAllExtensions(registry);
     TestAllExtensions message = TestAllExtensions.parseFrom(payload, registry);
 
-    assertEquals(
-        TestAllTypes.NestedEnum.BAR,
-        message.getExtension(UnittestProto.optionalNestedEnumExtension));
-    assertEquals(2, message.getExtension(UnittestProto.repeatedNestedEnumExtension).size());
-    assertEquals(
-        TestAllTypes.NestedEnum.FOO,
-        message.getExtension(UnittestProto.repeatedNestedEnumExtension, 0));
-    assertEquals(
-        TestAllTypes.NestedEnum.BAZ,
-        message.getExtension(UnittestProto.repeatedNestedEnumExtension, 1));
+    assertThat(message.getExtension(UnittestProto.optionalNestedEnumExtension))
+        .isEqualTo(TestAllTypes.NestedEnum.BAR);
+    assertThat(message.getExtension(UnittestProto.repeatedNestedEnumExtension).size()).isEqualTo(2);
+    assertThat(message.getExtension(UnittestProto.repeatedNestedEnumExtension, 0))
+        .isEqualTo(TestAllTypes.NestedEnum.FOO);
+    assertThat(message.getExtension(UnittestProto.repeatedNestedEnumExtension, 1))
+        .isEqualTo(TestAllTypes.NestedEnum.BAZ);
 
     // Unknown enum values should be found in UnknownFieldSet.
     UnknownFieldSet unknown = message.getUnknownFields();
-    assertEquals(
-        1901, unknown.getField(singularField.getNumber()).getVarintList().get(0).longValue());
-    assertEquals(
-        1902, unknown.getField(repeatedField.getNumber()).getVarintList().get(0).longValue());
-    assertEquals(
-        1903, unknown.getField(repeatedField.getNumber()).getVarintList().get(1).longValue());
+    assertThat(unknown.getField(singularField.getNumber()).getVarintList().get(0).longValue())
+        .isEqualTo(1901);
+    assertThat(unknown.getField(repeatedField.getNumber()).getVarintList().get(0).longValue())
+        .isEqualTo(1902);
+    assertThat(unknown.getField(repeatedField.getNumber()).getVarintList().get(1).longValue())
+        .isEqualTo(1903);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
index c42813c..18d90fe 100644
--- a/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
+++ b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
@@ -30,70 +30,77 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
 import java.util.Collections;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Tests for {@link RepeatedFieldBuilderV3}. This tests basic functionality. More extensive testing is
  * provided via other tests that exercise the builder.
- *
- * @author [email protected] (Jon Perlow)
  */
-public class RepeatedFieldBuilderV3Test extends TestCase {
+@RunWith(JUnit4.class)
+public class RepeatedFieldBuilderV3Test {
 
+  @Test
   public void testBasicUse() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
     RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder> builder =
         newRepeatedFieldBuilderV3(mockParent);
     builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
     builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
+    assertThat(builder.getMessage(0).getOptionalInt32()).isEqualTo(0);
+    assertThat(builder.getMessage(1).getOptionalInt32()).isEqualTo(1);
 
     List<TestAllTypes> list = builder.build();
-    assertEquals(2, list.size());
-    assertEquals(0, list.get(0).getOptionalInt32());
-    assertEquals(1, list.get(1).getOptionalInt32());
+    assertThat(list).hasSize(2);
+    assertThat(list.get(0).getOptionalInt32()).isEqualTo(0);
+    assertThat(list.get(1).getOptionalInt32()).isEqualTo(1);
     assertIsUnmodifiable(list);
 
     // Make sure it doesn't change.
     List<TestAllTypes> list2 = builder.build();
-    assertSame(list, list2);
-    assertEquals(0, mockParent.getInvalidationCount());
+    assertThat(list).isSameInstanceAs(list2);
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
   }
 
+  @Test
   public void testGoingBackAndForth() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
     RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder> builder =
         newRepeatedFieldBuilderV3(mockParent);
     builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
     builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
+    assertThat(builder.getMessage(0).getOptionalInt32()).isEqualTo(0);
+    assertThat(builder.getMessage(1).getOptionalInt32()).isEqualTo(1);
 
     // Convert to list
     List<TestAllTypes> list = builder.build();
-    assertEquals(2, list.size());
-    assertEquals(0, list.get(0).getOptionalInt32());
-    assertEquals(1, list.get(1).getOptionalInt32());
+    assertThat(list).hasSize(2);
+    assertThat(list.get(0).getOptionalInt32()).isEqualTo(0);
+    assertThat(list.get(1).getOptionalInt32()).isEqualTo(1);
     assertIsUnmodifiable(list);
 
     // Update 0th item
-    assertEquals(0, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
     builder.getBuilder(0).setOptionalString("foo");
-    assertEquals(1, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(1);
     list = builder.build();
-    assertEquals(2, list.size());
-    assertEquals(0, list.get(0).getOptionalInt32());
-    assertEquals("foo", list.get(0).getOptionalString());
-    assertEquals(1, list.get(1).getOptionalInt32());
+    assertThat(list).hasSize(2);
+    assertThat(list.get(0).getOptionalInt32()).isEqualTo(0);
+    assertThat(list.get(0).getOptionalString()).isEqualTo("foo");
+    assertThat(list.get(1).getOptionalInt32()).isEqualTo(1);
     assertIsUnmodifiable(list);
-    assertEquals(1, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(1);
   }
 
+  @Test
   public void testVariousMethods() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
     RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder> builder =
@@ -103,63 +110,64 @@
     builder.addBuilder(0, TestAllTypes.getDefaultInstance()).setOptionalInt32(0);
     builder.addBuilder(TestAllTypes.getDefaultInstance()).setOptionalInt32(3);
 
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-    assertEquals(2, builder.getMessage(2).getOptionalInt32());
-    assertEquals(3, builder.getMessage(3).getOptionalInt32());
+    assertThat(builder.getMessage(0).getOptionalInt32()).isEqualTo(0);
+    assertThat(builder.getMessage(1).getOptionalInt32()).isEqualTo(1);
+    assertThat(builder.getMessage(2).getOptionalInt32()).isEqualTo(2);
+    assertThat(builder.getMessage(3).getOptionalInt32()).isEqualTo(3);
 
-    assertEquals(0, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
     List<TestAllTypes> messages = builder.build();
-    assertEquals(4, messages.size());
-    assertSame(messages, builder.build()); // expect same list
+    assertThat(messages).hasSize(4);
+    assertThat(messages).isSameInstanceAs(builder.build()); // expect same list
 
     // Remove a message.
     builder.remove(2);
-    assertEquals(1, mockParent.getInvalidationCount());
-    assertEquals(3, builder.getCount());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-    assertEquals(3, builder.getMessage(2).getOptionalInt32());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(1);
+    assertThat(builder.getCount()).isEqualTo(3);
+    assertThat(builder.getMessage(0).getOptionalInt32()).isEqualTo(0);
+    assertThat(builder.getMessage(1).getOptionalInt32()).isEqualTo(1);
+    assertThat(builder.getMessage(2).getOptionalInt32()).isEqualTo(3);
 
     // Remove a builder.
     builder.remove(0);
-    assertEquals(1, mockParent.getInvalidationCount());
-    assertEquals(2, builder.getCount());
-    assertEquals(1, builder.getMessage(0).getOptionalInt32());
-    assertEquals(3, builder.getMessage(1).getOptionalInt32());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(1);
+    assertThat(builder.getCount()).isEqualTo(2);
+    assertThat(builder.getMessage(0).getOptionalInt32()).isEqualTo(1);
+    assertThat(builder.getMessage(1).getOptionalInt32()).isEqualTo(3);
 
     // Test clear.
     builder.clear();
-    assertEquals(1, mockParent.getInvalidationCount());
-    assertEquals(0, builder.getCount());
-    assertTrue(builder.isEmpty());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(1);
+    assertThat(builder.getCount()).isEqualTo(0);
+    assertThat(builder.isEmpty()).isTrue();
   }
 
+  @Test
   public void testLists() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
     RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder> builder =
         newRepeatedFieldBuilderV3(mockParent);
     builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
     builder.addMessage(0, TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
+    assertThat(builder.getMessage(0).getOptionalInt32()).isEqualTo(0);
+    assertThat(builder.getMessage(1).getOptionalInt32()).isEqualTo(1);
 
     // Use list of builders.
     List<TestAllTypes.Builder> builders = builder.getBuilderList();
-    assertEquals(0, builders.get(0).getOptionalInt32());
-    assertEquals(1, builders.get(1).getOptionalInt32());
+    assertThat(builders.get(0).getOptionalInt32()).isEqualTo(0);
+    assertThat(builders.get(1).getOptionalInt32()).isEqualTo(1);
     builders.get(0).setOptionalInt32(10);
     builders.get(1).setOptionalInt32(11);
 
     // Use list of protos
     List<TestAllTypes> protos = builder.getMessageList();
-    assertEquals(10, protos.get(0).getOptionalInt32());
-    assertEquals(11, protos.get(1).getOptionalInt32());
+    assertThat(protos.get(0).getOptionalInt32()).isEqualTo(10);
+    assertThat(protos.get(1).getOptionalInt32()).isEqualTo(11);
 
     // Add an item to the builders and verify it's updated in both
     builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(12).build());
-    assertEquals(3, builders.size());
-    assertEquals(3, protos.size());
+    assertThat(builders).hasSize(3);
+    assertThat(protos).hasSize(3);
   }
 
   private void assertIsUnmodifiable(List<?> list) {
@@ -168,7 +176,7 @@
     } else {
       try {
         list.clear();
-        fail("List wasn't immutable");
+        assertWithMessage("List wasn't immutable").fail();
       } catch (UnsupportedOperationException e) {
         // good
       }
diff --git a/java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java b/java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
index d726216..0bfc0be 100644
--- a/java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
@@ -30,19 +30,25 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import java.io.UnsupportedEncodingException;
 import java.util.Iterator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * This class tests {@link RopeByteString#substring(int, int)} by inheriting the tests from {@link
  * LiteralByteStringTest}. Only a couple of methods are overridden.
- *
- * @author [email protected] (Carl Haverl)
  */
+@RunWith(JUnit4.class)
 public class RopeByteStringSubstringTest extends LiteralByteStringTest {
 
   @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     classUnderTest = "RopeByteString";
     byte[] sourceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
     Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(sourceBytes).iterator();
@@ -60,12 +66,15 @@
   }
 
   @Override
+  @Test
   public void testGetTreeDepth() {
-    assertEquals(
-        classUnderTest + " must have the expected tree depth", 3, stringUnderTest.getTreeDepth());
+    assertWithMessage("%s must have the expected tree depth", classUnderTest)
+        .that(stringUnderTest.getTreeDepth())
+        .isEqualTo(3);
   }
 
   @Override
+  @Test
   public void testToString() throws UnsupportedEncodingException {
     String sourceString = "I love unicode \u1234\u5678 characters";
     ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
@@ -84,21 +93,24 @@
     testString = testString.substring(2, testString.length() - 6);
     unicode = unicode.substring(2, unicode.size() - 6);
 
-    assertEquals(
-        classUnderTest + " from string must have the expected type",
-        classUnderTest,
-        getActualClassName(unicode));
+    assertWithMessage("%s from string must have the expected type", classUnderTest)
+        .that(classUnderTest)
+        .isEqualTo(getActualClassName(unicode));
     String roundTripString = unicode.toString(UTF_8);
-    assertEquals(classUnderTest + " unicode bytes must match", testString, roundTripString);
+    assertWithMessage("%s unicode bytes must match", classUnderTest)
+        .that(testString)
+        .isEqualTo(roundTripString);
     ByteString flatString = ByteString.copyFromUtf8(testString);
-    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
-    assertEquals(
-        classUnderTest + " string must must have same hashCode as the flat string",
-        flatString.hashCode(),
-        unicode.hashCode());
+    assertWithMessage("%s string must equal the flat string", classUnderTest)
+        .that(flatString)
+        .isEqualTo(unicode);
+    assertWithMessage("%s string must must have same hashCode as the flat string", classUnderTest)
+        .that(flatString.hashCode())
+        .isEqualTo(unicode.hashCode());
   }
 
   @Override
+  @Test
   public void testCharsetToString() {
     String sourceString = "I love unicode \u1234\u5678 characters";
     ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
@@ -117,17 +129,19 @@
     testString = testString.substring(2, testString.length() - 6);
     unicode = unicode.substring(2, unicode.size() - 6);
 
-    assertEquals(
-        classUnderTest + " from string must have the expected type",
-        classUnderTest,
-        getActualClassName(unicode));
+    assertWithMessage("%s from string must have the expected type", classUnderTest)
+        .that(classUnderTest)
+        .isEqualTo(getActualClassName(unicode));
     String roundTripString = unicode.toString(Internal.UTF_8);
-    assertEquals(classUnderTest + " unicode bytes must match", testString, roundTripString);
+    assertWithMessage("%s unicode bytes must match", classUnderTest)
+        .that(testString)
+        .isEqualTo(roundTripString);
     ByteString flatString = ByteString.copyFromUtf8(testString);
-    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
-    assertEquals(
-        classUnderTest + " string must must have same hashCode as the flat string",
-        flatString.hashCode(),
-        unicode.hashCode());
+    assertWithMessage("%s string must equal the flat string", classUnderTest)
+        .that(flatString)
+        .isEqualTo(unicode);
+    assertWithMessage("%s string must must have same hashCode as the flat string", classUnderTest)
+        .that(flatString.hashCode())
+        .isEqualTo(unicode.hashCode());
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java b/java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java
index 46c2d86..bdb8132 100644
--- a/java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
@@ -38,6 +41,10 @@
 import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 import java.util.Iterator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * This class tests {@link RopeByteString} by inheriting the tests from {@link
@@ -45,13 +52,13 @@
  *
  * <p>A full test of the result of {@link RopeByteString#substring(int, int)} is found in the
  * separate class {@link RopeByteStringSubstringTest}.
- *
- * @author [email protected] (Carl Haverl)
  */
+@RunWith(JUnit4.class)
 public class RopeByteStringTest extends LiteralByteStringTest {
 
   @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     classUnderTest = "RopeByteString";
     referenceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
     Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(referenceBytes).iterator();
@@ -62,28 +69,32 @@
     expectedHashCode = -1214197238;
   }
 
+  @Test
   public void testMinLength() {
     // minLength should match the Fibonacci sequence
     int a = 1;
     int b = 1;
     int i;
     for (i = 0; a > 0; i++) {
-      assertEquals(a, RopeByteString.minLength(i));
+      assertThat(a).isEqualTo(RopeByteString.minLength(i));
       int c = a + b;
       a = b;
       b = c;
     }
-    assertEquals(Integer.MAX_VALUE, RopeByteString.minLength(i));
-    assertEquals(Integer.MAX_VALUE, RopeByteString.minLength(i + 1));
-    assertEquals(i + 1, RopeByteString.minLengthByDepth.length);
+    assertThat(RopeByteString.minLength(i)).isEqualTo(Integer.MAX_VALUE);
+    assertThat(RopeByteString.minLength(i + 1)).isEqualTo(Integer.MAX_VALUE);
+    assertThat(RopeByteString.minLengthByDepth).hasLength(i + 1);
   }
 
   @Override
+  @Test
   public void testGetTreeDepth() {
-    assertEquals(
-        classUnderTest + " must have the expected tree depth", 4, stringUnderTest.getTreeDepth());
+    assertWithMessage("%s must have the expected tree depth", classUnderTest)
+        .that(stringUnderTest.getTreeDepth())
+        .isEqualTo(4);
   }
 
+  @Test
   public void testBalance() {
     int numberOfPieces = 10000;
     int pieceSize = 64;
@@ -95,25 +106,26 @@
       concatenated = concatenated.concat(ByteString.copyFrom(testBytes, i * pieceSize, pieceSize));
     }
 
-    assertEquals(
-        classUnderTest + " from string must have the expected type",
-        classUnderTest,
-        getActualClassName(concatenated));
-    assertTrue(
-        classUnderTest + " underlying bytes must match after balancing",
-        Arrays.equals(testBytes, concatenated.toByteArray()));
+    assertWithMessage("%s from string must have the expected type", classUnderTest)
+        .that(classUnderTest)
+        .isEqualTo(getActualClassName(concatenated));
+    assertWithMessage("%s underlying bytes must match after balancing", classUnderTest)
+        .that(Arrays.equals(testBytes, concatenated.toByteArray()))
+        .isTrue();
     ByteString testString = ByteString.copyFrom(testBytes);
-    assertEquals(
-        classUnderTest + " balanced string must equal flat string", testString, concatenated);
-    assertEquals(
-        classUnderTest + " flat string must equal balanced string", concatenated, testString);
-    assertEquals(
-        classUnderTest + " balanced string must have same hash code as flat string",
-        testString.hashCode(),
-        concatenated.hashCode());
+    assertWithMessage("%s balanced string must equal flat string", classUnderTest)
+        .that(testString)
+        .isEqualTo(concatenated);
+    assertWithMessage("%s flat string must equal balanced string", classUnderTest)
+        .that(concatenated)
+        .isEqualTo(testString);
+    assertWithMessage("%s balanced string must have same hash code as flat string", classUnderTest)
+        .that(testString.hashCode())
+        .isEqualTo(concatenated.hashCode());
   }
 
   @Override
+  @Test
   public void testToString() throws UnsupportedEncodingException {
     String sourceString = "I love unicode \u1234\u5678 characters";
     ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
@@ -128,21 +140,24 @@
     }
     String testString = builder.toString();
 
-    assertEquals(
-        classUnderTest + " from string must have the expected type",
-        classUnderTest,
-        getActualClassName(unicode));
+    assertWithMessage("%s from string must have the expected type", classUnderTest)
+        .that(classUnderTest)
+        .isEqualTo(getActualClassName(unicode));
     String roundTripString = unicode.toString(UTF_8);
-    assertEquals(classUnderTest + " unicode bytes must match", testString, roundTripString);
+    assertWithMessage("%s unicode bytes must match", classUnderTest)
+        .that(testString)
+        .isEqualTo(roundTripString);
     ByteString flatString = ByteString.copyFromUtf8(testString);
-    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
-    assertEquals(
-        classUnderTest + " string must must have same hashCode as the flat string",
-        flatString.hashCode(),
-        unicode.hashCode());
+    assertWithMessage("%s string must equal the flat string", classUnderTest)
+        .that(flatString)
+        .isEqualTo(unicode);
+    assertWithMessage("%s string must must have same hashCode as the flat string", classUnderTest)
+        .that(flatString.hashCode())
+        .isEqualTo(unicode.hashCode());
   }
 
   @Override
+  @Test
   public void testCharsetToString() {
     String sourceString = "I love unicode \u1234\u5678 characters";
     ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
@@ -157,36 +172,39 @@
     }
     String testString = builder.toString();
 
-    assertEquals(
-        classUnderTest + " from string must have the expected type",
-        classUnderTest,
-        getActualClassName(unicode));
+    assertWithMessage("%s from string must have the expected type", classUnderTest)
+        .that(classUnderTest)
+        .isEqualTo(getActualClassName(unicode));
     String roundTripString = unicode.toString(Internal.UTF_8);
-    assertEquals(classUnderTest + " unicode bytes must match", testString, roundTripString);
+    assertWithMessage("%s unicode bytes must match", classUnderTest)
+        .that(testString)
+        .isEqualTo(roundTripString);
     ByteString flatString = ByteString.copyFromUtf8(testString);
-    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
-    assertEquals(
-        classUnderTest + " string must must have same hashCode as the flat string",
-        flatString.hashCode(),
-        unicode.hashCode());
+    assertWithMessage("%s string must equal the flat string", classUnderTest)
+        .that(flatString)
+        .isEqualTo(unicode);
+    assertWithMessage("%s string must must have same hashCode as the flat string", classUnderTest)
+        .that(flatString.hashCode())
+        .isEqualTo(unicode.hashCode());
   }
 
   @Override
+  @Test
   public void testToString_returnsCanonicalEmptyString() {
     RopeByteString ropeByteString =
         RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
-    assertSame(
-        classUnderTest + " must be the same string references",
-        ByteString.EMPTY.toString(Internal.UTF_8),
-        ropeByteString.toString(Internal.UTF_8));
+    assertWithMessage("%s must be the same string references", classUnderTest)
+        .that(ByteString.EMPTY.toString(Internal.UTF_8))
+        .isSameInstanceAs(ropeByteString.toString(Internal.UTF_8));
   }
 
   @Override
+  @Test
   public void testToString_raisesException() {
     try {
       ByteString byteString = RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
       byteString.toString("invalid");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (UnsupportedEncodingException expected) {
       // This is success
     }
@@ -196,13 +214,14 @@
           RopeByteString.concatenate(
               ByteString.copyFromUtf8("foo"), ByteString.copyFromUtf8("bar"));
       byteString.toString("invalid");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (UnsupportedEncodingException expected) {
       // This is success
     }
   }
 
   @Override
+  @Test
   public void testJavaSerialization() throws Exception {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(out);
@@ -212,7 +231,7 @@
     InputStream in = new ByteArrayInputStream(pickled);
     ObjectInputStream ois = new ObjectInputStream(in);
     Object o = ois.readObject();
-    assertTrue("Didn't get a ByteString back", o instanceof ByteString);
-    assertEquals("Should get an equal ByteString back", stringUnderTest, o);
+    assertWithMessage("Didn't get a ByteString back").that(o).isInstanceOf(ByteString.class);
+    assertWithMessage("Should get an equal ByteString back").that(o).isEqualTo(stringUnderTest);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
index 1592433..8b98661 100644
--- a/java/core/src/test/java/com/google/protobuf/ServiceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.google.protobuf.Descriptors.FileDescriptor;
 import com.google.protobuf.Descriptors.MethodDescriptor;
 import protobuf_unittest.MessageWithNoOuter;
@@ -43,17 +46,17 @@
 import protobuf_unittest.no_generic_services_test.UnittestNoGenericServices;
 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 org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests services and stubs.
- *
- * @author [email protected] Kenton Varda
- */
-public class ServiceTest extends TestCase {
+/** Tests services and stubs. */
+@RunWith(JUnit4.class)
+public class ServiceTest {
   private IMocksControl control;
   private RpcController mockController;
 
@@ -62,9 +65,8 @@
   private final Descriptors.MethodDescriptor barDescriptor =
       TestService.getDescriptor().getMethods().get(1);
 
-  @Override
-  protected void setUp() throws Exception {
-    super.setUp();
+  @Before
+  public void setUp() throws Exception {
     control = EasyMock.createStrictControl();
     mockController = control.createMock(RpcController.class);
   }
@@ -72,6 +74,7 @@
   // =================================================================
 
   /** Tests Service.callMethod(). */
+  @Test
   public void testCallMethod() throws Exception {
     FooRequest fooRequest = FooRequest.newBuilder().build();
     BarRequest barRequest = BarRequest.newBuilder().build();
@@ -99,16 +102,22 @@
   }
 
   /** Tests Service.get{Request,Response}Prototype(). */
+  @Test
   public void testGetPrototype() throws Exception {
     TestService mockService = control.createMock(TestService.class);
 
-    assertSame(mockService.getRequestPrototype(fooDescriptor), FooRequest.getDefaultInstance());
-    assertSame(mockService.getResponsePrototype(fooDescriptor), FooResponse.getDefaultInstance());
-    assertSame(mockService.getRequestPrototype(barDescriptor), BarRequest.getDefaultInstance());
-    assertSame(mockService.getResponsePrototype(barDescriptor), BarResponse.getDefaultInstance());
+    assertThat(mockService.getRequestPrototype(fooDescriptor))
+        .isSameInstanceAs(FooRequest.getDefaultInstance());
+    assertThat(mockService.getResponsePrototype(fooDescriptor))
+        .isSameInstanceAs(FooResponse.getDefaultInstance());
+    assertThat(mockService.getRequestPrototype(barDescriptor))
+        .isSameInstanceAs(BarRequest.getDefaultInstance());
+    assertThat(mockService.getResponsePrototype(barDescriptor))
+        .isSameInstanceAs(BarResponse.getDefaultInstance());
   }
 
   /** Tests generated stubs. */
+  @Test
   public void testStub() throws Exception {
     FooRequest fooRequest = FooRequest.newBuilder().build();
     BarRequest barRequest = BarRequest.newBuilder().build();
@@ -137,6 +146,7 @@
   }
 
   /** Tests generated blocking stubs. */
+  @Test
   public void testBlockingStub() throws Exception {
     FooRequest fooRequest = FooRequest.newBuilder().build();
     BarRequest barRequest = BarRequest.newBuilder().build();
@@ -162,11 +172,12 @@
         .andReturn(barResponse);
     control.replay();
 
-    assertSame(fooResponse, stub.foo(mockController, fooRequest));
-    assertSame(barResponse, stub.bar(mockController, barRequest));
+    assertThat(fooResponse).isSameInstanceAs(stub.foo(mockController, fooRequest));
+    assertThat(barResponse).isSameInstanceAs(stub.bar(mockController, barRequest));
     control.verify();
   }
 
+  @Test
   public void testNewReflectiveService() {
     ServiceWithNoOuter.Interface impl = control.createMock(ServiceWithNoOuter.Interface.class);
     RpcController controller = control.createMock(RpcController.class);
@@ -179,7 +190,7 @@
           @Override
           public void run(Message parameter) {
             // No reason this should be run.
-            fail();
+            assertWithMessage("should not run").fail();
           }
         };
     RpcCallback<TestAllTypes> specializedCallback = RpcUtil.specializeCallback(callback);
@@ -194,6 +205,7 @@
     control.verify();
   }
 
+  @Test
   public void testNewReflectiveBlockingService() throws ServiceException {
     ServiceWithNoOuter.BlockingInterface impl =
         control.createMock(ServiceWithNoOuter.BlockingInterface.class);
@@ -210,11 +222,12 @@
     control.replay();
 
     Message response = service.callBlockingMethod(fooMethod, controller, request);
-    assertEquals(expectedResponse, response);
+    assertThat(response).isEqualTo(expectedResponse);
 
     control.verify();
   }
 
+  @Test
   public void testNoGenericServices() throws Exception {
     // Non-services should be usable.
     UnittestNoGenericServices.TestMessage message =
@@ -222,8 +235,8 @@
             .setA(123)
             .setExtension(UnittestNoGenericServices.testExtension, 456)
             .build();
-    assertEquals(123, message.getA());
-    assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
+    assertThat(message.getA()).isEqualTo(123);
+    assertThat(UnittestNoGenericServices.TestEnum.FOO.getNumber()).isEqualTo(1);
 
     // Build a list of the class names nested in UnittestNoGenericServices.
     String outerName =
@@ -239,7 +252,7 @@
       //   mentioned in the documentation for java.lang.Class.  I don't want to
       //   make assumptions, so I'm just going to accept any character as the
       //   separator.
-      assertTrue(fullName.startsWith(outerName));
+      assertThat(fullName).startsWith(outerName);
 
       if (!Service.class.isAssignableFrom(innerClass)
           && !Message.class.isAssignableFrom(innerClass)
@@ -252,16 +265,16 @@
     }
 
     // No service class should have been generated.
-    assertTrue(innerClassNames.contains("TestMessage"));
-    assertTrue(innerClassNames.contains("TestEnum"));
-    assertFalse(innerClassNames.contains("TestService"));
+    assertThat(innerClassNames).contains("TestMessage");
+    assertThat(innerClassNames).contains("TestEnum");
+    assertThat(innerClassNames).doesNotContain("TestService");
 
     // But descriptors are there.
     FileDescriptor file = UnittestNoGenericServices.getDescriptor();
-    assertEquals(1, file.getServices().size());
-    assertEquals("TestService", file.getServices().get(0).getName());
-    assertEquals(1, file.getServices().get(0).getMethods().size());
-    assertEquals("Foo", file.getServices().get(0).getMethods().get(0).getName());
+    assertThat(file.getServices()).hasSize(1);
+    assertThat(file.getServices().get(0).getName()).isEqualTo("TestService");
+    assertThat(file.getServices().get(0).getMethods()).hasSize(1);
+    assertThat(file.getServices().get(0).getMethods().get(0).getName()).isEqualTo("Foo");
   }
 
 
@@ -308,7 +321,7 @@
       if (!(actual instanceof RpcCallback)) {
         return false;
       }
-      RpcCallback actualCallback = (RpcCallback) actual;
+      RpcCallback<?> actualCallback = (RpcCallback<?>) actual;
 
       callback.reset();
       actualCallback.run(null);
diff --git a/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
index f2ae8f9..d2215b0 100644
--- a/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
+++ b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
@@ -30,100 +30,103 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Tests for {@link SingleFieldBuilderV3}. This tests basic functionality. More extensive testing is
  * provided via other tests that exercise the builder.
- *
- * @author [email protected] (Jon Perlow)
  */
-public class SingleFieldBuilderV3Test extends TestCase {
+@RunWith(JUnit4.class)
+public class SingleFieldBuilderV3Test {
 
+  @Test
   public void testBasicUseAndInvalidations() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
     SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(), mockParent, false);
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-    assertEquals(TestAllTypes.getDefaultInstance(), builder.getBuilder().buildPartial());
-    assertEquals(0, mockParent.getInvalidationCount());
+        new SingleFieldBuilderV3<>(TestAllTypes.getDefaultInstance(), mockParent, false);
+    assertThat(builder.getMessage()).isSameInstanceAs(TestAllTypes.getDefaultInstance());
+    assertThat(builder.getBuilder().buildPartial()).isEqualTo(TestAllTypes.getDefaultInstance());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
 
     builder.getBuilder().setOptionalInt32(10);
-    assertEquals(0, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
     TestAllTypes message = builder.build();
-    assertEquals(10, message.getOptionalInt32());
+    assertThat(message.getOptionalInt32()).isEqualTo(10);
 
     // Test that we receive invalidations now that build has been called.
-    assertEquals(0, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
     builder.getBuilder().setOptionalInt32(20);
-    assertEquals(1, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(1);
 
     // Test that we don't keep getting invalidations on every change
     builder.getBuilder().setOptionalInt32(30);
-    assertEquals(1, mockParent.getInvalidationCount());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(1);
   }
 
+  @Test
   public void testSetMessage() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
     SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(), mockParent, false);
+        new SingleFieldBuilderV3<>(TestAllTypes.getDefaultInstance(), mockParent, false);
     builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    assertEquals(0, builder.getMessage().getOptionalInt32());
+    assertThat(builder.getMessage().getOptionalInt32()).isEqualTo(0);
 
     // Update message using the builder
     builder.getBuilder().setOptionalInt32(1);
-    assertEquals(0, mockParent.getInvalidationCount());
-    assertEquals(1, builder.getBuilder().getOptionalInt32());
-    assertEquals(1, builder.getMessage().getOptionalInt32());
+    assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
+    assertThat(builder.getBuilder().getOptionalInt32()).isEqualTo(1);
+    assertThat(builder.getMessage().getOptionalInt32()).isEqualTo(1);
     builder.build();
     builder.getBuilder().setOptionalInt32(2);
-    assertEquals(2, builder.getBuilder().getOptionalInt32());
-    assertEquals(2, builder.getMessage().getOptionalInt32());
+    assertThat(builder.getBuilder().getOptionalInt32()).isEqualTo(2);
+    assertThat(builder.getMessage().getOptionalInt32()).isEqualTo(2);
 
     // Make sure message stays cached
-    assertSame(builder.getMessage(), builder.getMessage());
+    assertThat(builder.getMessage()).isSameInstanceAs(builder.getMessage());
   }
 
+  @Test
   public void testClear() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
     SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(), mockParent, false);
+        new SingleFieldBuilderV3<>(TestAllTypes.getDefaultInstance(), mockParent, false);
     builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+    assertThat(TestAllTypes.getDefaultInstance()).isNotSameInstanceAs(builder.getMessage());
     builder.clear();
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+    assertThat(builder.getMessage()).isSameInstanceAs(TestAllTypes.getDefaultInstance());
 
     builder.getBuilder().setOptionalInt32(1);
-    assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+    assertThat(TestAllTypes.getDefaultInstance()).isNotSameInstanceAs(builder.getMessage());
     builder.clear();
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+    assertThat(builder.getMessage()).isSameInstanceAs(TestAllTypes.getDefaultInstance());
   }
 
+  @Test
   public void testMerge() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
     SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder, TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(), mockParent, false);
+        new SingleFieldBuilderV3<>(TestAllTypes.getDefaultInstance(), mockParent, false);
 
     // Merge into default field.
     builder.mergeFrom(TestAllTypes.getDefaultInstance());
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+    assertThat(builder.getMessage()).isSameInstanceAs(TestAllTypes.getDefaultInstance());
 
     // Merge into non-default field on existing builder.
     builder.getBuilder().setOptionalInt32(2);
     builder.mergeFrom(TestAllTypes.newBuilder().setOptionalDouble(4.0).buildPartial());
-    assertEquals(2, builder.getMessage().getOptionalInt32());
-    assertEquals(4.0, builder.getMessage().getOptionalDouble(), 0.0);
+    assertThat(builder.getMessage().getOptionalInt32()).isEqualTo(2);
+    assertThat(builder.getMessage().getOptionalDouble()).isEqualTo(4.0);
 
     // Merge into non-default field on existing message
     builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(10).buildPartial());
     builder.mergeFrom(TestAllTypes.newBuilder().setOptionalDouble(5.0).buildPartial());
-    assertEquals(10, builder.getMessage().getOptionalInt32());
-    assertEquals(5.0, builder.getMessage().getOptionalDouble(), 0.0);
+    assertThat(builder.getMessage().getOptionalInt32()).isEqualTo(10);
+    assertThat(builder.getMessage().getOptionalDouble()).isEqualTo(5.0);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
index a1a7194..fdeccc2 100644
--- a/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
@@ -30,6 +30,10 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+import static java.lang.Math.min;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -38,10 +42,12 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/** @author [email protected] Darick Tong */
-public class SmallSortedMapTest extends TestCase {
+@RunWith(JUnit4.class)
+public class SmallSortedMapTest {
   // java.util.AbstractMap.SimpleEntry is private in JDK 1.5. We re-implement it
   // here for JDK 1.5 users.
   private static class SimpleEntry<K, V> implements Map.Entry<K, V> {
@@ -79,7 +85,7 @@
       if (!(o instanceof Map.Entry)) {
         return false;
       }
-      Map.Entry e = (Map.Entry) o;
+      Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
       return eq(key, e.getKey()) && eq(value, e.getValue());
     }
 
@@ -89,10 +95,12 @@
     }
   }
 
+  @Test
   public void testPutAndGetArrayEntriesOnly() {
     runPutAndGetTest(3);
   }
 
+  @Test
   public void testPutAndGetOverflowEntries() {
     runPutAndGetTest(6);
   }
@@ -106,214 +114,224 @@
 
     // Test with puts in ascending order.
     for (int i = 0; i < numElements; i++) {
-      assertNull(map1.put(i, i + 1));
-      assertNull(map2.put(i, i + 1));
+      assertThat(map1.put(i, i + 1)).isNull();
+      assertThat(map2.put(i, i + 1)).isNull();
     }
     // Test with puts in descending order.
     for (int i = numElements - 1; i >= 0; i--) {
-      assertNull(map3.put(i, i + 1));
-      assertNull(map4.put(i, i + 1));
+      assertThat(map3.put(i, i + 1)).isNull();
+      assertThat(map4.put(i, i + 1)).isNull();
     }
 
-    assertEquals(Math.min(3, numElements), map1.getNumArrayEntries());
-    assertEquals(Math.min(4, numElements), map2.getNumArrayEntries());
-    assertEquals(Math.min(3, numElements), map3.getNumArrayEntries());
-    assertEquals(Math.min(4, numElements), map4.getNumArrayEntries());
+    assertThat(map1.getNumArrayEntries()).isEqualTo(min(3, numElements));
+    assertThat(map2.getNumArrayEntries()).isEqualTo(min(4, numElements));
+    assertThat(map3.getNumArrayEntries()).isEqualTo(min(3, numElements));
+    assertThat(map4.getNumArrayEntries()).isEqualTo(min(4, numElements));
 
-    List<SmallSortedMap<Integer, Integer>> allMaps =
-        new ArrayList<SmallSortedMap<Integer, Integer>>();
+    List<SmallSortedMap<Integer, Integer>> allMaps = new ArrayList<>();
     allMaps.add(map1);
     allMaps.add(map2);
     allMaps.add(map3);
     allMaps.add(map4);
 
     for (SmallSortedMap<Integer, Integer> map : allMaps) {
-      assertEquals(numElements, map.size());
+      assertThat(map).hasSize(numElements);
       for (int i = 0; i < numElements; i++) {
-        assertEquals(Integer.valueOf(i + 1), map.get(i));
+        assertThat(map).containsEntry(i, Integer.valueOf(i + 1));
       }
     }
 
-    assertEquals(map1, map2);
-    assertEquals(map2, map3);
-    assertEquals(map3, map4);
+    assertThat(map1).isEqualTo(map2);
+    assertThat(map2).isEqualTo(map3);
+    assertThat(map3).isEqualTo(map4);
   }
 
+  @Test
   public void testReplacingPut() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-      assertNull(map.remove(i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
+      assertThat(map.remove(i + 1)).isNull();
     }
     for (int i = 0; i < 6; i++) {
-      assertEquals(Integer.valueOf(i + 1), map.put(i, i + 2));
+      assertThat(map.put(i, i + 2)).isEqualTo(Integer.valueOf(i + 1));
     }
   }
 
+  @Test
   public void testRemove() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-      assertNull(map.remove(i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
+      assertThat(map.remove(i + 1)).isNull();
     }
 
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(3, map.getNumOverflowEntries());
-    assertEquals(6, map.size());
-    assertEquals(makeSortedKeySet(0, 1, 2, 3, 4, 5), map.keySet());
+    assertThat(map.getNumArrayEntries()).isEqualTo(3);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(3);
+    assertThat(map).hasSize(6);
+    assertThat(map.keySet()).isEqualTo(makeSortedKeySet(0, 1, 2, 3, 4, 5));
 
-    assertEquals(Integer.valueOf(2), map.remove(1));
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(2, map.getNumOverflowEntries());
-    assertEquals(5, map.size());
-    assertEquals(makeSortedKeySet(0, 2, 3, 4, 5), map.keySet());
+    assertThat(map.remove(1)).isEqualTo(Integer.valueOf(2));
+    assertThat(map.getNumArrayEntries()).isEqualTo(3);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(2);
+    assertThat(map).hasSize(5);
+    assertThat(map.keySet()).isEqualTo(makeSortedKeySet(0, 2, 3, 4, 5));
 
-    assertEquals(Integer.valueOf(5), map.remove(4));
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(1, map.getNumOverflowEntries());
-    assertEquals(4, map.size());
-    assertEquals(makeSortedKeySet(0, 2, 3, 5), map.keySet());
+    assertThat(map.remove(4)).isEqualTo(Integer.valueOf(5));
+    assertThat(map.getNumArrayEntries()).isEqualTo(3);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(1);
+    assertThat(map).hasSize(4);
+    assertThat(map.keySet()).isEqualTo(makeSortedKeySet(0, 2, 3, 5));
 
-    assertEquals(Integer.valueOf(4), map.remove(3));
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(3, map.size());
-    assertEquals(makeSortedKeySet(0, 2, 5), map.keySet());
+    assertThat(map.remove(3)).isEqualTo(Integer.valueOf(4));
+    assertThat(map.getNumArrayEntries()).isEqualTo(3);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(0);
+    assertThat(map).hasSize(3);
+    assertThat(map.keySet()).isEqualTo(makeSortedKeySet(0, 2, 5));
 
-    assertNull(map.remove(3));
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(3, map.size());
+    assertThat(map.remove(3)).isNull();
+    assertThat(map.getNumArrayEntries()).isEqualTo(3);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(0);
+    assertThat(map).hasSize(3);
 
-    assertEquals(Integer.valueOf(1), map.remove(0));
-    assertEquals(2, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(2, map.size());
+    assertThat(map.remove(0)).isEqualTo(Integer.valueOf(1));
+    assertThat(map.getNumArrayEntries()).isEqualTo(2);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(0);
+    assertThat(map).hasSize(2);
   }
 
+  @Test
   public void testClear() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
     }
     map.clear();
-    assertEquals(0, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(0, map.size());
+    assertThat(map.getNumArrayEntries()).isEqualTo(0);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(0);
+    assertThat(map).isEmpty();
   }
 
+  @Test
   public void testGetArrayEntryAndOverflowEntries() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
     }
-    assertEquals(3, map.getNumArrayEntries());
+    assertThat(map.getNumArrayEntries()).isEqualTo(3);
     for (int i = 0; i < 3; i++) {
       Map.Entry<Integer, Integer> entry = map.getArrayEntryAt(i);
-      assertEquals(Integer.valueOf(i), entry.getKey());
-      assertEquals(Integer.valueOf(i + 1), entry.getValue());
+      assertThat(entry.getKey()).isEqualTo(Integer.valueOf(i));
+      assertThat(entry.getValue()).isEqualTo(Integer.valueOf(i + 1));
     }
     Iterator<Map.Entry<Integer, Integer>> it = map.getOverflowEntries().iterator();
     for (int i = 3; i < 6; i++) {
-      assertTrue(it.hasNext());
+      assertThat(it.hasNext()).isTrue();
       Map.Entry<Integer, Integer> entry = it.next();
-      assertEquals(Integer.valueOf(i), entry.getKey());
-      assertEquals(Integer.valueOf(i + 1), entry.getValue());
+      assertThat(entry.getKey()).isEqualTo(Integer.valueOf(i));
+      assertThat(entry.getValue()).isEqualTo(Integer.valueOf(i + 1));
     }
-    assertFalse(it.hasNext());
+    assertThat(it.hasNext()).isFalse();
   }
 
+  @Test
   public void testEntrySetContains() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
     }
     Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
     for (int i = 0; i < 6; i++) {
-      assertTrue(entrySet.contains(new SimpleEntry<Integer, Integer>(i, i + 1)));
-      assertFalse(entrySet.contains(new SimpleEntry<Integer, Integer>(i, i)));
+      assertThat(entrySet).contains(new SimpleEntry<Integer, Integer>(i, i + 1));
+      assertThat(entrySet).doesNotContain(new SimpleEntry<Integer, Integer>(i, i));
     }
   }
 
+  @Test
   public void testEntrySetAdd() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
     for (int i = 0; i < 6; i++) {
-      Map.Entry<Integer, Integer> entry = new SimpleEntry<Integer, Integer>(i, i + 1);
-      assertTrue(entrySet.add(entry));
-      assertFalse(entrySet.add(entry));
+      Map.Entry<Integer, Integer> entry = new SimpleEntry<>(i, i + 1);
+      assertThat(entrySet.add(entry)).isTrue();
+      assertThat(entrySet.add(entry)).isFalse();
     }
     for (int i = 0; i < 6; i++) {
-      assertEquals(Integer.valueOf(i + 1), map.get(i));
+      assertThat(map).containsEntry(i, Integer.valueOf(i + 1));
     }
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(3, map.getNumOverflowEntries());
-    assertEquals(6, map.size());
+    assertThat(map.getNumArrayEntries()).isEqualTo(3);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(3);
+    assertThat(map).hasSize(6);
   }
 
+  @Test
   public void testEntrySetRemove() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
     }
     for (int i = 0; i < 6; i++) {
-      Map.Entry<Integer, Integer> entry = new SimpleEntry<Integer, Integer>(i, i + 1);
-      assertTrue(entrySet.remove(entry));
-      assertFalse(entrySet.remove(entry));
+      Map.Entry<Integer, Integer> entry = new SimpleEntry<>(i, i + 1);
+      assertThat(entrySet.remove(entry)).isTrue();
+      assertThat(entrySet.remove(entry)).isFalse();
     }
-    assertTrue(map.isEmpty());
-    assertEquals(0, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(0, map.size());
+    assertThat(map).isEmpty();
+    assertThat(map.getNumArrayEntries()).isEqualTo(0);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(0);
+    assertThat(map).isEmpty();
   }
 
+  @Test
   public void testEntrySetClear() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
     }
     map.clear();
-    assertTrue(map.isEmpty());
-    assertEquals(0, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(0, map.size());
+    assertThat(map).isEmpty();
+    assertThat(map.getNumArrayEntries()).isEqualTo(0);
+    assertThat(map.getNumOverflowEntries()).isEqualTo(0);
+    assertThat(map).isEmpty();
   }
 
+  @Test
   public void testEntrySetIteratorNext() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
     }
     Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
     for (int i = 0; i < 6; i++) {
-      assertTrue(it.hasNext());
+      assertThat(it.hasNext()).isTrue();
       Map.Entry<Integer, Integer> entry = it.next();
-      assertEquals(Integer.valueOf(i), entry.getKey());
-      assertEquals(Integer.valueOf(i + 1), entry.getValue());
+      assertThat(entry.getKey()).isEqualTo(Integer.valueOf(i));
+      assertThat(entry.getValue()).isEqualTo(Integer.valueOf(i + 1));
     }
-    assertFalse(it.hasNext());
+    assertThat(it.hasNext()).isFalse();
   }
 
+  @Test
   public void testEntrySetIteratorRemove() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
     }
     Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
     for (int i = 0; i < 6; i++) {
-      assertTrue(map.containsKey(i));
+      assertThat(map).containsKey(i);
       it.next();
       it.remove();
-      assertFalse(map.containsKey(i));
-      assertEquals(6 - i - 1, map.size());
+      assertThat(map).doesNotContainKey(i);
+      assertThat(map).hasSize(6 - i - 1);
     }
   }
 
+  @Test
   public void testMapEntryModification() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
     }
     Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
     for (int i = 0; i < 6; i++) {
@@ -321,49 +339,50 @@
       entry.setValue(i + 23);
     }
     for (int i = 0; i < 6; i++) {
-      assertEquals(Integer.valueOf(i + 23), map.get(i));
+      assertThat(map).containsEntry(i, Integer.valueOf(i + 23));
     }
   }
 
+  @Test
   public void testMakeImmutable() {
     SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
     for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
+      assertThat(map.put(i, i + 1)).isNull();
     }
     map.makeImmutable();
-    assertEquals(Integer.valueOf(1), map.get(0));
-    assertEquals(6, map.size());
+    assertThat(map).containsEntry(0, Integer.valueOf(1));
+    assertThat(map).hasSize(6);
 
     try {
       map.put(23, 23);
-      fail("Expected UnsupportedOperationException");
+      assertWithMessage("Expected UnsupportedOperationException").fail();
     } catch (UnsupportedOperationException expected) {
     }
 
-    Map<Integer, Integer> other = new HashMap<Integer, Integer>();
+    Map<Integer, Integer> other = new HashMap<>();
     other.put(23, 23);
     try {
       map.putAll(other);
-      fail("Expected UnsupportedOperationException");
+      assertWithMessage("Expected UnsupportedOperationException").fail();
     } catch (UnsupportedOperationException expected) {
     }
 
     try {
       map.remove(0);
-      fail("Expected UnsupportedOperationException");
+      assertWithMessage("Expected UnsupportedOperationException").fail();
     } catch (UnsupportedOperationException expected) {
     }
 
     try {
       map.clear();
-      fail("Expected UnsupportedOperationException");
+      assertWithMessage("Expected UnsupportedOperationException").fail();
     } catch (UnsupportedOperationException expected) {
     }
 
     Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
     try {
       entrySet.clear();
-      fail("Expected UnsupportedOperationException");
+      assertWithMessage("Expected UnsupportedOperationException").fail();
     } catch (UnsupportedOperationException expected) {
     }
 
@@ -372,12 +391,12 @@
       Map.Entry<Integer, Integer> entry = it.next();
       try {
         entry.setValue(0);
-        fail("Expected UnsupportedOperationException");
+        assertWithMessage("Expected UnsupportedOperationException").fail();
       } catch (UnsupportedOperationException expected) {
       }
       try {
         it.remove();
-        fail("Expected UnsupportedOperationException");
+        assertWithMessage("Expected UnsupportedOperationException").fail();
       } catch (UnsupportedOperationException expected) {
       }
     }
@@ -385,7 +404,7 @@
     Set<Integer> keySet = map.keySet();
     try {
       keySet.clear();
-      fail("Expected UnsupportedOperationException");
+      assertWithMessage("Expected UnsupportedOperationException").fail();
     } catch (UnsupportedOperationException expected) {
     }
 
@@ -394,18 +413,18 @@
       Integer key = keys.next();
       try {
         keySet.remove(key);
-        fail("Expected UnsupportedOperationException");
+        assertWithMessage("Expected UnsupportedOperationException").fail();
       } catch (UnsupportedOperationException expected) {
       }
       try {
         keys.remove();
-        fail("Expected UnsupportedOperationException");
+        assertWithMessage("Expected UnsupportedOperationException").fail();
       } catch (UnsupportedOperationException expected) {
       }
     }
   }
 
   private Set<Integer> makeSortedKeySet(Integer... keys) {
-    return new TreeSet<Integer>(Arrays.<Integer>asList(keys));
+    return new TreeSet<>(Arrays.<Integer>asList(keys));
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java
index 523e23a..ab32e2a 100644
--- a/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java
+++ b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import junit.framework.TestCase;
 
 /**
@@ -55,37 +57,37 @@
     TestBadIdentifiersProto.TestConflictingFieldNames message =
         TestBadIdentifiersProto.TestConflictingFieldNames.getDefaultInstance();
     // Make sure generated accessors are properly named.
-    assertEquals(0, message.getInt32Field1Count());
-    assertEquals(0, message.getEnumField2Count());
-    assertEquals(0, message.getStringField3Count());
-    assertEquals(0, message.getBytesField4Count());
-    assertEquals(0, message.getMessageField5Count());
+    assertThat(message.getInt32Field1Count()).isEqualTo(0);
+    assertThat(message.getEnumField2Count()).isEqualTo(0);
+    assertThat(message.getStringField3Count()).isEqualTo(0);
+    assertThat(message.getBytesField4Count()).isEqualTo(0);
+    assertThat(message.getMessageField5Count()).isEqualTo(0);
 
-    assertEquals(0, message.getInt32FieldCount11());
-    assertEquals(0, message.getEnumFieldCount12().getNumber());
-    assertEquals("", message.getStringFieldCount13());
-    assertEquals(ByteString.EMPTY, message.getBytesFieldCount14());
-    assertEquals(0, message.getMessageFieldCount15().getSerializedSize());
+    assertThat(message.getInt32FieldCount11()).isEqualTo(0);
+    assertThat(message.getEnumFieldCount12().getNumber()).isEqualTo(0);
+    assertThat(message.getStringFieldCount13()).isEmpty();
+    assertThat(message.getBytesFieldCount14()).isEqualTo(ByteString.EMPTY);
+    assertThat(message.getMessageFieldCount15().getSerializedSize()).isEqualTo(0);
 
-    assertEquals(0, message.getInt32Field21Count());
-    assertEquals(0, message.getEnumField22Count());
-    assertEquals(0, message.getStringField23Count());
-    assertEquals(0, message.getBytesField24Count());
-    assertEquals(0, message.getMessageField25Count());
+    assertThat(message.getInt32Field21Count()).isEqualTo(0);
+    assertThat(message.getEnumField22Count()).isEqualTo(0);
+    assertThat(message.getStringField23Count()).isEqualTo(0);
+    assertThat(message.getBytesField24Count()).isEqualTo(0);
+    assertThat(message.getMessageField25Count()).isEqualTo(0);
 
-    assertEquals(0, message.getInt32Field1List().size());
-    assertEquals(0, message.getInt32FieldList31());
+    assertThat(message.getInt32Field1List()).isEmpty();
+    assertThat(message.getInt32FieldList31()).isEqualTo(0);
 
-    assertEquals(0, message.getInt64FieldCount());
-    assertEquals(
-        0L,
-        message
-            .getExtension(TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount)
-            .longValue());
-    assertEquals(
-        0L,
-        message
-            .getExtension(TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList)
-            .longValue());
+    assertThat(message.getInt64FieldCount()).isEqualTo(0);
+    assertThat(
+            message
+                .getExtension(TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount)
+                .longValue())
+        .isEqualTo(0L);
+    assertThat(
+            message
+                .getExtension(TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList)
+                .longValue())
+        .isEqualTo(0L);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java
index 6c1021f..936a525 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -3770,7 +3770,7 @@
     } catch (IOException e) {
       throw new RuntimeException("Couldn't get canonical name of working directory.", e);
     }
-    
+
     String srcRootCheck = "src/google/protobuf";
 
     // If we're running w/ Bazel on Windows, we're not in a sandbox, so we
@@ -3779,6 +3779,7 @@
     if (testBinaryName != null && testBinaryName.endsWith(".exe")) {
       srcRootCheck = srcRootCheck + "/descriptor.cc";
     }
+
     while (ancestor != null && ancestor.exists()) {
       // Identify the true source root.
       if (new File(ancestor, srcRootCheck).exists()) {
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java
index ff41372..5d0eb62 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java
@@ -30,13 +30,20 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import protobuf_unittest.UnittestProto.TestAllTypes;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Test @{link TextFormatParseInfoTree}. */
-public class TextFormatParseInfoTreeTest extends TestCase {
+@RunWith(JUnit4.class)
+public class TextFormatParseInfoTreeTest {
 
   private static final Descriptor DESCRIPTOR = TestAllTypes.getDescriptor();
   private static final FieldDescriptor OPTIONAL_INT32 =
@@ -57,110 +64,121 @@
 
   private TextFormatParseInfoTree.Builder rootBuilder;
 
-  @Override
+  @Before
   public void setUp() {
     rootBuilder = TextFormatParseInfoTree.builder();
   }
 
+  @Test
   public void testBuildEmptyParseTree() {
     TextFormatParseInfoTree tree = rootBuilder.build();
-    assertTrue(tree.getLocations(null).isEmpty());
+    assertThat(tree.getLocations(null)).isEmpty();
   }
 
+  @Test
   public void testGetLocationReturnsSingleLocation() {
     rootBuilder.setLocation(OPTIONAL_INT32, LOC0);
     TextFormatParseInfoTree root = rootBuilder.build();
-    assertEquals(LOC0, root.getLocation(OPTIONAL_INT32, 0));
-    assertEquals(1, root.getLocations(OPTIONAL_INT32).size());
+    assertThat(root.getLocation(OPTIONAL_INT32, 0)).isEqualTo(LOC0);
+    assertThat(root.getLocations(OPTIONAL_INT32)).hasSize(1);
   }
 
+  @Test
   public void testGetLocationsReturnsNoParseLocationsForUnknownField() {
-    assertTrue(rootBuilder.build().getLocations(OPTIONAL_INT32).isEmpty());
+    assertThat(rootBuilder.build().getLocations(OPTIONAL_INT32)).isEmpty();
     rootBuilder.setLocation(OPTIONAL_BOOLEAN, LOC0);
     TextFormatParseInfoTree root = rootBuilder.build();
-    assertTrue(root.getLocations(OPTIONAL_INT32).isEmpty());
-    assertEquals(LOC0, root.getLocations(OPTIONAL_BOOLEAN).get(0));
+    assertThat(root.getLocations(OPTIONAL_INT32)).isEmpty();
+    assertThat(root.getLocations(OPTIONAL_BOOLEAN).get(0)).isEqualTo(LOC0);
   }
 
+  @Test
   public void testGetLocationThrowsIllegalArgumentExceptionForUnknownField() {
     rootBuilder.setLocation(REPEATED_INT32, LOC0);
     TextFormatParseInfoTree root = rootBuilder.build();
     try {
       root.getNestedTree(OPTIONAL_INT32, 0);
-      fail("Did not detect unknown field");
+      assertWithMessage("Did not detect unknown field").fail();
     } catch (IllegalArgumentException expected) {
       // pass
     }
   }
 
+  @Test
   public void testGetLocationThrowsIllegalArgumentExceptionForInvalidIndex() {
     TextFormatParseInfoTree root = rootBuilder.setLocation(OPTIONAL_INT32, LOC0).build();
     try {
       root.getLocation(OPTIONAL_INT32, 1);
-      fail("Invalid index not detected");
+      assertWithMessage("Invalid index not detected").fail();
     } catch (IllegalArgumentException expected) {
       // pass
     }
     try {
       root.getLocation(OPTIONAL_INT32, -1);
-      fail("Negative index not detected");
+      assertWithMessage("Negative index not detected").fail();
     } catch (IllegalArgumentException expected) {
       // pass
     }
   }
 
+  @Test
   public void testGetLocationsReturnsMultipleLocations() {
     rootBuilder.setLocation(REPEATED_INT32, LOC0);
     rootBuilder.setLocation(REPEATED_INT32, LOC1);
     TextFormatParseInfoTree root = rootBuilder.build();
-    assertEquals(LOC0, root.getLocation(REPEATED_INT32, 0));
-    assertEquals(LOC1, root.getLocation(REPEATED_INT32, 1));
-    assertEquals(2, root.getLocations(REPEATED_INT32).size());
+    assertThat(root.getLocation(REPEATED_INT32, 0)).isEqualTo(LOC0);
+    assertThat(root.getLocation(REPEATED_INT32, 1)).isEqualTo(LOC1);
+    assertThat(root.getLocations(REPEATED_INT32)).hasSize(2);
   }
 
+  @Test
   public void testGetNestedTreeThrowsIllegalArgumentExceptionForUnknownField() {
     rootBuilder.setLocation(REPEATED_INT32, LOC0);
     TextFormatParseInfoTree root = rootBuilder.build();
     try {
       root.getNestedTree(OPTIONAL_NESTED_MESSAGE, 0);
-      fail("Did not detect unknown field");
+      assertWithMessage("Did not detect unknown field").fail();
     } catch (IllegalArgumentException expected) {
       // pass
     }
   }
 
+  @Test
   public void testGetNestedTreesReturnsNoParseInfoTreesForUnknownField() {
     rootBuilder.setLocation(REPEATED_INT32, LOC0);
     TextFormatParseInfoTree root = rootBuilder.build();
-    assertTrue(root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).isEmpty());
+    assertThat(root.getNestedTrees(OPTIONAL_NESTED_MESSAGE)).isEmpty();
   }
 
+  @Test
   public void testGetNestedTreeThrowsIllegalArgumentExceptionForInvalidIndex() {
     rootBuilder.setLocation(REPEATED_INT32, LOC0);
     rootBuilder.getBuilderForSubMessageField(OPTIONAL_NESTED_MESSAGE);
     TextFormatParseInfoTree root = rootBuilder.build();
     try {
       root.getNestedTree(OPTIONAL_NESTED_MESSAGE, 1);
-      fail("Submessage index that is too large not detected");
+      assertWithMessage("Submessage index that is too large not detected").fail();
     } catch (IllegalArgumentException expected) {
       // pass
     }
     try {
       rootBuilder.build().getNestedTree(OPTIONAL_NESTED_MESSAGE, -1);
-      fail("Invalid submessage index (-1) not detected");
+      assertWithMessage("Invalid submessage index (-1) not detected").fail();
     } catch (IllegalArgumentException expected) {
       // pass
     }
   }
 
+  @Test
   public void testGetNestedTreesReturnsSingleTree() {
     rootBuilder.getBuilderForSubMessageField(OPTIONAL_NESTED_MESSAGE);
     TextFormatParseInfoTree root = rootBuilder.build();
-    assertEquals(1, root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).size());
+    assertThat(root.getNestedTrees(OPTIONAL_NESTED_MESSAGE)).hasSize(1);
     TextFormatParseInfoTree subtree = root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).get(0);
-    assertNotNull(subtree);
+    assertThat(subtree).isNotNull();
   }
 
+  @Test
   public void testGetNestedTreesReturnsMultipleTrees() {
     TextFormatParseInfoTree.Builder subtree1Builder =
         rootBuilder.getBuilderForSubMessageField(REPEATED_NESTED_MESSAGE);
@@ -170,10 +188,10 @@
         rootBuilder.getBuilderForSubMessageField(REPEATED_NESTED_MESSAGE);
     subtree2Builder.getBuilderForSubMessageField(FIELD_BB);
     TextFormatParseInfoTree root = rootBuilder.build();
-    assertEquals(2, root.getNestedTrees(REPEATED_NESTED_MESSAGE).size());
-    assertEquals(
-        2, root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(0).getNestedTrees(FIELD_BB).size());
-    assertEquals(
-        1, root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(1).getNestedTrees(FIELD_BB).size());
+    assertThat(root.getNestedTrees(REPEATED_NESTED_MESSAGE)).hasSize(2);
+    assertThat(root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(0).getNestedTrees(FIELD_BB))
+        .hasSize(2);
+    assertThat(root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(1).getNestedTrees(FIELD_BB))
+        .hasSize(1);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java
index 19abc3f..ed20df5 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java
@@ -30,55 +30,66 @@
 
 package com.google.protobuf;
 
-import junit.framework.TestCase;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Test @{link TextFormatParseLocation}. */
-public class TextFormatParseLocationTest extends TestCase {
+@RunWith(JUnit4.class)
+public class TextFormatParseLocationTest {
 
+  @Test
   public void testCreateEmpty() {
     TextFormatParseLocation location = TextFormatParseLocation.create(-1, -1);
-    assertEquals(TextFormatParseLocation.EMPTY, location);
+    assertThat(location).isEqualTo(TextFormatParseLocation.EMPTY);
   }
 
+  @Test
   public void testCreate() {
     TextFormatParseLocation location = TextFormatParseLocation.create(2, 1);
-    assertEquals(2, location.getLine());
-    assertEquals(1, location.getColumn());
+    assertThat(location.getLine()).isEqualTo(2);
+    assertThat(location.getColumn()).isEqualTo(1);
   }
 
+  @Test
   public void testCreateThrowsIllegalArgumentExceptionForInvalidIndex() {
     try {
       TextFormatParseLocation.create(-1, 0);
-      fail("Should throw IllegalArgumentException if line is less than 0");
+      assertWithMessage("Should throw IllegalArgumentException if line is less than 0").fail();
     } catch (IllegalArgumentException unused) {
       // pass
     }
     try {
       TextFormatParseLocation.create(0, -1);
-      fail("Should throw, column < 0");
+      assertWithMessage("Should throw, column < 0").fail();
     } catch (IllegalArgumentException unused) {
       // pass
     }
   }
 
+  @Test
   public void testHashCode() {
     TextFormatParseLocation loc0 = TextFormatParseLocation.create(2, 1);
     TextFormatParseLocation loc1 = TextFormatParseLocation.create(2, 1);
 
-    assertEquals(loc0.hashCode(), loc1.hashCode());
-    assertEquals(
-        TextFormatParseLocation.EMPTY.hashCode(), TextFormatParseLocation.EMPTY.hashCode());
+    assertThat(loc0.hashCode()).isEqualTo(loc1.hashCode());
+    assertThat(TextFormatParseLocation.EMPTY.hashCode())
+        .isEqualTo(TextFormatParseLocation.EMPTY.hashCode());
   }
 
+  @Test
   public void testEquals() {
     TextFormatParseLocation loc0 = TextFormatParseLocation.create(2, 1);
     TextFormatParseLocation loc1 = TextFormatParseLocation.create(1, 2);
     TextFormatParseLocation loc2 = TextFormatParseLocation.create(2, 2);
     TextFormatParseLocation loc3 = TextFormatParseLocation.create(2, 1);
 
-    assertEquals(loc0, loc3);
-    assertNotSame(loc0, loc1);
-    assertNotSame(loc0, loc2);
-    assertNotSame(loc1, loc2);
+    assertThat(loc0).isEqualTo(loc3);
+    assertThat(loc0).isNotSameInstanceAs(loc1);
+    assertThat(loc0).isNotSameInstanceAs(loc2);
+    assertThat(loc1).isNotSameInstanceAs(loc2);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
index a919f3b..69568e1 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -31,6 +31,7 @@
 package com.google.protobuf;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
 import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
 
@@ -59,16 +60,17 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.logging.Logger;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Test case for {@link TextFormat}.
  *
  * <p>TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc.
- *
- * @author [email protected] (Wenbo Zhu)
  */
-public class TextFormatTest extends TestCase {
+@RunWith(JUnit4.class)
+public class TextFormatTest {
 
   // A basic string with different escapable characters for testing.
   private static final String ESCAPE_TEST_STRING =
@@ -79,12 +81,12 @@
       "\\\"A string with \\' characters \\n and \\r newlines "
           + "and \\t tabs and \\001 slashes \\\\";
 
-  private static String allFieldsSetText =
+  private static final String ALL_FIELDS_SET_TEXT =
       TestUtil.readTextFromFile("text_format_unittest_data_oneof_implemented.txt");
-  private static String allExtensionsSetText =
+  private static final String ALL_EXTENSIONS_SET_TEXT =
       TestUtil.readTextFromFile("text_format_unittest_extensions_data.txt");
 
-  private static String exoticText =
+  private static final String EXOTIC_TEXT =
       ""
           + "repeated_int32: -1\n"
           + "repeated_int32: -2147483648\n"
@@ -114,8 +116,8 @@
           + "\\341\\210\\264\"\n"
           + "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
 
-  private static String canonicalExoticText =
-      exoticText
+  private static final String CANONICAL_EXOTIC_TEXT =
+      EXOTIC_TEXT
           .replace(": .", ": 0.")
           .replace(": -.", ": -0.") // short-form double
           .replace("23e", "23E")
@@ -123,7 +125,7 @@
           .replace("0.23E17", "2.3E16")
           .replace(",", "");
 
-  private String messageSetText =
+  private static final String MESSAGE_SET_TEXT =
       ""
           + "[protobuf_unittest.TestMessageSetExtension1] {\n"
           + "  i: 123\n"
@@ -132,7 +134,7 @@
           + "  str: \"foo\"\n"
           + "}\n";
 
-  private String messageSetTextWithRepeatedExtension =
+  private static final String MESSAGE_SET_TEXT_WITH_REPEATED_EXTENSION =
       ""
           + "[protobuf_unittest.TestMessageSetExtension1] {\n"
           + "  i: 123\n"
@@ -141,20 +143,21 @@
           + "  i: 456\n"
           + "}\n";
 
-  private final TextFormat.Parser parserAllowingUnknownFields =
+  private static final TextFormat.Parser PARSER_ALLOWING_UNKNOWN_FIELDS =
       TextFormat.Parser.newBuilder().setAllowUnknownFields(true).build();
 
-  private final TextFormat.Parser parserAllowingUnknownExtensions =
+  private static final TextFormat.Parser PARSER_ALLOWING_UNKNOWN_EXTENSIONS =
       TextFormat.Parser.newBuilder().setAllowUnknownExtensions(true).build();
 
-  private final TextFormat.Parser parserWithOverwriteForbidden =
+  private static final TextFormat.Parser PARSER_WITH_OVERWRITE_FORBIDDEN =
       TextFormat.Parser.newBuilder()
           .setSingularOverwritePolicy(SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
           .build();
 
-  private final TextFormat.Parser defaultParser = TextFormat.Parser.newBuilder().build();
+  private static final TextFormat.Parser DEFAULT_PARSER = TextFormat.Parser.newBuilder().build();
 
   /** Print TestAllTypes and compare with golden file. */
+  @Test
   public void testPrintMessage() throws Exception {
     String javaText = TextFormat.printer().printToString(TestUtil.getAllSet());
 
@@ -163,10 +166,11 @@
     // C++ and Java TextFormat classes, so we need to conform.
     javaText = javaText.replace(".0\n", "\n");
 
-    assertEquals(allFieldsSetText, javaText);
+    assertThat(javaText).isEqualTo(ALL_FIELDS_SET_TEXT);
   }
 
   /** Print TestAllTypes as Builder and compare with golden file. */
+  @Test
   public void testPrintMessageBuilder() throws Exception {
     String javaText = TextFormat.printer().printToString(TestUtil.getAllSetBuilder());
 
@@ -175,10 +179,11 @@
     // C++ and Java TextFormat classes, so we need to conform.
     javaText = javaText.replace(".0\n", "\n");
 
-    assertEquals(allFieldsSetText, javaText);
+    assertThat(javaText).isEqualTo(ALL_FIELDS_SET_TEXT);
   }
 
   /** Print TestAllExtensions and compare with golden file. */
+  @Test
   public void testPrintExtensions() throws Exception {
     String javaText = TextFormat.printer().printToString(TestUtil.getAllExtensionsSet());
 
@@ -187,7 +192,7 @@
     // C++ and Java TextFormat classes, so we need to conform.
     javaText = javaText.replace(".0\n", "\n");
 
-    assertEquals(allExtensionsSetText, javaText);
+    assertThat(javaText).isEqualTo(ALL_EXTENSIONS_SET_TEXT);
   }
 
   // Creates an example unknown field set.
@@ -223,44 +228,45 @@
         .build();
   }
 
+  @Test
   public void testPrintUnknownFields() throws Exception {
     // Test printing of unknown fields in a message.
 
     TestEmptyMessage message =
         TestEmptyMessage.newBuilder().setUnknownFields(makeUnknownFieldSet()).build();
 
-    assertEquals(
-        "5: 1\n"
-            + "5: 0x00000002\n"
-            + "5: 0x0000000000000003\n"
-            + "5: \"4\"\n"
-            + "5: {\n"
-            + "  12: 6\n"
-            + "}\n"
-            + "5 {\n"
-            + "  10: 5\n"
-            + "}\n"
-            + "8: 1\n"
-            + "8: 2\n"
-            + "8: 3\n"
-            + "15: 12379813812177893520\n"
-            + "15: 0xabcd1234\n"
-            + "15: 0xabcdef1234567890\n",
-        TextFormat.printer().printToString(message));
+    assertThat(TextFormat.printer().printToString(message))
+        .isEqualTo(
+            "5: 1\n"
+                + "5: 0x00000002\n"
+                + "5: 0x0000000000000003\n"
+                + "5: \"4\"\n"
+                + "5: {\n"
+                + "  12: 6\n"
+                + "}\n"
+                + "5 {\n"
+                + "  10: 5\n"
+                + "}\n"
+                + "8: 1\n"
+                + "8: 2\n"
+                + "8: 3\n"
+                + "15: 12379813812177893520\n"
+                + "15: 0xabcd1234\n"
+                + "15: 0xabcdef1234567890\n");
   }
 
+  @Test
   public void testPrintField() throws Exception {
     final FieldDescriptor dataField = OneString.getDescriptor().findFieldByName("data");
-    assertEquals(
-        "data: \"test data\"\n", TextFormat.printer().printFieldToString(dataField, "test data"));
+    assertThat(TextFormat.printer().printFieldToString(dataField, "test data"))
+        .isEqualTo("data: \"test data\"\n");
 
     final FieldDescriptor optionalField =
         TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
     final Object value = NestedMessage.newBuilder().setBb(42).build();
 
-    assertEquals(
-        "optional_nested_message {\n  bb: 42\n}\n",
-        TextFormat.printer().printFieldToString(optionalField, value));
+    assertThat(TextFormat.printer().printFieldToString(optionalField, value))
+        .isEqualTo("optional_nested_message {\n  bb: 42\n}\n");
   }
 
   /**
@@ -283,6 +289,7 @@
     return ByteString.copyFrom(bytes);
   }
 
+  @Test
   public void testPrintExotic() throws Exception {
     Message message =
         TestAllTypes.newBuilder()
@@ -319,9 +326,10 @@
             .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe"))
             .build();
 
-    assertEquals(canonicalExoticText, message.toString());
+    assertThat(message.toString()).isEqualTo(CANONICAL_EXOTIC_TEXT);
   }
 
+  @Test
   public void testRoundtripProto3Optional() throws Exception {
     Message message =
         TestProto3Optional.newBuilder()
@@ -332,14 +340,15 @@
     TestProto3Optional.Builder message2 = TestProto3Optional.newBuilder();
     TextFormat.merge(message.toString(), message2);
 
-    assertTrue(message2.hasOptionalInt32());
-    assertTrue(message2.hasOptionalInt64());
-    assertTrue(message2.hasOptionalNestedEnum());
-    assertEquals(1, message2.getOptionalInt32());
-    assertEquals(2, message2.getOptionalInt64());
-    assertEquals(NestedEnum.BAZ, message2.getOptionalNestedEnum());
+    assertThat(message2.hasOptionalInt32()).isTrue();
+    assertThat(message2.hasOptionalInt64()).isTrue();
+    assertThat(message2.hasOptionalNestedEnum()).isTrue();
+    assertThat(message2.getOptionalInt32()).isEqualTo(1);
+    assertThat(message2.getOptionalInt64()).isEqualTo(2);
+    assertThat(message2.getOptionalNestedEnum()).isEqualTo(NestedEnum.BAZ);
   }
 
+  @Test
   public void testPrintMessageSet() throws Exception {
     TestMessageSet messageSet =
         TestMessageSet.newBuilder()
@@ -351,69 +360,79 @@
                 TestMessageSetExtension2.newBuilder().setStr("foo").build())
             .build();
 
-    assertEquals(messageSetText, messageSet.toString());
+    assertThat(messageSet.toString()).isEqualTo(MESSAGE_SET_TEXT);
   }
 
   // =================================================================
 
+  @Test
   public void testMerge() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(allFieldsSetText, builder);
+    TextFormat.merge(ALL_FIELDS_SET_TEXT, builder);
     TestUtil.assertAllFieldsSet(builder.build());
   }
 
+  @Test
   public void testParse() throws Exception {
-    TestUtil.assertAllFieldsSet(TextFormat.parse(allFieldsSetText, TestAllTypes.class));
+    TestUtil.assertAllFieldsSet(TextFormat.parse(ALL_FIELDS_SET_TEXT, TestAllTypes.class));
   }
 
+  @Test
   public void testMergeInitialized() throws Exception {
     TestRequired.Builder builder = TestRequired.newBuilder();
     TextFormat.merge(TEST_REQUIRED_INITIALIZED.toString(), builder);
-    assertEquals(TEST_REQUIRED_INITIALIZED.toString(), builder.buildPartial().toString());
-    assertTrue(builder.isInitialized());
+    assertThat(builder.buildPartial().toString()).isEqualTo(TEST_REQUIRED_INITIALIZED.toString());
+    assertThat(builder.isInitialized()).isTrue();
   }
 
+  @Test
   public void testParseInitialized() throws Exception {
     TestRequired parsed =
         TextFormat.parse(TEST_REQUIRED_INITIALIZED.toString(), TestRequired.class);
-    assertEquals(TEST_REQUIRED_INITIALIZED.toString(), parsed.toString());
-    assertTrue(parsed.isInitialized());
+    assertThat(parsed.toString()).isEqualTo(TEST_REQUIRED_INITIALIZED.toString());
+    assertThat(parsed.isInitialized()).isTrue();
   }
 
+  @Test
   public void testMergeUninitialized() throws Exception {
     TestRequired.Builder builder = TestRequired.newBuilder();
     TextFormat.merge(TEST_REQUIRED_UNINITIALIZED.toString(), builder);
-    assertEquals(TEST_REQUIRED_UNINITIALIZED.toString(), builder.buildPartial().toString());
-    assertFalse(builder.isInitialized());
+    assertThat(builder.buildPartial().toString()).isEqualTo(TEST_REQUIRED_UNINITIALIZED.toString());
+    assertThat(builder.isInitialized()).isFalse();
   }
 
+  @Test
   public void testParseUninitialized() throws Exception {
     try {
       TextFormat.parse(TEST_REQUIRED_UNINITIALIZED.toString(), TestRequired.class);
-      fail("Expected UninitializedMessageException.");
+      assertWithMessage("Expected UninitializedMessageException.").fail();
     } catch (UninitializedMessageException e) {
-      assertEquals("Message missing required fields: b, c", e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: b, c");
     }
   }
 
+  @Test
   public void testMergeReader() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(new StringReader(allFieldsSetText), builder);
+    TextFormat.merge(new StringReader(ALL_FIELDS_SET_TEXT), builder);
     TestUtil.assertAllFieldsSet(builder.build());
   }
 
+  @Test
   public void testMergeExtensions() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    TextFormat.merge(allExtensionsSetText, TestUtil.getFullExtensionRegistry(), builder);
+    TextFormat.merge(ALL_EXTENSIONS_SET_TEXT, TestUtil.getFullExtensionRegistry(), builder);
     TestUtil.assertAllExtensionsSet(builder.build());
   }
 
+  @Test
   public void testParseExtensions() throws Exception {
     TestUtil.assertAllExtensionsSet(
         TextFormat.parse(
-            allExtensionsSetText, TestUtil.getFullExtensionRegistry(), TestAllExtensions.class));
+            ALL_EXTENSIONS_SET_TEXT, TestUtil.getFullExtensionRegistry(), TestAllExtensions.class));
   }
 
+  @Test
   public void testMergeAndParseCompatibility() throws Exception {
     String original =
         "repeated_float: inf\n"
@@ -445,82 +464,93 @@
     // Test merge().
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(original, builder);
-    assertEquals(canonical, builder.build().toString());
+    assertThat(builder.build().toString()).isEqualTo(canonical);
 
     // Test parse().
-    assertEquals(canonical, TextFormat.parse(original, TestAllTypes.class).toString());
+    assertThat(TextFormat.parse(original, TestAllTypes.class).toString()).isEqualTo(canonical);
   }
 
+  @Test
   public void testMergeAndParseExotic() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(exoticText, builder);
+    TextFormat.merge(EXOTIC_TEXT, builder);
 
     // Too lazy to check things individually.  Don't try to debug this
     // if testPrintExotic() is failing.
-    assertEquals(canonicalExoticText, builder.build().toString());
-    assertEquals(canonicalExoticText, TextFormat.parse(exoticText, TestAllTypes.class).toString());
+    assertThat(builder.build().toString()).isEqualTo(CANONICAL_EXOTIC_TEXT);
+    assertThat(TextFormat.parse(EXOTIC_TEXT, TestAllTypes.class).toString())
+        .isEqualTo(CANONICAL_EXOTIC_TEXT);
   }
 
+  @Test
   public void testMergeMessageSet() throws Exception {
     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
 
     TestMessageSet.Builder builder = TestMessageSet.newBuilder();
-    TextFormat.merge(messageSetText, extensionRegistry, builder);
+    TextFormat.merge(MESSAGE_SET_TEXT, extensionRegistry, builder);
     TestMessageSet messageSet = builder.build();
 
-    assertTrue(messageSet.hasExtension(TestMessageSetExtension1.messageSetExtension));
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
-    assertTrue(messageSet.hasExtension(TestMessageSetExtension2.messageSetExtension));
-    assertEquals(
-        "foo", messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr());
+    assertThat(messageSet.hasExtension(TestMessageSetExtension1.messageSetExtension)).isTrue();
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
+    assertThat(messageSet.hasExtension(TestMessageSetExtension2.messageSetExtension)).isTrue();
+    assertThat(messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr())
+        .isEqualTo("foo");
 
     builder = TestMessageSet.newBuilder();
-    TextFormat.merge(messageSetTextWithRepeatedExtension, extensionRegistry, builder);
+    TextFormat.merge(MESSAGE_SET_TEXT_WITH_REPEATED_EXTENSION, extensionRegistry, builder);
     messageSet = builder.build();
-    assertEquals(456, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(456);
   }
 
+  @Test
   public void testMergeMessageSetWithOverwriteForbidden() throws Exception {
     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
 
     TestMessageSet.Builder builder = TestMessageSet.newBuilder();
-    parserWithOverwriteForbidden.merge(messageSetText, extensionRegistry, builder);
+    PARSER_WITH_OVERWRITE_FORBIDDEN.merge(MESSAGE_SET_TEXT, extensionRegistry, builder);
     TestMessageSet messageSet = builder.build();
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
-    assertEquals(
-        "foo", messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
+    assertThat(messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr())
+        .isEqualTo("foo");
 
     builder = TestMessageSet.newBuilder();
     try {
-      parserWithOverwriteForbidden.merge(
-          messageSetTextWithRepeatedExtension, extensionRegistry, builder);
-      fail("expected parse exception");
+      PARSER_WITH_OVERWRITE_FORBIDDEN.merge(
+          MESSAGE_SET_TEXT_WITH_REPEATED_EXTENSION, extensionRegistry, builder);
+      assertWithMessage("expected parse exception").fail();
     } catch (TextFormat.ParseException e) {
-      assertEquals(
-          "4:44: Non-repeated field "
-              + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
-              + " cannot be overwritten.",
-          e.getMessage());
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo(
+              "4:44: Non-repeated field "
+                  + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
+                  + " cannot be overwritten.");
     }
   }
 
+  @Test
   public void testMergeNumericEnum() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge("optional_nested_enum: 2", builder);
-    assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
+    assertThat(builder.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.BAR);
   }
 
+  @Test
   public void testMergeAngleBrackets() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge("OptionalGroup: < a: 1 >", builder);
-    assertTrue(builder.hasOptionalGroup());
-    assertEquals(1, builder.getOptionalGroup().getA());
+    assertThat(builder.hasOptionalGroup()).isTrue();
+    assertThat(builder.getOptionalGroup().getA()).isEqualTo(1);
   }
 
+  @Test
   public void testMergeComment() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(
@@ -529,10 +559,11 @@
             + "optional_int64: 2\n"
             + "# EOF comment",
         builder);
-    assertEquals(1, builder.getOptionalInt32());
-    assertEquals(2, builder.getOptionalInt64());
+    assertThat(builder.getOptionalInt32()).isEqualTo(1);
+    assertThat(builder.getOptionalInt64()).isEqualTo(2);
   }
 
+  @Test
   public void testPrintAny_customBuiltTypeRegistry() throws Exception {
     TestAny testAny =
         TestAny.newBuilder()
@@ -553,7 +584,7 @@
             + "    optional_int32: 12345\n"
             + "  }\n"
             + "}\n";
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
   private static Descriptor createDescriptorForAny(FieldDescriptorProto... fields)
@@ -573,6 +604,7 @@
     return fileDescriptor.getMessageTypes().get(0);
   }
 
+  @Test
   public void testPrintAny_anyWithDynamicMessage() throws Exception {
     Descriptor descriptor =
         createDescriptorForAny(
@@ -605,9 +637,10 @@
         "[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n"
             + "  optional_int32: 12345\n"
             + "}\n";
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
+  @Test
   public void testPrintAny_anyFromWithNoValueField() throws Exception {
     Descriptor descriptor =
         createDescriptorForAny(
@@ -628,9 +661,10 @@
             .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
             .printToString(testAny);
     String expected = "type_url: \"type.googleapis.com/protobuf_unittest.TestAllTypes\"\n";
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
+  @Test
   public void testPrintAny_anyFromWithNoTypeUrlField() throws Exception {
     Descriptor descriptor =
         createDescriptorForAny(
@@ -651,9 +685,10 @@
             .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
             .printToString(testAny);
     String expected = "value: \"\\b\\271`\"\n";
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
+  @Test
   public void testPrintAny_anyWithInvalidFieldType() throws Exception {
     Descriptor descriptor =
         createDescriptorForAny(
@@ -682,10 +717,11 @@
             .printToString(testAny);
     String expected =
         "type_url: \"type.googleapis.com/protobuf_unittest.TestAllTypes\"\n" + "value: \"test\"\n";
-    assertEquals(expected, actual);
+    assertThat(actual).isEqualTo(expected);
   }
 
 
+  @Test
   public void testMergeAny_customBuiltTypeRegistry() throws Exception {
     TestAny.Builder builder = TestAny.newBuilder();
     TextFormat.Parser.newBuilder()
@@ -701,21 +737,22 @@
                 + "}\n"
                 + "}",
             builder);
-    assertEquals(
-        TestAny.newBuilder()
-            .setValue(
-                Any.newBuilder()
-                    .setTypeUrl("type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
-                    .setValue(
-                        TestAllTypes.newBuilder()
-                            .setOptionalInt32(12345)
-                            .setOptionalNestedMessage(
-                                TestAllTypes.NestedMessage.newBuilder().setBb(123))
-                            .build()
-                            .toByteString())
-                    .build())
-            .build(),
-        builder.build());
+    assertThat(builder.build())
+        .isEqualTo(
+            TestAny.newBuilder()
+                .setValue(
+                    Any.newBuilder()
+                        .setTypeUrl(
+                            "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
+                        .setValue(
+                            TestAllTypes.newBuilder()
+                                .setOptionalInt32(12345)
+                                .setOptionalNestedMessage(
+                                    TestAllTypes.NestedMessage.newBuilder().setBb(123))
+                                .build()
+                                .toByteString())
+                        .build())
+                .build());
   }
 
 
@@ -724,71 +761,72 @@
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
       TextFormat.merge(text, TestUtil.getFullExtensionRegistry(), builder);
-      fail("Expected parse exception.");
+      assertWithMessage("Expected parse exception.").fail();
     } catch (TextFormat.ParseException e) {
-      assertEquals(error, e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo(error);
     }
 
     // Test parse().
     try {
       TextFormat.parse(text, TestUtil.getFullExtensionRegistry(), TestAllTypes.class);
-      fail("Expected parse exception.");
+      assertWithMessage("Expected parse exception.").fail();
     } catch (TextFormat.ParseException e) {
-      assertEquals(error, e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo(error);
     }
   }
 
   private void assertParseErrorWithUnknownFields(String error, String text) {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
-      parserAllowingUnknownFields.merge(text, TestUtil.getFullExtensionRegistry(), builder);
-      fail("Expected parse exception.");
+      PARSER_ALLOWING_UNKNOWN_FIELDS.merge(text, TestUtil.getFullExtensionRegistry(), builder);
+      assertWithMessage("Expected parse exception.").fail();
     } catch (TextFormat.ParseException e) {
-      assertEquals(error, e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo(error);
     }
   }
 
   private TestAllTypes assertParseSuccessWithUnknownFields(String text)
       throws TextFormat.ParseException {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    parserAllowingUnknownFields.merge(text, TestUtil.getFullExtensionRegistry(), builder);
+    PARSER_ALLOWING_UNKNOWN_FIELDS.merge(text, TestUtil.getFullExtensionRegistry(), builder);
     return builder.build();
   }
 
   private void assertParseErrorWithUnknownExtensions(String error, String text) {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
-      parserAllowingUnknownExtensions.merge(text, builder);
-      fail("Expected parse exception.");
+      PARSER_ALLOWING_UNKNOWN_EXTENSIONS.merge(text, builder);
+      assertWithMessage("Expected parse exception.").fail();
     } catch (TextFormat.ParseException e) {
-      assertEquals(error, e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo(error);
     }
   }
 
   private TestAllTypes assertParseSuccessWithUnknownExtensions(String text)
       throws TextFormat.ParseException {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    parserAllowingUnknownExtensions.merge(text, builder);
+    PARSER_ALLOWING_UNKNOWN_EXTENSIONS.merge(text, builder);
     return builder.build();
   }
 
   private void assertParseErrorWithOverwriteForbidden(String error, String text) {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
-      parserWithOverwriteForbidden.merge(text, TestUtil.getFullExtensionRegistry(), builder);
-      fail("Expected parse exception.");
+      PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, TestUtil.getFullExtensionRegistry(), builder);
+      assertWithMessage("Expected parse exception.").fail();
     } catch (TextFormat.ParseException e) {
-      assertEquals(error, e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo(error);
     }
   }
 
   private TestAllTypes assertParseSuccessWithOverwriteForbidden(String text)
       throws TextFormat.ParseException {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    parserWithOverwriteForbidden.merge(text, TestUtil.getFullExtensionRegistry(), builder);
+    PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, TestUtil.getFullExtensionRegistry(), builder);
     return builder.build();
   }
 
+  @Test
   public void testParseErrors() throws Exception {
     assertParseError("1:16: Expected \":\".", "optional_int32 123");
     assertParseError("1:23: Expected identifier. Found '?'", "optional_nested_enum: ?");
@@ -837,73 +875,70 @@
 
   // =================================================================
 
+  @Test
   public void testEscape() throws Exception {
     // Escape sequences.
-    assertEquals(
-        "\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177",
-        TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\177")));
-    assertEquals(
-        "\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177",
-        TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\"\177"));
-    assertEquals(
-        bytes("\0\001\007\b\f\n\r\t\013\\\'\""),
-        TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
-    assertEquals(
-        "\0\001\007\b\f\n\r\t\013\\\'\"",
-        TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
-    assertEquals(ESCAPE_TEST_STRING_ESCAPED, TextFormat.escapeText(ESCAPE_TEST_STRING));
-    assertEquals(ESCAPE_TEST_STRING, TextFormat.unescapeText(ESCAPE_TEST_STRING_ESCAPED));
+    assertThat(TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\177")))
+        .isEqualTo("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177");
+    assertThat(TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\"\177"))
+        .isEqualTo("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177");
+    assertThat(TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""))
+        .isEqualTo(bytes("\0\001\007\b\f\n\r\t\013\\\'\""));
+    assertThat(TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""))
+        .isEqualTo("\0\001\007\b\f\n\r\t\013\\\'\"");
+    assertThat(TextFormat.escapeText(ESCAPE_TEST_STRING)).isEqualTo(ESCAPE_TEST_STRING_ESCAPED);
+    assertThat(TextFormat.unescapeText(ESCAPE_TEST_STRING_ESCAPED)).isEqualTo(ESCAPE_TEST_STRING);
 
     // Invariant
-    assertEquals("hello", TextFormat.escapeBytes(bytes("hello")));
-    assertEquals("hello", TextFormat.escapeText("hello"));
-    assertEquals(bytes("hello"), TextFormat.unescapeBytes("hello"));
-    assertEquals("hello", TextFormat.unescapeText("hello"));
+    assertThat(TextFormat.escapeBytes(bytes("hello"))).isEqualTo("hello");
+    assertThat(TextFormat.escapeText("hello")).isEqualTo("hello");
+    assertThat(TextFormat.unescapeBytes("hello")).isEqualTo(bytes("hello"));
+    assertThat(TextFormat.unescapeText("hello")).isEqualTo("hello");
 
     // Unicode handling.
-    assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234"));
-    assertEquals("\\341\\210\\264", TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4)));
-    assertEquals("\u1234", TextFormat.unescapeText("\\341\\210\\264"));
-    assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\341\\210\\264"));
-    assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4"));
-    assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\xe1\\x88\\xb4"));
-    assertEquals("\u1234", TextFormat.unescapeText("\\u1234"));
-    assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\u1234"));
-    assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\U00001234"));
-    assertEquals(
-        new String(new int[] {0x10437}, 0, 1), TextFormat.unescapeText("\\xf0\\x90\\x90\\xb7"));
-    assertEquals(bytes(0xf0, 0x90, 0x90, 0xb7), TextFormat.unescapeBytes("\\U00010437"));
+    assertThat(TextFormat.escapeText("\u1234")).isEqualTo("\\341\\210\\264");
+    assertThat(TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4))).isEqualTo("\\341\\210\\264");
+    assertThat(TextFormat.unescapeText("\\341\\210\\264")).isEqualTo("\u1234");
+    assertThat(TextFormat.unescapeBytes("\\341\\210\\264")).isEqualTo(bytes(0xe1, 0x88, 0xb4));
+    assertThat(TextFormat.unescapeText("\\xe1\\x88\\xb4")).isEqualTo("\u1234");
+    assertThat(TextFormat.unescapeBytes("\\xe1\\x88\\xb4")).isEqualTo(bytes(0xe1, 0x88, 0xb4));
+    assertThat(TextFormat.unescapeText("\\u1234")).isEqualTo("\u1234");
+    assertThat(TextFormat.unescapeBytes("\\u1234")).isEqualTo(bytes(0xe1, 0x88, 0xb4));
+    assertThat(TextFormat.unescapeBytes("\\U00001234")).isEqualTo(bytes(0xe1, 0x88, 0xb4));
+    assertThat(TextFormat.unescapeText("\\xf0\\x90\\x90\\xb7"))
+        .isEqualTo(new String(new int[] {0x10437}, 0, 1));
+    assertThat(TextFormat.unescapeBytes("\\U00010437")).isEqualTo(bytes(0xf0, 0x90, 0x90, 0xb7));
 
     // Handling of strings with unescaped Unicode characters > 255.
     final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
     ByteString zhByteString = ByteString.copyFromUtf8(zh);
-    assertEquals(zhByteString, TextFormat.unescapeBytes(zh));
+    assertThat(TextFormat.unescapeBytes(zh)).isEqualTo(zhByteString);
 
     // Errors.
     try {
       TextFormat.unescapeText("\\x");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       // success
     }
 
     try {
       TextFormat.unescapeText("\\z");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       // success
     }
 
     try {
       TextFormat.unescapeText("\\");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       // success
     }
 
     try {
       TextFormat.unescapeText("\\u");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       assertThat(e)
           .hasMessageThat()
@@ -912,7 +947,7 @@
 
     try {
       TextFormat.unescapeText("\\ud800");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       assertThat(e)
           .hasMessageThat()
@@ -921,7 +956,7 @@
 
     try {
       TextFormat.unescapeText("\\ud800\\u1234");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       assertThat(e)
           .hasMessageThat()
@@ -930,7 +965,7 @@
 
     try {
       TextFormat.unescapeText("\\udc00");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       assertThat(e)
           .hasMessageThat()
@@ -939,7 +974,7 @@
 
     try {
       TextFormat.unescapeText("\\ud801\\udc37");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       assertThat(e)
           .hasMessageThat()
@@ -948,7 +983,7 @@
 
     try {
       TextFormat.unescapeText("\\U1234");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       assertThat(e)
           .hasMessageThat()
@@ -957,7 +992,7 @@
 
     try {
       TextFormat.unescapeText("\\U1234no more hex");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       assertThat(e)
           .hasMessageThat()
@@ -966,7 +1001,7 @@
 
     try {
       TextFormat.unescapeText("\\U00110000");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       assertThat(e)
           .hasMessageThat()
@@ -975,7 +1010,7 @@
 
     try {
       TextFormat.unescapeText("\\U0000d801\\U00000dc37");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       assertThat(e)
           .hasMessageThat()
@@ -983,106 +1018,107 @@
     }
   }
 
+  @Test
   public void testParseInteger() throws Exception {
-    assertEquals(0, TextFormat.parseInt32("0"));
-    assertEquals(1, TextFormat.parseInt32("1"));
-    assertEquals(-1, TextFormat.parseInt32("-1"));
-    assertEquals(12345, TextFormat.parseInt32("12345"));
-    assertEquals(-12345, TextFormat.parseInt32("-12345"));
-    assertEquals(2147483647, TextFormat.parseInt32("2147483647"));
-    assertEquals(-2147483648, TextFormat.parseInt32("-2147483648"));
+    assertThat(TextFormat.parseInt32("0")).isEqualTo(0);
+    assertThat(TextFormat.parseInt32("1")).isEqualTo(1);
+    assertThat(TextFormat.parseInt32("-1")).isEqualTo(-1);
+    assertThat(TextFormat.parseInt32("12345")).isEqualTo(12345);
+    assertThat(TextFormat.parseInt32("-12345")).isEqualTo(-12345);
+    assertThat(TextFormat.parseInt32("2147483647")).isEqualTo(2147483647);
+    assertThat(TextFormat.parseInt32("-2147483648")).isEqualTo(-2147483648);
 
-    assertEquals(0, TextFormat.parseUInt32("0"));
-    assertEquals(1, TextFormat.parseUInt32("1"));
-    assertEquals(12345, TextFormat.parseUInt32("12345"));
-    assertEquals(2147483647, TextFormat.parseUInt32("2147483647"));
-    assertEquals((int) 2147483648L, TextFormat.parseUInt32("2147483648"));
-    assertEquals((int) 4294967295L, TextFormat.parseUInt32("4294967295"));
+    assertThat(TextFormat.parseUInt32("0")).isEqualTo(0);
+    assertThat(TextFormat.parseUInt32("1")).isEqualTo(1);
+    assertThat(TextFormat.parseUInt32("12345")).isEqualTo(12345);
+    assertThat(TextFormat.parseUInt32("2147483647")).isEqualTo(2147483647);
+    assertThat(TextFormat.parseUInt32("2147483648")).isEqualTo((int) 2147483648L);
+    assertThat(TextFormat.parseUInt32("4294967295")).isEqualTo((int) 4294967295L);
 
-    assertEquals(0L, TextFormat.parseInt64("0"));
-    assertEquals(1L, TextFormat.parseInt64("1"));
-    assertEquals(-1L, TextFormat.parseInt64("-1"));
-    assertEquals(12345L, TextFormat.parseInt64("12345"));
-    assertEquals(-12345L, TextFormat.parseInt64("-12345"));
-    assertEquals(2147483647L, TextFormat.parseInt64("2147483647"));
-    assertEquals(-2147483648L, TextFormat.parseInt64("-2147483648"));
-    assertEquals(4294967295L, TextFormat.parseInt64("4294967295"));
-    assertEquals(4294967296L, TextFormat.parseInt64("4294967296"));
-    assertEquals(9223372036854775807L, TextFormat.parseInt64("9223372036854775807"));
-    assertEquals(-9223372036854775808L, TextFormat.parseInt64("-9223372036854775808"));
+    assertThat(TextFormat.parseInt64("0")).isEqualTo(0L);
+    assertThat(TextFormat.parseInt64("1")).isEqualTo(1L);
+    assertThat(TextFormat.parseInt64("-1")).isEqualTo(-1L);
+    assertThat(TextFormat.parseInt64("12345")).isEqualTo(12345L);
+    assertThat(TextFormat.parseInt64("-12345")).isEqualTo(-12345L);
+    assertThat(TextFormat.parseInt64("2147483647")).isEqualTo(2147483647L);
+    assertThat(TextFormat.parseInt64("-2147483648")).isEqualTo(-2147483648L);
+    assertThat(TextFormat.parseInt64("4294967295")).isEqualTo(4294967295L);
+    assertThat(TextFormat.parseInt64("4294967296")).isEqualTo(4294967296L);
+    assertThat(TextFormat.parseInt64("9223372036854775807")).isEqualTo(9223372036854775807L);
+    assertThat(TextFormat.parseInt64("-9223372036854775808")).isEqualTo(-9223372036854775808L);
 
-    assertEquals(0L, TextFormat.parseUInt64("0"));
-    assertEquals(1L, TextFormat.parseUInt64("1"));
-    assertEquals(12345L, TextFormat.parseUInt64("12345"));
-    assertEquals(2147483647L, TextFormat.parseUInt64("2147483647"));
-    assertEquals(4294967295L, TextFormat.parseUInt64("4294967295"));
-    assertEquals(4294967296L, TextFormat.parseUInt64("4294967296"));
-    assertEquals(9223372036854775807L, TextFormat.parseUInt64("9223372036854775807"));
-    assertEquals(-9223372036854775808L, TextFormat.parseUInt64("9223372036854775808"));
-    assertEquals(-1L, TextFormat.parseUInt64("18446744073709551615"));
+    assertThat(TextFormat.parseUInt64("0")).isEqualTo(0L);
+    assertThat(TextFormat.parseUInt64("1")).isEqualTo(1L);
+    assertThat(TextFormat.parseUInt64("12345")).isEqualTo(12345L);
+    assertThat(TextFormat.parseUInt64("2147483647")).isEqualTo(2147483647L);
+    assertThat(TextFormat.parseUInt64("4294967295")).isEqualTo(4294967295L);
+    assertThat(TextFormat.parseUInt64("4294967296")).isEqualTo(4294967296L);
+    assertThat(TextFormat.parseUInt64("9223372036854775807")).isEqualTo(9223372036854775807L);
+    assertThat(TextFormat.parseUInt64("9223372036854775808")).isEqualTo(-9223372036854775808L);
+    assertThat(TextFormat.parseUInt64("18446744073709551615")).isEqualTo(-1L);
 
     // Hex
-    assertEquals(0x1234abcd, TextFormat.parseInt32("0x1234abcd"));
-    assertEquals(-0x1234abcd, TextFormat.parseInt32("-0x1234abcd"));
-    assertEquals(-1, TextFormat.parseUInt64("0xffffffffffffffff"));
-    assertEquals(0x7fffffffffffffffL, TextFormat.parseInt64("0x7fffffffffffffff"));
+    assertThat(TextFormat.parseInt32("0x1234abcd")).isEqualTo(0x1234abcd);
+    assertThat(TextFormat.parseInt32("-0x1234abcd")).isEqualTo(-0x1234abcd);
+    assertThat(TextFormat.parseUInt64("0xffffffffffffffff")).isEqualTo(-1);
+    assertThat(TextFormat.parseInt64("0x7fffffffffffffff")).isEqualTo(0x7fffffffffffffffL);
 
     // Octal
-    assertEquals(01234567, TextFormat.parseInt32("01234567"));
+    assertThat(TextFormat.parseInt32("01234567")).isEqualTo(01234567);
 
     // Out-of-range
     try {
       TextFormat.parseInt32("2147483648");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NumberFormatException e) {
       // success
     }
 
     try {
       TextFormat.parseInt32("-2147483649");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NumberFormatException e) {
       // success
     }
 
     try {
       TextFormat.parseUInt32("4294967296");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NumberFormatException e) {
       // success
     }
 
     try {
       TextFormat.parseUInt32("-1");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NumberFormatException e) {
       // success
     }
 
     try {
       TextFormat.parseInt64("9223372036854775808");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NumberFormatException e) {
       // success
     }
 
     try {
       TextFormat.parseInt64("-9223372036854775809");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NumberFormatException e) {
       // success
     }
 
     try {
       TextFormat.parseUInt64("18446744073709551616");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NumberFormatException e) {
       // success
     }
 
     try {
       TextFormat.parseUInt64("-1");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NumberFormatException e) {
       // success
     }
@@ -1090,19 +1126,21 @@
     // Not a number.
     try {
       TextFormat.parseInt32("abcd");
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (NumberFormatException e) {
       // success
     }
   }
 
+  @Test
   public void testParseString() throws Exception {
     final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge("optional_string: \"" + zh + "\"", builder);
-    assertEquals(zh, builder.getOptionalString());
+    assertThat(builder.getOptionalString()).isEqualTo(zh);
   }
 
+  @Test
   public void testParseLongString() throws Exception {
     String longText =
         "123456789012345678901234567890123456789012345678901234567890"
@@ -1128,9 +1166,10 @@
 
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge("optional_string: \"" + longText + "\"", builder);
-    assertEquals(longText, builder.getOptionalString());
+    assertThat(builder.getOptionalString()).isEqualTo(longText);
   }
 
+  @Test
   public void testParseBoolean() throws Exception {
     String goodText =
         "repeated_bool: t  repeated_bool : 0\n"
@@ -1145,30 +1184,32 @@
             + "repeated_bool: true\n";
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(goodText, builder);
-    assertEquals(goodTextCanonical, builder.build().toString());
+    assertThat(builder.build().toString()).isEqualTo(goodTextCanonical);
 
     try {
       TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
       TextFormat.merge("optional_bool:2", badBuilder);
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.ParseException e) {
       // success
     }
     try {
       TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
       TextFormat.merge("optional_bool: foo", badBuilder);
-      fail("Should have thrown an exception.");
+      assertWithMessage("Should have thrown an exception.").fail();
     } catch (TextFormat.ParseException e) {
       // success
     }
   }
 
+  @Test
   public void testParseAdjacentStringLiterals() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder);
-    assertEquals("foocorgegrault", builder.getOptionalString());
+    assertThat(builder.getOptionalString()).isEqualTo("foocorgegrault");
   }
 
+  @Test
   public void testPrintFieldValue() throws Exception {
     assertPrintFieldValue("\"Hello\"", "Hello", "repeated_string");
     assertPrintFieldValue("123.0", 123f, "repeated_float");
@@ -1187,133 +1228,139 @@
     StringBuilder sb = new StringBuilder();
     TextFormat.printer()
         .printFieldValue(TestAllTypes.getDescriptor().findFieldByName(fieldName), value, sb);
-    assertEquals(expect, sb.toString());
+    assertThat(sb.toString()).isEqualTo(expect);
   }
 
+  @Test
   public void testShortDebugString() {
-    assertEquals(
-        "optional_nested_message { bb: 42 } repeated_int32: 1 repeated_uint32: 2",
-        TextFormat.shortDebugString(
-            TestAllTypes.newBuilder()
-                .addRepeatedInt32(1)
-                .addRepeatedUint32(2)
-                .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(42).build())
-                .build()));
+    assertThat(
+            TextFormat.shortDebugString(
+                TestAllTypes.newBuilder()
+                    .addRepeatedInt32(1)
+                    .addRepeatedUint32(2)
+                    .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(42).build())
+                    .build()))
+        .isEqualTo("optional_nested_message { bb: 42 } repeated_int32: 1 repeated_uint32: 2");
   }
 
+  @Test
   public void testShortDebugString_field() {
     final FieldDescriptor dataField = OneString.getDescriptor().findFieldByName("data");
-    assertEquals(
-        "data: \"test data\"",
-        TextFormat.printer().shortDebugString(dataField, "test data"));
+    assertThat(TextFormat.printer().shortDebugString(dataField, "test data"))
+        .isEqualTo("data: \"test data\"");
 
     final FieldDescriptor optionalField =
         TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
     final Object value = NestedMessage.newBuilder().setBb(42).build();
 
-    assertEquals(
-        "optional_nested_message { bb: 42 }",
-        TextFormat.printer().shortDebugString(optionalField, value));
+    assertThat(TextFormat.printer().shortDebugString(optionalField, value))
+        .isEqualTo("optional_nested_message { bb: 42 }");
   }
 
+  @Test
   public void testShortDebugString_unknown() {
-    assertEquals(
-        "5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5: { 12: 6 } 5 { 10: 5 }"
-            + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
-            + " 0xabcdef1234567890",
-        TextFormat.printer().shortDebugString(makeUnknownFieldSet()));
+    assertThat(TextFormat.printer().shortDebugString(makeUnknownFieldSet()))
+        .isEqualTo(
+            "5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5: { 12: 6 } 5 { 10: 5 }"
+                + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
+                + " 0xabcdef1234567890");
   }
 
+  @Test
   public void testPrintToUnicodeString() throws Exception {
-    assertEquals(
-        "optional_string: \"abc\u3042efg\"\n"
-            + "optional_bytes: \"\\343\\201\\202\"\n"
-            + "repeated_string: \"\u3093XYZ\"\n",
-        TextFormat.printer()
-            .escapingNonAscii(false)
-            .printToString(
-                TestAllTypes.newBuilder()
-                    .setOptionalString("abc\u3042efg")
-                    .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
-                    .addRepeatedString("\u3093XYZ")
-                    .build()));
+    assertThat(
+            TextFormat.printer()
+                .escapingNonAscii(false)
+                .printToString(
+                    TestAllTypes.newBuilder()
+                        .setOptionalString("abc\u3042efg")
+                        .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
+                        .addRepeatedString("\u3093XYZ")
+                        .build()))
+        .isEqualTo(
+            "optional_string: \"abc\u3042efg\"\n"
+                + "optional_bytes: \"\\343\\201\\202\"\n"
+                + "repeated_string: \"\u3093XYZ\"\n");
 
     // Double quotes and backslashes should be escaped
-    assertEquals(
-        "optional_string: \"a\\\\bc\\\"ef\\\"g\"\n",
-        TextFormat.printer()
-            .escapingNonAscii(false)
-            .printToString(TestAllTypes.newBuilder().setOptionalString("a\\bc\"ef\"g").build()));
+    assertThat(
+            TextFormat.printer()
+                .escapingNonAscii(false)
+                .printToString(TestAllTypes.newBuilder().setOptionalString("a\\bc\"ef\"g").build()))
+        .isEqualTo("optional_string: \"a\\\\bc\\\"ef\\\"g\"\n");
 
     // Test escaping roundtrip
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("a\\bc\\\"ef\"g").build();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), builder);
-    assertEquals(message.getOptionalString(), builder.getOptionalString());
+    assertThat(builder.getOptionalString()).isEqualTo(message.getOptionalString());
   }
 
+  @Test
   public void testPrintToUnicodeStringWithNewlines() throws Exception {
     // No newlines at start and end
-    assertEquals(
-        "optional_string: \"test newlines\\n\\nin\\nstring\"\n",
-        TextFormat.printer()
-            .escapingNonAscii(false)
-            .printToString(
-                TestAllTypes.newBuilder()
-                    .setOptionalString("test newlines\n\nin\nstring")
-                    .build()));
+    assertThat(
+            TextFormat.printer()
+                .escapingNonAscii(false)
+                .printToString(
+                    TestAllTypes.newBuilder()
+                        .setOptionalString("test newlines\n\nin\nstring")
+                        .build()))
+        .isEqualTo("optional_string: \"test newlines\\n\\nin\\nstring\"\n");
 
     // Newlines at start and end
-    assertEquals(
-        "optional_string: \"\\ntest\\nnewlines\\n\\nin\\nstring\\n\"\n",
-        TextFormat.printer()
-            .escapingNonAscii(false)
-            .printToString(
-                TestAllTypes.newBuilder()
-                    .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
-                    .build()));
+    assertThat(
+            TextFormat.printer()
+                .escapingNonAscii(false)
+                .printToString(
+                    TestAllTypes.newBuilder()
+                        .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
+                        .build()))
+        .isEqualTo("optional_string: \"\\ntest\\nnewlines\\n\\nin\\nstring\\n\"\n");
 
     // Strings with 0, 1 and 2 newlines.
-    assertEquals(
-        "optional_string: \"\"\n",
-        TextFormat.printer()
-            .escapingNonAscii(false)
-            .printToString(TestAllTypes.newBuilder().setOptionalString("").build()));
-    assertEquals(
-        "optional_string: \"\\n\"\n",
-        TextFormat.printer()
-            .escapingNonAscii(false)
-            .printToString(TestAllTypes.newBuilder().setOptionalString("\n").build()));
-    assertEquals(
-        "optional_string: \"\\n\\n\"\n",
-        TextFormat.printer()
-            .escapingNonAscii(false)
-            .printToString(TestAllTypes.newBuilder().setOptionalString("\n\n").build()));
+    assertThat(
+            TextFormat.printer()
+                .escapingNonAscii(false)
+                .printToString(TestAllTypes.newBuilder().setOptionalString("").build()))
+        .isEqualTo("optional_string: \"\"\n");
+    assertThat(
+            TextFormat.printer()
+                .escapingNonAscii(false)
+                .printToString(TestAllTypes.newBuilder().setOptionalString("\n").build()))
+        .isEqualTo("optional_string: \"\\n\"\n");
+    assertThat(
+            TextFormat.printer()
+                .escapingNonAscii(false)
+                .printToString(TestAllTypes.newBuilder().setOptionalString("\n\n").build()))
+        .isEqualTo("optional_string: \"\\n\\n\"\n");
 
     // Test escaping roundtrip
     TestAllTypes message =
         TestAllTypes.newBuilder().setOptionalString("\ntest\nnewlines\n\nin\nstring\n").build();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), builder);
-    assertEquals(message.getOptionalString(), builder.getOptionalString());
+    assertThat(builder.getOptionalString()).isEqualTo(message.getOptionalString());
   }
 
+  @Test
   public void testPrintToUnicodeString_unknown() {
-    assertEquals(
-        "1: \"\\343\\201\\202\"\n",
-        TextFormat.printer()
-            .escapingNonAscii(false)
-            .printToString(
-                UnknownFieldSet.newBuilder()
-                    .addField(
-                        1,
-                        UnknownFieldSet.Field.newBuilder()
-                            .addLengthDelimited(bytes(0xe3, 0x81, 0x82))
-                            .build())
-                    .build()));
+    assertThat(
+            TextFormat.printer()
+                .escapingNonAscii(false)
+                .printToString(
+                    UnknownFieldSet.newBuilder()
+                        .addField(
+                            1,
+                            UnknownFieldSet.Field.newBuilder()
+                                .addLengthDelimited(bytes(0xe3, 0x81, 0x82))
+                                .build())
+                        .build()))
+        .isEqualTo("1: \"\\343\\201\\202\"\n");
   }
 
 
+  @Test
   public void testParseUnknownExtensions() throws Exception {
     TestUtil.TestLogHandler logHandler = new TestUtil.TestLogHandler();
     Logger logger = Logger.getLogger(TextFormat.class.getName());
@@ -1323,16 +1370,16 @@
     assertParseSuccessWithUnknownExtensions(
         "[unknown_extension]: 123\n" + "[unknown_ext]: inf\n" + "[unknown]: 1.234");
     // Test warning messages.
-    assertEquals(
-        "Input contains unknown fields and/or extensions:\n"
-            + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]",
-        logHandler.getStoredLogRecords().get(0).getMessage());
-    assertEquals(
-        "Input contains unknown fields and/or extensions:\n"
-            + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
-            + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_ext]\n"
-            + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown]",
-        logHandler.getStoredLogRecords().get(1).getMessage());
+    assertThat(logHandler.getStoredLogRecords().get(0).getMessage())
+        .isEqualTo(
+            "Input contains unknown fields and/or extensions:\n"
+                + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]");
+    assertThat(logHandler.getStoredLogRecords().get(1).getMessage())
+        .isEqualTo(
+            "Input contains unknown fields and/or extensions:\n"
+                + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+                + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_ext]\n"
+                + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown]");
 
     // Test unknown field can not pass.
     assertParseErrorWithUnknownExtensions(
@@ -1363,6 +1410,7 @@
   }
 
   // See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden.
+  @Test
   public void testParseNonRepeatedFields() throws Exception {
     assertParseSuccessWithOverwriteForbidden("repeated_int32: 1\nrepeated_int32: 2\n");
     assertParseSuccessWithOverwriteForbidden("RepeatedGroup { a: 1 }\nRepeatedGroup { a: 2 }\n");
@@ -1398,6 +1446,7 @@
         "default_string: \"zxcv\"\ndefault_string: \"asdf\"\n");
   }
 
+  @Test
   public void testParseShortRepeatedFormOfRepeatedFields() throws Exception {
     assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR]");
     assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n");
@@ -1406,6 +1455,7 @@
     // See also testMapShortForm.
   }
 
+  @Test
   public void testParseShortRepeatedFormOfEmptyRepeatedFields() throws Exception {
     assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: []");
     assertParseSuccessWithOverwriteForbidden("repeated_int32: []\n");
@@ -1414,6 +1464,7 @@
     // See also testMapShortFormEmpty.
   }
 
+  @Test
   public void testParseShortRepeatedFormWithTrailingComma() throws Exception {
     assertParseErrorWithOverwriteForbidden(
         "1:38: Expected identifier. Found \']\'", "repeated_foreign_enum: [FOREIGN_FOO, ]\n");
@@ -1425,6 +1476,7 @@
     // See also testMapShortFormTrailingComma.
   }
 
+  @Test
   public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
     assertParseErrorWithOverwriteForbidden(
         "1:17: Couldn't parse integer: For input string: \"[\"", "optional_int32: [1]\n");
@@ -1435,6 +1487,7 @@
   // =======================================================================
   // test oneof
 
+  @Test
   public void testOneofTextFormat() throws Exception {
     TestOneof2.Builder builder = TestOneof2.newBuilder();
     TestUtil.setOneof(builder);
@@ -1444,34 +1497,38 @@
     TestUtil.assertOneofSet(dest.build());
   }
 
+  @Test
   public void testOneofOverwriteForbidden() throws Exception {
     String input = "foo_string: \"stringvalue\" foo_int: 123";
     TestOneof2.Builder builder = TestOneof2.newBuilder();
     try {
-      parserWithOverwriteForbidden.merge(input, TestUtil.getFullExtensionRegistry(), builder);
-      fail("Expected parse exception.");
+      PARSER_WITH_OVERWRITE_FORBIDDEN.merge(input, TestUtil.getFullExtensionRegistry(), builder);
+      assertWithMessage("Expected parse exception.").fail();
     } catch (TextFormat.ParseException e) {
-      assertEquals(
-          "1:34: Field \"protobuf_unittest.TestOneof2.foo_int\""
-              + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
-              + " another member of oneof \"foo\".",
-          e.getMessage());
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo(
+              "1:34: Field \"protobuf_unittest.TestOneof2.foo_int\""
+                  + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
+                  + " another member of oneof \"foo\".");
     }
   }
 
+  @Test
   public void testOneofOverwriteAllowed() throws Exception {
     String input = "foo_string: \"stringvalue\" foo_int: 123";
     TestOneof2.Builder builder = TestOneof2.newBuilder();
-    defaultParser.merge(input, TestUtil.getFullExtensionRegistry(), builder);
+    DEFAULT_PARSER.merge(input, TestUtil.getFullExtensionRegistry(), builder);
     // Only the last value sticks.
     TestOneof2 oneof = builder.build();
-    assertFalse(oneof.hasFooString());
-    assertTrue(oneof.hasFooInt());
+    assertThat(oneof.hasFooString()).isFalse();
+    assertThat(oneof.hasFooInt()).isTrue();
   }
 
   // =======================================================================
   // test map
 
+  @Test
   public void testMapTextFormat() throws Exception {
     TestMap message =
         TestMap.newBuilder()
@@ -1483,15 +1540,16 @@
     {
       TestMap.Builder dest = TestMap.newBuilder();
       TextFormat.merge(text, dest);
-      assertEquals(message, dest.build());
+      assertThat(dest.build()).isEqualTo(message);
     }
     {
       TestMap.Builder dest = TestMap.newBuilder();
-      parserWithOverwriteForbidden.merge(text, dest);
-      assertEquals(message, dest.build());
+      PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, dest);
+      assertThat(dest.build()).isEqualTo(message);
     }
   }
 
+  @Test
   public void testMapDuplicateKeys() throws Exception {
     String input =
         "int32_to_int32_field: {\n"
@@ -1510,43 +1568,47 @@
     int i1 = msg.getInt32ToInt32FieldMap().get(1);
     TestMap msg2 = TextFormat.parse(msg.toString(), TestMap.class);
     int i2 = msg2.getInt32ToInt32FieldMap().get(1);
-    assertEquals(i1, i2);
+    assertThat(i1).isEqualTo(i2);
   }
 
+  @Test
   public void testMapShortForm() throws Exception {
     String text =
         "string_to_int32_field [{ key: 'x' value: 10 }, { key: 'y' value: 20 }]\n"
             + "int32_to_message_field "
             + "[{ key: 1 value { value: 100 } }, { key: 2 value: { value: 200 } }]\n";
     TestMap.Builder dest = TestMap.newBuilder();
-    parserWithOverwriteForbidden.merge(text, dest);
+    PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, dest);
     TestMap message = dest.build();
-    assertEquals(2, message.getStringToInt32FieldMap().size());
-    assertEquals(2, message.getInt32ToMessageFieldMap().size());
-    assertEquals(10, message.getStringToInt32FieldMap().get("x").intValue());
-    assertEquals(200, message.getInt32ToMessageFieldMap().get(2).getValue());
+    assertThat(message.getStringToInt32FieldMap()).hasSize(2);
+    assertThat(message.getInt32ToMessageFieldMap()).hasSize(2);
+    assertThat(message.getStringToInt32FieldMap().get("x").intValue()).isEqualTo(10);
+    assertThat(message.getInt32ToMessageFieldMap().get(2).getValue()).isEqualTo(200);
   }
 
+  @Test
   public void testMapShortFormEmpty() throws Exception {
     String text = "string_to_int32_field []\nint32_to_message_field: []\n";
     TestMap.Builder dest = TestMap.newBuilder();
-    parserWithOverwriteForbidden.merge(text, dest);
+    PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, dest);
     TestMap message = dest.build();
-    assertEquals(0, message.getStringToInt32FieldMap().size());
-    assertEquals(0, message.getInt32ToMessageFieldMap().size());
+    assertThat(message.getStringToInt32FieldMap()).isEmpty();
+    assertThat(message.getInt32ToMessageFieldMap()).isEmpty();
   }
 
+  @Test
   public void testMapShortFormTrailingComma() throws Exception {
     String text = "string_to_int32_field [{ key: 'x' value: 10 }, ]\n";
     TestMap.Builder dest = TestMap.newBuilder();
     try {
-      parserWithOverwriteForbidden.merge(text, dest);
-      fail("Expected parse exception.");
+      PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, dest);
+      assertWithMessage("Expected parse exception.").fail();
     } catch (TextFormat.ParseException e) {
-      assertEquals("1:48: Expected \"{\".", e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo("1:48: Expected \"{\".");
     }
   }
 
+  @Test
   public void testMapOverwrite() throws Exception {
     String text =
         "int32_to_int32_field { key: 1 value: 10 }\n"
@@ -1556,38 +1618,39 @@
     {
       // With default parser, last value set for the key holds.
       TestMap.Builder builder = TestMap.newBuilder();
-      defaultParser.merge(text, builder);
+      DEFAULT_PARSER.merge(text, builder);
       TestMap map = builder.build();
-      assertEquals(2, map.getInt32ToInt32FieldMap().size());
-      assertEquals(30, map.getInt32ToInt32FieldMap().get(1).intValue());
+      assertThat(map.getInt32ToInt32FieldMap()).hasSize(2);
+      assertThat(map.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(30);
     }
 
     {
       // With overwrite forbidden, same behavior.
       // TODO(b/29122459): Expect parse exception here.
       TestMap.Builder builder = TestMap.newBuilder();
-      parserWithOverwriteForbidden.merge(text, builder);
+      PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, builder);
       TestMap map = builder.build();
-      assertEquals(2, map.getInt32ToInt32FieldMap().size());
-      assertEquals(30, map.getInt32ToInt32FieldMap().get(1).intValue());
+      assertThat(map.getInt32ToInt32FieldMap()).hasSize(2);
+      assertThat(map.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(30);
     }
 
     {
       // With overwrite forbidden and a dynamic message, same behavior.
       // TODO(b/29122459): Expect parse exception here.
       Message.Builder builder = DynamicMessage.newBuilder(TestMap.getDescriptor());
-      parserWithOverwriteForbidden.merge(text, builder);
+      PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, builder);
       TestMap map =
           TestMap.parseFrom(
               builder.build().toByteString(), ExtensionRegistryLite.getEmptyRegistry());
-      assertEquals(2, map.getInt32ToInt32FieldMap().size());
-      assertEquals(30, map.getInt32ToInt32FieldMap().get(1).intValue());
+      assertThat(map.getInt32ToInt32FieldMap()).hasSize(2);
+      assertThat(map.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(30);
     }
   }
 
   // =======================================================================
   // test location information
 
+  @Test
   public void testParseInfoTreeBuilding() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
 
@@ -1652,7 +1715,7 @@
     // Verify a NULL tree for an unknown nested field.
     try {
       tree.getNestedTree(nestedField, 2);
-      fail("unknown nested field should throw");
+      assertWithMessage("unknown nested field should throw").fail();
     } catch (IllegalArgumentException unused) {
       // pass
     }
@@ -1669,15 +1732,16 @@
     if (index < locs.size()) {
       TextFormatParseLocation location = locs.get(index);
       TextFormatParseLocation expected = TextFormatParseLocation.create(line, column);
-      assertEquals(expected, location);
+      assertThat(location).isEqualTo(expected);
     } else if (line != -1 && column != -1) {
-      fail(
-          String.format(
+      assertWithMessage(
               "Tree/descriptor/fieldname did not contain index %d, line %d column %d expected",
-              index, line, column));
+              index, line, column)
+          .fail();
     }
   }
 
+  @Test
   public void testSortMapFields() throws Exception {
     TestMap message =
         TestMap.newBuilder()
@@ -1713,6 +1777,6 @@
             + "  key: \"cherry\"\n"
             + "  value: 30\n"
             + "}\n";
-    assertEquals(text, TextFormat.printer().printToString(message));
+    assertThat(TextFormat.printer().printToString(message)).isEqualTo(text);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/TypeRegistryTest.java b/java/core/src/test/java/com/google/protobuf/TypeRegistryTest.java
index 0cd9677..c9defb3 100644
--- a/java/core/src/test/java/com/google/protobuf/TypeRegistryTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TypeRegistryTest.java
@@ -30,8 +30,7 @@
 
 package com.google.protobuf;
 
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.protobuf.Descriptors.Descriptor;
 import protobuf_unittest.UnittestProto;
@@ -45,26 +44,26 @@
   @Test
   public void findDescriptorByFullName() throws Exception {
     Descriptor descriptor = UnittestProto.TestAllTypes.getDescriptor();
-    assertNull(TypeRegistry.getEmptyTypeRegistry().find(descriptor.getFullName()));
+    assertThat(TypeRegistry.getEmptyTypeRegistry().find(descriptor.getFullName())).isNull();
 
-    assertSame(
-        descriptor,
-        TypeRegistry.newBuilder().add(descriptor).build().find(descriptor.getFullName()));
+    assertThat(TypeRegistry.newBuilder().add(descriptor).build().find(descriptor.getFullName()))
+        .isSameInstanceAs(descriptor);
   }
 
   @Test
   public void findDescriptorByTypeUrl() throws Exception {
     Descriptor descriptor = UnittestProto.TestAllTypes.getDescriptor();
-    assertNull(
-        TypeRegistry.getEmptyTypeRegistry()
-            .getDescriptorForTypeUrl("type.googleapis.com/" + descriptor.getFullName()));
+    assertThat(
+            TypeRegistry.getEmptyTypeRegistry()
+                .getDescriptorForTypeUrl("type.googleapis.com/" + descriptor.getFullName()))
+        .isNull();
 
-    assertSame(
-        descriptor,
-        TypeRegistry.newBuilder()
-            .add(descriptor)
-            .build()
-            .getDescriptorForTypeUrl("type.googleapis.com/" + descriptor.getFullName()));
+    assertThat(
+            TypeRegistry.newBuilder()
+                .add(descriptor)
+                .build()
+                .getDescriptorForTypeUrl("type.googleapis.com/" + descriptor.getFullName()))
+        .isSameInstanceAs(descriptor);
   }
 
 }
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
index 7daef02..bf4af71 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
@@ -40,75 +43,83 @@
 import com.google.protobuf.Proto2UnknownEnumValuesTestProto.Proto2TestEnum;
 import com.google.protobuf.Proto2UnknownEnumValuesTestProto.Proto2TestEnumSubset;
 import com.google.protobuf.TextFormat.ParseException;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Unit tests for protos that keep unknown enum values rather than discard them as unknown fields.
  */
-public class UnknownEnumValueTest extends TestCase {
+@RunWith(JUnit4.class)
+public class UnknownEnumValueTest {
 
+  @Test
   public void testUnknownEnumValues() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     builder.setOptionalNestedEnumValue(4321);
     builder.addRepeatedNestedEnumValue(5432);
     builder.addPackedNestedEnumValue(6543);
     TestAllTypes message = builder.build();
-    assertEquals(4321, message.getOptionalNestedEnumValue());
-    assertEquals(5432, message.getRepeatedNestedEnumValue(0));
-    assertEquals(5432, message.getRepeatedNestedEnumValueList().get(0).intValue());
-    assertEquals(6543, message.getPackedNestedEnumValue(0));
+    assertThat(message.getOptionalNestedEnumValue()).isEqualTo(4321);
+    assertThat(message.getRepeatedNestedEnumValue(0)).isEqualTo(5432);
+    assertThat(message.getRepeatedNestedEnumValueList().get(0).intValue()).isEqualTo(5432);
+    assertThat(message.getPackedNestedEnumValue(0)).isEqualTo(6543);
     // Returns UNRECOGNIZED if an enum type is requested.
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getOptionalNestedEnum());
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnum(0));
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnumList().get(0));
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getPackedNestedEnum(0));
+    assertThat(message.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(message.getRepeatedNestedEnum(0)).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(message.getRepeatedNestedEnumList().get(0))
+        .isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(message.getPackedNestedEnum(0)).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
 
     // Test serialization and parsing.
     ByteString data = message.toByteString();
     message = TestAllTypes.parseFrom(data);
-    assertEquals(4321, message.getOptionalNestedEnumValue());
-    assertEquals(5432, message.getRepeatedNestedEnumValue(0));
-    assertEquals(5432, message.getRepeatedNestedEnumValueList().get(0).intValue());
-    assertEquals(6543, message.getPackedNestedEnumValue(0));
+    assertThat(message.getOptionalNestedEnumValue()).isEqualTo(4321);
+    assertThat(message.getRepeatedNestedEnumValue(0)).isEqualTo(5432);
+    assertThat(message.getRepeatedNestedEnumValueList().get(0).intValue()).isEqualTo(5432);
+    assertThat(message.getPackedNestedEnumValue(0)).isEqualTo(6543);
     // Returns UNRECOGNIZED if an enum type is requested.
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getOptionalNestedEnum());
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnum(0));
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnumList().get(0));
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getPackedNestedEnum(0));
+    assertThat(message.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(message.getRepeatedNestedEnum(0)).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(message.getRepeatedNestedEnumList().get(0))
+        .isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(message.getPackedNestedEnum(0)).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
 
     // Test toBuilder().
     builder = message.toBuilder();
-    assertEquals(4321, builder.getOptionalNestedEnumValue());
-    assertEquals(5432, builder.getRepeatedNestedEnumValue(0));
-    assertEquals(5432, builder.getRepeatedNestedEnumValueList().get(0).intValue());
-    assertEquals(6543, builder.getPackedNestedEnumValue(0));
+    assertThat(builder.getOptionalNestedEnumValue()).isEqualTo(4321);
+    assertThat(builder.getRepeatedNestedEnumValue(0)).isEqualTo(5432);
+    assertThat(builder.getRepeatedNestedEnumValueList().get(0).intValue()).isEqualTo(5432);
+    assertThat(builder.getPackedNestedEnumValue(0)).isEqualTo(6543);
     // Returns UNRECOGNIZED if an enum type is requested.
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getOptionalNestedEnum());
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnum(0));
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnumList().get(0));
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getPackedNestedEnum(0));
+    assertThat(builder.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(builder.getRepeatedNestedEnum(0)).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(builder.getRepeatedNestedEnumList().get(0))
+        .isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(builder.getPackedNestedEnum(0)).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
 
     // Test mergeFrom().
     builder = TestAllTypes.newBuilder().mergeFrom(message);
-    assertEquals(4321, builder.getOptionalNestedEnumValue());
-    assertEquals(5432, builder.getRepeatedNestedEnumValue(0));
-    assertEquals(5432, builder.getRepeatedNestedEnumValueList().get(0).intValue());
-    assertEquals(6543, builder.getPackedNestedEnumValue(0));
+    assertThat(builder.getOptionalNestedEnumValue()).isEqualTo(4321);
+    assertThat(builder.getRepeatedNestedEnumValue(0)).isEqualTo(5432);
+    assertThat(builder.getRepeatedNestedEnumValueList().get(0).intValue()).isEqualTo(5432);
+    assertThat(builder.getPackedNestedEnumValue(0)).isEqualTo(6543);
     // Returns UNRECOGNIZED if an enum type is requested.
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getOptionalNestedEnum());
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnum(0));
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnumList().get(0));
-    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getPackedNestedEnum(0));
+    assertThat(builder.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(builder.getRepeatedNestedEnum(0)).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(builder.getRepeatedNestedEnumList().get(0))
+        .isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(builder.getPackedNestedEnum(0)).isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
 
     // Test equals() and hashCode()
     TestAllTypes sameMessage = builder.build();
-    assertEquals(message, sameMessage);
-    assertEquals(message.hashCode(), sameMessage.hashCode());
+    assertThat(sameMessage).isEqualTo(message);
+    assertThat(sameMessage.hashCode()).isEqualTo(message.hashCode());
 
     // Getting the numeric value of UNRECOGNIZED will throw an exception.
     try {
       TestAllTypes.NestedEnum.UNRECOGNIZED.getNumber();
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IllegalArgumentException e) {
       // Expected.
     }
@@ -116,18 +127,19 @@
     // Setting an enum field to an UNRECOGNIZED value will throw an exception.
     try {
       builder.setOptionalNestedEnum(builder.getOptionalNestedEnum());
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IllegalArgumentException e) {
       // Expected.
     }
     try {
       builder.addRepeatedNestedEnum(builder.getOptionalNestedEnum());
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IllegalArgumentException e) {
       // Expected.
     }
   }
 
+  @Test
   public void testUnknownEnumValueInReflectionApi() throws Exception {
     Descriptor descriptor = TestAllTypes.getDescriptor();
     FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
@@ -150,17 +162,17 @@
         (EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0);
     EnumValueDescriptor unknown6543 =
         (EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0);
-    assertEquals(4321, unknown4321.getNumber());
-    assertEquals(5432, unknown5432.getNumber());
-    assertEquals(6543, unknown6543.getNumber());
+    assertThat(unknown4321.getNumber()).isEqualTo(4321);
+    assertThat(unknown5432.getNumber()).isEqualTo(5432);
+    assertThat(unknown6543.getNumber()).isEqualTo(6543);
 
     // Unknown EnumValueDescriptor will map to UNRECOGNIZED.
-    assertEquals(
-        TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown4321));
-    assertEquals(
-        TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown5432));
-    assertEquals(
-        TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown6543));
+    assertThat(TestAllTypes.NestedEnum.valueOf(unknown4321))
+        .isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(TestAllTypes.NestedEnum.valueOf(unknown5432))
+        .isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertThat(TestAllTypes.NestedEnum.valueOf(unknown6543))
+        .isEqualTo(TestAllTypes.NestedEnum.UNRECOGNIZED);
 
     // Setters also accept unknown EnumValueDescriptor.
     builder.setField(optionalNestedEnumField, unknown6543);
@@ -169,11 +181,12 @@
     message = builder.build();
     // Like other descriptors, unknown EnumValueDescriptor can be compared by
     // object identity.
-    assertSame(message.getField(optionalNestedEnumField), unknown6543);
-    assertSame(message.getRepeatedField(repeatedNestedEnumField, 0), unknown4321);
-    assertSame(message.getRepeatedField(packedNestedEnumField, 0), unknown5432);
+    assertThat(unknown6543).isSameInstanceAs(message.getField(optionalNestedEnumField));
+    assertThat(unknown4321).isSameInstanceAs(message.getRepeatedField(repeatedNestedEnumField, 0));
+    assertThat(unknown5432).isSameInstanceAs(message.getRepeatedField(packedNestedEnumField, 0));
   }
 
+  @Test
   public void testUnknownEnumValueWithDynamicMessage() throws Exception {
     Descriptor descriptor = TestAllTypes.getDescriptor();
     FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
@@ -190,26 +203,28 @@
     builder.addRepeatedField(
         packedNestedEnumField, enumType.findValueByNumberCreatingIfUnknown(6543));
     Message message = builder.build();
-    assertEquals(
-        4321, ((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber());
-    assertEquals(
-        5432,
-        ((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0)).getNumber());
-    assertEquals(
-        6543,
-        ((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber());
+    assertThat(((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber())
+        .isEqualTo(4321);
+    assertThat(
+            ((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0))
+                .getNumber())
+        .isEqualTo(5432);
+    assertThat(
+            ((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber())
+        .isEqualTo(6543);
 
     // Test reflection based serialization/parsing implementation.
     ByteString data = message.toByteString();
     message = dynamicMessageDefaultInstance.newBuilderForType().mergeFrom(data).build();
-    assertEquals(
-        4321, ((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber());
-    assertEquals(
-        5432,
-        ((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0)).getNumber());
-    assertEquals(
-        6543,
-        ((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber());
+    assertThat(((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber())
+        .isEqualTo(4321);
+    assertThat(
+            ((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0))
+                .getNumber())
+        .isEqualTo(5432);
+    assertThat(
+            ((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber())
+        .isEqualTo(6543);
 
     // Test reflection based equals()/hashCode().
     builder = dynamicMessageDefaultInstance.newBuilderForType();
@@ -219,13 +234,14 @@
     builder.addRepeatedField(
         packedNestedEnumField, enumType.findValueByNumberCreatingIfUnknown(6543));
     Message sameMessage = builder.build();
-    assertEquals(message, sameMessage);
-    assertEquals(message.hashCode(), sameMessage.hashCode());
+    assertThat(sameMessage).isEqualTo(message);
+    assertThat(sameMessage.hashCode()).isEqualTo(message.hashCode());
     builder.setField(optionalNestedEnumField, enumType.findValueByNumberCreatingIfUnknown(0));
     Message differentMessage = builder.build();
-    assertFalse(message.equals(differentMessage));
+    assertThat(message.equals(differentMessage)).isFalse();
   }
 
+  @Test
   public void testUnknownEnumValuesInTextFormat() {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     builder.setOptionalNestedEnumValue(4321);
@@ -235,22 +251,23 @@
 
     // We can print a message with unknown enum values.
     String textData = TextFormat.printer().printToString(message);
-    assertEquals(
-        "optional_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_4321\n"
-            + "repeated_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_5432\n"
-            + "packed_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_6543\n",
-        textData);
+    assertThat(textData)
+        .isEqualTo(
+            "optional_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_4321\n"
+                + "repeated_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_5432\n"
+                + "packed_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_6543\n");
 
     // Parsing unknown enum values will fail just like parsing other kinds of
     // unknown fields.
     try {
       TextFormat.merge(textData, builder);
-      fail();
+      assertWithMessage("Expected exception").fail();
     } catch (ParseException e) {
       // expected.
     }
   }
 
+  @Test
   public void testUnknownEnumValuesInProto2() throws Exception {
     Proto2EnumMessage.Builder sourceMessage = Proto2EnumMessage.newBuilder();
     sourceMessage
@@ -262,21 +279,24 @@
         Proto2EnumMessageWithEnumSubset.parseFrom(sourceMessage.build().toByteArray());
 
     // Known enum values should be preserved.
-    assertEquals(2, destMessage.getRepeatedPackedEnumCount());
-    assertEquals(Proto2TestEnumSubset.TESTENUM_SUBSET_ZERO, destMessage.getRepeatedPackedEnum(0));
-    assertEquals(Proto2TestEnumSubset.TESTENUM_SUBSET_ONE, destMessage.getRepeatedPackedEnum(1));
+    assertThat(destMessage.getRepeatedPackedEnumCount()).isEqualTo(2);
+    assertThat(destMessage.getRepeatedPackedEnum(0))
+        .isEqualTo(Proto2TestEnumSubset.TESTENUM_SUBSET_ZERO);
+    assertThat(destMessage.getRepeatedPackedEnum(1))
+        .isEqualTo(Proto2TestEnumSubset.TESTENUM_SUBSET_ONE);
 
     // Unknown enum values should be found in UnknownFieldSet.
     UnknownFieldSet unknown = destMessage.getUnknownFields();
-    assertEquals(
-        Proto2TestEnum.TWO_VALUE,
-        unknown
-            .getField(Proto2EnumMessageWithEnumSubset.REPEATED_PACKED_ENUM_FIELD_NUMBER)
-            .getVarintList()
-            .get(0)
-            .longValue());
+    assertThat(
+            unknown
+                .getField(Proto2EnumMessageWithEnumSubset.REPEATED_PACKED_ENUM_FIELD_NUMBER)
+                .getVarintList()
+                .get(0)
+                .longValue())
+        .isEqualTo(Proto2TestEnum.TWO_VALUE);
   }
 
+  @Test
   public void testUnknownEnumValuesInProto2WithDynamicMessage() throws Exception {
     Descriptor descriptor = Proto2EnumMessageWithEnumSubset.getDescriptor();
     FieldDescriptor repeatedPackedField = descriptor.findFieldByName("repeated_packed_enum");
@@ -292,19 +312,18 @@
             Proto2EnumMessageWithEnumSubset.getDescriptor(), sourceMessage.build().toByteArray());
 
     // Known enum values should be preserved.
-    assertEquals(2, message.getRepeatedFieldCount(repeatedPackedField));
+    assertThat(message.getRepeatedFieldCount(repeatedPackedField)).isEqualTo(2);
     EnumValueDescriptor enumValue0 =
         (EnumValueDescriptor) message.getRepeatedField(repeatedPackedField, 0);
     EnumValueDescriptor enumValue1 =
         (EnumValueDescriptor) message.getRepeatedField(repeatedPackedField, 1);
 
-    assertEquals(Proto2TestEnumSubset.TESTENUM_SUBSET_ZERO_VALUE, enumValue0.getNumber());
-    assertEquals(Proto2TestEnumSubset.TESTENUM_SUBSET_ONE_VALUE, enumValue1.getNumber());
+    assertThat(enumValue0.getNumber()).isEqualTo(Proto2TestEnumSubset.TESTENUM_SUBSET_ZERO_VALUE);
+    assertThat(enumValue1.getNumber()).isEqualTo(Proto2TestEnumSubset.TESTENUM_SUBSET_ONE_VALUE);
 
     // Unknown enum values should be found in UnknownFieldSet.
     UnknownFieldSet unknown = message.getUnknownFields();
-    assertEquals(
-        Proto2TestEnum.TWO_VALUE,
-        unknown.getField(repeatedPackedField.getNumber()).getVarintList().get(0).longValue());
+    assertThat(unknown.getField(repeatedPackedField.getNumber()).getVarintList().get(0).longValue())
+        .isEqualTo(Proto2TestEnum.TWO_VALUE);
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
index c7eb57c..1e5bc96 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import protobuf_unittest.UnittestProto;
 import protobuf_unittest.UnittestProto.ForeignEnum;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
@@ -39,17 +42,17 @@
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import proto3_unittest.UnittestProto3;
-import java.util.Arrays;
 import java.util.Map;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests related to unknown field handling.
- *
- * @author [email protected] (Kenton Varda)
- */
-public class UnknownFieldSetTest extends TestCase {
-  @Override
+/** Tests related to unknown field handling. */
+@RunWith(JUnit4.class)
+public class UnknownFieldSetTest {
+
+  @Before
   public void setUp() throws Exception {
     descriptor = TestAllTypes.getDescriptor();
     allFields = TestUtil.getAllSet();
@@ -60,7 +63,7 @@
 
   UnknownFieldSet.Field getField(String name) {
     Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
-    assertNotNull(field);
+    assertThat(field).isNotNull();
     return unknownFields.getField(field.getNumber());
   }
 
@@ -97,60 +100,69 @@
 
   // =================================================================
 
+  @Test
   public void testVarint() throws Exception {
     UnknownFieldSet.Field field = getField("optional_int32");
-    assertEquals(1, field.getVarintList().size());
-    assertEquals(allFields.getOptionalInt32(), (long) field.getVarintList().get(0));
+    assertThat(field.getVarintList()).hasSize(1);
+    assertThat((long) field.getVarintList().get(0)).isEqualTo(allFields.getOptionalInt32());
   }
 
+  @Test
   public void testFixed32() throws Exception {
     UnknownFieldSet.Field field = getField("optional_fixed32");
-    assertEquals(1, field.getFixed32List().size());
-    assertEquals(allFields.getOptionalFixed32(), (int) field.getFixed32List().get(0));
+    assertThat(field.getFixed32List()).hasSize(1);
+    assertThat((int) field.getFixed32List().get(0)).isEqualTo(allFields.getOptionalFixed32());
   }
 
+  @Test
   public void testFixed64() throws Exception {
     UnknownFieldSet.Field field = getField("optional_fixed64");
-    assertEquals(1, field.getFixed64List().size());
-    assertEquals(allFields.getOptionalFixed64(), (long) field.getFixed64List().get(0));
+    assertThat(field.getFixed64List()).hasSize(1);
+    assertThat((long) field.getFixed64List().get(0)).isEqualTo(allFields.getOptionalFixed64());
   }
 
+  @Test
   public void testLengthDelimited() throws Exception {
     UnknownFieldSet.Field field = getField("optional_bytes");
-    assertEquals(1, field.getLengthDelimitedList().size());
-    assertEquals(allFields.getOptionalBytes(), field.getLengthDelimitedList().get(0));
+    assertThat(field.getLengthDelimitedList()).hasSize(1);
+    assertThat(field.getLengthDelimitedList().get(0)).isEqualTo(allFields.getOptionalBytes());
   }
 
+  @Test
   public void testGroup() throws Exception {
     Descriptors.FieldDescriptor nestedFieldDescriptor =
         TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
-    assertNotNull(nestedFieldDescriptor);
+    assertThat(nestedFieldDescriptor).isNotNull();
 
     UnknownFieldSet.Field field = getField("optionalgroup");
-    assertEquals(1, field.getGroupList().size());
+    assertThat(field.getGroupList()).hasSize(1);
 
     UnknownFieldSet group = field.getGroupList().get(0);
-    assertEquals(1, group.asMap().size());
-    assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
+    assertThat(group.asMap()).hasSize(1);
+    assertThat(group.hasField(nestedFieldDescriptor.getNumber())).isTrue();
 
     UnknownFieldSet.Field nestedField = group.getField(nestedFieldDescriptor.getNumber());
-    assertEquals(1, nestedField.getVarintList().size());
-    assertEquals(allFields.getOptionalGroup().getA(), (long) nestedField.getVarintList().get(0));
+    assertThat(nestedField.getVarintList()).hasSize(1);
+    assertThat((long) nestedField.getVarintList().get(0))
+        .isEqualTo(allFields.getOptionalGroup().getA());
   }
 
+  @Test
   public void testSerialize() throws Exception {
     // Check that serializing the UnknownFieldSet produces the original data
     // again.
     ByteString data = emptyMessage.toByteString();
-    assertEquals(allFieldsData, data);
+    assertThat(data).isEqualTo(allFieldsData);
   }
 
+  @Test
   public void testCopyFrom() throws Exception {
     TestEmptyMessage message = TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
 
-    assertEquals(emptyMessage.toString(), message.toString());
+    assertThat(message.toString()).isEqualTo(emptyMessage.toString());
   }
 
+  @Test
   public void testMergeFrom() throws Exception {
     TestEmptyMessage source =
         TestEmptyMessage.newBuilder()
@@ -170,27 +182,31 @@
             .mergeFrom(source)
             .build();
 
-    assertEquals("1: 1\n2: 2\n3: 3\n3: 4\n", destination.toString());
+    assertThat(destination.toString()).isEqualTo("1: 1\n2: 2\n3: 3\n3: 4\n");
   }
 
+  @Test
   public void testClear() throws Exception {
     UnknownFieldSet fields = UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
-    assertTrue(fields.asMap().isEmpty());
+    assertThat(fields.asMap()).isEmpty();
   }
 
+  @Test
   public void testClearMessage() throws Exception {
     TestEmptyMessage message =
         TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
-    assertEquals(0, message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
   }
 
+  @Test
   public void testClearField() throws Exception {
     int fieldNumber = unknownFields.asMap().keySet().iterator().next();
     UnknownFieldSet fields =
         UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clearField(fieldNumber).build();
-    assertFalse(fields.hasField(fieldNumber));
+    assertThat(fields.hasField(fieldNumber)).isFalse();
   }
 
+  @Test
   public void testParseKnownAndUnknown() throws Exception {
     // Test mixing known and unknown fields when parsing.
 
@@ -203,13 +219,14 @@
     TestAllTypes destination = TestAllTypes.parseFrom(data);
 
     TestUtil.assertAllFieldsSet(destination);
-    assertEquals(1, destination.getUnknownFields().asMap().size());
+    assertThat(destination.getUnknownFields().asMap()).hasSize(1);
 
     UnknownFieldSet.Field field = destination.getUnknownFields().getField(123456);
-    assertEquals(1, field.getVarintList().size());
-    assertEquals(654321, (long) field.getVarintList().get(0));
+    assertThat(field.getVarintList()).hasSize(1);
+    assertThat((long) field.getVarintList().get(0)).isEqualTo(654321);
   }
 
+  @Test
   public void testWrongTypeTreatedAsUnknown() throws Exception {
     // Test that fields of the wrong wire type are treated like unknown fields
     // when parsing.
@@ -220,9 +237,10 @@
 
     // All fields should have been interpreted as unknown, so the debug strings
     // should be the same.
-    assertEquals(emptyMessage.toString(), allTypesMessage.toString());
+    assertThat(emptyMessage.toString()).isEqualTo(allTypesMessage.toString());
   }
 
+  @Test
   public void testUnknownExtensions() throws Exception {
     // Make sure fields are properly parsed to the UnknownFieldSet even when
     // they are declared as extension numbers.
@@ -230,10 +248,11 @@
     TestEmptyMessageWithExtensions message =
         TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
 
-    assertEquals(unknownFields.asMap().size(), message.getUnknownFields().asMap().size());
-    assertEquals(allFieldsData, message.toByteString());
+    assertThat(unknownFields.asMap()).hasSize(message.getUnknownFields().asMap().size());
+    assertThat(allFieldsData).isEqualTo(message.toByteString());
   }
 
+  @Test
   public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
     // Test that fields of the wrong wire type are treated like unknown fields
     // when parsing extensions.
@@ -244,16 +263,17 @@
 
     // All fields should have been interpreted as unknown, so the debug strings
     // should be the same.
-    assertEquals(emptyMessage.toString(), allExtensionsMessage.toString());
+    assertThat(emptyMessage.toString()).isEqualTo(allExtensionsMessage.toString());
   }
 
+  @Test
   public void testParseUnknownEnumValue() throws Exception {
     Descriptors.FieldDescriptor singularField =
         TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
     Descriptors.FieldDescriptor repeatedField =
         TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
-    assertNotNull(singularField);
-    assertNotNull(repeatedField);
+    assertThat(singularField).isNotNull();
+    assertThat(repeatedField).isNotNull();
 
     ByteString data =
         UnknownFieldSet.newBuilder()
@@ -276,36 +296,34 @@
 
     {
       TestAllTypes message = TestAllTypes.parseFrom(data);
-      assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
-      assertEquals(
-          Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
-          message.getRepeatedNestedEnumList());
-      assertEquals(
-          Arrays.asList(5L),
-          message.getUnknownFields().getField(singularField.getNumber()).getVarintList());
-      assertEquals(
-          Arrays.asList(4L, 6L),
-          message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList());
+      assertThat(message.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.BAR);
+      assertThat(message.getRepeatedNestedEnumList())
+          .containsExactly(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ)
+          .inOrder();
+      assertThat(message.getUnknownFields().getField(singularField.getNumber()).getVarintList())
+          .containsExactly(5L);
+      assertThat(message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList())
+          .containsExactly(4L, 6L)
+          .inOrder();
     }
 
     {
       TestAllExtensions message =
           TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
-      assertEquals(
-          TestAllTypes.NestedEnum.BAR,
-          message.getExtension(UnittestProto.optionalNestedEnumExtension));
-      assertEquals(
-          Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
-          message.getExtension(UnittestProto.repeatedNestedEnumExtension));
-      assertEquals(
-          Arrays.asList(5L),
-          message.getUnknownFields().getField(singularField.getNumber()).getVarintList());
-      assertEquals(
-          Arrays.asList(4L, 6L),
-          message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList());
+      assertThat(message.getExtension(UnittestProto.optionalNestedEnumExtension))
+          .isEqualTo(TestAllTypes.NestedEnum.BAR);
+      assertThat(message.getExtension(UnittestProto.repeatedNestedEnumExtension))
+          .containsExactly(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ)
+          .inOrder();
+      assertThat(message.getUnknownFields().getField(singularField.getNumber()).getVarintList())
+          .containsExactly(5L);
+      assertThat(message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList())
+          .containsExactly(4L, 6L)
+          .inOrder();
     }
   }
 
+  @Test
   public void testLargeVarint() throws Exception {
     ByteString data =
         UnknownFieldSet.newBuilder()
@@ -314,10 +332,11 @@
             .toByteString();
     UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
     UnknownFieldSet.Field field = parsed.getField(1);
-    assertEquals(1, field.getVarintList().size());
-    assertEquals(0x7FFFFFFFFFFFFFFFL, (long) field.getVarintList().get(0));
+    assertThat(field.getVarintList()).hasSize(1);
+    assertThat((long) field.getVarintList().get(0)).isEqualTo(0x7FFFFFFFFFFFFFFFL);
   }
 
+  @Test
   public void testEqualsAndHashCode() {
     UnknownFieldSet.Field fixed32Field = UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
     UnknownFieldSet.Field fixed64Field = UnknownFieldSet.Field.newBuilder().addFixed64(1).build();
@@ -359,49 +378,50 @@
    */
   private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
     String equalsError = String.format("%s should not be equal to %s", s1, s2);
-    assertFalse(equalsError, s1.equals(s2));
-    assertFalse(equalsError, s2.equals(s1));
+    assertWithMessage(equalsError).that(s1).isNotEqualTo(s2);
+    assertWithMessage(equalsError).that(s2).isNotEqualTo(s1);
 
-    assertFalse(
-        String.format("%s should have a different hash code from %s", s1, s2),
-        s1.hashCode() == s2.hashCode());
+    assertWithMessage("%s should have a different hash code from %s", s1, s2)
+        .that(s1.hashCode())
+        .isNotEqualTo(s2.hashCode());
   }
 
   /** Asserts that the given field sets are equal and have identical hash codes. */
   private void checkEqualsIsConsistent(UnknownFieldSet set) {
     // Object should be equal to itself.
-    assertEquals(set, set);
+    assertThat(set.equals(set)).isTrue();
 
     // Object should be equal to a copy of itself.
     UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build();
-    assertEquals(set, copy);
-    assertEquals(copy, set);
-    assertEquals(set.hashCode(), copy.hashCode());
+    assertThat(copy).isEqualTo(set);
+    assertThat(set).isEqualTo(copy);
+    assertThat(set.hashCode()).isEqualTo(copy.hashCode());
   }
 
   // =================================================================
 
+  @Test
   public void testProto3RoundTrip() throws Exception {
     ByteString data = getBizarroData();
 
     UnittestProto3.TestEmptyMessage message =
         UnittestProto3.TestEmptyMessage.parseFrom(data, ExtensionRegistryLite.getEmptyRegistry());
-    assertEquals(data, message.toByteString());
+    assertThat(message.toByteString()).isEqualTo(data);
 
     message = UnittestProto3.TestEmptyMessage.newBuilder().mergeFrom(message).build();
-    assertEquals(data, message.toByteString());
+    assertThat(message.toByteString()).isEqualTo(data);
 
-    assertEquals(
-        data,
-        UnittestProto3.TestMessageWithDummy.parseFrom(
-                data, ExtensionRegistryLite.getEmptyRegistry())
-            .toBuilder()
-            // force copy-on-write
-            .setDummy(true)
-            .build()
-            .toBuilder()
-            .clearDummy()
-            .build()
-            .toByteString());
+    assertThat(data)
+        .isEqualTo(
+            UnittestProto3.TestMessageWithDummy.parseFrom(
+                    data, ExtensionRegistryLite.getEmptyRegistry())
+                .toBuilder()
+                // force copy-on-write
+                .setDummy(true)
+                .build()
+                .toBuilder()
+                .clearDummy()
+                .build()
+                .toByteString());
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java b/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
index bc73cc9..d5d9195 100644
--- a/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
@@ -30,17 +30,19 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests for {@link UnmodifiableLazyStringList}.
- *
- * @author [email protected] (Jon Perlow)
- */
-public class UnmodifiableLazyStringListTest extends TestCase {
+/** Tests for {@link UnmodifiableLazyStringList}. */
+@RunWith(JUnit4.class)
+public class UnmodifiableLazyStringListTest {
 
   private static final String STRING_A = "A";
   private static final String STRING_B = "B";
@@ -50,80 +52,83 @@
   private static final ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
   private static final ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
 
+  @Test
   public void testReadOnlyMethods() {
     LazyStringArrayList rawList = createSampleList();
     UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
-    assertEquals(3, list.size());
-    assertSame(STRING_A, list.get(0));
-    assertSame(STRING_B, list.get(1));
-    assertSame(STRING_C, list.get(2));
-    assertEquals(BYTE_STRING_A, list.getByteString(0));
-    assertEquals(BYTE_STRING_B, list.getByteString(1));
-    assertEquals(BYTE_STRING_C, list.getByteString(2));
+    assertThat(list).hasSize(3);
+    assertThat(list.get(0)).isSameInstanceAs(STRING_A);
+    assertThat(list.get(1)).isSameInstanceAs(STRING_B);
+    assertThat(list.get(2)).isSameInstanceAs(STRING_C);
+    assertThat(list.getByteString(0)).isEqualTo(BYTE_STRING_A);
+    assertThat(list.getByteString(1)).isEqualTo(BYTE_STRING_B);
+    assertThat(list.getByteString(2)).isEqualTo(BYTE_STRING_C);
 
     List<ByteString> byteStringList = list.asByteStringList();
-    assertSame(list.getByteString(0), byteStringList.get(0));
-    assertSame(list.getByteString(1), byteStringList.get(1));
-    assertSame(list.getByteString(2), byteStringList.get(2));
+    assertThat(byteStringList.get(0)).isSameInstanceAs(list.getByteString(0));
+    assertThat(byteStringList.get(1)).isSameInstanceAs(list.getByteString(1));
+    assertThat(byteStringList.get(2)).isSameInstanceAs(list.getByteString(2));
   }
 
+  @Test
   public void testModifyMethods() {
     LazyStringArrayList rawList = createSampleList();
     UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
 
     try {
       list.remove(0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(3, list.size());
+    assertThat(list).hasSize(3);
 
     try {
       list.add(STRING_B);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(3, list.size());
+    assertThat(list).hasSize(3);
 
     try {
       list.set(1, STRING_B);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(3, list.size());
+    assertThat(list).hasSize(3);
 
     List<ByteString> byteStringList = list.asByteStringList();
     try {
       byteStringList.remove(0);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(3, list.size());
-    assertEquals(3, byteStringList.size());
+    assertThat(list).hasSize(3);
+    assertThat(byteStringList).hasSize(3);
 
     try {
       byteStringList.add(BYTE_STRING_B);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(3, list.size());
-    assertEquals(3, byteStringList.size());
+    assertThat(list).hasSize(3);
+    assertThat(byteStringList).hasSize(3);
 
     try {
       byteStringList.set(1, BYTE_STRING_B);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    assertEquals(3, list.size());
-    assertEquals(3, byteStringList.size());
+    assertThat(list).hasSize(3);
+    assertThat(byteStringList).hasSize(3);
   }
 
+  @Test
   public void testIterator() {
     LazyStringArrayList rawList = createSampleList();
     UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
@@ -135,12 +140,12 @@
       count++;
       try {
         iter.remove();
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
     }
-    assertEquals(3, count);
+    assertThat(count).isEqualTo(3);
 
     List<ByteString> byteStringList = list.asByteStringList();
     Iterator<ByteString> byteIter = byteStringList.iterator();
@@ -150,14 +155,15 @@
       count++;
       try {
         byteIter.remove();
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
     }
-    assertEquals(3, count);
+    assertThat(count).isEqualTo(3);
   }
 
+  @Test
   public void testListIterator() {
     LazyStringArrayList rawList = createSampleList();
     UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
@@ -169,24 +175,24 @@
       count++;
       try {
         iter.remove();
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
       try {
         iter.set("bar");
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
       try {
         iter.add("bar");
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
     }
-    assertEquals(3, count);
+    assertThat(count).isEqualTo(3);
 
     List<ByteString> byteStringList = list.asByteStringList();
     ListIterator<ByteString> byteIter = byteStringList.listIterator();
@@ -196,24 +202,24 @@
       count++;
       try {
         byteIter.remove();
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
       try {
         byteIter.set(BYTE_STRING_A);
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
       try {
         byteIter.add(BYTE_STRING_A);
-        fail();
+        assertWithMessage("expected exception").fail();
       } catch (UnsupportedOperationException e) {
         // expected
       }
     }
-    assertEquals(3, count);
+    assertThat(count).isEqualTo(3);
   }
 
   private LazyStringArrayList createSampleList() {
diff --git a/java/core/src/test/java/com/google/protobuf/Utf8Test.java b/java/core/src/test/java/com/google/protobuf/Utf8Test.java
index bc3c985..89f080e 100644
--- a/java/core/src/test/java/com/google/protobuf/Utf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/Utf8Test.java
@@ -30,19 +30,23 @@
 
 package com.google.protobuf;
 
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.regex.Pattern;
-import junit.framework.TestCase;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
-/** Unit tests for {@link Utf8}. */
-public class Utf8Test extends TestCase {
+import java.nio.ByteBuffer;
+import java.util.Random;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class Utf8Test {
   private static final int NUM_CHARS = 16384;
 
   private static final Utf8.Processor safeProcessor = new Utf8.SafeProcessor();
   private static final Utf8.Processor unsafeProcessor = new Utf8.UnsafeProcessor();
 
+  @Test
   public void testEncode() {
     assertEncoding(randomString(0x80));
     assertEncoding(randomString(0x90));
@@ -51,6 +55,7 @@
     assertEncoding(randomString(0x10ffff));
   }
 
+  @Test
   public void testEncode_insufficientSpace() {
     assertEncoding_insufficientSpace(randomString(0x80));
     assertEncoding_insufficientSpace(randomString(0x90));
@@ -59,22 +64,26 @@
     assertEncoding_insufficientSpace(randomString(0x10ffff));
   }
 
+  @Test
   public void testValid() {
     assertIsValid(new byte[] {(byte) 0xE0, (byte) 0xB9, (byte) 0x96}, true);
     assertIsValid(new byte[] {(byte) 0xF0, (byte) 0xB2, (byte) 0x83, (byte) 0xBC}, true);
   }
 
+  @Test
   public void testOverlongIsInvalid() {
     assertIsValid(new byte[] {(byte) 0xC0, (byte) 0x81}, false);
     assertIsValid(new byte[] {(byte) 0xE0, (byte) 0x81, (byte) 0x81}, false);
     assertIsValid(new byte[] {(byte) 0xF0, (byte) 0x81, (byte) 0x81, (byte) 0x81}, false);
   }
 
+  @Test
   public void testMaxCodepointExceeded() {
     // byte1 > 0xF4
     assertIsValid(new byte[] {(byte) 0xF5, (byte) 0x81, (byte) 0x81, (byte) 0x81}, false);
   }
 
+  @Test
   public void testInvalidSurrogateCodepoint() {
     assertIsValid(new byte[] {(byte) 0xED, (byte) 0xA1, (byte) 0x81}, false);
 
@@ -99,46 +108,51 @@
   }
 
   private static void assertIsValid(byte[] data, boolean valid) {
-    assertEquals("isValidUtf8[ARRAY]", valid, safeProcessor.isValidUtf8(data, 0, data.length));
-    assertEquals(
-        "isValidUtf8[ARRAY_UNSAFE]", valid, unsafeProcessor.isValidUtf8(data, 0, data.length));
+    assertWithMessage("isValidUtf8[ARRAY]")
+        .that(safeProcessor.isValidUtf8(data, 0, data.length))
+        .isEqualTo(valid);
+    assertWithMessage("isValidUtf8[ARRAY_UNSAFE]")
+        .that(unsafeProcessor.isValidUtf8(data, 0, data.length))
+        .isEqualTo(valid);
 
     ByteBuffer buffer = ByteBuffer.wrap(data);
-    assertEquals(
-        "isValidUtf8[NIO_HEAP]",
-        valid,
-        safeProcessor.isValidUtf8(buffer, buffer.position(), buffer.remaining()));
+    assertWithMessage("isValidUtf8[NIO_HEAP]")
+        .that(safeProcessor.isValidUtf8(buffer, buffer.position(), buffer.remaining()))
+        .isEqualTo(valid);
 
     // Direct buffers.
     buffer = ByteBuffer.allocateDirect(data.length);
     buffer.put(data);
     buffer.flip();
-    assertEquals(
-        "isValidUtf8[NIO_DEFAULT]",
-        valid,
-        safeProcessor.isValidUtf8(buffer, buffer.position(), buffer.remaining()));
-    assertEquals(
-        "isValidUtf8[NIO_UNSAFE]",
-        valid,
-        unsafeProcessor.isValidUtf8(buffer, buffer.position(), buffer.remaining()));
+    assertWithMessage("isValidUtf8[NIO_DEFAULT]")
+        .that(safeProcessor.isValidUtf8(buffer, buffer.position(), buffer.remaining()))
+        .isEqualTo(valid);
+    assertWithMessage("isValidUtf8[NIO_UNSAFE]")
+        .that(unsafeProcessor.isValidUtf8(buffer, buffer.position(), buffer.remaining()))
+        .isEqualTo(valid);
   }
 
   private static void assertEncoding(String message) {
     byte[] expected = message.getBytes(Internal.UTF_8);
     byte[] output = encodeToByteArray(message, expected.length, safeProcessor);
-    assertTrue("encodeUtf8[ARRAY]", Arrays.equals(expected, output));
+    assertWithMessage("encodeUtf8[ARRAY]")
+        .that(output).isEqualTo(expected);
 
     output = encodeToByteArray(message, expected.length, unsafeProcessor);
-    assertTrue("encodeUtf8[ARRAY_UNSAFE]", Arrays.equals(expected, output));
+    assertWithMessage("encodeUtf8[ARRAY_UNSAFE]")
+        .that(output).isEqualTo(expected);
 
     output = encodeToByteBuffer(message, expected.length, false, safeProcessor);
-    assertTrue("encodeUtf8[NIO_HEAP]", Arrays.equals(expected, output));
+    assertWithMessage("encodeUtf8[NIO_HEAP]")
+        .that(output).isEqualTo(expected);
 
     output = encodeToByteBuffer(message, expected.length, true, safeProcessor);
-    assertTrue("encodeUtf8[NIO_DEFAULT]", Arrays.equals(expected, output));
+    assertWithMessage("encodeUtf8[NIO_DEFAULT]")
+        .that(output).isEqualTo(expected);
 
     output = encodeToByteBuffer(message, expected.length, true, unsafeProcessor);
-    assertTrue("encodeUtf8[NIO_UNSAFE]", Arrays.equals(expected, output));
+    assertWithMessage("encodeUtf8[NIO_UNSAFE]")
+        .that(output).isEqualTo(expected);
   }
 
   private void assertEncoding_insufficientSpace(String message) {
@@ -147,54 +161,56 @@
 
     try {
       encodeToByteArray(message, length, safeProcessor);
-      fail("Expected " + clazz.getSimpleName());
+      assertWithMessage("Expected " + clazz.getSimpleName()).fail();
     } catch (Throwable t) {
       // Expected
-      assertExceptionType(t, clazz);
+      assertThat(t).isInstanceOf(clazz);
       // byte[] + safeProcessor will not exit early. We can't match the message since we don't
       // know which char/index due to random input.
     }
 
     try {
       encodeToByteArray(message, length, unsafeProcessor);
-      fail("Expected " + clazz.getSimpleName());
+      assertWithMessage("Expected " + clazz.getSimpleName()).fail();
     } catch (Throwable t) {
-      assertExceptionType(t, clazz);
+      assertThat(t).isInstanceOf(clazz);
       // byte[] + unsafeProcessor will exit early, so we have can match the message.
-      assertExceptionMessage(t, length);
+      String pattern = "Failed writing (.) at index " + length;
+      assertThat(t).hasMessageThat().matches(pattern);
     }
 
     try {
       encodeToByteBuffer(message, length, false, safeProcessor);
-      fail("Expected " + clazz.getSimpleName());
+      assertWithMessage("Expected " + clazz.getSimpleName()).fail();
     } catch (Throwable t) {
       // Expected
-      assertExceptionType(t, clazz);
+      assertThat(t).isInstanceOf(clazz);
       // ByteBuffer + safeProcessor will not exit early. We can't match the message since we don't
       // know which char/index due to random input.
     }
 
     try {
       encodeToByteBuffer(message, length, true, safeProcessor);
-      fail("Expected " + clazz.getSimpleName());
+      assertWithMessage("Expected " + clazz.getSimpleName()).fail();
     } catch (Throwable t) {
       // Expected
-      assertExceptionType(t, clazz);
+      assertThat(t).isInstanceOf(clazz);
       // ByteBuffer + safeProcessor will not exit early. We can't match the message since we don't
       // know which char/index due to random input.
     }
 
     try {
       encodeToByteBuffer(message, length, true, unsafeProcessor);
-      fail("Expected " + clazz.getSimpleName());
+      assertWithMessage("Expected " + clazz.getSimpleName()).fail();
     } catch (Throwable t) {
       // Expected
-      assertExceptionType(t, clazz);
+      assertThat(t).isInstanceOf(clazz);
       // Direct ByteBuffer + unsafeProcessor will exit early if it's not on Android, so we can
       // match the message. On Android, a direct ByteBuffer will have hasArray() being true and
       // it will take a different code path and produces a different message.
       if (!Android.isOnAndroidDevice()) {
-        assertExceptionMessage(t, length);
+        String pattern = "Failed writing (.) at index " + length;
+        assertThat(t).hasMessageThat().matches(pattern);
       }
     }
   }
@@ -217,16 +233,4 @@
     return output;
   }
 
-  private <T extends Throwable> void assertExceptionType(Throwable t, Class<T> expected) {
-    if (!expected.isAssignableFrom(t.getClass())) {
-      fail("Expected " + expected.getSimpleName() + ", but found " + t.getClass().getSimpleName());
-    }
-  }
-
-  private void assertExceptionMessage(Throwable t, int index) {
-    String pattern = "Failed writing (.) at index " + index;
-    assertTrue(
-        t.getMessage() + " does not match pattern " + pattern,
-        Pattern.matches(pattern, t.getMessage()));
-  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/WireFormatLiteTest.java b/java/core/src/test/java/com/google/protobuf/WireFormatLiteTest.java
index a725d41..cbed9fc 100644
--- a/java/core/src/test/java/com/google/protobuf/WireFormatLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/WireFormatLiteTest.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
 
 import com.google.protobuf.UnittestLite.ForeignEnumLite;
@@ -55,11 +57,15 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Arrays;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class WireFormatLiteTest extends TestCase {
+@RunWith(JUnit4.class)
+public class WireFormatLiteTest {
+
+  @Test
   public void testSerializeExtensionsLite() throws Exception {
     // TestAllTypes and TestAllExtensions should have compatible wire formats,
     // so if we serialize a TestAllExtensions then parse it as TestAllTypes
@@ -67,13 +73,14 @@
 
     TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet();
     ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
 
     TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
 
     TestUtil.assertAllFieldsSet(message2);
   }
 
+  @Test
   public void testSerializePackedExtensionsLite() throws Exception {
     // TestPackedTypes and TestPackedExtensions should have compatible wire
     // formats; check that they serialize to the same string.
@@ -83,9 +90,10 @@
     TestPackedTypes message2 = TestUtil.getPackedSet();
     ByteString rawBytes2 = message2.toByteString();
 
-    assertEquals(rawBytes, rawBytes2);
+    assertThat(rawBytes2).isEqualTo(rawBytes);
   }
 
+  @Test
   public void testParseExtensionsLite() throws Exception {
     // TestAllTypes and TestAllExtensions should have compatible wire formats,
     // so if we serialize a TestAllTypes then parse it as TestAllExtensions
@@ -102,6 +110,7 @@
     TestUtil.assertAllExtensionsSet(message2);
   }
 
+  @Test
   public void testParsePackedExtensionsLite() throws Exception {
     // Ensure that packed extensions can be properly parsed.
     TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet();
@@ -115,28 +124,31 @@
     TestUtil.assertPackedExtensionsSet(message2);
   }
 
+  @Test
   public void testSerialization() throws Exception {
     TestAllTypes message = TestUtil.getAllSet();
 
     ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
 
     TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
 
     TestUtil.assertAllFieldsSet(message2);
   }
 
+  @Test
   public void testSerializationPacked() throws Exception {
     TestPackedTypes message = TestUtil.getPackedSet();
 
     ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
 
     TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
 
     TestUtil.assertPackedFieldsSet(message2);
   }
 
+  @Test
   public void testSerializeExtensions() throws Exception {
     // TestAllTypes and TestAllExtensions should have compatible wire formats,
     // so if we serialize a TestAllExtensions then parse it as TestAllTypes
@@ -144,13 +156,14 @@
 
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
 
     TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
 
     TestUtil.assertAllFieldsSet(message2);
   }
 
+  @Test
   public void testSerializePackedExtensions() throws Exception {
     // TestPackedTypes and TestPackedExtensions should have compatible wire
     // formats; check that they serialize to the same string.
@@ -160,9 +173,10 @@
     TestPackedTypes message2 = TestUtil.getPackedSet();
     ByteString rawBytes2 = message2.toByteString();
 
-    assertEquals(rawBytes, rawBytes2);
+    assertThat(rawBytes2).isEqualTo(rawBytes);
   }
 
+  @Test
   public void testSerializationPackedWithoutGetSerializedSize() throws Exception {
     // Write directly to an OutputStream, without invoking getSerializedSize()
     // This used to be a bug where the size of a packed field was incorrect,
@@ -183,6 +197,7 @@
     TestUtil.assertPackedFieldsSet(message2);
   }
 
+  @Test
   public void testParseExtensions() throws Exception {
     // TestAllTypes and TestAllExtensions should have compatible wire formats,
     // so if we serialize a TestAllTypes then parse it as TestAllExtensions
@@ -198,6 +213,7 @@
     TestUtil.assertAllExtensionsSet(message2);
   }
 
+  @Test
   public void testParsePackedExtensions() throws Exception {
     // Ensure that packed extensions can be properly parsed.
     TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
@@ -210,6 +226,7 @@
     TestUtil.assertPackedExtensionsSet(message2);
   }
 
+  @Test
   public void testSerializeDelimited() throws Exception {
     ByteArrayOutputStream output = new ByteArrayOutputStream();
     TestUtil.getAllSet().writeDelimitedTo(output);
@@ -220,13 +237,13 @@
     ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
 
     TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input));
-    assertEquals(12, input.read());
+    assertThat(input.read()).isEqualTo(12);
     TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input));
-    assertEquals(34, input.read());
-    assertEquals(-1, input.read());
+    assertThat(input.read()).isEqualTo(34);
+    assertThat(input.read()).isEqualTo(-1);
 
     // We're at EOF, so parsing again should return null.
-    assertNull(TestAllTypes.parseDelimitedFrom(input));
+    assertThat(TestAllTypes.parseDelimitedFrom(input)).isNull();
   }
 
   private ExtensionRegistryLite getTestFieldOrderingsRegistry() {
@@ -236,6 +253,7 @@
     return result;
   }
 
+  @Test
   public void testParseMultipleExtensionRanges() throws Exception {
     // Make sure we can parse a message that contains multiple extensions
     // ranges.
@@ -249,7 +267,7 @@
             .build();
     TestFieldOrderings dest =
         TestFieldOrderings.parseFrom(source.toByteString(), getTestFieldOrderingsRegistry());
-    assertEquals(source, dest);
+    assertThat(dest).isEqualTo(source);
   }
 
   private static ExtensionRegistryLite getTestExtensionInsideTableRegistry() {
@@ -258,6 +276,7 @@
     return result;
   }
 
+  @Test
   public void testExtensionInsideTable() throws Exception {
     // Make sure the extension within the range of table is parsed correctly in experimental
     // runtime.
@@ -269,17 +288,19 @@
     TestExtensionInsideTable dest =
         TestExtensionInsideTable.parseFrom(
             source.toByteString(), getTestExtensionInsideTableRegistry());
-    assertEquals(source, dest);
+    assertThat(dest).isEqualTo(source);
   }
 
   private static final int UNKNOWN_TYPE_ID = 1550055;
   private static final int TYPE_ID_1 = 1545008;
   private static final int TYPE_ID_2 = 1547769;
 
+  @Test
   public void testSerializeMessageSetEagerly() throws Exception {
     testSerializeMessageSetWithFlag(true);
   }
 
+  @Test
   public void testSerializeMessageSetNotEagerly() throws Exception {
     testSerializeMessageSetWithFlag(false);
   }
@@ -309,26 +330,28 @@
     // Parse back using RawMessageSet and check the contents.
     RawMessageSet raw = RawMessageSet.parseFrom(data);
 
-    assertEquals(3, raw.getItemCount());
-    assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId());
-    assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId());
-    assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId());
+    assertThat(raw.getItemCount()).isEqualTo(3);
+    assertThat(raw.getItem(0).getTypeId()).isEqualTo(TYPE_ID_1);
+    assertThat(raw.getItem(1).getTypeId()).isEqualTo(TYPE_ID_2);
+    assertThat(raw.getItem(2).getTypeId()).isEqualTo(UNKNOWN_TYPE_ID);
 
     TestMessageSetExtension1 message1 =
         TestMessageSetExtension1.parseFrom(raw.getItem(0).getMessage());
-    assertEquals(123, message1.getI());
+    assertThat(message1.getI()).isEqualTo(123);
 
     TestMessageSetExtension2 message2 =
         TestMessageSetExtension2.parseFrom(raw.getItem(1).getMessage());
-    assertEquals("foo", message2.getStr());
+    assertThat(message2.getStr()).isEqualTo("foo");
 
-    assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
+    assertThat(raw.getItem(2).getMessage().toStringUtf8()).isEqualTo("bar");
   }
 
+  @Test
   public void testParseMessageSetEagerly() throws Exception {
     testParseMessageSetWithFlag(true);
   }
 
+  @Test
   public void testParseMessageSetNotEagerly() throws Exception {
     testParseMessageSetWithFlag(false);
   }
@@ -366,15 +389,18 @@
     // Parse as a TestMessageSet and check the contents.
     TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry);
 
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
-    assertEquals(
-        "foo", messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
+    assertThat(messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr())
+        .isEqualTo("foo");
   }
 
+  @Test
   public void testParseMessageSetExtensionEagerly() throws Exception {
     testParseMessageSetExtensionWithFlag(true);
   }
 
+  @Test
   public void testParseMessageSetExtensionNotEagerly() throws Exception {
     testParseMessageSetExtensionWithFlag(false);
   }
@@ -400,13 +426,16 @@
 
     // Parse as a TestMessageSet and check the contents.
     TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry);
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
   }
 
+  @Test
   public void testMergeLazyMessageSetExtensionEagerly() throws Exception {
     testMergeLazyMessageSetExtensionWithFlag(true);
   }
 
+  @Test
   public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception {
     testMergeLazyMessageSetExtensionWithFlag(false);
   }
@@ -434,13 +463,16 @@
     TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry);
     // Merge lazy field check the contents.
     messageSet = messageSet.toBuilder().mergeFrom(data, extensionRegistry).build();
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
   }
 
+  @Test
   public void testMergeMessageSetExtensionEagerly() throws Exception {
     testMergeMessageSetExtensionWithFlag(true);
   }
 
+  @Test
   public void testMergeMessageSetExtensionNotEagerly() throws Exception {
     testMergeMessageSetExtensionWithFlag(false);
   }
@@ -477,31 +509,34 @@
     // Merge bytes into TestMessageSet and check the contents.
     TestMessageSet messageSet =
         TestMessageSet.newBuilder().mergeFrom(data, extensionRegistry).build();
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
   }
 
   // ================================================================
   // oneof
+  @Test
   public void testOneofWireFormat() throws Exception {
     TestOneof2.Builder builder = TestOneof2.newBuilder();
     TestUtil.setOneof(builder);
     TestOneof2 message = builder.build();
     ByteString rawBytes = message.toByteString();
 
-    assertEquals(rawBytes.size(), message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
 
     TestOneof2 message2 = TestOneof2.parseFrom(rawBytes);
     TestUtil.assertOneofSet(message2);
   }
 
+  @Test
   public void testOneofOnlyLastSet() throws Exception {
     TestOneofBackwardsCompatible source =
         TestOneofBackwardsCompatible.newBuilder().setFooInt(100).setFooString("101").build();
 
     ByteString rawBytes = source.toByteString();
     TestOneof2 message = TestOneof2.parseFrom(rawBytes);
-    assertFalse(message.hasFooInt());
-    assertTrue(message.hasFooString());
+    assertThat(message.hasFooInt()).isFalse();
+    assertThat(message.hasFooString()).isTrue();
   }
 
   private void assertInvalidWireFormat(
@@ -509,27 +544,27 @@
     // Test all combinations: (builder vs parser) x (byte[] vs. InputStream).
     try {
       defaultInstance.newBuilderForType().mergeFrom(data, offset, length);
-      fail("Expected exception");
+      assertWithMessage("Expected exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Pass.
     }
     try {
       defaultInstance.getParserForType().parseFrom(data, offset, length);
-      fail("Expected exception");
+      assertWithMessage("Expected exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Pass.
     }
     try {
       InputStream input = new ByteArrayInputStream(data, offset, length);
       defaultInstance.newBuilderForType().mergeFrom(input);
-      fail("Expected exception");
+      assertWithMessage("Expected exception").fail();
     } catch (IOException e) {
       // Pass.
     }
     try {
       InputStream input = new ByteArrayInputStream(data, offset, length);
       defaultInstance.getParserForType().parseFrom(input);
-      fail("Expected exception");
+      assertWithMessage("Expected exception").fail();
     } catch (IOException e) {
       // Pass.
     }
@@ -544,6 +579,7 @@
     assertInvalidWireFormat(UnittestProto3.TestAllTypes.getDefaultInstance(), data);
   }
 
+  @Test
   public void testParserRejectInvalidTag() throws Exception {
     byte[] invalidTags =
         new byte[] {
@@ -609,6 +645,7 @@
     }
   }
 
+  @Test
   public void testUnmatchedGroupTag() throws Exception {
     int startTag = WireFormat.makeTag(16, WireFormat.WIRETYPE_START_GROUP);
     byte[] data =
@@ -637,11 +674,12 @@
         defaultInstance.newBuilderForType().mergeFrom(new ByteArrayInputStream(data)).build();
     MessageLite message4 =
         defaultInstance.getParserForType().parseFrom(new ByteArrayInputStream(data));
-    assertEquals(message1, message2);
-    assertEquals(message2, message3);
-    assertEquals(message3, message4);
+    assertThat(message2).isEqualTo(message1);
+    assertThat(message3).isEqualTo(message2);
+    assertThat(message4).isEqualTo(message3);
   }
 
+  @Test
   public void testUnmatchedWireType() throws Exception {
     // Build a payload with all fields from 1 to 128 being varints. Parsing it into TestAllTypes
     // or other message types should succeed even though the wire type doesn't match for some
@@ -660,6 +698,7 @@
     assertAccepted(MapForProto2TestProto.TestMap.getDefaultInstance(), data);
   }
 
+  @Test
   public void testParseTruncatedPackedFields() throws Exception {
     TestPackedTypes all = TestUtil.getPackedSet();
     TestPackedTypes[] messages =
@@ -687,6 +726,7 @@
     }
   }
 
+  @Test
   public void testParsePackedFieldsWithIncorrectLength() throws Exception {
     // Set the length-prefix to 1 with a 4-bytes payload to test what happens when reading a packed
     // element moves the reading position past the given length limit. It should result in an
@@ -758,6 +798,7 @@
     }
   }
 
+  @Test
   public void testParseVarintMinMax() throws Exception {
     TestAllTypes message =
         TestAllTypes.newBuilder()
@@ -767,55 +808,61 @@
             .addRepeatedInt64(Long.MAX_VALUE)
             .build();
     TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals(Integer.MIN_VALUE, parsed.getOptionalInt32());
-    assertEquals(Integer.MAX_VALUE, parsed.getRepeatedInt32(0));
-    assertEquals(Long.MIN_VALUE, parsed.getOptionalInt64());
-    assertEquals(Long.MAX_VALUE, parsed.getRepeatedInt64(0));
+    assertThat(parsed.getOptionalInt32()).isEqualTo(Integer.MIN_VALUE);
+    assertThat(parsed.getRepeatedInt32(0)).isEqualTo(Integer.MAX_VALUE);
+    assertThat(parsed.getOptionalInt64()).isEqualTo(Long.MIN_VALUE);
+    assertThat(parsed.getRepeatedInt64(0)).isEqualTo(Long.MAX_VALUE);
   }
 
+  @Test
   public void testParseAllVarintBits() throws Exception {
     for (int i = 0; i < 32; i++) {
       final int value = 1 << i;
       TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(value).build();
       TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray());
-      assertEquals(value, parsed.getOptionalInt32());
+      assertThat(parsed.getOptionalInt32()).isEqualTo(value);
     }
     for (int i = 0; i < 64; i++) {
       final long value = 1L << i;
       TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt64(value).build();
       TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray());
-      assertEquals(value, parsed.getOptionalInt64());
+      assertThat(parsed.getOptionalInt64()).isEqualTo(value);
     }
   }
 
+  @Test
   public void testParseEmptyUnknownLengthDelimitedField() throws Exception {
     byte[] data =
         new byte[] {(byte) WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED), 0};
     TestAllTypes parsed = TestAllTypes.parseFrom(data);
-    assertTrue(Arrays.equals(data, parsed.toByteArray()));
+    assertThat(parsed.toByteArray()).isEqualTo(data);
   }
 
+  @Test
   public void testParseEmptyString() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("").build();
     TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals("", parsed.getOptionalString());
+    assertThat(parsed.getOptionalString()).isEmpty();
   }
 
+  @Test
   public void testParseEmptyStringProto3() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("").build();
     // Note that we are parsing from a proto2 proto to a proto3 proto because empty string field is
     // not serialized in proto3.
     UnittestProto3.TestAllTypes parsed =
         UnittestProto3.TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals("", parsed.getOptionalString());
+    assertThat(parsed.getOptionalString()).isEmpty();
   }
 
+  @Test
   public void testParseEmptyBytes() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalBytes(ByteString.EMPTY).build();
     TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals(ByteString.EMPTY, parsed.getOptionalBytes());
+    assertThat(parsed.getOptionalBytes()).isEqualTo(ByteString.EMPTY);
   }
 
+  @Test
   public void testParseEmptyRepeatedStringField() throws Exception {
     TestAllTypes message =
         TestAllTypes.newBuilder()
@@ -824,12 +871,13 @@
             .addRepeatedString("0")
             .build();
     TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals(3, parsed.getRepeatedStringCount());
-    assertEquals("", parsed.getRepeatedString(0));
-    assertEquals("", parsed.getRepeatedString(1));
-    assertEquals("0", parsed.getRepeatedString(2));
+    assertThat(parsed.getRepeatedStringCount()).isEqualTo(3);
+    assertThat(parsed.getRepeatedString(0)).isEmpty();
+    assertThat(parsed.getRepeatedString(1)).isEmpty();
+    assertThat(parsed.getRepeatedString(2)).isEqualTo("0");
   }
 
+  @Test
   public void testParseEmptyRepeatedStringFieldProto3() throws Exception {
     TestAllTypes message =
         TestAllTypes.newBuilder()
@@ -840,12 +888,13 @@
             .build();
     UnittestProto3.TestAllTypes parsed =
         UnittestProto3.TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals(3, parsed.getRepeatedStringCount());
-    assertEquals("", parsed.getRepeatedString(0));
-    assertEquals("", parsed.getRepeatedString(1));
-    assertEquals("0", parsed.getRepeatedString(2));
+    assertThat(parsed.getRepeatedStringCount()).isEqualTo(3);
+    assertThat(parsed.getRepeatedString(0)).isEmpty();
+    assertThat(parsed.getRepeatedString(1)).isEmpty();
+    assertThat(parsed.getRepeatedString(2)).isEqualTo("0");
   }
 
+  @Test
   public void testParseEmptyRepeatedBytesField() throws Exception {
     ByteString oneByte = ByteString.copyFrom(new byte[] {1});
     TestAllTypes message =
@@ -855,12 +904,13 @@
             .addRepeatedBytes(oneByte)
             .build();
     TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals(3, parsed.getRepeatedBytesCount());
-    assertEquals(ByteString.EMPTY, parsed.getRepeatedBytes(0));
-    assertEquals(ByteString.EMPTY, parsed.getRepeatedBytes(1));
-    assertEquals(oneByte, parsed.getRepeatedBytes(2));
+    assertThat(parsed.getRepeatedBytesCount()).isEqualTo(3);
+    assertThat(parsed.getRepeatedBytes(0)).isEqualTo(ByteString.EMPTY);
+    assertThat(parsed.getRepeatedBytes(1)).isEqualTo(ByteString.EMPTY);
+    assertThat(parsed.getRepeatedBytes(2)).isEqualTo(oneByte);
   }
 
+  @Test
   public void testSkipUnknownFieldInMessageSetItem() throws Exception {
     ByteArrayOutputStream output = new ByteArrayOutputStream();
     // MessageSet item's start tag.
@@ -881,109 +931,119 @@
 
     // Convert to RawMessageSet for inspection.
     RawMessageSet raw = RawMessageSet.parseFrom(parsed.toByteArray());
-    assertEquals(1, raw.getItemCount());
-    assertEquals(100, raw.getItem(0).getTypeId());
-    assertEquals(0, raw.getItem(0).getMessage().size());
+    assertThat(raw.getItemCount()).isEqualTo(1);
+    assertThat(raw.getItem(0).getTypeId()).isEqualTo(100);
+    assertThat(raw.getItem(0).getMessage().size()).isEqualTo(0);
   }
 
+  @Test
   public void testProto2UnknownEnumValuesInOptionalField() throws Exception {
     // Proto2 doesn't allow setting unknown enum values so we use proto3 to build a message with
     // unknown enum values
     UnittestProto3.TestAllTypes message =
         UnittestProto3.TestAllTypes.newBuilder().setOptionalNestedEnumValue(4321).build();
     TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray());
-    assertFalse(parsed.hasOptionalNestedEnum());
+    assertThat(parsed.hasOptionalNestedEnum()).isFalse();
     // Make sure unknown enum values are preserved.
     UnittestProto3.TestAllTypes actual =
         UnittestProto3.TestAllTypes.parseFrom(parsed.toByteArray());
-    assertEquals(4321, actual.getOptionalNestedEnumValue());
+    assertThat(actual.getOptionalNestedEnumValue()).isEqualTo(4321);
   }
 
+  @Test
   public void testProto2UnknownEnumValuesInRepeatedField() throws Exception {
     // Proto2 doesn't allow setting unknown enum values so we use proto3 to build a message with
     // unknown enum values
     UnittestProto3.TestAllTypes message =
         UnittestProto3.TestAllTypes.newBuilder().addRepeatedNestedEnumValue(5432).build();
     TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals(0, parsed.getRepeatedNestedEnumCount());
+    assertThat(parsed.getRepeatedNestedEnumCount()).isEqualTo(0);
     // Make sure unknown enum values are preserved.
     UnittestProto3.TestAllTypes actual =
         UnittestProto3.TestAllTypes.parseFrom(parsed.toByteArray());
-    assertEquals(1, actual.getRepeatedNestedEnumCount());
-    assertEquals(5432, actual.getRepeatedNestedEnumValue(0));
+    assertThat(actual.getRepeatedNestedEnumCount()).isEqualTo(1);
+    assertThat(actual.getRepeatedNestedEnumValue(0)).isEqualTo(5432);
   }
 
+  @Test
   public void testProto2UnknownEnumValuesInMapField() throws Exception {
     // Proto2 doesn't allow setting unknown enum values so we use proto3 to build a message with
     // unknown enum values
     TestMap message = TestMap.newBuilder().putInt32ToEnumFieldValue(1, 4321).build();
     MapForProto2TestProto.TestMap parsed =
         MapForProto2TestProto.TestMap.parseFrom(message.toByteArray());
-    assertEquals(0, parsed.getInt32ToEnumFieldMap().size());
+    assertThat(parsed.getInt32ToEnumFieldMap()).isEmpty();
     // Make sure unknown enum values are preserved.
     TestMap actual = TestMap.parseFrom(parsed.toByteArray());
-    assertEquals(1, actual.getInt32ToEnumFieldMap().size());
-    assertEquals(4321, actual.getInt32ToEnumFieldValueOrThrow(1));
+    assertThat(actual.getInt32ToEnumFieldMap()).hasSize(1);
+    assertThat(actual.getInt32ToEnumFieldValueOrThrow(1)).isEqualTo(4321);
   }
 
+  @Test
   public void testProto2UnknownEnumValuesInOneof() throws Exception {
     // Proto2 doesn't allow setting unknown enum values so we use proto3 to build a message with
     // unknown enum values
     UnittestProto3.TestOneof2 message =
         UnittestProto3.TestOneof2.newBuilder().setFooEnumValue(1234).build();
     TestOneof2 parsed = TestOneof2.parseFrom(message.toByteArray());
-    assertFalse(parsed.hasFooEnum());
+    assertThat(parsed.hasFooEnum()).isFalse();
     // Make sure unknown enum values are preserved.
     UnittestProto3.TestOneof2 actual = UnittestProto3.TestOneof2.parseFrom(parsed.toByteArray());
-    assertEquals(1234, actual.getFooEnumValue());
+    assertThat(actual.getFooEnumValue()).isEqualTo(1234);
   }
 
+  @Test
   public void testProto2UnknownEnumValuesInExtension() throws Exception {
     ExtensionRegistryLite extensionRegistry = TestUtilLite.getExtensionRegistryLite();
     // Raw bytes for "[.optional_foreign_enum_extension_lite]: 10"
     final byte[] rawBytes = new byte[]{-80, 1, 10};
     TestAllExtensionsLite testAllExtensionsLite =
         TestAllExtensionsLite.parseFrom(rawBytes, extensionRegistry);
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO,
-        testAllExtensionsLite.getExtension(optionalForeignEnumExtensionLite));
+    assertThat(testAllExtensionsLite.getExtension(optionalForeignEnumExtensionLite))
+        .isEqualTo(ForeignEnumLite.FOREIGN_LITE_FOO);
     final byte[] resultRawBytes = testAllExtensionsLite.toByteArray();
-    assertEquals(rawBytes.length, resultRawBytes.length);
+    assertThat(resultRawBytes).hasLength(rawBytes.length);
     for (int i = 0; i < rawBytes.length; i++) {
-      assertEquals(rawBytes[i], resultRawBytes[i]);
+      assertThat(resultRawBytes[i]).isEqualTo(rawBytes[i]);
     }
   }
 
+  @Test
   public void testProto3UnknownEnumValuesInOptionalField() throws Exception {
     UnittestProto3.TestAllTypes message =
         UnittestProto3.TestAllTypes.newBuilder().setOptionalNestedEnumValue(4321).build();
     UnittestProto3.TestAllTypes parsed =
         UnittestProto3.TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals(4321, parsed.getOptionalNestedEnumValue());
+    assertThat(parsed.getOptionalNestedEnumValue()).isEqualTo(4321);
   }
 
+  @Test
   public void testProto3UnknownEnumValuesInRepeatedField() throws Exception {
     UnittestProto3.TestAllTypes message =
         UnittestProto3.TestAllTypes.newBuilder().addRepeatedNestedEnumValue(5432).build();
     UnittestProto3.TestAllTypes parsed =
         UnittestProto3.TestAllTypes.parseFrom(message.toByteArray());
-    assertEquals(1, parsed.getRepeatedNestedEnumCount());
-    assertEquals(5432, parsed.getRepeatedNestedEnumValue(0));
+    assertThat(parsed.getRepeatedNestedEnumCount()).isEqualTo(1);
+    assertThat(parsed.getRepeatedNestedEnumValue(0)).isEqualTo(5432);
   }
 
+  @Test
   public void testProto3UnknownEnumValuesInMapField() throws Exception {
     TestMap message = TestMap.newBuilder().putInt32ToEnumFieldValue(1, 4321).build();
     TestMap parsed = TestMap.parseFrom(message.toByteArray());
-    assertEquals(1, parsed.getInt32ToEnumFieldMap().size());
-    assertEquals(4321, parsed.getInt32ToEnumFieldValueOrThrow(1));
+    assertThat(parsed.getInt32ToEnumFieldMap()).hasSize(1);
+    assertThat(parsed.getInt32ToEnumFieldValueOrThrow(1)).isEqualTo(4321);
   }
 
+  @Test
   public void testProto3UnknownEnumValuesInOneof() throws Exception {
     UnittestProto3.TestOneof2 message =
         UnittestProto3.TestOneof2.newBuilder().setFooEnumValue(1234).build();
     UnittestProto3.TestOneof2 parsed = UnittestProto3.TestOneof2.parseFrom(message.toByteArray());
-    assertEquals(1234, parsed.getFooEnumValue());
+    assertThat(parsed.getFooEnumValue()).isEqualTo(1234);
   }
 
+  @Test
   public void testProto3MessageFieldMergeBehavior() throws Exception {
     UnittestProto3.NestedTestAllTypes message1 =
         UnittestProto3.NestedTestAllTypes.newBuilder()
@@ -1006,12 +1066,13 @@
             .mergeFrom(message2.toByteArray())
             .build();
     // Field values coming later in the stream override earlier values.
-    assertEquals(4321, merged.getPayload().getOptionalInt32());
+    assertThat(merged.getPayload().getOptionalInt32()).isEqualTo(4321);
     // Field values present in either message should be present in the merged result.
-    assertEquals(5678, merged.getPayload().getOptionalInt64());
-    assertEquals(8765, merged.getPayload().getOptionalUint32());
+    assertThat(merged.getPayload().getOptionalInt64()).isEqualTo(5678);
+    assertThat(merged.getPayload().getOptionalUint32()).isEqualTo(8765);
   }
 
+  @Test
   public void testMergeFromPartialByteArray() throws Exception {
     byte[] data = TestUtil.getAllSet().toByteArray();
     byte[] dataWithPaddings = new byte[data.length + 2];
diff --git a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
index 45a396a..e072eb8 100644
--- a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import protobuf_unittest.UnittestMset.RawMessageSet;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
@@ -46,14 +48,13 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Tests related to parsing and serialization.
- *
- * @author [email protected] (Kenton Varda)
- */
-public class WireFormatTest extends TestCase {
+/** Tests related to parsing and serialization. */
+@RunWith(JUnit4.class)
+public class WireFormatTest {
 
   private static final int TYPE_ID_1 =
       TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
@@ -61,28 +62,31 @@
       TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
   private static final int UNKNOWN_TYPE_ID = 1550055;
 
+  @Test
   public void testSerialization() throws Exception {
     TestAllTypes message = TestUtil.getAllSet();
 
     ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
+    assertThat(rawBytes.size()).isEqualTo(message.getSerializedSize());
 
     TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
 
     TestUtil.assertAllFieldsSet(message2);
   }
 
+  @Test
   public void testSerializationPacked() throws Exception {
     TestPackedTypes message = TestUtil.getPackedSet();
 
     ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
 
     TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
 
     TestUtil.assertPackedFieldsSet(message2);
   }
 
+  @Test
   public void testSerializeExtensions() throws Exception {
     // TestAllTypes and TestAllExtensions should have compatible wire formats,
     // so if we serialize a TestAllExtensions then parse it as TestAllTypes
@@ -90,13 +94,14 @@
 
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
 
     TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
 
     TestUtil.assertAllFieldsSet(message2);
   }
 
+  @Test
   public void testSerializePackedExtensions() throws Exception {
     // TestPackedTypes and TestPackedExtensions should have compatible wire
     // formats; check that they serialize to the same string.
@@ -106,9 +111,10 @@
     TestPackedTypes message2 = TestUtil.getPackedSet();
     ByteString rawBytes2 = message2.toByteString();
 
-    assertEquals(rawBytes, rawBytes2);
+    assertThat(rawBytes).isEqualTo(rawBytes2);
   }
 
+  @Test
   public void testSerializationPackedWithoutGetSerializedSize() throws Exception {
     // Write directly to an OutputStream, without invoking getSerializedSize()
     // This used to be a bug where the size of a packed field was incorrect,
@@ -129,6 +135,7 @@
     TestUtil.assertPackedFieldsSet(message2);
   }
 
+  @Test
   public void testParseExtensions() throws Exception {
     // TestAllTypes and TestAllExtensions should have compatible wire formats,
     // so if we serialize a TestAllTypes then parse it as TestAllExtensions
@@ -144,6 +151,7 @@
     TestUtil.assertAllExtensionsSet(message2);
   }
 
+  @Test
   public void testParsePackedExtensions() throws Exception {
     // Ensure that packed extensions can be properly parsed.
     TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
@@ -156,6 +164,7 @@
     TestUtil.assertPackedExtensionsSet(message2);
   }
 
+  @Test
   public void testSerializeDelimited() throws Exception {
     ByteArrayOutputStream output = new ByteArrayOutputStream();
     TestUtil.getAllSet().writeDelimitedTo(output);
@@ -166,13 +175,13 @@
     ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
 
     TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input));
-    assertEquals(12, input.read());
+    assertThat(input.read()).isEqualTo(12);
     TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input));
-    assertEquals(34, input.read());
-    assertEquals(-1, input.read());
+    assertThat(input.read()).isEqualTo(34);
+    assertThat(input.read()).isEqualTo(-1);
 
     // We're at EOF, so parsing again should return null.
-    assertTrue(TestAllTypes.parseDelimitedFrom(input) == null);
+    assertThat(TestAllTypes.parseDelimitedFrom(input)).isNull();
   }
 
   private void assertFieldsInOrder(ByteString data) throws Exception {
@@ -185,12 +194,13 @@
         break;
       }
 
-      assertTrue(tag > previousTag);
+      assertThat(tag).isGreaterThan(previousTag);
       previousTag = tag;
       input.skipField(tag);
     }
   }
 
+  @Test
   public void testInterleavedFieldsAndExtensions() throws Exception {
     // Tests that fields are written in order even when extension ranges
     // are interleaved with field numbers.
@@ -225,6 +235,7 @@
     return result;
   }
 
+  @Test
   public void testParseMultipleExtensionRanges() throws Exception {
     // Make sure we can parse a message that contains multiple extensions
     // ranges.
@@ -238,7 +249,7 @@
             .build();
     TestFieldOrderings dest =
         TestFieldOrderings.parseFrom(source.toByteString(), getTestFieldOrderingsRegistry());
-    assertEquals(source, dest);
+    assertThat(source).isEqualTo(dest);
   }
 
   private static ExtensionRegistry getTestExtensionInsideTableRegistry() {
@@ -247,6 +258,7 @@
     return result;
   }
 
+  @Test
   public void testExtensionInsideTable() throws Exception {
     // Make sure the extension within the range of table is parsed correctly in experimental
     // runtime.
@@ -258,9 +270,10 @@
     TestExtensionInsideTable dest =
         TestExtensionInsideTable.parseFrom(
             source.toByteString(), getTestExtensionInsideTableRegistry());
-    assertEquals(source, dest);
+    assertThat(source).isEqualTo(dest);
   }
 
+  @Test
   public void testParseMultipleExtensionRangesDynamic() throws Exception {
     // Same as above except with DynamicMessage.
     Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
@@ -275,13 +288,15 @@
     DynamicMessage dest =
         DynamicMessage.parseFrom(
             descriptor, source.toByteString(), getTestFieldOrderingsRegistry());
-    assertEquals(source, dest);
+    assertThat(source).isEqualTo(dest);
   }
 
+  @Test
   public void testSerializeMessageSetEagerly() throws Exception {
     testSerializeMessageSetWithFlag(true);
   }
 
+  @Test
   public void testSerializeMessageSetNotEagerly() throws Exception {
     testSerializeMessageSetWithFlag(false);
   }
@@ -312,28 +327,30 @@
     // Parse back using RawMessageSet and check the contents.
     RawMessageSet raw = RawMessageSet.parseFrom(data);
 
-    assertTrue(raw.getUnknownFields().asMap().isEmpty());
+    assertThat(raw.getUnknownFields().asMap()).isEmpty();
 
-    assertEquals(3, raw.getItemCount());
-    assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId());
-    assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId());
-    assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId());
+    assertThat(raw.getItemCount()).isEqualTo(3);
+    assertThat(raw.getItem(0).getTypeId()).isEqualTo(TYPE_ID_1);
+    assertThat(raw.getItem(1).getTypeId()).isEqualTo(TYPE_ID_2);
+    assertThat(raw.getItem(2).getTypeId()).isEqualTo(UNKNOWN_TYPE_ID);
 
     TestMessageSetExtension1 message1 =
         TestMessageSetExtension1.parseFrom(raw.getItem(0).getMessage());
-    assertEquals(123, message1.getI());
+    assertThat(message1.getI()).isEqualTo(123);
 
     TestMessageSetExtension2 message2 =
         TestMessageSetExtension2.parseFrom(raw.getItem(1).getMessage());
-    assertEquals("foo", message2.getStr());
+    assertThat(message2.getStr()).isEqualTo("foo");
 
-    assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
+    assertThat(raw.getItem(2).getMessage().toStringUtf8()).isEqualTo("bar");
   }
 
+  @Test
   public void testParseMessageSetEagerly() throws Exception {
     testParseMessageSetWithFlag(true);
   }
 
+  @Test
   public void testParseMessageSetNotEagerly() throws Exception {
     testParseMessageSetWithFlag(false);
   }
@@ -371,25 +388,28 @@
     // Parse as a TestMessageSet and check the contents.
     TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry);
 
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
-    assertEquals(
-        "foo", messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
+    assertThat(messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr())
+        .isEqualTo("foo");
 
     // Check for unknown field with type LENGTH_DELIMITED,
     //   number UNKNOWN_TYPE_ID, and contents "bar".
     UnknownFieldSet unknownFields = messageSet.getUnknownFields();
-    assertEquals(1, unknownFields.asMap().size());
-    assertTrue(unknownFields.hasField(UNKNOWN_TYPE_ID));
+    assertThat(unknownFields.asMap()).hasSize(1);
+    assertThat(unknownFields.hasField(UNKNOWN_TYPE_ID)).isTrue();
 
     UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID);
-    assertEquals(1, field.getLengthDelimitedList().size());
-    assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8());
+    assertThat(field.getLengthDelimitedList()).hasSize(1);
+    assertThat(field.getLengthDelimitedList().get(0).toStringUtf8()).isEqualTo("bar");
   }
 
+  @Test
   public void testParseMessageSetExtensionEagerly() throws Exception {
     testParseMessageSetExtensionWithFlag(true);
   }
 
+  @Test
   public void testParseMessageSetExtensionNotEagerly() throws Exception {
     testParseMessageSetExtensionWithFlag(false);
   }
@@ -414,13 +434,16 @@
 
     // Parse as a TestMessageSet and check the contents.
     TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry);
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
   }
 
+  @Test
   public void testMergeLazyMessageSetExtensionEagerly() throws Exception {
     testMergeLazyMessageSetExtensionWithFlag(true);
   }
 
+  @Test
   public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception {
     testMergeLazyMessageSetExtensionWithFlag(false);
   }
@@ -447,13 +470,16 @@
     TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry);
     // Merge lazy field check the contents.
     messageSet = messageSet.toBuilder().mergeFrom(data, extensionRegistry).build();
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
   }
 
+  @Test
   public void testMergeMessageSetExtensionEagerly() throws Exception {
     testMergeMessageSetExtensionWithFlag(true);
   }
 
+  @Test
   public void testMergeMessageSetExtensionNotEagerly() throws Exception {
     testMergeMessageSetExtensionWithFlag(false);
   }
@@ -490,30 +516,33 @@
     // Merge bytes into TestMessageSet and check the contents.
     TestMessageSet messageSet =
         TestMessageSet.newBuilder().mergeFrom(data, extensionRegistry).build();
-    assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI());
+    assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
+        .isEqualTo(123);
   }
 
   // ================================================================
   // oneof
+  @Test
   public void testOneofWireFormat() throws Exception {
     TestOneof2.Builder builder = TestOneof2.newBuilder();
     TestUtil.setOneof(builder);
     TestOneof2 message = builder.build();
     ByteString rawBytes = message.toByteString();
 
-    assertEquals(rawBytes.size(), message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
 
     TestOneof2 message2 = TestOneof2.parseFrom(rawBytes);
     TestUtil.assertOneofSet(message2);
   }
 
+  @Test
   public void testOneofOnlyLastSet() throws Exception {
     TestOneofBackwardsCompatible source =
         TestOneofBackwardsCompatible.newBuilder().setFooInt(100).setFooString("101").build();
 
     ByteString rawBytes = source.toByteString();
     TestOneof2 message = TestOneof2.parseFrom(rawBytes);
-    assertFalse(message.hasFooInt());
-    assertTrue(message.hasFooString());
+    assertThat(message.hasFooInt()).isFalse();
+    assertThat(message.hasFooString()).isTrue();
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/WrappersLiteOfMethodTest.java b/java/core/src/test/java/com/google/protobuf/WrappersLiteOfMethodTest.java
index 4a3c764..fc1e09f 100644
--- a/java/core/src/test/java/com/google/protobuf/WrappersLiteOfMethodTest.java
+++ b/java/core/src/test/java/com/google/protobuf/WrappersLiteOfMethodTest.java
@@ -30,11 +30,17 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.protobuf.wrapperstest.WrappersTestProto.TopLevelMessage;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class WrappersLiteOfMethodTest extends TestCase {
+@RunWith(JUnit4.class)
+public class WrappersLiteOfMethodTest {
 
+  @Test
   public void testOf() throws Exception {
     TopLevelMessage.Builder builder = TopLevelMessage.newBuilder();
     builder.setFieldDouble(DoubleValue.of(2.333));
@@ -48,14 +54,14 @@
     builder.setFieldBytes(BytesValue.of(ByteString.wrap("233".getBytes(Internal.UTF_8))));
 
     TopLevelMessage message = builder.build();
-    assertTrue(2.333 == message.getFieldDouble().getValue());
-    assertTrue(2.333f == message.getFieldFloat().getValue());
-    assertTrue(2333 == message.getFieldInt32().getValue());
-    assertTrue(23333333333333L == message.getFieldInt64().getValue());
-    assertTrue(2333 == message.getFieldUint32().getValue());
-    assertTrue(23333333333333L == message.getFieldUint64().getValue());
-    assertTrue(true == message.getFieldBool().getValue());
-    assertTrue(message.getFieldString().getValue().equals("23333"));
-    assertTrue(message.getFieldBytes().getValue().toStringUtf8().equals("233"));
+    assertThat(message.getFieldDouble().getValue()).isEqualTo(2.333);
+    assertThat(message.getFieldFloat().getValue()).isEqualTo(2.333F);
+    assertThat(message.getFieldInt32().getValue()).isEqualTo(2333);
+    assertThat(message.getFieldInt64().getValue()).isEqualTo(23333333333333L);
+    assertThat(message.getFieldUint32().getValue()).isEqualTo(2333);
+    assertThat(message.getFieldUint64().getValue()).isEqualTo(23333333333333L);
+    assertThat(true).isSameInstanceAs(message.getFieldBool().getValue());
+    assertThat(message.getFieldString().getValue().equals("23333")).isTrue();
+    assertThat(message.getFieldBytes().getValue().toStringUtf8().equals("233")).isTrue();
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/WrappersOfMethodTest.java b/java/core/src/test/java/com/google/protobuf/WrappersOfMethodTest.java
index f0d662d..44c4ad6 100644
--- a/java/core/src/test/java/com/google/protobuf/WrappersOfMethodTest.java
+++ b/java/core/src/test/java/com/google/protobuf/WrappersOfMethodTest.java
@@ -30,11 +30,17 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.protobuf.wrapperstest.WrappersTestProto.TopLevelMessage;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class WrappersOfMethodTest extends TestCase {
+@RunWith(JUnit4.class)
+public class WrappersOfMethodTest {
 
+  @Test
   public void testOf() throws Exception {
     TopLevelMessage.Builder builder = TopLevelMessage.newBuilder();
     builder.setFieldDouble(DoubleValue.of(2.333));
@@ -48,14 +54,14 @@
     builder.setFieldBytes(BytesValue.of(ByteString.wrap("233".getBytes(Internal.UTF_8))));
 
     TopLevelMessage message = builder.build();
-    assertTrue(2.333 == message.getFieldDouble().getValue());
-    assertTrue(2.333f == message.getFieldFloat().getValue());
-    assertTrue(2333 == message.getFieldInt32().getValue());
-    assertTrue(23333333333333L == message.getFieldInt64().getValue());
-    assertTrue(2333 == message.getFieldUint32().getValue());
-    assertTrue(23333333333333L == message.getFieldUint64().getValue());
-    assertTrue(true == message.getFieldBool().getValue());
-    assertTrue(message.getFieldString().getValue().equals("23333"));
-    assertTrue(message.getFieldBytes().getValue().toStringUtf8().equals("233"));
+    assertThat(message.getFieldDouble().getValue()).isEqualTo(2.333);
+    assertThat(message.getFieldFloat().getValue()).isEqualTo(2.333F);
+    assertThat(message.getFieldInt32().getValue()).isEqualTo(2333);
+    assertThat(message.getFieldInt64().getValue()).isEqualTo(23333333333333L);
+    assertThat(message.getFieldUint32().getValue()).isEqualTo(2333);
+    assertThat(message.getFieldUint64().getValue()).isEqualTo(23333333333333L);
+    assertThat(true).isSameInstanceAs(message.getFieldBool().getValue());
+    assertThat(message.getFieldString().getValue().equals("23333")).isTrue();
+    assertThat(message.getFieldBytes().getValue().toStringUtf8().equals("233")).isTrue();
   }
 }
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/ByteStrings.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/ByteStrings.kt
new file mode 100644
index 0000000..3befb3b
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/ByteStrings.kt
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.kotlin
+
+import com.google.protobuf.ByteString
+import java.nio.ByteBuffer
+
+/** Encodes this String into a sequence of UTF-8 bytes and returns the result as a [ByteString]. */
+fun String.toByteStringUtf8(): ByteString = ByteString.copyFromUtf8(this)
+// symmetric from ByteString.toStringUtf8()
+
+/** Concatenates the given [ByteString] to this one. */
+operator fun ByteString.plus(other: ByteString): ByteString = concat(other)
+
+/** Gets the byte at [index]. */
+operator fun ByteString.get(index: Int): Byte = byteAt(index)
+
+/** Returns a copy of this [ByteArray] as an immutable [ByteString]. */
+fun ByteArray.toByteString(): ByteString = ByteString.copyFrom(this)
+
+/** Copies the remaining bytes from this [ByteBuffer] to a [ByteString]. */
+fun ByteBuffer.toByteString(): ByteString = ByteString.copyFrom(this)
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/ByteStringsTest.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/ByteStringsTest.kt
new file mode 100644
index 0000000..99c8c98
--- /dev/null
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/ByteStringsTest.kt
@@ -0,0 +1,97 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.ByteString
+import java.lang.IndexOutOfBoundsException
+import java.nio.ByteBuffer
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/** Tests for the extension functions in ByteStrings.kt. */
+@RunWith(JUnit4::class)
+class ByteStringsTest {
+  @Test
+  fun toByteStringUtf8() {
+    assertThat("abc".toByteStringUtf8())
+      .isEqualTo(ByteString.copyFrom("abc".toByteArray(Charsets.UTF_8)))
+  }
+
+  @Test
+  fun plus() {
+    assertThat("abc".toByteStringUtf8() + "def".toByteStringUtf8())
+      .isEqualTo(ByteString.copyFrom("abcdef".toByteArray(Charsets.UTF_8)))
+  }
+
+  @Test
+  fun byteAt() {
+    val str = "abc".toByteStringUtf8()
+    assertThat(str[0]).isEqualTo('a'.toByte())
+    assertThat(str[2]).isEqualTo('c'.toByte())
+  }
+
+  @Test
+  fun byteAtBelowZero() {
+    val str = "abc".toByteStringUtf8()
+    assertFailsWith<IndexOutOfBoundsException> { str[-1] }
+    assertFailsWith<IndexOutOfBoundsException> { str[-2] }
+  }
+
+  @Test
+  fun byteAtAboveLength() {
+    val str = "abc".toByteStringUtf8()
+    assertFailsWith<IndexOutOfBoundsException> { str[3] }
+    assertFailsWith<IndexOutOfBoundsException> { str[4] }
+  }
+
+  @Test
+  fun byteArrayToByteString() {
+    assertThat("abc".toByteArray(Charsets.UTF_8).toByteString())
+      .isEqualTo(ByteString.copyFromUtf8("abc"))
+  }
+
+  @Test
+  fun byteBufferToByteString() {
+    val buffer = ByteBuffer.wrap("abc".toByteArray(Charsets.UTF_8))
+    assertThat(buffer.toByteString()).isEqualTo(ByteString.copyFromUtf8("abc"))
+  }
+
+  @Test
+  fun byteBufferToByteStringRespectsPositionAndLimit() {
+    val buffer = ByteBuffer.wrap("abc".toByteArray(Charsets.UTF_8))
+    buffer.position(1)
+    buffer.limit(2)
+    assertThat(buffer.toByteString()).isEqualTo(ByteString.copyFromUtf8("b"))
+  }
+}
diff --git a/java/lite/src/test/java/com/google/protobuf/LiteTest.java b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
index f2ce461..7cbc764 100644
--- a/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
@@ -30,7 +30,8 @@
 
 package com.google.protobuf;
 
-import static java.util.Collections.emptyList;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static java.util.Collections.singletonList;
 
 import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
@@ -70,15 +71,16 @@
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-/**
- * Test lite runtime.
- *
- * @author [email protected] Kenton Varda
- */
-public class LiteTest extends TestCase {
-  @Override
+/** Test lite runtime. */
+@RunWith(JUnit4.class)
+public class LiteTest {
+
+  @Before
   public void setUp() throws Exception {
     // Test that nested extensions are initialized correctly even if the outer
     // class has not been accessed directly.  This was once a bug with lite
@@ -86,9 +88,10 @@
     //
     // We put this in setUp() rather than in its own test method because we
     // need to make sure it runs before any actual tests.
-    assertNotNull(TestNestedExtensionLite.nestedExtension);
+    assertThat(TestNestedExtensionLite.nestedExtension).isNotNull();
   }
 
+  @Test
   public void testLite() throws Exception {
     // Since lite messages are a subset of regular messages, we can mostly
     // assume that the functionality of lite messages is already thoroughly
@@ -109,12 +112,13 @@
 
     TestAllTypesLite message2 = TestAllTypesLite.parseFrom(data);
 
-    assertEquals(123, message2.getOptionalInt32());
-    assertEquals(1, message2.getRepeatedStringCount());
-    assertEquals("hello", message2.getRepeatedString(0));
-    assertEquals(7, message2.getOptionalNestedMessage().getBb());
+    assertThat(message2.getOptionalInt32()).isEqualTo(123);
+    assertThat(message2.getRepeatedStringCount()).isEqualTo(1);
+    assertThat(message2.getRepeatedString(0)).isEqualTo("hello");
+    assertThat(message2.getOptionalNestedMessage().getBb()).isEqualTo(7);
   }
 
+  @Test
   public void testLite_unknownEnumAtListBoundary() throws Exception {
     ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
     CodedOutputStream output = CodedOutputStream.newInstance(byteStream);
@@ -129,6 +133,7 @@
     TestAllTypesLite.parseFrom(new ByteArrayInputStream(byteStream.toByteArray()));
   }
 
+  @Test
   public void testLiteExtensions() throws Exception {
     // TODO(kenton):  Unlike other features of the lite library, extensions are
     //   implemented completely differently from the regular library.  We
@@ -149,61 +154,66 @@
     // writing, parsing hasn't been implemented yet.
     TestAllExtensionsLite message2 = message.toBuilder().build();
 
-    assertEquals(123, (int) message2.getExtension(UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(1, message2.getExtensionCount(UnittestLite.repeatedStringExtensionLite));
-    assertEquals(1, message2.getExtension(UnittestLite.repeatedStringExtensionLite).size());
-    assertEquals("hello", message2.getExtension(UnittestLite.repeatedStringExtensionLite, 0));
-    assertEquals(
-        NestedEnum.BAZ, message2.getExtension(UnittestLite.optionalNestedEnumExtensionLite));
-    assertEquals(7, message2.getExtension(UnittestLite.optionalNestedMessageExtensionLite).getBb());
+    assertThat((int) message2.getExtension(UnittestLite.optionalInt32ExtensionLite)).isEqualTo(123);
+    assertThat(message2.getExtensionCount(UnittestLite.repeatedStringExtensionLite)).isEqualTo(1);
+    assertThat(message2.getExtension(UnittestLite.repeatedStringExtensionLite)).hasSize(1);
+    assertThat(message2.getExtension(UnittestLite.repeatedStringExtensionLite, 0))
+        .isEqualTo("hello");
+    assertThat(message2.getExtension(UnittestLite.optionalNestedEnumExtensionLite))
+        .isEqualTo(NestedEnum.BAZ);
+    assertThat(message2.getExtension(UnittestLite.optionalNestedMessageExtensionLite).getBb())
+        .isEqualTo(7);
   }
 
+  @Test
   public void testClone() {
     TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder().setOptionalInt32(123);
-    assertEquals(expected.getOptionalInt32(), expected.clone().getOptionalInt32());
+    assertThat(expected.getOptionalInt32()).isEqualTo(expected.clone().getOptionalInt32());
 
     TestAllExtensionsLite.Builder expected2 =
         TestAllExtensionsLite.newBuilder()
             .setExtension(UnittestLite.optionalInt32ExtensionLite, 123);
-    assertEquals(
-        expected2.getExtension(UnittestLite.optionalInt32ExtensionLite),
-        expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertThat(expected2.getExtension(UnittestLite.optionalInt32ExtensionLite))
+        .isEqualTo(expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite));
   }
 
+  @Test
   public void testAddAll() {
     try {
       TestAllTypesLite.newBuilder().addAllRepeatedBytes(null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // expected.
     }
   }
 
+  @Test
   public void testMemoization() throws Exception {
     TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet();
 
     // Test serialized size is memoized
     message.memoizedSerializedSize = -1;
     int size = message.getSerializedSize();
-    assertTrue(size > 0);
-    assertEquals(size, message.memoizedSerializedSize);
+    assertThat(size).isGreaterThan(0);
+    assertThat(message.memoizedSerializedSize).isEqualTo(size);
 
     // Test hashCode is memoized
-    assertEquals(0, message.memoizedHashCode);
+    assertThat(message.memoizedHashCode).isEqualTo(0);
     int hashCode = message.hashCode();
-    assertTrue(hashCode != 0);
-    assertEquals(hashCode, message.memoizedHashCode);
+    assertThat(hashCode).isNotEqualTo(0);
+    assertThat(hashCode).isEqualTo(message.memoizedHashCode);
 
     // Test isInitialized is memoized
     Field memo = message.getClass().getDeclaredField("memoizedIsInitialized");
     memo.setAccessible(true);
     memo.set(message, (byte) -1);
     boolean initialized = message.isInitialized();
-    assertTrue(initialized);
+    assertThat(initialized).isTrue();
     // We have to cast to Byte first. Casting to byte causes a type error
-    assertEquals(1, ((Byte) memo.get(message)).intValue());
+    assertThat(((Byte) memo.get(message)).intValue()).isEqualTo(1);
   }
 
+  @Test
   public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
     // Since builders are implemented as a thin wrapper around a message
     // instance, we attempt to verify that we can't cause the builder to modify
@@ -213,1093 +223,1107 @@
     TestAllTypesLite message = builder.build();
     TestAllTypesLite messageAfterBuild;
     builder.setOptionalBool(true);
-    assertEquals(false, message.getOptionalBool());
-    assertEquals(true, builder.getOptionalBool());
+    assertThat(message.getOptionalBool()).isFalse();
+    assertThat(builder.getOptionalBool()).isTrue();
     messageAfterBuild = builder.build();
-    assertEquals(true, messageAfterBuild.getOptionalBool());
-    assertEquals(false, message.getOptionalBool());
+    assertThat(messageAfterBuild.getOptionalBool()).isTrue();
+    assertThat(message.getOptionalBool()).isFalse();
     builder.clearOptionalBool();
-    assertEquals(false, builder.getOptionalBool());
-    assertEquals(true, messageAfterBuild.getOptionalBool());
+    assertThat(builder.getOptionalBool()).isFalse();
+    assertThat(messageAfterBuild.getOptionalBool()).isTrue();
 
     message = builder.build();
     builder.setOptionalBytes(ByteString.copyFromUtf8("hi"));
-    assertEquals(ByteString.EMPTY, message.getOptionalBytes());
-    assertEquals(ByteString.copyFromUtf8("hi"), builder.getOptionalBytes());
+    assertThat(message.getOptionalBytes()).isEqualTo(ByteString.EMPTY);
+    assertThat(builder.getOptionalBytes()).isEqualTo(ByteString.copyFromUtf8("hi"));
     messageAfterBuild = builder.build();
-    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
-    assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+    assertThat(messageAfterBuild.getOptionalBytes()).isEqualTo(ByteString.copyFromUtf8("hi"));
+    assertThat(message.getOptionalBytes()).isEqualTo(ByteString.EMPTY);
     builder.clearOptionalBytes();
-    assertEquals(ByteString.EMPTY, builder.getOptionalBytes());
-    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
+    assertThat(builder.getOptionalBytes()).isEqualTo(ByteString.EMPTY);
+    assertThat(messageAfterBuild.getOptionalBytes()).isEqualTo(ByteString.copyFromUtf8("hi"));
 
     message = builder.build();
     builder.setOptionalCord("hi");
-    assertEquals("", message.getOptionalCord());
-    assertEquals("hi", builder.getOptionalCord());
+    assertThat(message.getOptionalCord()).isEmpty();
+    assertThat(builder.getOptionalCord()).isEqualTo("hi");
     messageAfterBuild = builder.build();
-    assertEquals("hi", messageAfterBuild.getOptionalCord());
-    assertEquals("", message.getOptionalCord());
+    assertThat(messageAfterBuild.getOptionalCord()).isEqualTo("hi");
+    assertThat(message.getOptionalCord()).isEmpty();
     builder.clearOptionalCord();
-    assertEquals("", builder.getOptionalCord());
-    assertEquals("hi", messageAfterBuild.getOptionalCord());
+    assertThat(builder.getOptionalCord()).isEmpty();
+    assertThat(messageAfterBuild.getOptionalCord()).isEqualTo("hi");
 
     message = builder.build();
     builder.setOptionalCordBytes(ByteString.copyFromUtf8("no"));
-    assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
-    assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalCordBytes());
+    assertThat(message.getOptionalCordBytes()).isEqualTo(ByteString.EMPTY);
+    assertThat(builder.getOptionalCordBytes()).isEqualTo(ByteString.copyFromUtf8("no"));
     messageAfterBuild = builder.build();
-    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalCordBytes());
-    assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
+    assertThat(messageAfterBuild.getOptionalCordBytes()).isEqualTo(ByteString.copyFromUtf8("no"));
+    assertThat(message.getOptionalCordBytes()).isEqualTo(ByteString.EMPTY);
     builder.clearOptionalCord();
-    assertEquals(ByteString.EMPTY, builder.getOptionalCordBytes());
-    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalCordBytes());
+    assertThat(builder.getOptionalCordBytes()).isEqualTo(ByteString.EMPTY);
+    assertThat(messageAfterBuild.getOptionalCordBytes()).isEqualTo(ByteString.copyFromUtf8("no"));
 
     message = builder.build();
     builder.setOptionalDouble(1);
-    assertEquals(0D, message.getOptionalDouble(), 0.0);
-    assertEquals(1D, builder.getOptionalDouble(), 0.0);
+    assertThat(message.getOptionalDouble()).isEqualTo(0D);
+    assertThat(builder.getOptionalDouble()).isEqualTo(1D);
     messageAfterBuild = builder.build();
-    assertEquals(1D, messageAfterBuild.getOptionalDouble(), 0.0);
-    assertEquals(0D, message.getOptionalDouble(), 0.0);
+    assertThat(messageAfterBuild.getOptionalDouble()).isEqualTo(1D);
+    assertThat(message.getOptionalDouble()).isEqualTo(0D);
     builder.clearOptionalDouble();
-    assertEquals(0D, builder.getOptionalDouble(), 0.0);
-    assertEquals(1D, messageAfterBuild.getOptionalDouble(), 0.0);
+    assertThat(builder.getOptionalDouble()).isEqualTo(0D);
+    assertThat(messageAfterBuild.getOptionalDouble()).isEqualTo(1D);
 
     message = builder.build();
     builder.setOptionalFixed32(1);
-    assertEquals(0, message.getOptionalFixed32());
-    assertEquals(1, builder.getOptionalFixed32());
+    assertThat(message.getOptionalFixed32()).isEqualTo(0);
+    assertThat(builder.getOptionalFixed32()).isEqualTo(1);
     messageAfterBuild = builder.build();
-    assertEquals(1, messageAfterBuild.getOptionalFixed32());
-    assertEquals(0, message.getOptionalFixed32());
+    assertThat(messageAfterBuild.getOptionalFixed32()).isEqualTo(1);
+    assertThat(message.getOptionalFixed32()).isEqualTo(0);
     builder.clearOptionalFixed32();
-    assertEquals(0, builder.getOptionalFixed32());
-    assertEquals(1, messageAfterBuild.getOptionalFixed32());
+    assertThat(builder.getOptionalFixed32()).isEqualTo(0);
+    assertThat(messageAfterBuild.getOptionalFixed32()).isEqualTo(1);
 
     message = builder.build();
     builder.setOptionalFixed64(1);
-    assertEquals(0L, message.getOptionalFixed64());
-    assertEquals(1L, builder.getOptionalFixed64());
+    assertThat(message.getOptionalFixed64()).isEqualTo(0L);
+    assertThat(builder.getOptionalFixed64()).isEqualTo(1L);
     messageAfterBuild = builder.build();
-    assertEquals(1L, messageAfterBuild.getOptionalFixed64());
-    assertEquals(0L, message.getOptionalFixed64());
+    assertThat(messageAfterBuild.getOptionalFixed64()).isEqualTo(1L);
+    assertThat(message.getOptionalFixed64()).isEqualTo(0L);
     builder.clearOptionalFixed64();
-    assertEquals(0L, builder.getOptionalFixed64());
-    assertEquals(1L, messageAfterBuild.getOptionalFixed64());
+    assertThat(builder.getOptionalFixed64()).isEqualTo(0L);
+    assertThat(messageAfterBuild.getOptionalFixed64()).isEqualTo(1L);
 
     message = builder.build();
     builder.setOptionalFloat(1);
-    assertEquals(0F, message.getOptionalFloat(), 0.0f);
-    assertEquals(1F, builder.getOptionalFloat(), 0.0f);
+    assertThat(message.getOptionalFloat()).isEqualTo(0F);
+    assertThat(builder.getOptionalFloat()).isEqualTo(1F);
     messageAfterBuild = builder.build();
-    assertEquals(1F, messageAfterBuild.getOptionalFloat(), 0.0f);
-    assertEquals(0F, message.getOptionalFloat(), 0.0f);
+    assertThat(messageAfterBuild.getOptionalFloat()).isEqualTo(1F);
+    assertThat(message.getOptionalFloat()).isEqualTo(0F);
     builder.clearOptionalFloat();
-    assertEquals(0F, builder.getOptionalFloat(), 0.0f);
-    assertEquals(1F, messageAfterBuild.getOptionalFloat(), 0.0f);
+    assertThat(builder.getOptionalFloat()).isEqualTo(0F);
+    assertThat(messageAfterBuild.getOptionalFloat()).isEqualTo(1F);
 
     message = builder.build();
     builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, builder.getOptionalForeignEnum());
+    assertThat(message.getOptionalForeignEnum()).isEqualTo(ForeignEnumLite.FOREIGN_LITE_FOO);
+    assertThat(builder.getOptionalForeignEnum()).isEqualTo(ForeignEnumLite.FOREIGN_LITE_BAR);
     messageAfterBuild = builder.build();
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, messageAfterBuild.getOptionalForeignEnum());
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
+    assertThat(messageAfterBuild.getOptionalForeignEnum())
+        .isEqualTo(ForeignEnumLite.FOREIGN_LITE_BAR);
+    assertThat(message.getOptionalForeignEnum()).isEqualTo(ForeignEnumLite.FOREIGN_LITE_FOO);
     builder.clearOptionalForeignEnum();
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, builder.getOptionalForeignEnum());
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, messageAfterBuild.getOptionalForeignEnum());
+    assertThat(builder.getOptionalForeignEnum()).isEqualTo(ForeignEnumLite.FOREIGN_LITE_FOO);
+    assertThat(messageAfterBuild.getOptionalForeignEnum())
+        .isEqualTo(ForeignEnumLite.FOREIGN_LITE_BAR);
 
     message = builder.build();
     ForeignMessageLite foreignMessage = ForeignMessageLite.newBuilder().setC(1).build();
     builder.setOptionalForeignMessage(foreignMessage);
-    assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
-    assertEquals(foreignMessage, builder.getOptionalForeignMessage());
+    assertThat(message.getOptionalForeignMessage())
+        .isEqualTo(ForeignMessageLite.getDefaultInstance());
+    assertThat(builder.getOptionalForeignMessage()).isEqualTo(foreignMessage);
     messageAfterBuild = builder.build();
-    assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
-    assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
+    assertThat(messageAfterBuild.getOptionalForeignMessage()).isEqualTo(foreignMessage);
+    assertThat(message.getOptionalForeignMessage())
+        .isEqualTo(ForeignMessageLite.getDefaultInstance());
     builder.clearOptionalForeignMessage();
-    assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage());
-    assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
+    assertThat(builder.getOptionalForeignMessage())
+        .isEqualTo(ForeignMessageLite.getDefaultInstance());
+    assertThat(messageAfterBuild.getOptionalForeignMessage()).isEqualTo(foreignMessage);
 
     message = builder.build();
     ForeignMessageLite foreignMessageC3 = ForeignMessageLite.newBuilder().setC(3).build();
     builder.setOptionalForeignMessage(foreignMessageC3);
-    assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
-    assertEquals(foreignMessageC3, builder.getOptionalForeignMessage());
+    assertThat(message.getOptionalForeignMessage())
+        .isEqualTo(ForeignMessageLite.getDefaultInstance());
+    assertThat(builder.getOptionalForeignMessage()).isEqualTo(foreignMessageC3);
     messageAfterBuild = builder.build();
-    assertEquals(foreignMessageC3, messageAfterBuild.getOptionalForeignMessage());
-    assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
+    assertThat(messageAfterBuild.getOptionalForeignMessage()).isEqualTo(foreignMessageC3);
+    assertThat(message.getOptionalForeignMessage())
+        .isEqualTo(ForeignMessageLite.getDefaultInstance());
     builder.clearOptionalForeignMessage();
-    assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage());
-    assertEquals(foreignMessageC3, messageAfterBuild.getOptionalForeignMessage());
+    assertThat(builder.getOptionalForeignMessage())
+        .isEqualTo(ForeignMessageLite.getDefaultInstance());
+    assertThat(messageAfterBuild.getOptionalForeignMessage()).isEqualTo(foreignMessageC3);
 
     message = builder.build();
     OptionalGroup optionalGroup = OptionalGroup.newBuilder().setA(1).build();
     builder.setOptionalGroup(optionalGroup);
-    assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
-    assertEquals(optionalGroup, builder.getOptionalGroup());
+    assertThat(message.getOptionalGroup()).isEqualTo(OptionalGroup.getDefaultInstance());
+    assertThat(builder.getOptionalGroup()).isEqualTo(optionalGroup);
     messageAfterBuild = builder.build();
-    assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
-    assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    assertThat(messageAfterBuild.getOptionalGroup()).isEqualTo(optionalGroup);
+    assertThat(message.getOptionalGroup()).isEqualTo(OptionalGroup.getDefaultInstance());
     builder.clearOptionalGroup();
-    assertEquals(OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
-    assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
+    assertThat(builder.getOptionalGroup()).isEqualTo(OptionalGroup.getDefaultInstance());
+    assertThat(messageAfterBuild.getOptionalGroup()).isEqualTo(optionalGroup);
 
     message = builder.build();
     OptionalGroup.Builder optionalGroupBuilder = OptionalGroup.newBuilder().setA(3);
     builder.setOptionalGroup(optionalGroupBuilder);
-    assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
-    assertEquals(optionalGroupBuilder.build(), builder.getOptionalGroup());
+    assertThat(message.getOptionalGroup()).isEqualTo(OptionalGroup.getDefaultInstance());
+    assertThat(builder.getOptionalGroup()).isEqualTo(optionalGroupBuilder.build());
     messageAfterBuild = builder.build();
-    assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
-    assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    assertThat(messageAfterBuild.getOptionalGroup()).isEqualTo(optionalGroupBuilder.build());
+    assertThat(message.getOptionalGroup()).isEqualTo(OptionalGroup.getDefaultInstance());
     builder.clearOptionalGroup();
-    assertEquals(OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
-    assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
+    assertThat(builder.getOptionalGroup()).isEqualTo(OptionalGroup.getDefaultInstance());
+    assertThat(messageAfterBuild.getOptionalGroup()).isEqualTo(optionalGroupBuilder.build());
 
     message = builder.build();
     builder.setOptionalInt32(1);
-    assertEquals(0, message.getOptionalInt32());
-    assertEquals(1, builder.getOptionalInt32());
+    assertThat(message.getOptionalInt32()).isEqualTo(0);
+    assertThat(builder.getOptionalInt32()).isEqualTo(1);
     messageAfterBuild = builder.build();
-    assertEquals(1, messageAfterBuild.getOptionalInt32());
-    assertEquals(0, message.getOptionalInt32());
+    assertThat(messageAfterBuild.getOptionalInt32()).isEqualTo(1);
+    assertThat(message.getOptionalInt32()).isEqualTo(0);
     builder.clearOptionalInt32();
-    assertEquals(0, builder.getOptionalInt32());
-    assertEquals(1, messageAfterBuild.getOptionalInt32());
+    assertThat(builder.getOptionalInt32()).isEqualTo(0);
+    assertThat(messageAfterBuild.getOptionalInt32()).isEqualTo(1);
 
     message = builder.build();
     builder.setOptionalInt64(1);
-    assertEquals(0L, message.getOptionalInt64());
-    assertEquals(1L, builder.getOptionalInt64());
+    assertThat(message.getOptionalInt64()).isEqualTo(0L);
+    assertThat(builder.getOptionalInt64()).isEqualTo(1L);
     messageAfterBuild = builder.build();
-    assertEquals(1L, messageAfterBuild.getOptionalInt64());
-    assertEquals(0L, message.getOptionalInt64());
+    assertThat(messageAfterBuild.getOptionalInt64()).isEqualTo(1L);
+    assertThat(message.getOptionalInt64()).isEqualTo(0L);
     builder.clearOptionalInt64();
-    assertEquals(0L, builder.getOptionalInt64());
-    assertEquals(1L, messageAfterBuild.getOptionalInt64());
+    assertThat(builder.getOptionalInt64()).isEqualTo(0L);
+    assertThat(messageAfterBuild.getOptionalInt64()).isEqualTo(1L);
 
     message = builder.build();
     NestedMessage nestedMessage = NestedMessage.newBuilder().setBb(1).build();
     builder.setOptionalLazyMessage(nestedMessage);
-    assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
-    assertEquals(nestedMessage, builder.getOptionalLazyMessage());
+    assertThat(message.getOptionalLazyMessage()).isEqualTo(NestedMessage.getDefaultInstance());
+    assertThat(builder.getOptionalLazyMessage()).isEqualTo(nestedMessage);
     messageAfterBuild = builder.build();
-    assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
-    assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
+    assertThat(messageAfterBuild.getOptionalLazyMessage()).isEqualTo(nestedMessage);
+    assertThat(message.getOptionalLazyMessage()).isEqualTo(NestedMessage.getDefaultInstance());
     builder.clearOptionalLazyMessage();
-    assertEquals(NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
-    assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
+    assertThat(builder.getOptionalLazyMessage()).isEqualTo(NestedMessage.getDefaultInstance());
+    assertThat(messageAfterBuild.getOptionalLazyMessage()).isEqualTo(nestedMessage);
 
     message = builder.build();
     NestedMessage.Builder nestedMessageBuilder = NestedMessage.newBuilder().setBb(3);
     builder.setOptionalLazyMessage(nestedMessageBuilder);
-    assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
-    assertEquals(nestedMessageBuilder.build(), builder.getOptionalLazyMessage());
+    assertThat(message.getOptionalLazyMessage()).isEqualTo(NestedMessage.getDefaultInstance());
+    assertThat(builder.getOptionalLazyMessage()).isEqualTo(nestedMessageBuilder.build());
     messageAfterBuild = builder.build();
-    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
-    assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
+    assertThat(messageAfterBuild.getOptionalLazyMessage()).isEqualTo(nestedMessageBuilder.build());
+    assertThat(message.getOptionalLazyMessage()).isEqualTo(NestedMessage.getDefaultInstance());
     builder.clearOptionalLazyMessage();
-    assertEquals(NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
-    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
+    assertThat(builder.getOptionalLazyMessage()).isEqualTo(NestedMessage.getDefaultInstance());
+    assertThat(messageAfterBuild.getOptionalLazyMessage()).isEqualTo(nestedMessageBuilder.build());
 
     message = builder.build();
     builder.setOptionalSfixed32(1);
-    assertEquals(0, message.getOptionalSfixed32());
-    assertEquals(1, builder.getOptionalSfixed32());
+    assertThat(message.getOptionalSfixed32()).isEqualTo(0);
+    assertThat(builder.getOptionalSfixed32()).isEqualTo(1);
     messageAfterBuild = builder.build();
-    assertEquals(1, messageAfterBuild.getOptionalSfixed32());
-    assertEquals(0, message.getOptionalSfixed32());
+    assertThat(messageAfterBuild.getOptionalSfixed32()).isEqualTo(1);
+    assertThat(message.getOptionalSfixed32()).isEqualTo(0);
     builder.clearOptionalSfixed32();
-    assertEquals(0, builder.getOptionalSfixed32());
-    assertEquals(1, messageAfterBuild.getOptionalSfixed32());
+    assertThat(builder.getOptionalSfixed32()).isEqualTo(0);
+    assertThat(messageAfterBuild.getOptionalSfixed32()).isEqualTo(1);
 
     message = builder.build();
     builder.setOptionalSfixed64(1);
-    assertEquals(0L, message.getOptionalSfixed64());
-    assertEquals(1L, builder.getOptionalSfixed64());
+    assertThat(message.getOptionalSfixed64()).isEqualTo(0L);
+    assertThat(builder.getOptionalSfixed64()).isEqualTo(1L);
     messageAfterBuild = builder.build();
-    assertEquals(1L, messageAfterBuild.getOptionalSfixed64());
-    assertEquals(0L, message.getOptionalSfixed64());
+    assertThat(messageAfterBuild.getOptionalSfixed64()).isEqualTo(1L);
+    assertThat(message.getOptionalSfixed64()).isEqualTo(0L);
     builder.clearOptionalSfixed64();
-    assertEquals(0L, builder.getOptionalSfixed64());
-    assertEquals(1L, messageAfterBuild.getOptionalSfixed64());
+    assertThat(builder.getOptionalSfixed64()).isEqualTo(0L);
+    assertThat(messageAfterBuild.getOptionalSfixed64()).isEqualTo(1L);
 
     message = builder.build();
     builder.setOptionalSint32(1);
-    assertEquals(0, message.getOptionalSint32());
-    assertEquals(1, builder.getOptionalSint32());
+    assertThat(message.getOptionalSint32()).isEqualTo(0);
+    assertThat(builder.getOptionalSint32()).isEqualTo(1);
     messageAfterBuild = builder.build();
-    assertEquals(1, messageAfterBuild.getOptionalSint32());
+    assertThat(messageAfterBuild.getOptionalSint32()).isEqualTo(1);
     builder.clearOptionalSint32();
-    assertEquals(0, builder.getOptionalSint32());
-    assertEquals(1, messageAfterBuild.getOptionalSint32());
+    assertThat(builder.getOptionalSint32()).isEqualTo(0);
+    assertThat(messageAfterBuild.getOptionalSint32()).isEqualTo(1);
 
     message = builder.build();
     builder.setOptionalSint64(1);
-    assertEquals(0L, message.getOptionalSint64());
-    assertEquals(1L, builder.getOptionalSint64());
+    assertThat(message.getOptionalSint64()).isEqualTo(0L);
+    assertThat(builder.getOptionalSint64()).isEqualTo(1L);
     messageAfterBuild = builder.build();
-    assertEquals(1L, messageAfterBuild.getOptionalSint64());
-    assertEquals(0L, message.getOptionalSint64());
+    assertThat(messageAfterBuild.getOptionalSint64()).isEqualTo(1L);
+    assertThat(message.getOptionalSint64()).isEqualTo(0L);
     builder.clearOptionalSint64();
-    assertEquals(0L, builder.getOptionalSint64());
-    assertEquals(1L, messageAfterBuild.getOptionalSint64());
+    assertThat(builder.getOptionalSint64()).isEqualTo(0L);
+    assertThat(messageAfterBuild.getOptionalSint64()).isEqualTo(1L);
 
     message = builder.build();
     builder.setOptionalString("hi");
-    assertEquals("", message.getOptionalString());
-    assertEquals("hi", builder.getOptionalString());
+    assertThat(message.getOptionalString()).isEmpty();
+    assertThat(builder.getOptionalString()).isEqualTo("hi");
     messageAfterBuild = builder.build();
-    assertEquals("hi", messageAfterBuild.getOptionalString());
-    assertEquals("", message.getOptionalString());
+    assertThat(messageAfterBuild.getOptionalString()).isEqualTo("hi");
+    assertThat(message.getOptionalString()).isEmpty();
     builder.clearOptionalString();
-    assertEquals("", builder.getOptionalString());
-    assertEquals("hi", messageAfterBuild.getOptionalString());
+    assertThat(builder.getOptionalString()).isEmpty();
+    assertThat(messageAfterBuild.getOptionalString()).isEqualTo("hi");
 
     message = builder.build();
     builder.setOptionalStringBytes(ByteString.copyFromUtf8("no"));
-    assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
-    assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalStringBytes());
+    assertThat(message.getOptionalStringBytes()).isEqualTo(ByteString.EMPTY);
+    assertThat(builder.getOptionalStringBytes()).isEqualTo(ByteString.copyFromUtf8("no"));
     messageAfterBuild = builder.build();
-    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringBytes());
-    assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
+    assertThat(messageAfterBuild.getOptionalStringBytes()).isEqualTo(ByteString.copyFromUtf8("no"));
+    assertThat(message.getOptionalStringBytes()).isEqualTo(ByteString.EMPTY);
     builder.clearOptionalString();
-    assertEquals(ByteString.EMPTY, builder.getOptionalStringBytes());
-    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringBytes());
+    assertThat(builder.getOptionalStringBytes()).isEqualTo(ByteString.EMPTY);
+    assertThat(messageAfterBuild.getOptionalStringBytes()).isEqualTo(ByteString.copyFromUtf8("no"));
 
     message = builder.build();
     builder.setOptionalStringPiece("hi");
-    assertEquals("", message.getOptionalStringPiece());
-    assertEquals("hi", builder.getOptionalStringPiece());
+    assertThat(message.getOptionalStringPiece()).isEmpty();
+    assertThat(builder.getOptionalStringPiece()).isEqualTo("hi");
     messageAfterBuild = builder.build();
-    assertEquals("hi", messageAfterBuild.getOptionalStringPiece());
-    assertEquals("", message.getOptionalStringPiece());
+    assertThat(messageAfterBuild.getOptionalStringPiece()).isEqualTo("hi");
+    assertThat(message.getOptionalStringPiece()).isEmpty();
     builder.clearOptionalStringPiece();
-    assertEquals("", builder.getOptionalStringPiece());
-    assertEquals("hi", messageAfterBuild.getOptionalStringPiece());
+    assertThat(builder.getOptionalStringPiece()).isEmpty();
+    assertThat(messageAfterBuild.getOptionalStringPiece()).isEqualTo("hi");
 
     message = builder.build();
     builder.setOptionalStringPieceBytes(ByteString.copyFromUtf8("no"));
-    assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
-    assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalStringPieceBytes());
+    assertThat(message.getOptionalStringPieceBytes()).isEqualTo(ByteString.EMPTY);
+    assertThat(builder.getOptionalStringPieceBytes()).isEqualTo(ByteString.copyFromUtf8("no"));
     messageAfterBuild = builder.build();
-    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringPieceBytes());
-    assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
+    assertThat(messageAfterBuild.getOptionalStringPieceBytes())
+        .isEqualTo(ByteString.copyFromUtf8("no"));
+    assertThat(message.getOptionalStringPieceBytes()).isEqualTo(ByteString.EMPTY);
     builder.clearOptionalStringPiece();
-    assertEquals(ByteString.EMPTY, builder.getOptionalStringPieceBytes());
-    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringPieceBytes());
+    assertThat(builder.getOptionalStringPieceBytes()).isEqualTo(ByteString.EMPTY);
+    assertThat(messageAfterBuild.getOptionalStringPieceBytes())
+        .isEqualTo(ByteString.copyFromUtf8("no"));
 
     message = builder.build();
     builder.setOptionalUint32(1);
-    assertEquals(0, message.getOptionalUint32());
-    assertEquals(1, builder.getOptionalUint32());
+    assertThat(message.getOptionalUint32()).isEqualTo(0);
+    assertThat(builder.getOptionalUint32()).isEqualTo(1);
     messageAfterBuild = builder.build();
-    assertEquals(1, messageAfterBuild.getOptionalUint32());
-    assertEquals(0, message.getOptionalUint32());
+    assertThat(messageAfterBuild.getOptionalUint32()).isEqualTo(1);
+    assertThat(message.getOptionalUint32()).isEqualTo(0);
     builder.clearOptionalUint32();
-    assertEquals(0, builder.getOptionalUint32());
-    assertEquals(1, messageAfterBuild.getOptionalUint32());
+    assertThat(builder.getOptionalUint32()).isEqualTo(0);
+    assertThat(messageAfterBuild.getOptionalUint32()).isEqualTo(1);
 
     message = builder.build();
     builder.setOptionalUint64(1);
-    assertEquals(0L, message.getOptionalUint64());
-    assertEquals(1L, builder.getOptionalUint64());
+    assertThat(message.getOptionalUint64()).isEqualTo(0L);
+    assertThat(builder.getOptionalUint64()).isEqualTo(1L);
     messageAfterBuild = builder.build();
-    assertEquals(1L, messageAfterBuild.getOptionalUint64());
-    assertEquals(0L, message.getOptionalUint64());
+    assertThat(messageAfterBuild.getOptionalUint64()).isEqualTo(1L);
+    assertThat(message.getOptionalUint64()).isEqualTo(0L);
     builder.clearOptionalUint64();
-    assertEquals(0L, builder.getOptionalUint64());
-    assertEquals(1L, messageAfterBuild.getOptionalUint64());
+    assertThat(builder.getOptionalUint64()).isEqualTo(0L);
+    assertThat(messageAfterBuild.getOptionalUint64()).isEqualTo(1L);
 
     message = builder.build();
     builder.addAllRepeatedBool(singletonList(true));
-    assertEquals(emptyList(), message.getRepeatedBoolList());
-    assertEquals(singletonList(true), builder.getRepeatedBoolList());
-    assertEquals(emptyList(), message.getRepeatedBoolList());
+    assertThat(message.getRepeatedBoolList()).isEmpty();
+    assertThat(builder.getRepeatedBoolList()).containsExactly(true);
+    assertThat(message.getRepeatedBoolList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedBool();
-    assertEquals(emptyList(), builder.getRepeatedBoolList());
-    assertEquals(singletonList(true), messageAfterBuild.getRepeatedBoolList());
+    assertThat(builder.getRepeatedBoolList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedBoolList()).containsExactly(true);
 
     message = builder.build();
     builder.addAllRepeatedBytes(singletonList(ByteString.copyFromUtf8("hi")));
-    assertEquals(emptyList(), message.getRepeatedBytesList());
-    assertEquals(singletonList(ByteString.copyFromUtf8("hi")), builder.getRepeatedBytesList());
-    assertEquals(emptyList(), message.getRepeatedBytesList());
+    assertThat(message.getRepeatedBytesList()).isEmpty();
+    assertThat(builder.getRepeatedBytesList()).containsExactly(ByteString.copyFromUtf8("hi"));
+    assertThat(message.getRepeatedBytesList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedBytes();
-    assertEquals(emptyList(), builder.getRepeatedBytesList());
-    assertEquals(
-        singletonList(ByteString.copyFromUtf8("hi")), messageAfterBuild.getRepeatedBytesList());
+    assertThat(builder.getRepeatedBytesList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedBytesList())
+        .containsExactly(ByteString.copyFromUtf8("hi"));
 
     message = builder.build();
     builder.addAllRepeatedCord(singletonList("hi"));
-    assertEquals(emptyList(), message.getRepeatedCordList());
-    assertEquals(singletonList("hi"), builder.getRepeatedCordList());
-    assertEquals(emptyList(), message.getRepeatedCordList());
+    assertThat(message.getRepeatedCordList()).isEmpty();
+    assertThat(builder.getRepeatedCordList()).containsExactly("hi");
+    assertThat(message.getRepeatedCordList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedCord();
-    assertEquals(emptyList(), builder.getRepeatedCordList());
-    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedCordList());
+    assertThat(builder.getRepeatedCordList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedCordList()).containsExactly("hi");
 
     message = builder.build();
     builder.addAllRepeatedDouble(singletonList(1D));
-    assertEquals(emptyList(), message.getRepeatedDoubleList());
-    assertEquals(singletonList(1D), builder.getRepeatedDoubleList());
-    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    assertThat(message.getRepeatedDoubleList()).isEmpty();
+    assertThat(builder.getRepeatedDoubleList()).containsExactly(1D);
+    assertThat(message.getRepeatedDoubleList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedDouble();
-    assertEquals(emptyList(), builder.getRepeatedDoubleList());
-    assertEquals(singletonList(1D), messageAfterBuild.getRepeatedDoubleList());
+    assertThat(builder.getRepeatedDoubleList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedDoubleList()).containsExactly(1D);
 
     message = builder.build();
     builder.addAllRepeatedFixed32(singletonList(1));
-    assertEquals(emptyList(), message.getRepeatedFixed32List());
-    assertEquals(singletonList(1), builder.getRepeatedFixed32List());
-    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    assertThat(message.getRepeatedFixed32List()).isEmpty();
+    assertThat(builder.getRepeatedFixed32List()).containsExactly(1);
+    assertThat(message.getRepeatedFixed32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedFixed32();
-    assertEquals(emptyList(), builder.getRepeatedFixed32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedFixed32List());
+    assertThat(builder.getRepeatedFixed32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedFixed32List()).containsExactly(1);
 
     message = builder.build();
     builder.addAllRepeatedFixed64(singletonList(1L));
-    assertEquals(emptyList(), message.getRepeatedFixed64List());
-    assertEquals(singletonList(1L), builder.getRepeatedFixed64List());
-    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    assertThat(message.getRepeatedFixed64List()).isEmpty();
+    assertThat(builder.getRepeatedFixed64List()).containsExactly(1L);
+    assertThat(message.getRepeatedFixed64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedFixed64();
-    assertEquals(emptyList(), builder.getRepeatedFixed64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedFixed64List());
+    assertThat(builder.getRepeatedFixed64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedFixed64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addAllRepeatedFloat(singletonList(1F));
-    assertEquals(emptyList(), message.getRepeatedFloatList());
-    assertEquals(singletonList(1F), builder.getRepeatedFloatList());
-    assertEquals(emptyList(), message.getRepeatedFloatList());
+    assertThat(message.getRepeatedFloatList()).isEmpty();
+    assertThat(builder.getRepeatedFloatList()).containsExactly(1F);
+    assertThat(message.getRepeatedFloatList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedFloat();
-    assertEquals(emptyList(), builder.getRepeatedFloatList());
-    assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList());
+    assertThat(builder.getRepeatedFloatList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedFloatList()).containsExactly(1F);
 
     message = builder.build();
     builder.addAllRepeatedForeignEnum(singletonList(ForeignEnumLite.FOREIGN_LITE_BAR));
-    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
-    assertEquals(
-        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), builder.getRepeatedForeignEnumList());
-    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    assertThat(message.getRepeatedForeignEnumList()).isEmpty();
+    assertThat(builder.getRepeatedForeignEnumList())
+        .containsExactly(ForeignEnumLite.FOREIGN_LITE_BAR);
+    assertThat(message.getRepeatedForeignEnumList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedForeignEnum();
-    assertEquals(emptyList(), builder.getRepeatedForeignEnumList());
-    assertEquals(
-        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
-        messageAfterBuild.getRepeatedForeignEnumList());
+    assertThat(builder.getRepeatedForeignEnumList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedForeignEnumList())
+        .containsExactly(ForeignEnumLite.FOREIGN_LITE_BAR);
 
     message = builder.build();
     builder.addAllRepeatedForeignMessage(singletonList(foreignMessage));
-    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
-    assertEquals(singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
-    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    assertThat(message.getRepeatedForeignMessageList()).isEmpty();
+    assertThat(builder.getRepeatedForeignMessageList()).containsExactly(foreignMessage);
+    assertThat(message.getRepeatedForeignMessageList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedForeignMessage();
-    assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
-    assertEquals(singletonList(foreignMessage), messageAfterBuild.getRepeatedForeignMessageList());
+    assertThat(builder.getRepeatedForeignMessageList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedForeignMessageList()).containsExactly(foreignMessage);
 
     message = builder.build();
     builder.addAllRepeatedGroup(singletonList(RepeatedGroup.getDefaultInstance()));
-    assertEquals(emptyList(), message.getRepeatedGroupList());
-    assertEquals(singletonList(RepeatedGroup.getDefaultInstance()), builder.getRepeatedGroupList());
-    assertEquals(emptyList(), message.getRepeatedGroupList());
+    assertThat(message.getRepeatedGroupList()).isEmpty();
+    assertThat(builder.getRepeatedGroupList()).containsExactly(RepeatedGroup.getDefaultInstance());
+    assertThat(message.getRepeatedGroupList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedGroup();
-    assertEquals(emptyList(), builder.getRepeatedGroupList());
-    assertEquals(
-        singletonList(RepeatedGroup.getDefaultInstance()),
-        messageAfterBuild.getRepeatedGroupList());
+    assertThat(builder.getRepeatedGroupList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedGroupList())
+        .containsExactly(RepeatedGroup.getDefaultInstance());
 
     message = builder.build();
     builder.addAllRepeatedInt32(singletonList(1));
-    assertEquals(emptyList(), message.getRepeatedInt32List());
-    assertEquals(singletonList(1), builder.getRepeatedInt32List());
-    assertEquals(emptyList(), message.getRepeatedInt32List());
+    assertThat(message.getRepeatedInt32List()).isEmpty();
+    assertThat(builder.getRepeatedInt32List()).containsExactly(1);
+    assertThat(message.getRepeatedInt32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedInt32();
-    assertEquals(emptyList(), builder.getRepeatedInt32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedInt32List());
+    assertThat(builder.getRepeatedInt32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedInt32List()).containsExactly(1);
 
     message = builder.build();
     builder.addAllRepeatedInt64(singletonList(1L));
-    assertEquals(emptyList(), message.getRepeatedInt64List());
-    assertEquals(singletonList(1L), builder.getRepeatedInt64List());
-    assertEquals(emptyList(), message.getRepeatedInt64List());
+    assertThat(message.getRepeatedInt64List()).isEmpty();
+    assertThat(builder.getRepeatedInt64List()).containsExactly(1L);
+    assertThat(message.getRepeatedInt64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedInt64();
-    assertEquals(emptyList(), builder.getRepeatedInt64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedInt64List());
+    assertThat(builder.getRepeatedInt64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedInt64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addAllRepeatedLazyMessage(singletonList(nestedMessage));
-    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
-    assertEquals(singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
-    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    assertThat(message.getRepeatedLazyMessageList()).isEmpty();
+    assertThat(builder.getRepeatedLazyMessageList()).containsExactly(nestedMessage);
+    assertThat(message.getRepeatedLazyMessageList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedLazyMessage();
-    assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
-    assertEquals(singletonList(nestedMessage), messageAfterBuild.getRepeatedLazyMessageList());
+    assertThat(builder.getRepeatedLazyMessageList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedLazyMessageList()).containsExactly(nestedMessage);
 
     message = builder.build();
     builder.addAllRepeatedSfixed32(singletonList(1));
-    assertEquals(emptyList(), message.getRepeatedSfixed32List());
-    assertEquals(singletonList(1), builder.getRepeatedSfixed32List());
-    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    assertThat(message.getRepeatedSfixed32List()).isEmpty();
+    assertThat(builder.getRepeatedSfixed32List()).containsExactly(1);
+    assertThat(message.getRepeatedSfixed32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedSfixed32();
-    assertEquals(emptyList(), builder.getRepeatedSfixed32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSfixed32List());
+    assertThat(builder.getRepeatedSfixed32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedSfixed32List()).containsExactly(1);
 
     message = builder.build();
     builder.addAllRepeatedSfixed64(singletonList(1L));
-    assertEquals(emptyList(), message.getRepeatedSfixed64List());
-    assertEquals(singletonList(1L), builder.getRepeatedSfixed64List());
-    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    assertThat(message.getRepeatedSfixed64List()).isEmpty();
+    assertThat(builder.getRepeatedSfixed64List()).containsExactly(1L);
+    assertThat(message.getRepeatedSfixed64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedSfixed64();
-    assertEquals(emptyList(), builder.getRepeatedSfixed64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+    assertThat(builder.getRepeatedSfixed64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedSfixed64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addAllRepeatedSint32(singletonList(1));
-    assertEquals(emptyList(), message.getRepeatedSint32List());
-    assertEquals(singletonList(1), builder.getRepeatedSint32List());
-    assertEquals(emptyList(), message.getRepeatedSint32List());
+    assertThat(message.getRepeatedSint32List()).isEmpty();
+    assertThat(builder.getRepeatedSint32List()).containsExactly(1);
+    assertThat(message.getRepeatedSint32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedSint32();
-    assertEquals(emptyList(), builder.getRepeatedSint32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSint32List());
+    assertThat(builder.getRepeatedSint32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedSint32List()).containsExactly(1);
 
     message = builder.build();
     builder.addAllRepeatedSint64(singletonList(1L));
-    assertEquals(emptyList(), message.getRepeatedSint64List());
-    assertEquals(singletonList(1L), builder.getRepeatedSint64List());
-    assertEquals(emptyList(), message.getRepeatedSint64List());
+    assertThat(message.getRepeatedSint64List()).isEmpty();
+    assertThat(builder.getRepeatedSint64List()).containsExactly(1L);
+    assertThat(message.getRepeatedSint64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedSint64();
-    assertEquals(emptyList(), builder.getRepeatedSint64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSint64List());
+    assertThat(builder.getRepeatedSint64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedSint64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addAllRepeatedString(singletonList("hi"));
-    assertEquals(emptyList(), message.getRepeatedStringList());
-    assertEquals(singletonList("hi"), builder.getRepeatedStringList());
-    assertEquals(emptyList(), message.getRepeatedStringList());
+    assertThat(message.getRepeatedStringList()).isEmpty();
+    assertThat(builder.getRepeatedStringList()).containsExactly("hi");
+    assertThat(message.getRepeatedStringList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedString();
-    assertEquals(emptyList(), builder.getRepeatedStringList());
-    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+    assertThat(builder.getRepeatedStringList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedStringList()).containsExactly("hi");
 
     message = builder.build();
     builder.addAllRepeatedStringPiece(singletonList("hi"));
-    assertEquals(emptyList(), message.getRepeatedStringPieceList());
-    assertEquals(singletonList("hi"), builder.getRepeatedStringPieceList());
-    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    assertThat(message.getRepeatedStringPieceList()).isEmpty();
+    assertThat(builder.getRepeatedStringPieceList()).containsExactly("hi");
+    assertThat(message.getRepeatedStringPieceList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedStringPiece();
-    assertEquals(emptyList(), builder.getRepeatedStringPieceList());
-    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+    assertThat(builder.getRepeatedStringPieceList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedStringPieceList()).containsExactly("hi");
 
     message = builder.build();
     builder.addAllRepeatedUint32(singletonList(1));
-    assertEquals(emptyList(), message.getRepeatedUint32List());
-    assertEquals(singletonList(1), builder.getRepeatedUint32List());
-    assertEquals(emptyList(), message.getRepeatedUint32List());
+    assertThat(message.getRepeatedUint32List()).isEmpty();
+    assertThat(builder.getRepeatedUint32List()).containsExactly(1);
+    assertThat(message.getRepeatedUint32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedUint32();
-    assertEquals(emptyList(), builder.getRepeatedUint32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedUint32List());
+    assertThat(builder.getRepeatedUint32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedUint32List()).containsExactly(1);
 
     message = builder.build();
     builder.addAllRepeatedUint64(singletonList(1L));
-    assertEquals(emptyList(), message.getRepeatedUint64List());
-    assertEquals(singletonList(1L), builder.getRepeatedUint64List());
-    assertEquals(emptyList(), message.getRepeatedUint64List());
+    assertThat(message.getRepeatedUint64List()).isEmpty();
+    assertThat(builder.getRepeatedUint64List()).containsExactly(1L);
+    assertThat(message.getRepeatedUint64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedUint64();
-    assertEquals(emptyList(), builder.getRepeatedUint64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List());
+    assertThat(builder.getRepeatedUint64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedUint64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addRepeatedBool(true);
-    assertEquals(emptyList(), message.getRepeatedBoolList());
-    assertEquals(singletonList(true), builder.getRepeatedBoolList());
-    assertEquals(emptyList(), message.getRepeatedBoolList());
+    assertThat(message.getRepeatedBoolList()).isEmpty();
+    assertThat(builder.getRepeatedBoolList()).containsExactly(true);
+    assertThat(message.getRepeatedBoolList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedBool();
-    assertEquals(emptyList(), builder.getRepeatedBoolList());
-    assertEquals(singletonList(true), messageAfterBuild.getRepeatedBoolList());
+    assertThat(builder.getRepeatedBoolList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedBoolList()).containsExactly(true);
 
     message = builder.build();
     builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
-    assertEquals(emptyList(), message.getRepeatedBytesList());
-    assertEquals(singletonList(ByteString.copyFromUtf8("hi")), builder.getRepeatedBytesList());
-    assertEquals(emptyList(), message.getRepeatedBytesList());
+    assertThat(message.getRepeatedBytesList()).isEmpty();
+    assertThat(builder.getRepeatedBytesList()).containsExactly(ByteString.copyFromUtf8("hi"));
+    assertThat(message.getRepeatedBytesList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedBytes();
-    assertEquals(emptyList(), builder.getRepeatedBytesList());
-    assertEquals(
-        singletonList(ByteString.copyFromUtf8("hi")), messageAfterBuild.getRepeatedBytesList());
+    assertThat(builder.getRepeatedBytesList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedBytesList())
+        .containsExactly(ByteString.copyFromUtf8("hi"));
 
     message = builder.build();
     builder.addRepeatedCord("hi");
-    assertEquals(emptyList(), message.getRepeatedCordList());
-    assertEquals(singletonList("hi"), builder.getRepeatedCordList());
-    assertEquals(emptyList(), message.getRepeatedCordList());
+    assertThat(message.getRepeatedCordList()).isEmpty();
+    assertThat(builder.getRepeatedCordList()).containsExactly("hi");
+    assertThat(message.getRepeatedCordList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedCord();
-    assertEquals(emptyList(), builder.getRepeatedCordList());
-    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedCordList());
+    assertThat(builder.getRepeatedCordList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedCordList()).containsExactly("hi");
 
     message = builder.build();
     builder.addRepeatedDouble(1D);
-    assertEquals(emptyList(), message.getRepeatedDoubleList());
-    assertEquals(singletonList(1D), builder.getRepeatedDoubleList());
-    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    assertThat(message.getRepeatedDoubleList()).isEmpty();
+    assertThat(builder.getRepeatedDoubleList()).containsExactly(1D);
+    assertThat(message.getRepeatedDoubleList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedDouble();
-    assertEquals(emptyList(), builder.getRepeatedDoubleList());
-    assertEquals(singletonList(1D), messageAfterBuild.getRepeatedDoubleList());
+    assertThat(builder.getRepeatedDoubleList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedDoubleList()).containsExactly(1D);
 
     message = builder.build();
     builder.addRepeatedFixed32(1);
-    assertEquals(emptyList(), message.getRepeatedFixed32List());
-    assertEquals(singletonList(1), builder.getRepeatedFixed32List());
-    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    assertThat(message.getRepeatedFixed32List()).isEmpty();
+    assertThat(builder.getRepeatedFixed32List()).containsExactly(1);
+    assertThat(message.getRepeatedFixed32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedFixed32();
-    assertEquals(emptyList(), builder.getRepeatedFixed32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedFixed32List());
+    assertThat(builder.getRepeatedFixed32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedFixed32List()).containsExactly(1);
 
     message = builder.build();
     builder.addRepeatedFixed64(1L);
-    assertEquals(emptyList(), message.getRepeatedFixed64List());
-    assertEquals(singletonList(1L), builder.getRepeatedFixed64List());
-    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    assertThat(message.getRepeatedFixed64List()).isEmpty();
+    assertThat(builder.getRepeatedFixed64List()).containsExactly(1L);
+    assertThat(message.getRepeatedFixed64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedFixed64();
-    assertEquals(emptyList(), builder.getRepeatedFixed64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedFixed64List());
+    assertThat(builder.getRepeatedFixed64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedFixed64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addRepeatedFloat(1F);
-    assertEquals(emptyList(), message.getRepeatedFloatList());
-    assertEquals(singletonList(1F), builder.getRepeatedFloatList());
-    assertEquals(emptyList(), message.getRepeatedFloatList());
+    assertThat(message.getRepeatedFloatList()).isEmpty();
+    assertThat(builder.getRepeatedFloatList()).containsExactly(1F);
+    assertThat(message.getRepeatedFloatList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedFloat();
-    assertEquals(emptyList(), builder.getRepeatedFloatList());
-    assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList());
+    assertThat(builder.getRepeatedFloatList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedFloatList()).containsExactly(1F);
 
     message = builder.build();
     builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
-    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
-    assertEquals(
-        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), builder.getRepeatedForeignEnumList());
-    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    assertThat(message.getRepeatedForeignEnumList()).isEmpty();
+    assertThat(builder.getRepeatedForeignEnumList())
+        .containsExactly(ForeignEnumLite.FOREIGN_LITE_BAR);
+    assertThat(message.getRepeatedForeignEnumList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedForeignEnum();
-    assertEquals(emptyList(), builder.getRepeatedForeignEnumList());
-    assertEquals(
-        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
-        messageAfterBuild.getRepeatedForeignEnumList());
+    assertThat(builder.getRepeatedForeignEnumList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedForeignEnumList())
+        .containsExactly(ForeignEnumLite.FOREIGN_LITE_BAR);
 
     message = builder.build();
     builder.addRepeatedForeignMessage(foreignMessage);
-    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
-    assertEquals(singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
-    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    assertThat(message.getRepeatedForeignMessageList()).isEmpty();
+    assertThat(builder.getRepeatedForeignMessageList()).containsExactly(foreignMessage);
+    assertThat(message.getRepeatedForeignMessageList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.removeRepeatedForeignMessage(0);
-    assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
-    assertEquals(singletonList(foreignMessage), messageAfterBuild.getRepeatedForeignMessageList());
+    assertThat(builder.getRepeatedForeignMessageList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedForeignMessageList()).containsExactly(foreignMessage);
 
     message = builder.build();
     builder.addRepeatedGroup(RepeatedGroup.getDefaultInstance());
-    assertEquals(emptyList(), message.getRepeatedGroupList());
-    assertEquals(singletonList(RepeatedGroup.getDefaultInstance()), builder.getRepeatedGroupList());
-    assertEquals(emptyList(), message.getRepeatedGroupList());
+    assertThat(message.getRepeatedGroupList()).isEmpty();
+    assertThat(builder.getRepeatedGroupList()).containsExactly(RepeatedGroup.getDefaultInstance());
+    assertThat(message.getRepeatedGroupList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.removeRepeatedGroup(0);
-    assertEquals(emptyList(), builder.getRepeatedGroupList());
-    assertEquals(
-        singletonList(RepeatedGroup.getDefaultInstance()),
-        messageAfterBuild.getRepeatedGroupList());
+    assertThat(builder.getRepeatedGroupList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedGroupList())
+        .containsExactly(RepeatedGroup.getDefaultInstance());
 
     message = builder.build();
     builder.addRepeatedInt32(1);
-    assertEquals(emptyList(), message.getRepeatedInt32List());
-    assertEquals(singletonList(1), builder.getRepeatedInt32List());
-    assertEquals(emptyList(), message.getRepeatedInt32List());
+    assertThat(message.getRepeatedInt32List()).isEmpty();
+    assertThat(builder.getRepeatedInt32List()).containsExactly(1);
+    assertThat(message.getRepeatedInt32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedInt32();
-    assertEquals(emptyList(), builder.getRepeatedInt32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedInt32List());
+    assertThat(builder.getRepeatedInt32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedInt32List()).containsExactly(1);
 
     message = builder.build();
     builder.addRepeatedInt64(1L);
-    assertEquals(emptyList(), message.getRepeatedInt64List());
-    assertEquals(singletonList(1L), builder.getRepeatedInt64List());
-    assertEquals(emptyList(), message.getRepeatedInt64List());
+    assertThat(message.getRepeatedInt64List()).isEmpty();
+    assertThat(builder.getRepeatedInt64List()).containsExactly(1L);
+    assertThat(message.getRepeatedInt64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedInt64();
-    assertEquals(emptyList(), builder.getRepeatedInt64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedInt64List());
+    assertThat(builder.getRepeatedInt64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedInt64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addRepeatedLazyMessage(nestedMessage);
-    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
-    assertEquals(singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
-    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    assertThat(message.getRepeatedLazyMessageList()).isEmpty();
+    assertThat(builder.getRepeatedLazyMessageList()).containsExactly(nestedMessage);
+    assertThat(message.getRepeatedLazyMessageList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.removeRepeatedLazyMessage(0);
-    assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
-    assertEquals(singletonList(nestedMessage), messageAfterBuild.getRepeatedLazyMessageList());
+    assertThat(builder.getRepeatedLazyMessageList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedLazyMessageList()).containsExactly(nestedMessage);
 
     message = builder.build();
     builder.addRepeatedSfixed32(1);
-    assertEquals(emptyList(), message.getRepeatedSfixed32List());
-    assertEquals(singletonList(1), builder.getRepeatedSfixed32List());
-    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    assertThat(message.getRepeatedSfixed32List()).isEmpty();
+    assertThat(builder.getRepeatedSfixed32List()).containsExactly(1);
+    assertThat(message.getRepeatedSfixed32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedSfixed32();
-    assertEquals(emptyList(), builder.getRepeatedSfixed32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSfixed32List());
+    assertThat(builder.getRepeatedSfixed32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedSfixed32List()).containsExactly(1);
 
     message = builder.build();
     builder.addRepeatedSfixed64(1L);
-    assertEquals(emptyList(), message.getRepeatedSfixed64List());
-    assertEquals(singletonList(1L), builder.getRepeatedSfixed64List());
-    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    assertThat(message.getRepeatedSfixed64List()).isEmpty();
+    assertThat(builder.getRepeatedSfixed64List()).containsExactly(1L);
+    assertThat(message.getRepeatedSfixed64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedSfixed64();
-    assertEquals(emptyList(), builder.getRepeatedSfixed64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+    assertThat(builder.getRepeatedSfixed64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedSfixed64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addRepeatedSint32(1);
-    assertEquals(emptyList(), message.getRepeatedSint32List());
-    assertEquals(singletonList(1), builder.getRepeatedSint32List());
-    assertEquals(emptyList(), message.getRepeatedSint32List());
+    assertThat(message.getRepeatedSint32List()).isEmpty();
+    assertThat(builder.getRepeatedSint32List()).containsExactly(1);
+    assertThat(message.getRepeatedSint32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedSint32();
-    assertEquals(emptyList(), builder.getRepeatedSint32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSint32List());
+    assertThat(builder.getRepeatedSint32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedSint32List()).containsExactly(1);
 
     message = builder.build();
     builder.addRepeatedSint64(1L);
-    assertEquals(emptyList(), message.getRepeatedSint64List());
-    assertEquals(singletonList(1L), builder.getRepeatedSint64List());
-    assertEquals(emptyList(), message.getRepeatedSint64List());
+    assertThat(message.getRepeatedSint64List()).isEmpty();
+    assertThat(builder.getRepeatedSint64List()).containsExactly(1L);
+    assertThat(message.getRepeatedSint64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedSint64();
-    assertEquals(emptyList(), builder.getRepeatedSint64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSint64List());
+    assertThat(builder.getRepeatedSint64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedSint64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addRepeatedString("hi");
-    assertEquals(emptyList(), message.getRepeatedStringList());
-    assertEquals(singletonList("hi"), builder.getRepeatedStringList());
-    assertEquals(emptyList(), message.getRepeatedStringList());
+    assertThat(message.getRepeatedStringList()).isEmpty();
+    assertThat(builder.getRepeatedStringList()).containsExactly("hi");
+    assertThat(message.getRepeatedStringList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedString();
-    assertEquals(emptyList(), builder.getRepeatedStringList());
-    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+    assertThat(builder.getRepeatedStringList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedStringList()).containsExactly("hi");
 
     message = builder.build();
     builder.addRepeatedStringPiece("hi");
-    assertEquals(emptyList(), message.getRepeatedStringPieceList());
-    assertEquals(singletonList("hi"), builder.getRepeatedStringPieceList());
-    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    assertThat(message.getRepeatedStringPieceList()).isEmpty();
+    assertThat(builder.getRepeatedStringPieceList()).containsExactly("hi");
+    assertThat(message.getRepeatedStringPieceList()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedStringPiece();
-    assertEquals(emptyList(), builder.getRepeatedStringPieceList());
-    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+    assertThat(builder.getRepeatedStringPieceList()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedStringPieceList()).containsExactly("hi");
 
     message = builder.build();
     builder.addRepeatedUint32(1);
-    assertEquals(emptyList(), message.getRepeatedUint32List());
-    assertEquals(singletonList(1), builder.getRepeatedUint32List());
-    assertEquals(emptyList(), message.getRepeatedUint32List());
+    assertThat(message.getRepeatedUint32List()).isEmpty();
+    assertThat(builder.getRepeatedUint32List()).containsExactly(1);
+    assertThat(message.getRepeatedUint32List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedUint32();
-    assertEquals(emptyList(), builder.getRepeatedUint32List());
-    assertEquals(singletonList(1), messageAfterBuild.getRepeatedUint32List());
+    assertThat(builder.getRepeatedUint32List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedUint32List()).containsExactly(1);
 
     message = builder.build();
     builder.addRepeatedUint64(1L);
-    assertEquals(emptyList(), message.getRepeatedUint64List());
-    assertEquals(singletonList(1L), builder.getRepeatedUint64List());
-    assertEquals(emptyList(), message.getRepeatedUint64List());
+    assertThat(message.getRepeatedUint64List()).isEmpty();
+    assertThat(builder.getRepeatedUint64List()).containsExactly(1L);
+    assertThat(message.getRepeatedUint64List()).isEmpty();
     messageAfterBuild = builder.build();
     builder.clearRepeatedUint64();
-    assertEquals(emptyList(), builder.getRepeatedUint64List());
-    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List());
+    assertThat(builder.getRepeatedUint64List()).isEmpty();
+    assertThat(messageAfterBuild.getRepeatedUint64List()).containsExactly(1L);
 
     message = builder.build();
     builder.addRepeatedBool(true);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedBoolCount());
+    assertThat(message.getRepeatedBoolCount()).isEqualTo(0);
     builder.setRepeatedBool(0, false);
-    assertEquals(true, messageAfterBuild.getRepeatedBool(0));
-    assertEquals(false, builder.getRepeatedBool(0));
+    assertThat(messageAfterBuild.getRepeatedBool(0)).isTrue();
+    assertThat(builder.getRepeatedBool(0)).isFalse();
     builder.clearRepeatedBool();
 
     message = builder.build();
     builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedBytesCount());
+    assertThat(message.getRepeatedBytesCount()).isEqualTo(0);
     builder.setRepeatedBytes(0, ByteString.EMPTY);
-    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedBytes(0));
-    assertEquals(ByteString.EMPTY, builder.getRepeatedBytes(0));
+    assertThat(messageAfterBuild.getRepeatedBytes(0)).isEqualTo(ByteString.copyFromUtf8("hi"));
+    assertThat(builder.getRepeatedBytes(0)).isEqualTo(ByteString.EMPTY);
     builder.clearRepeatedBytes();
 
     message = builder.build();
     builder.addRepeatedCord("hi");
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedCordCount());
+    assertThat(message.getRepeatedCordCount()).isEqualTo(0);
     builder.setRepeatedCord(0, "");
-    assertEquals("hi", messageAfterBuild.getRepeatedCord(0));
-    assertEquals("", builder.getRepeatedCord(0));
+    assertThat(messageAfterBuild.getRepeatedCord(0)).isEqualTo("hi");
+    assertThat(builder.getRepeatedCord(0)).isEmpty();
     builder.clearRepeatedCord();
     message = builder.build();
 
     builder.addRepeatedCordBytes(ByteString.copyFromUtf8("hi"));
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedCordCount());
+    assertThat(message.getRepeatedCordCount()).isEqualTo(0);
     builder.setRepeatedCord(0, "");
-    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedCordBytes(0));
-    assertEquals(ByteString.EMPTY, builder.getRepeatedCordBytes(0));
+    assertThat(messageAfterBuild.getRepeatedCordBytes(0)).isEqualTo(ByteString.copyFromUtf8("hi"));
+    assertThat(builder.getRepeatedCordBytes(0)).isEqualTo(ByteString.EMPTY);
     builder.clearRepeatedCord();
 
     message = builder.build();
     builder.addRepeatedDouble(1D);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedDoubleCount());
+    assertThat(message.getRepeatedDoubleCount()).isEqualTo(0);
     builder.setRepeatedDouble(0, 0D);
-    assertEquals(1D, messageAfterBuild.getRepeatedDouble(0), 0.0);
-    assertEquals(0D, builder.getRepeatedDouble(0), 0.0);
+    assertThat(messageAfterBuild.getRepeatedDouble(0)).isEqualTo(1D);
+    assertThat(builder.getRepeatedDouble(0)).isEqualTo(0D);
     builder.clearRepeatedDouble();
 
     message = builder.build();
     builder.addRepeatedFixed32(1);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedFixed32Count());
+    assertThat(message.getRepeatedFixed32Count()).isEqualTo(0);
     builder.setRepeatedFixed32(0, 0);
-    assertEquals(1, messageAfterBuild.getRepeatedFixed32(0));
-    assertEquals(0, builder.getRepeatedFixed32(0));
+    assertThat(messageAfterBuild.getRepeatedFixed32(0)).isEqualTo(1);
+    assertThat(builder.getRepeatedFixed32(0)).isEqualTo(0);
     builder.clearRepeatedFixed32();
 
     message = builder.build();
     builder.addRepeatedFixed64(1L);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedFixed64Count());
+    assertThat(message.getRepeatedFixed64Count()).isEqualTo(0);
     builder.setRepeatedFixed64(0, 0L);
-    assertEquals(1L, messageAfterBuild.getRepeatedFixed64(0));
-    assertEquals(0L, builder.getRepeatedFixed64(0));
+    assertThat(messageAfterBuild.getRepeatedFixed64(0)).isEqualTo(1L);
+    assertThat(builder.getRepeatedFixed64(0)).isEqualTo(0L);
     builder.clearRepeatedFixed64();
 
     message = builder.build();
     builder.addRepeatedFloat(1F);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedFloatCount());
+    assertThat(message.getRepeatedFloatCount()).isEqualTo(0);
     builder.setRepeatedFloat(0, 0F);
-    assertEquals(1F, messageAfterBuild.getRepeatedFloat(0), 0.0f);
-    assertEquals(0F, builder.getRepeatedFloat(0), 0.0f);
+    assertThat(messageAfterBuild.getRepeatedFloat(0)).isEqualTo(1F);
+    assertThat(builder.getRepeatedFloat(0)).isEqualTo(0F);
     builder.clearRepeatedFloat();
 
     message = builder.build();
     builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedForeignEnumCount());
+    assertThat(message.getRepeatedForeignEnumCount()).isEqualTo(0);
     builder.setRepeatedForeignEnum(0, ForeignEnumLite.FOREIGN_LITE_FOO);
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, messageAfterBuild.getRepeatedForeignEnum(0));
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, builder.getRepeatedForeignEnum(0));
+    assertThat(messageAfterBuild.getRepeatedForeignEnum(0))
+        .isEqualTo(ForeignEnumLite.FOREIGN_LITE_BAR);
+    assertThat(builder.getRepeatedForeignEnum(0)).isEqualTo(ForeignEnumLite.FOREIGN_LITE_FOO);
     builder.clearRepeatedForeignEnum();
 
     message = builder.build();
     builder.addRepeatedForeignMessage(foreignMessage);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedForeignMessageCount());
+    assertThat(message.getRepeatedForeignMessageCount()).isEqualTo(0);
     builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance());
-    assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
-    assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0));
+    assertThat(messageAfterBuild.getRepeatedForeignMessage(0)).isEqualTo(foreignMessage);
+    assertThat(builder.getRepeatedForeignMessage(0))
+        .isEqualTo(ForeignMessageLite.getDefaultInstance());
     builder.clearRepeatedForeignMessage();
 
     message = builder.build();
     builder.addRepeatedForeignMessage(foreignMessageC3);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedForeignMessageCount());
+    assertThat(message.getRepeatedForeignMessageCount()).isEqualTo(0);
     builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance());
-    assertEquals(foreignMessageC3, messageAfterBuild.getRepeatedForeignMessage(0));
-    assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0));
+    assertThat(messageAfterBuild.getRepeatedForeignMessage(0)).isEqualTo(foreignMessageC3);
+    assertThat(builder.getRepeatedForeignMessage(0))
+        .isEqualTo(ForeignMessageLite.getDefaultInstance());
     builder.clearRepeatedForeignMessage();
 
     message = builder.build();
     builder.addRepeatedForeignMessage(0, foreignMessage);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedForeignMessageCount());
+    assertThat(message.getRepeatedForeignMessageCount()).isEqualTo(0);
     builder.setRepeatedForeignMessage(0, foreignMessageC3);
-    assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
-    assertEquals(foreignMessageC3, builder.getRepeatedForeignMessage(0));
+    assertThat(messageAfterBuild.getRepeatedForeignMessage(0)).isEqualTo(foreignMessage);
+    assertThat(builder.getRepeatedForeignMessage(0)).isEqualTo(foreignMessageC3);
     builder.clearRepeatedForeignMessage();
 
     message = builder.build();
     RepeatedGroup repeatedGroup = RepeatedGroup.newBuilder().setA(1).build();
     builder.addRepeatedGroup(repeatedGroup);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedGroupCount());
+    assertThat(message.getRepeatedGroupCount()).isEqualTo(0);
     builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
-    assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
-    assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    assertThat(messageAfterBuild.getRepeatedGroup(0)).isEqualTo(repeatedGroup);
+    assertThat(builder.getRepeatedGroup(0)).isEqualTo(RepeatedGroup.getDefaultInstance());
     builder.clearRepeatedGroup();
 
     message = builder.build();
     builder.addRepeatedGroup(0, repeatedGroup);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedGroupCount());
+    assertThat(message.getRepeatedGroupCount()).isEqualTo(0);
     builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
-    assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
-    assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    assertThat(messageAfterBuild.getRepeatedGroup(0)).isEqualTo(repeatedGroup);
+    assertThat(builder.getRepeatedGroup(0)).isEqualTo(RepeatedGroup.getDefaultInstance());
     builder.clearRepeatedGroup();
 
     message = builder.build();
     RepeatedGroup.Builder repeatedGroupBuilder = RepeatedGroup.newBuilder().setA(3);
     builder.addRepeatedGroup(repeatedGroupBuilder);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedGroupCount());
+    assertThat(message.getRepeatedGroupCount()).isEqualTo(0);
     builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
-    assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
-    assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    assertThat(messageAfterBuild.getRepeatedGroup(0)).isEqualTo(repeatedGroupBuilder.build());
+    assertThat(builder.getRepeatedGroup(0)).isEqualTo(RepeatedGroup.getDefaultInstance());
     builder.clearRepeatedGroup();
 
     message = builder.build();
     builder.addRepeatedGroup(0, repeatedGroupBuilder);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedGroupCount());
+    assertThat(message.getRepeatedGroupCount()).isEqualTo(0);
     builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
-    assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
-    assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    assertThat(messageAfterBuild.getRepeatedGroup(0)).isEqualTo(repeatedGroupBuilder.build());
+    assertThat(builder.getRepeatedGroup(0)).isEqualTo(RepeatedGroup.getDefaultInstance());
     builder.clearRepeatedGroup();
 
     message = builder.build();
     builder.addRepeatedInt32(1);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedInt32Count());
+    assertThat(message.getRepeatedInt32Count()).isEqualTo(0);
     builder.setRepeatedInt32(0, 0);
-    assertEquals(1, messageAfterBuild.getRepeatedInt32(0));
-    assertEquals(0, builder.getRepeatedInt32(0));
+    assertThat(messageAfterBuild.getRepeatedInt32(0)).isEqualTo(1);
+    assertThat(builder.getRepeatedInt32(0)).isEqualTo(0);
     builder.clearRepeatedInt32();
 
     message = builder.build();
     builder.addRepeatedInt64(1L);
     messageAfterBuild = builder.build();
-    assertEquals(0L, message.getRepeatedInt64Count());
+    assertThat(message.getRepeatedInt64Count()).isEqualTo(0L);
     builder.setRepeatedInt64(0, 0L);
-    assertEquals(1L, messageAfterBuild.getRepeatedInt64(0));
-    assertEquals(0L, builder.getRepeatedInt64(0));
+    assertThat(messageAfterBuild.getRepeatedInt64(0)).isEqualTo(1L);
+    assertThat(builder.getRepeatedInt64(0)).isEqualTo(0L);
     builder.clearRepeatedInt64();
 
     message = builder.build();
     builder.addRepeatedLazyMessage(nestedMessage);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedLazyMessageCount());
+    assertThat(message.getRepeatedLazyMessageCount()).isEqualTo(0);
     builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
-    assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
-    assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    assertThat(messageAfterBuild.getRepeatedLazyMessage(0)).isEqualTo(nestedMessage);
+    assertThat(builder.getRepeatedLazyMessage(0)).isEqualTo(NestedMessage.getDefaultInstance());
     builder.clearRepeatedLazyMessage();
 
     message = builder.build();
     builder.addRepeatedLazyMessage(0, nestedMessage);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedLazyMessageCount());
+    assertThat(message.getRepeatedLazyMessageCount()).isEqualTo(0);
     builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
-    assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
-    assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    assertThat(messageAfterBuild.getRepeatedLazyMessage(0)).isEqualTo(nestedMessage);
+    assertThat(builder.getRepeatedLazyMessage(0)).isEqualTo(NestedMessage.getDefaultInstance());
     builder.clearRepeatedLazyMessage();
 
     message = builder.build();
     builder.addRepeatedLazyMessage(nestedMessageBuilder);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedLazyMessageCount());
+    assertThat(message.getRepeatedLazyMessageCount()).isEqualTo(0);
     builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
-    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
-    assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    assertThat(messageAfterBuild.getRepeatedLazyMessage(0)).isEqualTo(nestedMessageBuilder.build());
+    assertThat(builder.getRepeatedLazyMessage(0)).isEqualTo(NestedMessage.getDefaultInstance());
     builder.clearRepeatedLazyMessage();
 
     message = builder.build();
     builder.addRepeatedLazyMessage(0, nestedMessageBuilder);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedLazyMessageCount());
+    assertThat(message.getRepeatedLazyMessageCount()).isEqualTo(0);
     builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
-    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
-    assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    assertThat(messageAfterBuild.getRepeatedLazyMessage(0)).isEqualTo(nestedMessageBuilder.build());
+    assertThat(builder.getRepeatedLazyMessage(0)).isEqualTo(NestedMessage.getDefaultInstance());
     builder.clearRepeatedLazyMessage();
 
     message = builder.build();
     builder.addRepeatedSfixed32(1);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedSfixed32Count());
+    assertThat(message.getRepeatedSfixed32Count()).isEqualTo(0);
     builder.setRepeatedSfixed32(0, 0);
-    assertEquals(1, messageAfterBuild.getRepeatedSfixed32(0));
-    assertEquals(0, builder.getRepeatedSfixed32(0));
+    assertThat(messageAfterBuild.getRepeatedSfixed32(0)).isEqualTo(1);
+    assertThat(builder.getRepeatedSfixed32(0)).isEqualTo(0);
     builder.clearRepeatedSfixed32();
 
     message = builder.build();
     builder.addRepeatedSfixed64(1L);
     messageAfterBuild = builder.build();
-    assertEquals(0L, message.getRepeatedSfixed64Count());
+    assertThat(message.getRepeatedSfixed64Count()).isEqualTo(0L);
     builder.setRepeatedSfixed64(0, 0L);
-    assertEquals(1L, messageAfterBuild.getRepeatedSfixed64(0));
-    assertEquals(0L, builder.getRepeatedSfixed64(0));
+    assertThat(messageAfterBuild.getRepeatedSfixed64(0)).isEqualTo(1L);
+    assertThat(builder.getRepeatedSfixed64(0)).isEqualTo(0L);
     builder.clearRepeatedSfixed64();
 
     message = builder.build();
     builder.addRepeatedSint32(1);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedSint32Count());
+    assertThat(message.getRepeatedSint32Count()).isEqualTo(0);
     builder.setRepeatedSint32(0, 0);
-    assertEquals(1, messageAfterBuild.getRepeatedSint32(0));
-    assertEquals(0, builder.getRepeatedSint32(0));
+    assertThat(messageAfterBuild.getRepeatedSint32(0)).isEqualTo(1);
+    assertThat(builder.getRepeatedSint32(0)).isEqualTo(0);
     builder.clearRepeatedSint32();
 
     message = builder.build();
     builder.addRepeatedSint64(1L);
     messageAfterBuild = builder.build();
-    assertEquals(0L, message.getRepeatedSint64Count());
+    assertThat(message.getRepeatedSint64Count()).isEqualTo(0L);
     builder.setRepeatedSint64(0, 0L);
-    assertEquals(1L, messageAfterBuild.getRepeatedSint64(0));
-    assertEquals(0L, builder.getRepeatedSint64(0));
+    assertThat(messageAfterBuild.getRepeatedSint64(0)).isEqualTo(1L);
+    assertThat(builder.getRepeatedSint64(0)).isEqualTo(0L);
     builder.clearRepeatedSint64();
 
     message = builder.build();
     builder.addRepeatedString("hi");
     messageAfterBuild = builder.build();
-    assertEquals(0L, message.getRepeatedStringCount());
+    assertThat(message.getRepeatedStringCount()).isEqualTo(0L);
     builder.setRepeatedString(0, "");
-    assertEquals("hi", messageAfterBuild.getRepeatedString(0));
-    assertEquals("", builder.getRepeatedString(0));
+    assertThat(messageAfterBuild.getRepeatedString(0)).isEqualTo("hi");
+    assertThat(builder.getRepeatedString(0)).isEmpty();
     builder.clearRepeatedString();
 
     message = builder.build();
     builder.addRepeatedStringBytes(ByteString.copyFromUtf8("hi"));
     messageAfterBuild = builder.build();
-    assertEquals(0L, message.getRepeatedStringCount());
+    assertThat(message.getRepeatedStringCount()).isEqualTo(0L);
     builder.setRepeatedString(0, "");
-    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedStringBytes(0));
-    assertEquals(ByteString.EMPTY, builder.getRepeatedStringBytes(0));
+    assertThat(messageAfterBuild.getRepeatedStringBytes(0))
+        .isEqualTo(ByteString.copyFromUtf8("hi"));
+    assertThat(builder.getRepeatedStringBytes(0)).isEqualTo(ByteString.EMPTY);
     builder.clearRepeatedString();
 
     message = builder.build();
     builder.addRepeatedStringPiece("hi");
     messageAfterBuild = builder.build();
-    assertEquals(0L, message.getRepeatedStringPieceCount());
+    assertThat(message.getRepeatedStringPieceCount()).isEqualTo(0L);
     builder.setRepeatedStringPiece(0, "");
-    assertEquals("hi", messageAfterBuild.getRepeatedStringPiece(0));
-    assertEquals("", builder.getRepeatedStringPiece(0));
+    assertThat(messageAfterBuild.getRepeatedStringPiece(0)).isEqualTo("hi");
+    assertThat(builder.getRepeatedStringPiece(0)).isEmpty();
     builder.clearRepeatedStringPiece();
 
     message = builder.build();
     builder.addRepeatedStringPieceBytes(ByteString.copyFromUtf8("hi"));
     messageAfterBuild = builder.build();
-    assertEquals(0L, message.getRepeatedStringPieceCount());
+    assertThat(message.getRepeatedStringPieceCount()).isEqualTo(0L);
     builder.setRepeatedStringPiece(0, "");
-    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedStringPieceBytes(0));
-    assertEquals(ByteString.EMPTY, builder.getRepeatedStringPieceBytes(0));
+    assertThat(messageAfterBuild.getRepeatedStringPieceBytes(0))
+        .isEqualTo(ByteString.copyFromUtf8("hi"));
+    assertThat(builder.getRepeatedStringPieceBytes(0)).isEqualTo(ByteString.EMPTY);
     builder.clearRepeatedStringPiece();
 
     message = builder.build();
     builder.addRepeatedUint32(1);
     messageAfterBuild = builder.build();
-    assertEquals(0, message.getRepeatedUint32Count());
+    assertThat(message.getRepeatedUint32Count()).isEqualTo(0);
     builder.setRepeatedUint32(0, 0);
-    assertEquals(1, messageAfterBuild.getRepeatedUint32(0));
-    assertEquals(0, builder.getRepeatedUint32(0));
+    assertThat(messageAfterBuild.getRepeatedUint32(0)).isEqualTo(1);
+    assertThat(builder.getRepeatedUint32(0)).isEqualTo(0);
     builder.clearRepeatedUint32();
 
     message = builder.build();
     builder.addRepeatedUint64(1L);
     messageAfterBuild = builder.build();
-    assertEquals(0L, message.getRepeatedUint64Count());
+    assertThat(message.getRepeatedUint64Count()).isEqualTo(0L);
     builder.setRepeatedUint64(0, 0L);
-    assertEquals(1L, messageAfterBuild.getRepeatedUint64(0));
-    assertEquals(0L, builder.getRepeatedUint64(0));
+    assertThat(messageAfterBuild.getRepeatedUint64(0)).isEqualTo(1L);
+    assertThat(builder.getRepeatedUint64(0)).isEqualTo(0L);
     builder.clearRepeatedUint64();
 
     message = builder.build();
-    assertEquals(0, message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
     builder.mergeFrom(TestAllTypesLite.newBuilder().setOptionalBool(true).build());
-    assertEquals(0, message.getSerializedSize());
-    assertEquals(true, builder.build().getOptionalBool());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
+    assertThat(builder.build().getOptionalBool()).isTrue();
     builder.clearOptionalBool();
 
     message = builder.build();
-    assertEquals(0, message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
     builder.mergeFrom(TestAllTypesLite.newBuilder().setOptionalBool(true).build());
-    assertEquals(0, message.getSerializedSize());
-    assertEquals(true, builder.build().getOptionalBool());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
+    assertThat(builder.build().getOptionalBool()).isTrue();
     builder.clear();
-    assertEquals(0, builder.build().getSerializedSize());
+    assertThat(builder.build().getSerializedSize()).isEqualTo(0);
 
     message = builder.build();
-    assertEquals(0, message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
     builder.mergeOptionalForeignMessage(foreignMessage);
-    assertEquals(0, message.getSerializedSize());
-    assertEquals(foreignMessage.getC(), builder.build().getOptionalForeignMessage().getC());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
+    assertThat(builder.build().getOptionalForeignMessage().getC()).isEqualTo(foreignMessage.getC());
     builder.clearOptionalForeignMessage();
 
     message = builder.build();
-    assertEquals(0, message.getSerializedSize());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
     builder.mergeOptionalLazyMessage(nestedMessage);
-    assertEquals(0, message.getSerializedSize());
-    assertEquals(nestedMessage.getBb(), builder.build().getOptionalLazyMessage().getBb());
+    assertThat(message.getSerializedSize()).isEqualTo(0);
+    assertThat(builder.build().getOptionalLazyMessage().getBb()).isEqualTo(nestedMessage.getBb());
     builder.clearOptionalLazyMessage();
 
     message = builder.build();
     builder.setOneofString("hi");
-    assertEquals(OneofFieldCase.ONEOFFIELD_NOT_SET, message.getOneofFieldCase());
-    assertEquals(OneofFieldCase.ONEOF_STRING, builder.getOneofFieldCase());
-    assertEquals("hi", builder.getOneofString());
+    assertThat(message.getOneofFieldCase()).isEqualTo(OneofFieldCase.ONEOFFIELD_NOT_SET);
+    assertThat(builder.getOneofFieldCase()).isEqualTo(OneofFieldCase.ONEOF_STRING);
+    assertThat(builder.getOneofString()).isEqualTo("hi");
     messageAfterBuild = builder.build();
-    assertEquals(OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
-    assertEquals("hi", messageAfterBuild.getOneofString());
+    assertThat(messageAfterBuild.getOneofFieldCase()).isEqualTo(OneofFieldCase.ONEOF_STRING);
+    assertThat(messageAfterBuild.getOneofString()).isEqualTo("hi");
     builder.setOneofUint32(1);
-    assertEquals(OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
-    assertEquals("hi", messageAfterBuild.getOneofString());
-    assertEquals(OneofFieldCase.ONEOF_UINT32, builder.getOneofFieldCase());
-    assertEquals(1, builder.getOneofUint32());
+    assertThat(messageAfterBuild.getOneofFieldCase()).isEqualTo(OneofFieldCase.ONEOF_STRING);
+    assertThat(messageAfterBuild.getOneofString()).isEqualTo("hi");
+    assertThat(builder.getOneofFieldCase()).isEqualTo(OneofFieldCase.ONEOF_UINT32);
+    assertThat(builder.getOneofUint32()).isEqualTo(1);
     TestAllTypesLiteOrBuilder messageOrBuilder = builder;
-    assertEquals(OneofFieldCase.ONEOF_UINT32, messageOrBuilder.getOneofFieldCase());
+    assertThat(messageOrBuilder.getOneofFieldCase()).isEqualTo(OneofFieldCase.ONEOF_UINT32);
 
     TestAllExtensionsLite.Builder extendableMessageBuilder = TestAllExtensionsLite.newBuilder();
     TestAllExtensionsLite extendableMessage = extendableMessageBuilder.build();
     extendableMessageBuilder.setExtension(UnittestLite.optionalInt32ExtensionLite, 1);
-    assertFalse(extendableMessage.hasExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertThat(extendableMessage.hasExtension(UnittestLite.optionalInt32ExtensionLite)).isFalse();
     extendableMessage = extendableMessageBuilder.build();
-    assertEquals(
-        1, (int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(1, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertThat((int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite))
+        .isEqualTo(1);
+    assertThat((int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite))
+        .isEqualTo(1);
     extendableMessageBuilder.setExtension(UnittestLite.optionalInt32ExtensionLite, 3);
-    assertEquals(
-        3, (int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(1, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertThat((int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite))
+        .isEqualTo(3);
+    assertThat((int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite))
+        .isEqualTo(1);
     extendableMessage = extendableMessageBuilder.build();
-    assertEquals(
-        3, (int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(3, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertThat((int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite))
+        .isEqualTo(3);
+    assertThat((int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite))
+        .isEqualTo(3);
 
     // No extension registry, so it should be in unknown fields.
     extendableMessage = TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray());
-    assertFalse(extendableMessage.hasExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertThat(extendableMessage.hasExtension(UnittestLite.optionalInt32ExtensionLite)).isFalse();
 
     extendableMessageBuilder = extendableMessage.toBuilder();
     extendableMessageBuilder.mergeFrom(
@@ -1313,21 +1337,24 @@
     extendableMessage = TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray(), registry);
 
     // The unknown field was preserved.
-    assertEquals(3, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(
-        11, (int) extendableMessage.getExtension(UnittestLite.optionalFixed32ExtensionLite));
+    assertThat((int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite))
+        .isEqualTo(3);
+    assertThat((int) extendableMessage.getExtension(UnittestLite.optionalFixed32ExtensionLite))
+        .isEqualTo(11);
   }
 
+  @Test
   public void testBuilderMergeFromNull() throws Exception {
     try {
       TestAllTypesLite.newBuilder().mergeFrom((TestAllTypesLite) null);
-      fail("Expected exception");
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException e) {
       // Pass.
     }
   }
 
   // Builder.mergeFrom() should keep existing extensions.
+  @Test
   public void testBuilderMergeFromWithExtensions() throws Exception {
     TestAllExtensionsLite message =
         TestAllExtensionsLite.newBuilder()
@@ -1341,12 +1368,15 @@
     builder.mergeFrom(message.toByteArray(), registry);
     builder.mergeFrom(message.toByteArray(), registry);
     TestAllExtensionsLite result = builder.build();
-    assertEquals(2, result.getExtensionCount(UnittestLite.repeatedInt32ExtensionLite));
-    assertEquals(12, result.getExtension(UnittestLite.repeatedInt32ExtensionLite, 0).intValue());
-    assertEquals(12, result.getExtension(UnittestLite.repeatedInt32ExtensionLite, 1).intValue());
+    assertThat(result.getExtensionCount(UnittestLite.repeatedInt32ExtensionLite)).isEqualTo(2);
+    assertThat(result.getExtension(UnittestLite.repeatedInt32ExtensionLite, 0).intValue())
+        .isEqualTo(12);
+    assertThat(result.getExtension(UnittestLite.repeatedInt32ExtensionLite, 1).intValue())
+        .isEqualTo(12);
   }
 
   // Builder.mergeFrom() should keep existing unknown fields.
+  @Test
   public void testBuilderMergeFromWithUnknownFields() throws Exception {
     TestAllTypesLite message = TestAllTypesLite.newBuilder().addRepeatedInt32(1).build();
 
@@ -1354,9 +1384,10 @@
     builder.mergeFrom(message.toByteArray());
     builder.mergeFrom(message.toByteArray());
     NestedMessage result = builder.build();
-    assertEquals(message.getSerializedSize() * 2, result.getSerializedSize());
+    assertThat(result.getSerializedSize()).isEqualTo(message.getSerializedSize() * 2);
   }
 
+  @Test
   public void testMergeFrom_differentFieldsSetWithinOneField() throws Exception {
     TestAllTypesLite result =
         TestAllTypesLite.newBuilder()
@@ -1370,6 +1401,7 @@
     assertToStringEquals("oneof_nested_message2 {\n  dd: 3\n}", result);
   }
 
+  @Test
   public void testMergeFrom_differentFieldsOfSameTypeSetWithinOneField() throws Exception {
     TestAllTypesLite result =
         TestAllTypesLite.newBuilder()
@@ -1383,6 +1415,7 @@
     assertToStringEquals("oneof_lazy_nested_message {\n  cc: 3\n}", result);
   }
 
+  @Test
   public void testMergeFrom_sameFieldSetWithinOneofField() throws Exception {
     TestAllTypesLite result =
         TestAllTypesLite.newBuilder()
@@ -1396,16 +1429,19 @@
     assertToStringEquals("oneof_nested_message {\n  bb: 2\n  cc: 4\n}", result);
   }
 
+  @Test
   public void testToStringDefaultInstance() throws Exception {
     assertToStringEquals("", TestAllTypesLite.getDefaultInstance());
   }
 
+  @Test
   public void testToStringScalarFieldsSuffixedWithList() throws Exception {
     assertToStringEquals(
         "deceptively_named_list: 7",
         TestAllTypesLite.newBuilder().setDeceptivelyNamedList(7).build());
   }
 
+  @Test
   public void testToStringPrimitives() throws Exception {
     TestAllTypesLite proto =
         TestAllTypesLite.newBuilder()
@@ -1427,6 +1463,7 @@
   }
 
 
+  @Test
   public void testToStringStringFields() throws Exception {
     TestAllTypesLite proto =
         TestAllTypesLite.newBuilder().setOptionalString("foo\"bar\nbaz\\").build();
@@ -1436,6 +1473,7 @@
     assertToStringEquals("optional_string: \"\\346\\226\\207\"", proto);
   }
 
+  @Test
   public void testToStringNestedMessage() throws Exception {
     TestAllTypesLite proto =
         TestAllTypesLite.newBuilder()
@@ -1450,6 +1488,7 @@
     assertToStringEquals("optional_nested_message {\n  bb: 7\n}", proto);
   }
 
+  @Test
   public void testToStringRepeatedFields() throws Exception {
     TestAllTypesLite proto =
         TestAllTypesLite.newBuilder()
@@ -1468,6 +1507,7 @@
         "repeated_lazy_message {\n  bb: 7\n}\nrepeated_lazy_message {\n  bb: 8\n}", proto);
   }
 
+  @Test
   public void testToStringForeignFields() throws Exception {
     TestAllTypesLite proto =
         TestAllTypesLite.newBuilder()
@@ -1481,6 +1521,7 @@
         proto);
   }
 
+  @Test
   public void testToStringExtensions() throws Exception {
     TestAllExtensionsLite message =
         TestAllExtensionsLite.newBuilder()
@@ -1496,6 +1537,7 @@
         "[1]: 123\n[18] {\n  bb: 7\n}\n[21]: 3\n[44]: \"spam\"\n[44]: \"eggs\"", message);
   }
 
+  @Test
   public void testToStringUnknownFields() throws Exception {
     TestAllExtensionsLite messageWithExtensions =
         TestAllExtensionsLite.newBuilder()
@@ -1513,6 +1555,7 @@
         "1: 123\n18: \"\\b\\a\"\n21: 3\n44: \"spam\"\n44: \"eggs\"", messageWithUnknownFields);
   }
 
+  @Test
   public void testToStringLazyMessage() throws Exception {
     TestAllTypesLite message =
         TestAllTypesLite.newBuilder()
@@ -1521,6 +1564,7 @@
     assertToStringEquals("optional_lazy_message {\n  bb: 1\n}", message);
   }
 
+  @Test
   public void testToStringGroup() throws Exception {
     TestAllTypesLite message =
         TestAllTypesLite.newBuilder()
@@ -1529,11 +1573,13 @@
     assertToStringEquals("optional_group {\n  a: 1\n}", message);
   }
 
+  @Test
   public void testToStringOneof() throws Exception {
     TestAllTypesLite message = TestAllTypesLite.newBuilder().setOneofString("hello").build();
     assertToStringEquals("oneof_string: \"hello\"", message);
   }
 
+  @Test
   public void testToStringMapFields() throws Exception {
     TestMap message1 =
         TestMap.newBuilder()
@@ -1577,15 +1623,16 @@
   // comparison as it contains unstable addresses.
   private static void assertToStringEquals(String expected, MessageLite message) {
     String toString = message.toString();
-    assertEquals('#', toString.charAt(0));
+    assertThat(toString.charAt(0)).isEqualTo('#');
     if (toString.contains("\n")) {
       toString = toString.substring(toString.indexOf("\n") + 1);
     } else {
       toString = "";
     }
-    assertEquals(expected, toString);
+    assertThat(toString).isEqualTo(expected);
   }
 
+  @Test
   public void testParseLazy() throws Exception {
     ByteString bb =
         TestAllTypesLite.newBuilder()
@@ -1601,10 +1648,11 @@
     ByteString concat = bb.concat(cc);
     TestAllTypesLite message = TestAllTypesLite.parseFrom(concat);
 
-    assertEquals(11, message.getOptionalLazyMessage().getBb());
-    assertEquals(22L, message.getOptionalLazyMessage().getCc());
+    assertThat(message.getOptionalLazyMessage().getBb()).isEqualTo(11);
+    assertThat(message.getOptionalLazyMessage().getCc()).isEqualTo(22L);
   }
 
+  @Test
   public void testParseLazy_oneOf() throws Exception {
     ByteString bb =
         TestAllTypesLite.newBuilder()
@@ -1620,26 +1668,29 @@
     ByteString concat = bb.concat(cc);
     TestAllTypesLite message = TestAllTypesLite.parseFrom(concat);
 
-    assertEquals(11, message.getOneofLazyNestedMessage().getBb());
-    assertEquals(22L, message.getOneofLazyNestedMessage().getCc());
+    assertThat(message.getOneofLazyNestedMessage().getBb()).isEqualTo(11);
+    assertThat(message.getOneofLazyNestedMessage().getCc()).isEqualTo(22L);
   }
 
+  @Test
   public void testMergeFromStream_repeatedField() throws Exception {
     TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder().addRepeatedString("hello");
     builder.mergeFrom(CodedInputStream.newInstance(builder.build().toByteArray()));
 
-    assertEquals(2, builder.getRepeatedStringCount());
+    assertThat(builder.getRepeatedStringCount()).isEqualTo(2);
   }
 
+  @Test
   public void testMergeFromStream_invalidBytes() throws Exception {
     TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder().setDefaultBool(true);
     try {
       builder.mergeFrom(CodedInputStream.newInstance("Invalid bytes".getBytes(Internal.UTF_8)));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
   }
 
+  @Test
   public void testParseFromStream_IOExceptionNotLost() throws Exception {
     final IOException readException = new IOException();
     try {
@@ -1651,7 +1702,7 @@
                   throw readException;
                 }
               }));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
       boolean found = false;
       for (Throwable exception = expected; exception != null; exception = exception.getCause()) {
@@ -1666,6 +1717,7 @@
     }
   }
 
+  @Test
   public void testParseDelimitedFromStream_IOExceptionNotLost() throws Exception {
     final IOException readException = new IOException();
     try {
@@ -1676,7 +1728,7 @@
               throw readException;
             }
           });
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
       boolean found = false;
       for (Throwable exception = expected; exception != null; exception = exception.getCause()) {
@@ -1691,6 +1743,7 @@
     }
   }
 
+  @Test
   public void testParseFromArray_manyNestedMessagesError() throws Exception {
     RecursiveMessage.Builder recursiveMessage =
         RecursiveMessage.newBuilder().setPayload(ByteString.copyFrom(new byte[1]));
@@ -1705,7 +1758,7 @@
         0; // Set invalid tag
     try {
       RecursiveMessage.parseFrom(result);
-      fail("Result was: " + Arrays.toString(result));
+      assertWithMessage("Result was: " + Arrays.toString(result)).fail();
     } catch (InvalidProtocolBufferException expected) {
       boolean found = false;
       int exceptionCount = 0;
@@ -1733,6 +1786,7 @@
     }
   }
 
+  @Test
   public void testParseFromStream_manyNestedMessagesError() throws Exception {
     RecursiveMessage.Builder recursiveMessage =
         RecursiveMessage.newBuilder().setPayload(ByteString.copyFrom(new byte[1]));
@@ -1747,7 +1801,7 @@
         0; // Set invalid tag
     try {
       RecursiveMessage.parseFrom(CodedInputStream.newInstance(new ByteArrayInputStream(result)));
-      fail("Result was: " + Arrays.toString(result));
+      assertWithMessage("Result was: " + Arrays.toString(result)).fail();
     } catch (InvalidProtocolBufferException expected) {
       boolean found = false;
       int exceptionCount = 0;
@@ -1774,6 +1828,7 @@
     }
   }
 
+  @Test
   public void testParseFromStream_sneakyNestedException() throws Exception {
     final InvalidProtocolBufferException sketchy =
         new InvalidProtocolBufferException("Created in a sketchy way!")
@@ -1787,13 +1842,14 @@
                   throw sketchy;
                 }
               }));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
-      assertNotSame(expected, sketchy);
+      assertThat(expected).isNotSameInstanceAs(sketchy);
     }
-    assertEquals(sketchy.getUnfinishedMessage(), TestAllTypesLite.getDefaultInstance());
+    assertThat(sketchy.getUnfinishedMessage()).isEqualTo(TestAllTypesLite.getDefaultInstance());
   }
 
+  @Test
   public void testMergeFrom_sanity() throws Exception {
     TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
     byte[] bytes = one.toByteArray();
@@ -1801,388 +1857,391 @@
 
     one = one.toBuilder().mergeFrom(one).build();
     two = two.toBuilder().mergeFrom(bytes).build();
-    assertEquals(one, two);
-    assertEquals(two, one);
-    assertEquals(one.hashCode(), two.hashCode());
+    assertThat(one).isEqualTo(two);
+    assertThat(two).isEqualTo(one);
+    assertThat(one.hashCode()).isEqualTo(two.hashCode());
   }
 
+  @Test
   public void testMergeFromNoLazyFieldSharing() throws Exception {
     TestAllTypesLite.Builder sourceBuilder =
         TestAllTypesLite.newBuilder().setOptionalLazyMessage(NestedMessage.newBuilder().setBb(1));
     TestAllTypesLite.Builder targetBuilder =
         TestAllTypesLite.newBuilder().mergeFrom(sourceBuilder.build());
-    assertEquals(1, sourceBuilder.getOptionalLazyMessage().getBb());
+    assertThat(sourceBuilder.getOptionalLazyMessage().getBb()).isEqualTo(1);
     // now change the sourceBuilder, and target value shouldn't be affected.
     sourceBuilder.setOptionalLazyMessage(NestedMessage.newBuilder().setBb(2));
-    assertEquals(1, targetBuilder.getOptionalLazyMessage().getBb());
+    assertThat(targetBuilder.getOptionalLazyMessage().getBb()).isEqualTo(1);
   }
 
+  @Test
   public void testEquals_notEqual() throws Exception {
     TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
     byte[] bytes = one.toByteArray();
     TestAllTypesLite two = one.toBuilder().mergeFrom(one).mergeFrom(bytes).build();
 
-    assertFalse(one.equals(two));
-    assertFalse(two.equals(one));
+    assertThat(one.equals(two)).isFalse();
+    assertThat(two.equals(one)).isFalse();
 
-    assertFalse(one.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(one));
+    assertThat(one.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(one)).isFalse();
 
     TestAllTypesLite oneFieldSet = TestAllTypesLite.newBuilder().setDefaultBool(true).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultCord("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultCordBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultDouble(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultFixed32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultFixed64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultFloat(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder()
             .setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
             .build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder().setDefaultImportEnum(ImportEnumLite.IMPORT_LITE_BAR).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultInt32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultInt64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultNestedEnum(NestedEnum.BAR).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSfixed32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSfixed64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSint32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSint64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultString("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultStringBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultStringPiece("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder().setDefaultStringPieceBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultUint32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setDefaultUint64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedBool(true).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedCord("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedCordBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedDouble(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedFixed32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedFixed64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedFloat(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder()
             .addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
             .build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder().addRepeatedImportEnum(ImportEnumLite.IMPORT_LITE_BAR).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedInt32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedInt64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedNestedEnum(NestedEnum.BAR).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSfixed32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSfixed64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSint32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSint64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedString("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedStringBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedStringPiece("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder().addRepeatedStringPieceBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedUint32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedUint64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalBool(true).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalCord("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalCordBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalDouble(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalFixed32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalFixed64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalFloat(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder()
             .setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
             .build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder().setOptionalImportEnum(ImportEnumLite.IMPORT_LITE_BAR).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalInt32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalInt64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalNestedEnum(NestedEnum.BAR).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSfixed32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSfixed64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSint32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSint64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalString("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalStringBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalStringPiece("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder().setOptionalStringPieceBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalUint32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOptionalUint64(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOneofBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder()
             .setOneofLazyNestedMessage(NestedMessage.getDefaultInstance())
             .build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder()
             .setOneofNestedMessage(NestedMessage.getDefaultInstance())
             .build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOneofString("").build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOneofStringBytes(ByteString.EMPTY).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet = TestAllTypesLite.newBuilder().setOneofUint32(0).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder()
             .setOptionalForeignMessage(ForeignMessageLite.getDefaultInstance())
             .build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder().setOptionalGroup(OptionalGroup.getDefaultInstance()).build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder()
             .setOptionalPublicImportMessage(PublicImportMessageLite.getDefaultInstance())
             .build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
 
     oneFieldSet =
         TestAllTypesLite.newBuilder()
             .setOptionalLazyMessage(NestedMessage.getDefaultInstance())
             .build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
 
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
     oneFieldSet =
         TestAllTypesLite.newBuilder()
             .addRepeatedLazyMessage(NestedMessage.getDefaultInstance())
             .build();
-    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
-    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    assertThat(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())).isFalse();
+    assertThat(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)).isFalse();
   }
 
+  @Test
   public void testEquals() throws Exception {
     // Check that two identical objs are equal.
     Foo foo1a = Foo.newBuilder().setValue(1).addBar(Bar.newBuilder().setName("foo1")).build();
@@ -2190,19 +2249,20 @@
     Foo foo2 = Foo.newBuilder().setValue(1).addBar(Bar.newBuilder().setName("foo2")).build();
 
     // Check that equals is doing value rather than object equality.
-    assertEquals(foo1a, foo1b);
-    assertEquals(foo1a.hashCode(), foo1b.hashCode());
+    assertThat(foo1a).isEqualTo(foo1b);
+    assertThat(foo1a.hashCode()).isEqualTo(foo1b.hashCode());
 
     // Check that a different object is not equal.
-    assertFalse(foo1a.equals(foo2));
+    assertThat(foo1a.equals(foo2)).isFalse();
 
     // Check that two objects which have different types but the same field values are not
     // considered to be equal.
     Bar bar = Bar.newBuilder().setName("bar").build();
     BarPrime barPrime = BarPrime.newBuilder().setName("bar").build();
-    assertFalse(bar.equals(barPrime));
+    assertThat(bar).isNotEqualTo((Object) barPrime); // compiler already won't let this happen.
   }
 
+  @Test
   public void testEqualsAndHashCodeForTrickySchemaTypes() {
     Foo foo1 = Foo.getDefaultInstance();
     Foo foo2 = Foo.newBuilder().setSint64(1).build();
@@ -2214,6 +2274,7 @@
     assertEqualsAndHashCodeAreFalse(foo1, foo4);
   }
 
+  @Test
   public void testOneofEquals() throws Exception {
     TestOneofEquals.Builder builder = TestOneofEquals.newBuilder();
     TestOneofEquals message1 = builder.build();
@@ -2221,20 +2282,21 @@
     // check with the oneof case.
     builder.setName("");
     TestOneofEquals message2 = builder.build();
-    assertFalse(message1.equals(message2));
+    assertThat(message1.equals(message2)).isFalse();
   }
 
+  @Test
   public void testEquals_sanity() throws Exception {
     TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
     TestAllTypesLite two = TestAllTypesLite.parseFrom(one.toByteArray());
-    assertEquals(one, two);
-    assertEquals(one.hashCode(), two.hashCode());
+    assertThat(one).isEqualTo(two);
+    assertThat(one.hashCode()).isEqualTo(two.hashCode());
 
-    assertEquals(
-        one.toBuilder().mergeFrom(two).build(),
-        two.toBuilder().mergeFrom(two.toByteArray()).build());
+    assertThat(one.toBuilder().mergeFrom(two).build())
+        .isEqualTo(two.toBuilder().mergeFrom(two.toByteArray()).build());
   }
 
+  @Test
   public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException {
     Foo fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
 
@@ -2251,6 +2313,7 @@
     assertEqualsAndHashCodeAreFalse(fooWithValueAndExtension, fooWithValueAndUnknownFields);
   }
 
+  @Test
   public void testEqualsAndHashCodeWithExtensions() throws InvalidProtocolBufferException {
     Foo fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
 
@@ -2265,6 +2328,7 @@
   }
 
   // Test to ensure we avoid a class cast exception with oneofs.
+  @Test
   public void testEquals_oneOfMessages() {
     TestAllTypesLite mine = TestAllTypesLite.newBuilder().setOneofString("Hello").build();
 
@@ -2273,10 +2337,11 @@
             .setOneofNestedMessage(NestedMessage.getDefaultInstance())
             .build();
 
-    assertFalse(mine.equals(other));
-    assertFalse(other.equals(mine));
+    assertThat(mine.equals(other)).isFalse();
+    assertThat(other.equals(mine)).isFalse();
   }
 
+  @Test
   public void testHugeFieldNumbers() throws InvalidProtocolBufferException {
     TestHugeFieldNumbersLite message =
         TestHugeFieldNumbersLite.newBuilder()
@@ -2289,23 +2354,25 @@
 
     TestHugeFieldNumbersLite parsedMessage =
         TestHugeFieldNumbersLite.parseFrom(message.toByteArray());
-    assertEquals(1, parsedMessage.getOptionalInt32());
-    assertEquals(2, parsedMessage.getRepeatedInt32(0));
-    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, parsedMessage.getOptionalEnum());
-    assertEquals("xyz", parsedMessage.getOptionalString());
-    assertEquals(3, parsedMessage.getOptionalMessage().getC());
+    assertThat(parsedMessage.getOptionalInt32()).isEqualTo(1);
+    assertThat(parsedMessage.getRepeatedInt32(0)).isEqualTo(2);
+    assertThat(parsedMessage.getOptionalEnum()).isEqualTo(ForeignEnumLite.FOREIGN_LITE_FOO);
+    assertThat(parsedMessage.getOptionalString()).isEqualTo("xyz");
+    assertThat(parsedMessage.getOptionalMessage().getC()).isEqualTo(3);
   }
 
   private void assertEqualsAndHashCodeAreFalse(Object o1, Object o2) {
-    assertFalse(o1.equals(o2));
-    assertFalse(o1.hashCode() == o2.hashCode());
+    assertThat(o1.equals(o2)).isFalse();
+    assertThat(o1.hashCode()).isNotEqualTo(o2.hashCode());
   }
 
+  @Test
   public void testRecursiveHashcode() {
     // This tests that we don't infinite loop.
-    TestRecursiveOneof.getDefaultInstance().hashCode();
+    int unused = TestRecursiveOneof.getDefaultInstance().hashCode();
   }
 
+  @Test
   public void testParseFromByteBuffer() throws Exception {
     TestAllTypesLite message =
         TestAllTypesLite.newBuilder()
@@ -2317,13 +2384,14 @@
     TestAllTypesLite copy =
         TestAllTypesLite.parseFrom(message.toByteString().asReadOnlyByteBuffer());
 
-    assertEquals(message, copy);
+    assertThat(message).isEqualTo(copy);
   }
 
+  @Test
   public void testParseFromByteBufferThrows() {
     try {
       TestAllTypesLite.parseFrom(ByteBuffer.wrap(new byte[] {0x5}));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
 
@@ -2333,14 +2401,14 @@
     ByteBuffer buffer = ByteBuffer.wrap(message.toByteArray(), 0, message.getSerializedSize() - 1);
     try {
       TestAllTypesLite.parseFrom(buffer);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
-      assertEquals(
-          TestAllTypesLite.newBuilder().setOptionalInt32(123).build(),
-          expected.getUnfinishedMessage());
+      assertThat(TestAllTypesLite.newBuilder().setOptionalInt32(123).build())
+          .isEqualTo(expected.getUnfinishedMessage());
     }
   }
 
+  @Test
   public void testParseFromByteBuffer_extensions() throws Exception {
     TestAllExtensionsLite message =
         TestAllExtensionsLite.newBuilder()
@@ -2358,15 +2426,16 @@
     TestAllExtensionsLite copy =
         TestAllExtensionsLite.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry);
 
-    assertEquals(message, copy);
+    assertThat(message).isEqualTo(copy);
   }
 
+  @Test
   public void testParseFromByteBufferThrows_extensions() {
     ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
     UnittestLite.registerAllExtensions(registry);
     try {
       TestAllExtensionsLite.parseFrom(ByteBuffer.wrap(new byte[] {0x5}), registry);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
     }
 
@@ -2379,17 +2448,18 @@
     ByteBuffer buffer = ByteBuffer.wrap(message.toByteArray(), 0, message.getSerializedSize() - 1);
     try {
       TestAllExtensionsLite.parseFrom(buffer, registry);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
-      assertEquals(
-          TestAllExtensionsLite.newBuilder()
-              .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
-              .build(),
-          expected.getUnfinishedMessage());
+      assertThat(
+              TestAllExtensionsLite.newBuilder()
+                  .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+                  .build())
+          .isEqualTo(expected.getUnfinishedMessage());
     }
   }
 
   // Make sure we haven't screwed up the code generation for packing fields by default.
+  @Test
   public void testPackedSerialization() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     builder.addRepeatedInt32(4321);
@@ -2400,11 +2470,12 @@
 
     while (!in.isAtEnd()) {
       int tag = in.readTag();
-      assertEquals(WireFormat.WIRETYPE_LENGTH_DELIMITED, WireFormat.getTagWireType(tag));
+      assertThat(WireFormat.getTagWireType(tag)).isEqualTo(WireFormat.WIRETYPE_LENGTH_DELIMITED);
       in.skipField(tag);
     }
   }
 
+  @Test
   public void testAddAllIteratesOnce() {
     TestAllTypesLite unused =
         TestAllTypesLite.newBuilder()
@@ -2428,133 +2499,134 @@
             .build();
   }
 
+  @Test
   public void testAddAllIteratesOnce_throwsOnNull() {
     TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
     try {
       builder.addAllRepeatedBool(new OneTimeIterableList<>(true, false, null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 2 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedBoolCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 2 is null.");
+      assertThat(builder.getRepeatedBoolCount()).isEqualTo(0);
     }
 
     try {
       builder.addAllRepeatedBool(new OneTimeIterable<>(true, false, null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 2 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedBoolCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 2 is null.");
+      assertThat(builder.getRepeatedBoolCount()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedBool(new OneTimeIterableList<>((Boolean) null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 0 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedBoolCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 0 is null.");
+      assertThat(builder.getRepeatedBoolCount()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedInt32(new OneTimeIterableList<>((Integer) null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 0 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedInt32Count());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 0 is null.");
+      assertThat(builder.getRepeatedInt32Count()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedInt64(new OneTimeIterableList<>((Long) null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 0 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedInt64Count());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 0 is null.");
+      assertThat(builder.getRepeatedInt64Count()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedFloat(new OneTimeIterableList<>((Float) null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 0 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedFloatCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 0 is null.");
+      assertThat(builder.getRepeatedFloatCount()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedDouble(new OneTimeIterableList<>((Double) null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 0 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedDoubleCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 0 is null.");
+      assertThat(builder.getRepeatedDoubleCount()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedBytes(new OneTimeIterableList<>((ByteString) null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 0 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedBytesCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 0 is null.");
+      assertThat(builder.getRepeatedBytesCount()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedString(new OneTimeIterableList<>("", "", null, ""));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 2 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedStringCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 2 is null.");
+      assertThat(builder.getRepeatedStringCount()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedString(new OneTimeIterable<>("", "", null, ""));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 2 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedStringCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 2 is null.");
+      assertThat(builder.getRepeatedStringCount()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedString(new OneTimeIterableList<>((String) null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 0 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedStringCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 0 is null.");
+      assertThat(builder.getRepeatedStringCount()).isEqualTo(0);
     }
 
     try {
       builder = TestAllTypesLite.newBuilder();
       builder.addAllRepeatedNestedMessage(new OneTimeIterableList<>((NestedMessage) null));
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
-      assertEquals("Element at index 0 is null.", expected.getMessage());
-      assertEquals(0, builder.getRepeatedNestedMessageCount());
+      assertThat(expected).hasMessageThat().isEqualTo("Element at index 0 is null.");
+      assertThat(builder.getRepeatedNestedMessageCount()).isEqualTo(0);
     }
   }
 
+  @Test
   public void testExtensionRenamesKeywords() {
-    assertTrue(NonNestedExtensionLite.package_ instanceof GeneratedMessageLite.GeneratedExtension);
-    assertTrue(
-        NestedExtensionLite.MyNestedExtensionLite.private_
-            instanceof GeneratedMessageLite.GeneratedExtension);
+    assertThat(NonNestedExtensionLite.package_)
+        .isInstanceOf(GeneratedMessageLite.GeneratedExtension.class);
+    assertThat(NestedExtensionLite.MyNestedExtensionLite.private_)
+        .isInstanceOf(GeneratedMessageLite.GeneratedExtension.class);
 
     NonNestedExtensionLite.MessageLiteToBeExtended msg =
         NonNestedExtensionLite.MessageLiteToBeExtended.newBuilder()
             .setExtension(NonNestedExtensionLite.package_, true)
             .build();
-    assertTrue(msg.getExtension(NonNestedExtensionLite.package_));
+    assertThat(msg.getExtension(NonNestedExtensionLite.package_)).isTrue();
 
     msg =
         NonNestedExtensionLite.MessageLiteToBeExtended.newBuilder()
             .setExtension(NestedExtensionLite.MyNestedExtensionLite.private_, 2.4)
             .build();
-    assertEquals(
-        2.4, msg.getExtension(NestedExtensionLite.MyNestedExtensionLite.private_), 0.001);
+    assertThat(msg.getExtension(NestedExtensionLite.MyNestedExtensionLite.private_)).isEqualTo(2.4);
   }
 
   private static final class OneTimeIterableList<T> extends ArrayList<T> {
@@ -2567,7 +2639,7 @@
     @Override
     public Iterator<T> iterator() {
       if (wasIterated) {
-        fail();
+        assertWithMessage("expected exception").fail();
       }
       wasIterated = true;
       return super.iterator();
@@ -2585,21 +2657,23 @@
     @Override
     public Iterator<T> iterator() {
       if (wasIterated) {
-        fail();
+        assertWithMessage("expected exception").fail();
       }
       wasIterated = true;
       return list.iterator();
     }
   }
 
+  @Test
   public void testNullExtensionRegistry() throws Exception {
     try {
       TestAllTypesLite.parseFrom(new byte[] {}, null);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (NullPointerException expected) {
     }
   }
 
+  @Test
   public void testSerializeToOutputStreamThrowsIOException() {
     try {
       TestAllTypesLite.newBuilder()
@@ -2613,11 +2687,12 @@
                   throw new IOException();
                 }
               });
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (IOException expected) {
     }
   }
 
+  @Test
   public void testUnpairedSurrogatesReplacedByQuestionMark() throws InvalidProtocolBufferException {
     String testString = "foo \ud83d bar";
     String expectedString = "foo ? bar";
@@ -2629,15 +2704,16 @@
     // Behavior is compatible with String.getBytes("UTF-8"), which replaces
     // unpaired surrogates with a question mark.
     TestAllTypesLite parsedMessage = TestAllTypesLite.parseFrom(serializedMessage);
-    assertEquals(expectedString, parsedMessage.getOptionalString());
+    assertThat(parsedMessage.getOptionalString()).isEqualTo(expectedString);
 
     // Conversion happens during serialization.
     ByteString expectedBytes = ByteString.copyFromUtf8(expectedString);
-    assertTrue(
-        String.format(
-            "Expected serializedMessage (%s) to contain \"%s\" (%s).",
-            encodeHex(serializedMessage), expectedString, encodeHex(expectedBytes)),
-        contains(serializedMessage, expectedBytes));
+    assertWithMessage(
+            String.format(
+                "Expected serializedMessage (%s) to contain \"%s\" (%s).",
+                encodeHex(serializedMessage), expectedString, encodeHex(expectedBytes)))
+        .that(contains(serializedMessage, expectedBytes))
+        .isTrue();
   }
 
   private String encodeHex(ByteString bytes) {
diff --git a/java/util/src/main/java/com/google/protobuf/util/Durations.java b/java/util/src/main/java/com/google/protobuf/util/Durations.java
index fd13771..f81da1f 100644
--- a/java/util/src/main/java/com/google/protobuf/util/Durations.java
+++ b/java/util/src/main/java/com/google/protobuf/util/Durations.java
@@ -43,6 +43,7 @@
 import static com.google.protobuf.util.Timestamps.NANOS_PER_SECOND;
 
 import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.CompileTimeConstant;
 import com.google.protobuf.Duration;
 import java.io.Serializable;
 import java.text.ParseException;
@@ -275,6 +276,25 @@
     }
   }
 
+  /**
+   * Parses a string in RFC 3339 format into a {@link Duration}.
+   *
+   * <p>Identical to {@link #parse(String)}, but throws an {@link IllegalArgumentException} instead
+   * of a {@link ParseException} if parsing fails.
+   *
+   * @return a {@link Duration} parsed from the string
+   * @throws IllegalArgumentException if parsing fails
+   */
+  public static Duration parseUnchecked(@CompileTimeConstant String value) {
+    try {
+      return parse(value);
+    } catch (ParseException e) {
+      // While `java.time.format.DateTimeParseException` is a more accurate representation of the
+      // failure, this library is currently not JDK8 ready because of Android dependencies.
+      throw new IllegalArgumentException(e);
+    }
+  }
+
   // Static factories
 
   /** Create a Duration from the number of days. */
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
index c32d10a..2de2bd1 100644
--- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
@@ -398,4 +398,21 @@
   public static void merge(FieldMask mask, Message source, Message.Builder destination) {
     merge(mask, source, destination, new MergeOptions());
   }
+
+  /**
+   * Returns the result of merging the given proto with the given mask and a default instance.
+   */
+  public static <P extends Message> P trim(FieldMask mask, P source) {
+   return trim(mask, source, new MergeOptions());
+  }
+
+   /**
+   * Returns the result of merging the given proto with the given mask and a default instance.
+   */
+  @SuppressWarnings("unchecked")
+  public static <P extends Message> P trim(FieldMask mask, P source, MergeOptions options) {
+    Message.Builder destination = source.newBuilderForType();
+    merge(mask, source, destination, options);
+    return (P) destination.build();
+  }
 }
diff --git a/java/util/src/main/java/com/google/protobuf/util/Timestamps.java b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
index fe9b9a5..8461f67 100644
--- a/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
+++ b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
@@ -37,6 +37,7 @@
 import static com.google.common.math.LongMath.checkedSubtract;
 
 import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.CompileTimeConstant;
 import com.google.protobuf.Duration;
 import com.google.protobuf.Timestamp;
 import java.io.Serializable;
@@ -283,6 +284,25 @@
     }
   }
 
+  /**
+   * Parses a string in RFC 3339 format into a {@link Timestamp}.
+   *
+   * <p>Identical to {@link #parse(String)}, but throws an {@link IllegalArgumentException} instead
+   * of a {@link ParseException} if parsing fails.
+   *
+   * @return a {@link Timestamp} parsed from the string
+   * @throws IllegalArgumentException if parsing fails
+   */
+  public static Timestamp parseUnchecked(@CompileTimeConstant String value) {
+    try {
+      return parse(value);
+    } catch (ParseException e) {
+      // While `java.time.format.DateTimeParseException` is a more accurate representation of the
+      // failure, this library is currently not JDK8 ready because of Android dependencies.
+      throw new IllegalArgumentException(e);
+    }
+  }
+
   /** Create a Timestamp from the number of seconds elapsed from the epoch. */
   @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static Timestamp fromSeconds(long seconds) {
diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
index c829722..98aef02 100644
--- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
@@ -40,9 +40,13 @@
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto.TestRequiredMessage;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class FieldMaskTreeTest extends TestCase {
+@RunWith(JUnit4.class)
+public class FieldMaskTreeTest {
+  @Test
   public void testAddFieldPath() throws Exception {
     FieldMaskTree tree = new FieldMaskTree();
     assertThat(tree.toString()).isEmpty();
@@ -50,31 +54,33 @@
     assertThat(tree.toString()).isEmpty();
     // New branch.
     tree.addFieldPath("foo");
-    assertEquals("foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("foo");
     // Redundant path.
     tree.addFieldPath("foo");
-    assertEquals("foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("foo");
     // New branch.
     tree.addFieldPath("bar.baz");
-    assertEquals("bar.baz,foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("bar.baz,foo");
     // Redundant sub-path.
     tree.addFieldPath("foo.bar");
-    assertEquals("bar.baz,foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("bar.baz,foo");
     // New branch from a non-root node.
     tree.addFieldPath("bar.quz");
-    assertEquals("bar.baz,bar.quz,foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("bar.baz,bar.quz,foo");
     // A path that matches several existing sub-paths.
     tree.addFieldPath("bar");
-    assertEquals("bar,foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("bar,foo");
   }
 
+  @Test
   public void testMergeFromFieldMask() throws Exception {
     FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
-    assertEquals("bar.baz,bar.quz,foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("bar.baz,bar.quz,foo");
     tree.mergeFromFieldMask(FieldMaskUtil.fromString("foo.bar,bar"));
-    assertEquals("bar,foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("bar,foo");
   }
 
+  @Test
   public void testRemoveFieldPath() throws Exception {
     String initialTreeString = "bar.baz,bar.quz.bar,foo";
     FieldMaskTree tree;
@@ -82,41 +88,43 @@
     // Empty path.
     tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("");
-    assertEquals(initialTreeString, tree.toString());
+    assertThat(tree.toString()).isEqualTo(initialTreeString);
 
     // Non-exist sub-path of an existing leaf.
     tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("foo.bar");
-    assertEquals(initialTreeString, tree.toString());
+    assertThat(tree.toString()).isEqualTo(initialTreeString);
 
     // Non-exist path.
     tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("bar.foo");
-    assertEquals(initialTreeString, tree.toString());
+    assertThat(tree.toString()).isEqualTo(initialTreeString);
 
     // Match an existing leaf node -> remove leaf node.
     tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("foo");
-    assertEquals("bar.baz,bar.quz.bar", tree.toString());
+    assertThat(tree.toString()).isEqualTo("bar.baz,bar.quz.bar");
 
     // Match sub-path of an existing leaf node -> recursive removal.
     tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("bar.quz.bar");
-    assertEquals("bar.baz,foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("bar.baz,foo");
 
     // Match a non-leaf node -> remove all children.
     tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("bar");
-    assertEquals("foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("foo");
   }
 
+  @Test
   public void testRemoveFromFieldMask() throws Exception {
     FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
-    assertEquals("bar.baz,bar.quz,foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("bar.baz,bar.quz,foo");
     tree.removeFromFieldMask(FieldMaskUtil.fromString("foo.bar,bar"));
-    assertEquals("foo", tree.toString());
+    assertThat(tree.toString()).isEqualTo("foo");
   }
 
+  @Test
   public void testIntersectFieldPath() throws Exception {
     FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
     FieldMaskTree result = new FieldMaskTree();
@@ -128,18 +136,19 @@
     assertThat(result.toString()).isEmpty();
     // Sub-path of an existing leaf.
     tree.intersectFieldPath("foo.bar", result);
-    assertEquals("foo.bar", result.toString());
+    assertThat(result.toString()).isEqualTo("foo.bar");
     // Match an existing leaf node.
     tree.intersectFieldPath("foo", result);
-    assertEquals("foo", result.toString());
+    assertThat(result.toString()).isEqualTo("foo");
     // Non-exist path.
     tree.intersectFieldPath("bar.foo", result);
-    assertEquals("foo", result.toString());
+    assertThat(result.toString()).isEqualTo("foo");
     // Match a non-leaf node.
     tree.intersectFieldPath("bar", result);
-    assertEquals("bar.baz,bar.quz,foo", result.toString());
+    assertThat(result.toString()).isEqualTo("bar.baz,bar.quz,foo");
   }
 
+  @Test
   public void testMerge() throws Exception {
     testMergeImpl(true);
     testMergeImpl(false);
@@ -183,10 +192,10 @@
         builder,
         options,
         useDynamicMessage);
-    assertTrue(builder.hasRequiredMessage());
-    assertTrue(builder.getRequiredMessage().hasA());
-    assertFalse(builder.getRequiredMessage().hasB());
-    assertFalse(builder.getRequiredMessage().hasC());
+    assertThat(builder.hasRequiredMessage()).isTrue();
+    assertThat(builder.getRequiredMessage().hasA()).isTrue();
+    assertThat(builder.getRequiredMessage().hasB()).isFalse();
+    assertThat(builder.getRequiredMessage().hasC()).isFalse();
     merge(
         new FieldMaskTree().addFieldPath("required_message.b").addFieldPath("required_message.c"),
         source,
@@ -194,7 +203,7 @@
         options,
         useDynamicMessage);
     try {
-      assertEquals(builder.build(), source);
+      assertThat(source).isEqualTo(builder.build());
     } catch (UninitializedMessageException e) {
       throw new AssertionError("required field isn't set", e);
     }
@@ -232,7 +241,7 @@
     merge(new FieldMaskTree(), source, builder, options, useDynamicMessage);
     NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().addRepeatedInt32(1000);
-    assertEquals(expected.build(), builder.build());
+    assertThat(builder.build()).isEqualTo(expected.build());
 
     // Test merging each individual field.
     builder = NestedTestAllTypes.newBuilder();
@@ -240,28 +249,28 @@
         source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().setOptionalInt32(1234);
-    assertEquals(expected.build(), builder.build());
+    assertThat(builder.build()).isEqualTo(expected.build());
 
     builder = NestedTestAllTypes.newBuilder();
     merge(new FieldMaskTree().addFieldPath("payload.optional_nested_message"),
         source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
-    assertEquals(expected.build(), builder.build());
+    assertThat(builder.build()).isEqualTo(expected.build());
 
     builder = NestedTestAllTypes.newBuilder();
     merge(new FieldMaskTree().addFieldPath("payload.repeated_int32"),
         source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().addRepeatedInt32(4321);
-    assertEquals(expected.build(), builder.build());
+    assertThat(builder.build()).isEqualTo(expected.build());
 
     builder = NestedTestAllTypes.newBuilder();
     merge(new FieldMaskTree().addFieldPath("payload.repeated_nested_message"),
         source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
-    assertEquals(expected.build(), builder.build());
+    assertThat(builder.build()).isEqualTo(expected.build());
 
     builder = NestedTestAllTypes.newBuilder();
     merge(
@@ -272,7 +281,7 @@
         useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected.getChildBuilder().getPayloadBuilder().setOptionalInt32(1234);
-    assertEquals(expected.build(), builder.build());
+    assertThat(builder.build()).isEqualTo(expected.build());
 
     builder = NestedTestAllTypes.newBuilder();
     merge(
@@ -286,14 +295,14 @@
         .getChildBuilder()
         .getPayloadBuilder()
         .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
-    assertEquals(expected.build(), builder.build());
+    assertThat(builder.build()).isEqualTo(expected.build());
 
     builder = NestedTestAllTypes.newBuilder();
     merge(new FieldMaskTree().addFieldPath("child.payload.repeated_int32"),
         source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected.getChildBuilder().getPayloadBuilder().addRepeatedInt32(4321);
-    assertEquals(expected.build(), builder.build());
+    assertThat(builder.build()).isEqualTo(expected.build());
 
     builder = NestedTestAllTypes.newBuilder();
     merge(new FieldMaskTree().addFieldPath("child.payload.repeated_nested_message"),
@@ -303,13 +312,13 @@
         .getChildBuilder()
         .getPayloadBuilder()
         .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
-    assertEquals(expected.build(), builder.build());
+    assertThat(builder.build()).isEqualTo(expected.build());
 
     // Test merging all fields.
     builder = NestedTestAllTypes.newBuilder();
     merge(new FieldMaskTree().addFieldPath("child").addFieldPath("payload"),
         source, builder, options, useDynamicMessage);
-    assertEquals(source, builder.build());
+    assertThat(builder.build()).isEqualTo(source);
 
     // Test repeated options.
     builder = NestedTestAllTypes.newBuilder();
@@ -317,15 +326,15 @@
     merge(new FieldMaskTree().addFieldPath("payload.repeated_int32"),
         source, builder, options, useDynamicMessage);
     // Default behavior is to append repeated fields.
-    assertEquals(2, builder.getPayload().getRepeatedInt32Count());
-    assertEquals(1000, builder.getPayload().getRepeatedInt32(0));
-    assertEquals(4321, builder.getPayload().getRepeatedInt32(1));
+    assertThat(builder.getPayload().getRepeatedInt32Count()).isEqualTo(2);
+    assertThat(builder.getPayload().getRepeatedInt32(0)).isEqualTo(1000);
+    assertThat(builder.getPayload().getRepeatedInt32(1)).isEqualTo(4321);
     // Change to replace repeated fields.
     options.setReplaceRepeatedFields(true);
     merge(new FieldMaskTree().addFieldPath("payload.repeated_int32"),
         source, builder, options, useDynamicMessage);
-    assertEquals(1, builder.getPayload().getRepeatedInt32Count());
-    assertEquals(4321, builder.getPayload().getRepeatedInt32(0));
+    assertThat(builder.getPayload().getRepeatedInt32Count()).isEqualTo(1);
+    assertThat(builder.getPayload().getRepeatedInt32(0)).isEqualTo(4321);
 
     // Test message options.
     builder = NestedTestAllTypes.newBuilder();
@@ -334,21 +343,21 @@
     merge(new FieldMaskTree().addFieldPath("payload"),
         source, builder, options, useDynamicMessage);
     // Default behavior is to merge message fields.
-    assertEquals(1234, builder.getPayload().getOptionalInt32());
-    assertEquals(2000, builder.getPayload().getOptionalUint32());
+    assertThat(builder.getPayload().getOptionalInt32()).isEqualTo(1234);
+    assertThat(builder.getPayload().getOptionalUint32()).isEqualTo(2000);
 
     // Test merging unset message fields.
     NestedTestAllTypes clearedSource = source.toBuilder().clearPayload().build();
     builder = NestedTestAllTypes.newBuilder();
     merge(new FieldMaskTree().addFieldPath("payload"),
         clearedSource, builder, options, useDynamicMessage);
-    assertEquals(false, builder.hasPayload());
+    assertThat(builder.hasPayload()).isFalse();
 
     // Skip a message field if they are unset in both source and target.
     builder = NestedTestAllTypes.newBuilder();
     merge(new FieldMaskTree().addFieldPath("payload.optional_int32"),
         clearedSource, builder, options, useDynamicMessage);
-    assertEquals(false, builder.hasPayload());
+    assertThat(builder.hasPayload()).isFalse();
 
     // Change to replace message fields.
     options.setReplaceMessageFields(true);
@@ -357,8 +366,8 @@
     builder.getPayloadBuilder().setOptionalUint32(2000);
     merge(new FieldMaskTree().addFieldPath("payload"),
         source, builder, options, useDynamicMessage);
-    assertEquals(1234, builder.getPayload().getOptionalInt32());
-    assertEquals(0, builder.getPayload().getOptionalUint32());
+    assertThat(builder.getPayload().getOptionalInt32()).isEqualTo(1234);
+    assertThat(builder.getPayload().getOptionalUint32()).isEqualTo(0);
 
     // Test merging unset message fields.
     builder = NestedTestAllTypes.newBuilder();
@@ -366,7 +375,7 @@
     builder.getPayloadBuilder().setOptionalUint32(2000);
     merge(new FieldMaskTree().addFieldPath("payload"),
         clearedSource, builder, options, useDynamicMessage);
-    assertEquals(false, builder.hasPayload());
+    assertThat(builder.hasPayload()).isFalse();
 
     // Test merging unset primitive fields.
     builder = source.toBuilder();
@@ -375,15 +384,15 @@
     builder = source.toBuilder();
     merge(new FieldMaskTree().addFieldPath("payload.optional_int32"),
         sourceWithPayloadInt32Unset, builder, options, useDynamicMessage);
-    assertEquals(true, builder.getPayload().hasOptionalInt32());
-    assertEquals(0, builder.getPayload().getOptionalInt32());
+    assertThat(builder.getPayload().hasOptionalInt32()).isTrue();
+    assertThat(builder.getPayload().getOptionalInt32()).isEqualTo(0);
 
     // Change to clear unset primitive fields.
     options.setReplacePrimitiveFields(true);
     builder = source.toBuilder();
     merge(new FieldMaskTree().addFieldPath("payload.optional_int32"),
         sourceWithPayloadInt32Unset, builder, options, useDynamicMessage);
-    assertEquals(true, builder.hasPayload());
-    assertEquals(false, builder.getPayload().hasOptionalInt32());
+    assertThat(builder.hasPayload()).isTrue();
+    assertThat(builder.getPayload().hasOptionalInt32()).isFalse();
   }
 }
diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
index 28e43a7..367fe52 100644
--- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
@@ -31,57 +31,72 @@
 package com.google.protobuf.util;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import com.google.common.collect.ImmutableList;
 import com.google.protobuf.FieldMask;
 import protobuf_unittest.UnittestProto.NestedTestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /** Unit tests for {@link FieldMaskUtil}. */
-public class FieldMaskUtilTest extends TestCase {
+@RunWith(JUnit4.class)
+public class FieldMaskUtilTest {
+  @Test
   public void testIsValid() throws Exception {
-    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload"));
-    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "nonexist"));
-    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_int32"));
-    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_int32"));
-    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_nested_message"));
-    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_nested_message"));
-    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.nonexist"));
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload")).isTrue();
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.class, "nonexist")).isFalse();
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_int32")).isTrue();
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_int32")).isTrue();
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_nested_message"))
+        .isTrue();
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_nested_message"))
+        .isTrue();
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.nonexist")).isFalse();
 
-    assertTrue(
-        FieldMaskUtil.isValid(NestedTestAllTypes.class, FieldMaskUtil.fromString("payload")));
-    assertFalse(
-        FieldMaskUtil.isValid(NestedTestAllTypes.class, FieldMaskUtil.fromString("nonexist")));
-    assertFalse(
-        FieldMaskUtil.isValid(
-            NestedTestAllTypes.class, FieldMaskUtil.fromString("payload,nonexist")));
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.class, FieldMaskUtil.fromString("payload")))
+        .isTrue();
+    assertThat(
+            FieldMaskUtil.isValid(NestedTestAllTypes.class, FieldMaskUtil.fromString("nonexist")))
+        .isFalse();
+    assertThat(
+            FieldMaskUtil.isValid(
+                NestedTestAllTypes.class, FieldMaskUtil.fromString("payload,nonexist")))
+        .isFalse();
 
-    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "payload"));
-    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "nonexist"));
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "payload")).isTrue();
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "nonexist")).isFalse();
 
-    assertTrue(
-        FieldMaskUtil.isValid(
-            NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("payload")));
-    assertFalse(
-        FieldMaskUtil.isValid(
-            NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("nonexist")));
+    assertThat(
+            FieldMaskUtil.isValid(
+                NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("payload")))
+        .isTrue();
+    assertThat(
+            FieldMaskUtil.isValid(
+                NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("nonexist")))
+        .isFalse();
 
-    assertTrue(
-        FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_nested_message.bb"));
+    assertThat(
+            FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_nested_message.bb"))
+        .isTrue();
     // Repeated fields cannot have sub-paths.
-    assertFalse(
-        FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_nested_message.bb"));
+    assertThat(
+            FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_nested_message.bb"))
+        .isFalse();
     // Non-message fields cannot have sub-paths.
-    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_int32.bb"));
+    assertThat(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_int32.bb"))
+        .isFalse();
   }
 
+  @Test
   public void testToString() throws Exception {
-    assertEquals("", FieldMaskUtil.toString(FieldMask.getDefaultInstance()));
+    assertThat(FieldMaskUtil.toString(FieldMask.getDefaultInstance())).isEmpty();
     FieldMask mask = FieldMask.newBuilder().addPaths("foo").build();
-    assertEquals("foo", FieldMaskUtil.toString(mask));
+    assertThat(FieldMaskUtil.toString(mask)).isEqualTo("foo");
     mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar").build();
-    assertEquals("foo,bar", FieldMaskUtil.toString(mask));
+    assertThat(FieldMaskUtil.toString(mask)).isEqualTo("foo,bar");
 
     // Empty field paths are ignored.
     mask =
@@ -92,88 +107,93 @@
             .addPaths("bar")
             .addPaths("")
             .build();
-    assertEquals("foo,bar", FieldMaskUtil.toString(mask));
+    assertThat(FieldMaskUtil.toString(mask)).isEqualTo("foo,bar");
   }
 
+  @Test
   public void testFromString() throws Exception {
     FieldMask mask = FieldMaskUtil.fromString("");
-    assertEquals(0, mask.getPathsCount());
+    assertThat(mask.getPathsCount()).isEqualTo(0);
     mask = FieldMaskUtil.fromString("foo");
-    assertEquals(1, mask.getPathsCount());
-    assertEquals("foo", mask.getPaths(0));
+    assertThat(mask.getPathsCount()).isEqualTo(1);
+    assertThat(mask.getPaths(0)).isEqualTo("foo");
     mask = FieldMaskUtil.fromString("foo,bar.baz");
-    assertEquals(2, mask.getPathsCount());
-    assertEquals("foo", mask.getPaths(0));
-    assertEquals("bar.baz", mask.getPaths(1));
+    assertThat(mask.getPathsCount()).isEqualTo(2);
+    assertThat(mask.getPaths(0)).isEqualTo("foo");
+    assertThat(mask.getPaths(1)).isEqualTo("bar.baz");
 
     // Empty field paths are ignore.
     mask = FieldMaskUtil.fromString(",foo,,bar,");
-    assertEquals(2, mask.getPathsCount());
-    assertEquals("foo", mask.getPaths(0));
-    assertEquals("bar", mask.getPaths(1));
+    assertThat(mask.getPathsCount()).isEqualTo(2);
+    assertThat(mask.getPaths(0)).isEqualTo("foo");
+    assertThat(mask.getPaths(1)).isEqualTo("bar");
 
     // Check whether the field paths are valid if a class parameter is provided.
     mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, ",payload");
 
     try {
       mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, "payload,nonexist");
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IllegalArgumentException e) {
       // Expected.
     }
   }
 
+  @Test
   public void testFromFieldNumbers() throws Exception {
     FieldMask mask = FieldMaskUtil.fromFieldNumbers(TestAllTypes.class);
-    assertEquals(0, mask.getPathsCount());
+    assertThat(mask.getPathsCount()).isEqualTo(0);
     mask =
         FieldMaskUtil.fromFieldNumbers(
             TestAllTypes.class, TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER);
-    assertEquals(1, mask.getPathsCount());
-    assertEquals("optional_int32", mask.getPaths(0));
+    assertThat(mask.getPathsCount()).isEqualTo(1);
+    assertThat(mask.getPaths(0)).isEqualTo("optional_int32");
     mask =
         FieldMaskUtil.fromFieldNumbers(
             TestAllTypes.class,
             TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER,
             TestAllTypes.OPTIONAL_INT64_FIELD_NUMBER);
-    assertEquals(2, mask.getPathsCount());
-    assertEquals("optional_int32", mask.getPaths(0));
-    assertEquals("optional_int64", mask.getPaths(1));
+    assertThat(mask.getPathsCount()).isEqualTo(2);
+    assertThat(mask.getPaths(0)).isEqualTo("optional_int32");
+    assertThat(mask.getPaths(1)).isEqualTo("optional_int64");
 
     try {
       int invalidFieldNumber = 1000;
       mask = FieldMaskUtil.fromFieldNumbers(TestAllTypes.class, invalidFieldNumber);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IllegalArgumentException expected) {
     }
   }
 
+  @Test
   public void testToJsonString() throws Exception {
     FieldMask mask = FieldMask.getDefaultInstance();
-    assertEquals("", FieldMaskUtil.toJsonString(mask));
+    assertThat(FieldMaskUtil.toJsonString(mask)).isEmpty();
     mask = FieldMask.newBuilder().addPaths("foo").build();
-    assertEquals("foo", FieldMaskUtil.toJsonString(mask));
+    assertThat(FieldMaskUtil.toJsonString(mask)).isEqualTo("foo");
     mask = FieldMask.newBuilder().addPaths("foo.bar_baz").addPaths("").build();
-    assertEquals("foo.barBaz", FieldMaskUtil.toJsonString(mask));
+    assertThat(FieldMaskUtil.toJsonString(mask)).isEqualTo("foo.barBaz");
     mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar_baz").build();
-    assertEquals("foo,barBaz", FieldMaskUtil.toJsonString(mask));
+    assertThat(FieldMaskUtil.toJsonString(mask)).isEqualTo("foo,barBaz");
   }
 
+  @Test
   public void testFromJsonString() throws Exception {
     FieldMask mask = FieldMaskUtil.fromJsonString("");
-    assertEquals(0, mask.getPathsCount());
+    assertThat(mask.getPathsCount()).isEqualTo(0);
     mask = FieldMaskUtil.fromJsonString("foo");
-    assertEquals(1, mask.getPathsCount());
-    assertEquals("foo", mask.getPaths(0));
+    assertThat(mask.getPathsCount()).isEqualTo(1);
+    assertThat(mask.getPaths(0)).isEqualTo("foo");
     mask = FieldMaskUtil.fromJsonString("foo.barBaz");
-    assertEquals(1, mask.getPathsCount());
-    assertEquals("foo.bar_baz", mask.getPaths(0));
+    assertThat(mask.getPathsCount()).isEqualTo(1);
+    assertThat(mask.getPaths(0)).isEqualTo("foo.bar_baz");
     mask = FieldMaskUtil.fromJsonString("foo,barBaz");
-    assertEquals(2, mask.getPathsCount());
-    assertEquals("foo", mask.getPaths(0));
-    assertEquals("bar_baz", mask.getPaths(1));
+    assertThat(mask.getPathsCount()).isEqualTo(2);
+    assertThat(mask.getPaths(0)).isEqualTo("foo");
+    assertThat(mask.getPaths(1)).isEqualTo("bar_baz");
   }
 
+  @Test
   public void testFromStringList() throws Exception {
     FieldMask mask =
         FieldMaskUtil.fromStringList(
@@ -206,33 +226,37 @@
                 .build());
   }
 
+  @Test
   public void testUnion() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testAddFieldPath} to cover all scenarios.
     FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz");
     FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar");
     FieldMask result = FieldMaskUtil.union(mask1, mask2);
-    assertEquals("bar,foo", FieldMaskUtil.toString(result));
+    assertThat(FieldMaskUtil.toString(result)).isEqualTo("bar,foo");
   }
 
+  @Test
   public void testUnion_usingVarArgs() throws Exception {
     FieldMask mask1 = FieldMaskUtil.fromString("foo");
     FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar.quz");
     FieldMask mask3 = FieldMaskUtil.fromString("bar.quz");
     FieldMask mask4 = FieldMaskUtil.fromString("bar");
     FieldMask result = FieldMaskUtil.union(mask1, mask2, mask3, mask4);
-    assertEquals("bar,foo", FieldMaskUtil.toString(result));
+    assertThat(FieldMaskUtil.toString(result)).isEqualTo("bar,foo");
   }
 
+  @Test
   public void testSubstract() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testRemoveFieldPath} to cover all scenarios.
     FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz");
     FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar");
     FieldMask result = FieldMaskUtil.subtract(mask1, mask2);
-    assertEquals("foo", FieldMaskUtil.toString(result));
+    assertThat(FieldMaskUtil.toString(result)).isEqualTo("foo");
   }
 
+  @Test
   public void testSubstract_usingVarArgs() throws Exception {
     FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz.bar");
     FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar.baz.quz");
@@ -242,15 +266,17 @@
     assertThat(FieldMaskUtil.toString(result)).isEmpty();
   }
 
+  @Test
   public void testIntersection() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testIntersectFieldPath} to cover all scenarios.
     FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz");
     FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar");
     FieldMask result = FieldMaskUtil.intersection(mask1, mask2);
-    assertEquals("bar.baz,bar.quz,foo.bar", FieldMaskUtil.toString(result));
+    assertThat(FieldMaskUtil.toString(result)).isEqualTo("bar.baz,bar.quz,foo.bar");
   }
 
+  @Test
   public void testMerge() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testMerge} to cover all scenarios.
@@ -260,6 +286,6 @@
             .build();
     NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
     FieldMaskUtil.merge(FieldMaskUtil.fromString("payload"), source, builder);
-    assertEquals(1234, builder.getPayload().getOptionalInt32());
+    assertThat(builder.getPayload().getOptionalInt32()).isEqualTo(1234);
   }
 }
diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
index 6133bb4..fc61a28 100644
--- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf.util;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import com.google.common.collect.ImmutableSet;
 import com.google.protobuf.Any;
 import com.google.protobuf.BoolValue;
@@ -76,9 +79,12 @@
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class JsonFormatTest extends TestCase {
+@RunWith(JUnit4.class)
+public class JsonFormatTest {
   public JsonFormatTest() {
     // Test that locale does not affect JsonFormat.
     Locale.setDefault(Locale.forLanguageTag("hi-IN"));
@@ -150,7 +156,7 @@
     Message.Builder builder = message.newBuilderForType();
     parser.merge(printer.print(message), builder);
     Message parsedMessage = builder.build();
-    assertEquals(message.toString(), parsedMessage.toString());
+    assertThat(parsedMessage.toString()).isEqualTo(message.toString());
   }
 
   private void assertRoundTripEquals(Message message, com.google.protobuf.TypeRegistry registry)
@@ -160,7 +166,7 @@
     Message.Builder builder = message.newBuilderForType();
     parser.merge(printer.print(message), builder);
     Message parsedMessage = builder.build();
-    assertEquals(message.toString(), parsedMessage.toString());
+    assertThat(parsedMessage.toString()).isEqualTo(message.toString());
   }
 
   private String toJsonString(Message message) throws IOException {
@@ -182,59 +188,61 @@
     JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
   }
 
+  @Test
   public void testAllFields() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     setAllFields(builder);
     TestAllTypes message = builder.build();
 
-    assertEquals(
-        "{\n"
-            + "  \"optionalInt32\": 1234,\n"
-            + "  \"optionalInt64\": \"1234567890123456789\",\n"
-            + "  \"optionalUint32\": 5678,\n"
-            + "  \"optionalUint64\": \"2345678901234567890\",\n"
-            + "  \"optionalSint32\": 9012,\n"
-            + "  \"optionalSint64\": \"3456789012345678901\",\n"
-            + "  \"optionalFixed32\": 3456,\n"
-            + "  \"optionalFixed64\": \"4567890123456789012\",\n"
-            + "  \"optionalSfixed32\": 7890,\n"
-            + "  \"optionalSfixed64\": \"5678901234567890123\",\n"
-            + "  \"optionalFloat\": 1.5,\n"
-            + "  \"optionalDouble\": 1.25,\n"
-            + "  \"optionalBool\": true,\n"
-            + "  \"optionalString\": \"Hello world!\",\n"
-            + "  \"optionalBytes\": \"AAEC\",\n"
-            + "  \"optionalNestedMessage\": {\n"
-            + "    \"value\": 100\n"
-            + "  },\n"
-            + "  \"optionalNestedEnum\": \"BAR\",\n"
-            + "  \"repeatedInt32\": [1234, 234],\n"
-            + "  \"repeatedInt64\": [\"1234567890123456789\", \"234567890123456789\"],\n"
-            + "  \"repeatedUint32\": [5678, 678],\n"
-            + "  \"repeatedUint64\": [\"2345678901234567890\", \"345678901234567890\"],\n"
-            + "  \"repeatedSint32\": [9012, 10],\n"
-            + "  \"repeatedSint64\": [\"3456789012345678901\", \"456789012345678901\"],\n"
-            + "  \"repeatedFixed32\": [3456, 456],\n"
-            + "  \"repeatedFixed64\": [\"4567890123456789012\", \"567890123456789012\"],\n"
-            + "  \"repeatedSfixed32\": [7890, 890],\n"
-            + "  \"repeatedSfixed64\": [\"5678901234567890123\", \"678901234567890123\"],\n"
-            + "  \"repeatedFloat\": [1.5, 11.5],\n"
-            + "  \"repeatedDouble\": [1.25, 11.25],\n"
-            + "  \"repeatedBool\": [true, true],\n"
-            + "  \"repeatedString\": [\"Hello world!\", \"ello world!\"],\n"
-            + "  \"repeatedBytes\": [\"AAEC\", \"AQI=\"],\n"
-            + "  \"repeatedNestedMessage\": [{\n"
-            + "    \"value\": 100\n"
-            + "  }, {\n"
-            + "    \"value\": 200\n"
-            + "  }],\n"
-            + "  \"repeatedNestedEnum\": [\"BAR\", \"BAZ\"]\n"
-            + "}",
-        toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"optionalInt32\": 1234,\n"
+                + "  \"optionalInt64\": \"1234567890123456789\",\n"
+                + "  \"optionalUint32\": 5678,\n"
+                + "  \"optionalUint64\": \"2345678901234567890\",\n"
+                + "  \"optionalSint32\": 9012,\n"
+                + "  \"optionalSint64\": \"3456789012345678901\",\n"
+                + "  \"optionalFixed32\": 3456,\n"
+                + "  \"optionalFixed64\": \"4567890123456789012\",\n"
+                + "  \"optionalSfixed32\": 7890,\n"
+                + "  \"optionalSfixed64\": \"5678901234567890123\",\n"
+                + "  \"optionalFloat\": 1.5,\n"
+                + "  \"optionalDouble\": 1.25,\n"
+                + "  \"optionalBool\": true,\n"
+                + "  \"optionalString\": \"Hello world!\",\n"
+                + "  \"optionalBytes\": \"AAEC\",\n"
+                + "  \"optionalNestedMessage\": {\n"
+                + "    \"value\": 100\n"
+                + "  },\n"
+                + "  \"optionalNestedEnum\": \"BAR\",\n"
+                + "  \"repeatedInt32\": [1234, 234],\n"
+                + "  \"repeatedInt64\": [\"1234567890123456789\", \"234567890123456789\"],\n"
+                + "  \"repeatedUint32\": [5678, 678],\n"
+                + "  \"repeatedUint64\": [\"2345678901234567890\", \"345678901234567890\"],\n"
+                + "  \"repeatedSint32\": [9012, 10],\n"
+                + "  \"repeatedSint64\": [\"3456789012345678901\", \"456789012345678901\"],\n"
+                + "  \"repeatedFixed32\": [3456, 456],\n"
+                + "  \"repeatedFixed64\": [\"4567890123456789012\", \"567890123456789012\"],\n"
+                + "  \"repeatedSfixed32\": [7890, 890],\n"
+                + "  \"repeatedSfixed64\": [\"5678901234567890123\", \"678901234567890123\"],\n"
+                + "  \"repeatedFloat\": [1.5, 11.5],\n"
+                + "  \"repeatedDouble\": [1.25, 11.25],\n"
+                + "  \"repeatedBool\": [true, true],\n"
+                + "  \"repeatedString\": [\"Hello world!\", \"ello world!\"],\n"
+                + "  \"repeatedBytes\": [\"AAEC\", \"AQI=\"],\n"
+                + "  \"repeatedNestedMessage\": [{\n"
+                + "    \"value\": 100\n"
+                + "  }, {\n"
+                + "    \"value\": 200\n"
+                + "  }],\n"
+                + "  \"repeatedNestedEnum\": [\"BAR\", \"BAZ\"]\n"
+                + "}");
 
     assertRoundTripEquals(message);
   }
 
+  @Test
   public void testUnknownEnumValues() throws Exception {
     TestAllTypes message =
         TestAllTypes.newBuilder()
@@ -242,29 +250,30 @@
             .addRepeatedNestedEnumValue(12345)
             .addRepeatedNestedEnumValue(0)
             .build();
-    assertEquals(
-        "{\n"
-            + "  \"optionalNestedEnum\": 12345,\n"
-            + "  \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
-            + "}",
-        toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"optionalNestedEnum\": 12345,\n"
+                + "  \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
+                + "}");
     assertRoundTripEquals(message);
 
     TestMap.Builder mapBuilder = TestMap.newBuilder();
     mapBuilder.putInt32ToEnumMapValue(1, 0);
     mapBuilder.putInt32ToEnumMapValue(2, 12345);
     TestMap mapMessage = mapBuilder.build();
-    assertEquals(
-        "{\n"
-            + "  \"int32ToEnumMap\": {\n"
-            + "    \"1\": \"FOO\",\n"
-            + "    \"2\": 12345\n"
-            + "  }\n"
-            + "}",
-        toJsonString(mapMessage));
+    assertThat(toJsonString(mapMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"int32ToEnumMap\": {\n"
+                + "    \"1\": \"FOO\",\n"
+                + "    \"2\": 12345\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(mapMessage);
   }
 
+  @Test
   public void testSpecialFloatValues() throws Exception {
     TestAllTypes message =
         TestAllTypes.newBuilder()
@@ -275,16 +284,17 @@
             .addRepeatedDouble(Double.POSITIVE_INFINITY)
             .addRepeatedDouble(Double.NEGATIVE_INFINITY)
             .build();
-    assertEquals(
-        "{\n"
-            + "  \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n"
-            + "  \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n"
-            + "}",
-        toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n"
+                + "  \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n"
+                + "}");
 
     assertRoundTripEquals(message);
   }
 
+  @Test
   public void testParserAcceptStringForNumericField() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     mergeFromJson(
@@ -300,16 +310,17 @@
             + "}",
         builder);
     TestAllTypes message = builder.build();
-    assertEquals(1234, message.getOptionalInt32());
-    assertEquals(5678, message.getOptionalUint32());
-    assertEquals(9012, message.getOptionalSint32());
-    assertEquals(3456, message.getOptionalFixed32());
-    assertEquals(7890, message.getOptionalSfixed32());
-    assertEquals(1.5f, message.getOptionalFloat(), 0.0f);
-    assertEquals(1.25, message.getOptionalDouble(), 0.0);
-    assertEquals(true, message.getOptionalBool());
+    assertThat(message.getOptionalInt32()).isEqualTo(1234);
+    assertThat(message.getOptionalUint32()).isEqualTo(5678);
+    assertThat(message.getOptionalSint32()).isEqualTo(9012);
+    assertThat(message.getOptionalFixed32()).isEqualTo(3456);
+    assertThat(message.getOptionalSfixed32()).isEqualTo(7890);
+    assertThat(message.getOptionalFloat()).isEqualTo(1.5f);
+    assertThat(message.getOptionalDouble()).isEqualTo(1.25);
+    assertThat(message.getOptionalBool()).isTrue();
   }
 
+  @Test
   public void testParserAcceptFloatingPointValueForIntegerField() throws Exception {
     // Test that numeric values like "1.000", "1e5" will also be accepted.
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -322,15 +333,15 @@
             + "}",
         builder);
     int[] expectedValues = new int[] {1, 100000, 1, 100000};
-    assertEquals(4, builder.getRepeatedInt32Count());
-    assertEquals(4, builder.getRepeatedUint32Count());
-    assertEquals(4, builder.getRepeatedInt64Count());
-    assertEquals(4, builder.getRepeatedUint64Count());
+    assertThat(builder.getRepeatedInt32Count()).isEqualTo(4);
+    assertThat(builder.getRepeatedUint32Count()).isEqualTo(4);
+    assertThat(builder.getRepeatedInt64Count()).isEqualTo(4);
+    assertThat(builder.getRepeatedUint64Count()).isEqualTo(4);
     for (int i = 0; i < 4; ++i) {
-      assertEquals(expectedValues[i], builder.getRepeatedInt32(i));
-      assertEquals(expectedValues[i], builder.getRepeatedUint32(i));
-      assertEquals(expectedValues[i], builder.getRepeatedInt64(i));
-      assertEquals(expectedValues[i], builder.getRepeatedUint64(i));
+      assertThat(builder.getRepeatedInt32(i)).isEqualTo(expectedValues[i]);
+      assertThat(builder.getRepeatedUint32(i)).isEqualTo(expectedValues[i]);
+      assertThat(builder.getRepeatedInt64(i)).isEqualTo(expectedValues[i]);
+      assertThat(builder.getRepeatedUint64(i)).isEqualTo(expectedValues[i]);
     }
 
     // Non-integers will still be rejected.
@@ -345,14 +356,14 @@
     try {
       // Numeric form is rejected.
       mergeFromJson("{\"" + name + "\":" + value + "}", builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IOException e) {
       // Expected.
     }
     try {
       // String form is also rejected.
       mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IOException e) {
       // Expected.
     }
@@ -366,6 +377,7 @@
     mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder);
   }
 
+  @Test
   public void testParserRejectOutOfRangeNumericValues() throws Exception {
     assertAccepts("optionalInt32", String.valueOf(Integer.MAX_VALUE));
     assertAccepts("optionalInt32", String.valueOf(Integer.MIN_VALUE));
@@ -376,7 +388,7 @@
     assertRejects("optionalUint32", "123456789012345");
     assertRejects("optionalUint32", "-1");
 
-    BigInteger one = new BigInteger("1");
+    BigInteger one = BigInteger.ONE;
     BigInteger maxLong = new BigInteger(String.valueOf(Long.MAX_VALUE));
     BigInteger minLong = new BigInteger(String.valueOf(Long.MIN_VALUE));
     assertAccepts("optionalInt64", maxLong.toString());
@@ -406,6 +418,7 @@
     assertRejects("optionalDouble", minDouble.multiply(moreThanOne).toString());
   }
 
+  @Test
   public void testParserAcceptNull() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     mergeFromJson(
@@ -447,13 +460,13 @@
             + "}",
         builder);
     TestAllTypes message = builder.build();
-    assertEquals(TestAllTypes.getDefaultInstance(), message);
+    assertThat(message).isEqualTo(TestAllTypes.getDefaultInstance());
 
     // Repeated field elements cannot be null.
     try {
       builder = TestAllTypes.newBuilder();
       mergeFromJson("{\n" + "  \"repeatedInt32\": [null, null],\n" + "}", builder);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
@@ -461,34 +474,38 @@
     try {
       builder = TestAllTypes.newBuilder();
       mergeFromJson("{\n" + "  \"repeatedNestedMessage\": [null, null],\n" + "}", builder);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
   }
 
+  @Test
   public void testNullInOneof() throws Exception {
     TestOneof.Builder builder = TestOneof.newBuilder();
     mergeFromJson("{\n" + "  \"oneofNullValue\": null \n" + "}", builder);
     TestOneof message = builder.build();
-    assertEquals(TestOneof.OneofFieldCase.ONEOF_NULL_VALUE, message.getOneofFieldCase());
-    assertEquals(NullValue.NULL_VALUE, message.getOneofNullValue());
+    assertThat(message.getOneofFieldCase()).isEqualTo(TestOneof.OneofFieldCase.ONEOF_NULL_VALUE);
+    assertThat(message.getOneofNullValue()).isEqualTo(NullValue.NULL_VALUE);
   }
 
+  @Test
   public void testNullFirstInDuplicateOneof() throws Exception {
     TestOneof.Builder builder = TestOneof.newBuilder();
     mergeFromJson("{\"oneofNestedMessage\": null, \"oneofInt32\": 1}", builder);
     TestOneof message = builder.build();
-    assertEquals(1, message.getOneofInt32());
+    assertThat(message.getOneofInt32()).isEqualTo(1);
   }
 
+  @Test
   public void testNullLastInDuplicateOneof() throws Exception {
     TestOneof.Builder builder = TestOneof.newBuilder();
     mergeFromJson("{\"oneofInt32\": 1, \"oneofNestedMessage\": null}", builder);
     TestOneof message = builder.build();
-    assertEquals(1, message.getOneofInt32());
+    assertThat(message.getOneofInt32()).isEqualTo(1);
   }
 
+  @Test
   public void testParserRejectDuplicatedFields() throws Exception {
     // TODO(xiaofeng): The parser we are currently using (GSON) will accept and keep the last
     // one if multiple entries have the same name. This is not the desired behavior but it can
@@ -504,7 +521,7 @@
               + "  \"optional_nested_message\": {}\n"
               + "}",
           builder);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
@@ -518,7 +535,7 @@
               + "  \"repeated_int32\": [5, 6]\n"
               + "}",
           builder);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
@@ -527,7 +544,7 @@
     try {
       TestOneof.Builder builder = TestOneof.newBuilder();
       mergeFromJson("{\n" + "  \"oneofInt32\": 1,\n" + "  \"oneof_int32\": 2\n" + "}", builder);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
@@ -537,12 +554,13 @@
       TestOneof.Builder builder = TestOneof.newBuilder();
       mergeFromJson(
           "{\n" + "  \"oneofInt32\": 1,\n" + "  \"oneofNullValue\": null\n" + "}", builder);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
   }
 
+  @Test
   public void testMapFields() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     builder.putInt32ToInt32Map(1, 10);
@@ -576,96 +594,96 @@
     builder.putInt32ToEnumMap(9, NestedEnum.BAR);
     TestMap message = builder.build();
 
-    assertEquals(
-        "{\n"
-            + "  \"int32ToInt32Map\": {\n"
-            + "    \"1\": 10\n"
-            + "  },\n"
-            + "  \"int64ToInt32Map\": {\n"
-            + "    \"1234567890123456789\": 10\n"
-            + "  },\n"
-            + "  \"uint32ToInt32Map\": {\n"
-            + "    \"2\": 20\n"
-            + "  },\n"
-            + "  \"uint64ToInt32Map\": {\n"
-            + "    \"2234567890123456789\": 20\n"
-            + "  },\n"
-            + "  \"sint32ToInt32Map\": {\n"
-            + "    \"3\": 30\n"
-            + "  },\n"
-            + "  \"sint64ToInt32Map\": {\n"
-            + "    \"3234567890123456789\": 30\n"
-            + "  },\n"
-            + "  \"fixed32ToInt32Map\": {\n"
-            + "    \"4\": 40\n"
-            + "  },\n"
-            + "  \"fixed64ToInt32Map\": {\n"
-            + "    \"4234567890123456789\": 40\n"
-            + "  },\n"
-            + "  \"sfixed32ToInt32Map\": {\n"
-            + "    \"5\": 50\n"
-            + "  },\n"
-            + "  \"sfixed64ToInt32Map\": {\n"
-            + "    \"5234567890123456789\": 50\n"
-            + "  },\n"
-            + "  \"boolToInt32Map\": {\n"
-            + "    \"false\": 6\n"
-            + "  },\n"
-            + "  \"stringToInt32Map\": {\n"
-            + "    \"Hello\": 10\n"
-            + "  },\n"
-            + "  \"int32ToInt64Map\": {\n"
-            + "    \"1\": \"1234567890123456789\"\n"
-            + "  },\n"
-            + "  \"int32ToUint32Map\": {\n"
-            + "    \"2\": 20\n"
-            + "  },\n"
-            + "  \"int32ToUint64Map\": {\n"
-            + "    \"2\": \"2234567890123456789\"\n"
-            + "  },\n"
-            + "  \"int32ToSint32Map\": {\n"
-            + "    \"3\": 30\n"
-            + "  },\n"
-            + "  \"int32ToSint64Map\": {\n"
-            + "    \"3\": \"3234567890123456789\"\n"
-            + "  },\n"
-            + "  \"int32ToFixed32Map\": {\n"
-            + "    \"4\": 40\n"
-            + "  },\n"
-            + "  \"int32ToFixed64Map\": {\n"
-            + "    \"4\": \"4234567890123456789\"\n"
-            + "  },\n"
-            + "  \"int32ToSfixed32Map\": {\n"
-            + "    \"5\": 50\n"
-            + "  },\n"
-            + "  \"int32ToSfixed64Map\": {\n"
-            + "    \"5\": \"5234567890123456789\"\n"
-            + "  },\n"
-            + "  \"int32ToFloatMap\": {\n"
-            + "    \"6\": 1.5\n"
-            + "  },\n"
-            + "  \"int32ToDoubleMap\": {\n"
-            + "    \"6\": 1.25\n"
-            + "  },\n"
-            + "  \"int32ToBoolMap\": {\n"
-            + "    \"7\": false\n"
-            + "  },\n"
-            + "  \"int32ToStringMap\": {\n"
-            + "    \"7\": \"World\"\n"
-            + "  },\n"
-            + "  \"int32ToBytesMap\": {\n"
-            + "    \"8\": \"AQID\"\n"
-            + "  },\n"
-            + "  \"int32ToMessageMap\": {\n"
-            + "    \"8\": {\n"
-            + "      \"value\": 1234\n"
-            + "    }\n"
-            + "  },\n"
-            + "  \"int32ToEnumMap\": {\n"
-            + "    \"9\": \"BAR\"\n"
-            + "  }\n"
-            + "}",
-        toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"int32ToInt32Map\": {\n"
+                + "    \"1\": 10\n"
+                + "  },\n"
+                + "  \"int64ToInt32Map\": {\n"
+                + "    \"1234567890123456789\": 10\n"
+                + "  },\n"
+                + "  \"uint32ToInt32Map\": {\n"
+                + "    \"2\": 20\n"
+                + "  },\n"
+                + "  \"uint64ToInt32Map\": {\n"
+                + "    \"2234567890123456789\": 20\n"
+                + "  },\n"
+                + "  \"sint32ToInt32Map\": {\n"
+                + "    \"3\": 30\n"
+                + "  },\n"
+                + "  \"sint64ToInt32Map\": {\n"
+                + "    \"3234567890123456789\": 30\n"
+                + "  },\n"
+                + "  \"fixed32ToInt32Map\": {\n"
+                + "    \"4\": 40\n"
+                + "  },\n"
+                + "  \"fixed64ToInt32Map\": {\n"
+                + "    \"4234567890123456789\": 40\n"
+                + "  },\n"
+                + "  \"sfixed32ToInt32Map\": {\n"
+                + "    \"5\": 50\n"
+                + "  },\n"
+                + "  \"sfixed64ToInt32Map\": {\n"
+                + "    \"5234567890123456789\": 50\n"
+                + "  },\n"
+                + "  \"boolToInt32Map\": {\n"
+                + "    \"false\": 6\n"
+                + "  },\n"
+                + "  \"stringToInt32Map\": {\n"
+                + "    \"Hello\": 10\n"
+                + "  },\n"
+                + "  \"int32ToInt64Map\": {\n"
+                + "    \"1\": \"1234567890123456789\"\n"
+                + "  },\n"
+                + "  \"int32ToUint32Map\": {\n"
+                + "    \"2\": 20\n"
+                + "  },\n"
+                + "  \"int32ToUint64Map\": {\n"
+                + "    \"2\": \"2234567890123456789\"\n"
+                + "  },\n"
+                + "  \"int32ToSint32Map\": {\n"
+                + "    \"3\": 30\n"
+                + "  },\n"
+                + "  \"int32ToSint64Map\": {\n"
+                + "    \"3\": \"3234567890123456789\"\n"
+                + "  },\n"
+                + "  \"int32ToFixed32Map\": {\n"
+                + "    \"4\": 40\n"
+                + "  },\n"
+                + "  \"int32ToFixed64Map\": {\n"
+                + "    \"4\": \"4234567890123456789\"\n"
+                + "  },\n"
+                + "  \"int32ToSfixed32Map\": {\n"
+                + "    \"5\": 50\n"
+                + "  },\n"
+                + "  \"int32ToSfixed64Map\": {\n"
+                + "    \"5\": \"5234567890123456789\"\n"
+                + "  },\n"
+                + "  \"int32ToFloatMap\": {\n"
+                + "    \"6\": 1.5\n"
+                + "  },\n"
+                + "  \"int32ToDoubleMap\": {\n"
+                + "    \"6\": 1.25\n"
+                + "  },\n"
+                + "  \"int32ToBoolMap\": {\n"
+                + "    \"7\": false\n"
+                + "  },\n"
+                + "  \"int32ToStringMap\": {\n"
+                + "    \"7\": \"World\"\n"
+                + "  },\n"
+                + "  \"int32ToBytesMap\": {\n"
+                + "    \"8\": \"AQID\"\n"
+                + "  },\n"
+                + "  \"int32ToMessageMap\": {\n"
+                + "    \"8\": {\n"
+                + "      \"value\": 1234\n"
+                + "    }\n"
+                + "  },\n"
+                + "  \"int32ToEnumMap\": {\n"
+                + "    \"9\": \"BAR\"\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(message);
 
     // Test multiple entries.
@@ -674,12 +692,18 @@
     builder.putInt32ToInt32Map(3, 4);
     message = builder.build();
 
-    assertEquals(
-        "{\n" + "  \"int32ToInt32Map\": {\n" + "    \"1\": 2,\n" + "    \"3\": 4\n" + "  }\n" + "}",
-        toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"int32ToInt32Map\": {\n"
+                + "    \"1\": 2,\n"
+                + "    \"3\": 4\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(message);
   }
 
+  @Test
   public void testMapNullValueIsRejected() throws Exception {
     try {
       TestMap.Builder builder = TestMap.newBuilder();
@@ -689,7 +713,7 @@
               + "  \"int32ToMessageMap\": {null: 2}\n"
               + "}",
           builder);
-      fail();
+      assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
@@ -702,30 +726,33 @@
               + "  \"int32ToMessageMap\": {\"2\": null}\n"
               + "}",
           builder);
-      fail();
+      assertWithMessage("expected exception").fail();
 
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
   }
 
+  @Test
   public void testMapEnumNullValueIsIgnored() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     mergeFromJsonIgnoringUnknownFields(
         "{\n" + "  \"int32ToEnumMap\": {\"1\": null}\n" + "}", builder);
     TestMap map = builder.build();
-    assertEquals(0, map.getInt32ToEnumMapMap().size());
+    assertThat(map.getInt32ToEnumMapMap()).isEmpty();
   }
 
+  @Test
   public void testParserAcceptNonQuotedObjectKey() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     mergeFromJson(
         "{\n" + "  int32ToInt32Map: {1: 2},\n" + "  stringToInt32Map: {hello: 3}\n" + "}", builder);
     TestMap message = builder.build();
-    assertEquals(2, message.getInt32ToInt32MapMap().get(1).intValue());
-    assertEquals(3, message.getStringToInt32MapMap().get("hello").intValue());
+    assertThat(message.getInt32ToInt32MapMap().get(1).intValue()).isEqualTo(2);
+    assertThat(message.getStringToInt32MapMap().get("hello").intValue()).isEqualTo(3);
   }
 
+  @Test
   public void testWrappers() throws Exception {
     TestWrappers.Builder builder = TestWrappers.newBuilder();
     builder.getBoolValueBuilder().setValue(false);
@@ -739,19 +766,19 @@
     builder.getBytesValueBuilder().setValue(ByteString.EMPTY);
     TestWrappers message = builder.build();
 
-    assertEquals(
-        "{\n"
-            + "  \"int32Value\": 0,\n"
-            + "  \"uint32Value\": 0,\n"
-            + "  \"int64Value\": \"0\",\n"
-            + "  \"uint64Value\": \"0\",\n"
-            + "  \"floatValue\": 0.0,\n"
-            + "  \"doubleValue\": 0.0,\n"
-            + "  \"boolValue\": false,\n"
-            + "  \"stringValue\": \"\",\n"
-            + "  \"bytesValue\": \"\"\n"
-            + "}",
-        toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"int32Value\": 0,\n"
+                + "  \"uint32Value\": 0,\n"
+                + "  \"int64Value\": \"0\",\n"
+                + "  \"uint64Value\": \"0\",\n"
+                + "  \"floatValue\": 0.0,\n"
+                + "  \"doubleValue\": 0.0,\n"
+                + "  \"boolValue\": false,\n"
+                + "  \"stringValue\": \"\",\n"
+                + "  \"bytesValue\": \"\"\n"
+                + "}");
     assertRoundTripEquals(message);
 
     builder = TestWrappers.newBuilder();
@@ -766,52 +793,56 @@
     builder.getBytesValueBuilder().setValue(ByteString.copyFrom(new byte[] {8}));
     message = builder.build();
 
-    assertEquals(
-        "{\n"
-            + "  \"int32Value\": 1,\n"
-            + "  \"uint32Value\": 3,\n"
-            + "  \"int64Value\": \"2\",\n"
-            + "  \"uint64Value\": \"4\",\n"
-            + "  \"floatValue\": 5.0,\n"
-            + "  \"doubleValue\": 6.0,\n"
-            + "  \"boolValue\": true,\n"
-            + "  \"stringValue\": \"7\",\n"
-            + "  \"bytesValue\": \"CA==\"\n"
-            + "}",
-        toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"int32Value\": 1,\n"
+                + "  \"uint32Value\": 3,\n"
+                + "  \"int64Value\": \"2\",\n"
+                + "  \"uint64Value\": \"4\",\n"
+                + "  \"floatValue\": 5.0,\n"
+                + "  \"doubleValue\": 6.0,\n"
+                + "  \"boolValue\": true,\n"
+                + "  \"stringValue\": \"7\",\n"
+                + "  \"bytesValue\": \"CA==\"\n"
+                + "}");
     assertRoundTripEquals(message);
   }
 
+  @Test
   public void testTimestamp() throws Exception {
     TestTimestamp message =
         TestTimestamp.newBuilder()
             .setTimestampValue(Timestamps.parse("1970-01-01T00:00:00Z"))
             .build();
 
-    assertEquals(
-        "{\n" + "  \"timestampValue\": \"1970-01-01T00:00:00Z\"\n" + "}", toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo("{\n" + "  \"timestampValue\": \"1970-01-01T00:00:00Z\"\n" + "}");
     assertRoundTripEquals(message);
   }
 
+  @Test
   public void testDuration() throws Exception {
     TestDuration message =
         TestDuration.newBuilder().setDurationValue(Durations.parse("12345s")).build();
 
-    assertEquals("{\n" + "  \"durationValue\": \"12345s\"\n" + "}", toJsonString(message));
+    assertThat(toJsonString(message)).isEqualTo("{\n" + "  \"durationValue\": \"12345s\"\n" + "}");
     assertRoundTripEquals(message);
   }
 
+  @Test
   public void testFieldMask() throws Exception {
     TestFieldMask message =
         TestFieldMask.newBuilder()
             .setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz,foo_bar.baz"))
             .build();
 
-    assertEquals(
-        "{\n" + "  \"fieldMaskValue\": \"foo.bar,baz,fooBar.baz\"\n" + "}", toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo("{\n" + "  \"fieldMaskValue\": \"foo.bar,baz,fooBar.baz\"\n" + "}");
     assertRoundTripEquals(message);
   }
 
+  @Test
   public void testStruct() throws Exception {
     // Build a struct with all possible values.
     TestStruct.Builder builder = TestStruct.newBuilder();
@@ -830,25 +861,25 @@
         "list_value", Value.newBuilder().setListValue(listBuilder.build()).build());
     TestStruct message = builder.build();
 
-    assertEquals(
-        "{\n"
-            + "  \"structValue\": {\n"
-            + "    \"null_value\": null,\n"
-            + "    \"number_value\": 1.25,\n"
-            + "    \"string_value\": \"hello\",\n"
-            + "    \"struct_value\": {\n"
-            + "      \"number_value\": 1234.0\n"
-            + "    },\n"
-            + "    \"list_value\": [1.125, null]\n"
-            + "  }\n"
-            + "}",
-        toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"structValue\": {\n"
+                + "    \"null_value\": null,\n"
+                + "    \"number_value\": 1.25,\n"
+                + "    \"string_value\": \"hello\",\n"
+                + "    \"struct_value\": {\n"
+                + "      \"number_value\": 1234.0\n"
+                + "    },\n"
+                + "    \"list_value\": [1.125, null]\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(message);
 
     builder = TestStruct.newBuilder();
     builder.setValue(Value.newBuilder().setNullValueValue(0).build());
     message = builder.build();
-    assertEquals("{\n" + "  \"value\": null\n" + "}", toJsonString(message));
+    assertThat(toJsonString(message)).isEqualTo("{\n" + "  \"value\": null\n" + "}");
     assertRoundTripEquals(message);
 
     builder = TestStruct.newBuilder();
@@ -856,11 +887,13 @@
     listBuilder.addValues(Value.newBuilder().setNumberValue(31831.125).build());
     listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build());
     message = builder.build();
-    assertEquals("{\n" + "  \"listValue\": [31831.125, null]\n" + "}", toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo("{\n" + "  \"listValue\": [31831.125, null]\n" + "}");
     assertRoundTripEquals(message);
   }
 
 
+  @Test
   public void testAnyFieldsWithCustomAddedTypeRegistry() throws Exception {
     TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build();
     TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build();
@@ -869,37 +902,39 @@
         com.google.protobuf.TypeRegistry.newBuilder().add(content.getDescriptorForType()).build();
     JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
 
-    assertEquals(
-        "{\n"
-            + "  \"anyValue\": {\n"
-            + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
-            + "    \"optionalInt32\": 1234\n"
-            + "  }\n"
-            + "}",
-        printer.print(message));
+    assertThat(printer.print(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"anyValue\": {\n"
+                + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+                + "    \"optionalInt32\": 1234\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(message, registry);
 
     TestAny messageWithDefaultAnyValue =
         TestAny.newBuilder().setAnyValue(Any.getDefaultInstance()).build();
-    assertEquals("{\n" + "  \"anyValue\": {}\n" + "}", printer.print(messageWithDefaultAnyValue));
+    assertThat(printer.print(messageWithDefaultAnyValue))
+        .isEqualTo("{\n" + "  \"anyValue\": {}\n" + "}");
     assertRoundTripEquals(messageWithDefaultAnyValue, registry);
 
     // Well-known types have a special formatting when embedded in Any.
     //
     // 1. Any in Any.
     Any anyMessage = Any.pack(Any.pack(content));
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
-            + "  \"value\": {\n"
-            + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
-            + "    \"optionalInt32\": 1234\n"
-            + "  }\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+                + "  \"value\": {\n"
+                + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+                + "    \"optionalInt32\": 1234\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
   }
 
+  @Test
   public void testAnyFields() throws Exception {
     TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build();
     TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build();
@@ -907,7 +942,7 @@
     // A TypeRegistry must be provided in order to convert Any types.
     try {
       toJsonString(message);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IOException e) {
       // Expected.
     }
@@ -916,190 +951,187 @@
         JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build();
     JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
 
-    assertEquals(
-        "{\n"
-            + "  \"anyValue\": {\n"
-            + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
-            + "    \"optionalInt32\": 1234\n"
-            + "  }\n"
-            + "}",
-        printer.print(message));
+    assertThat(printer.print(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"anyValue\": {\n"
+                + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+                + "    \"optionalInt32\": 1234\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(message, registry);
 
     TestAny messageWithDefaultAnyValue =
         TestAny.newBuilder().setAnyValue(Any.getDefaultInstance()).build();
-    assertEquals(
-        "{\n"
-            + "  \"anyValue\": {}\n"
-            + "}",
-        printer.print(messageWithDefaultAnyValue));
+    assertThat(printer.print(messageWithDefaultAnyValue))
+        .isEqualTo("{\n" + "  \"anyValue\": {}\n" + "}");
     assertRoundTripEquals(messageWithDefaultAnyValue, registry);
 
     // Well-known types have a special formatting when embedded in Any.
     //
     // 1. Any in Any.
     Any anyMessage = Any.pack(Any.pack(content));
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
-            + "  \"value\": {\n"
-            + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
-            + "    \"optionalInt32\": 1234\n"
-            + "  }\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+                + "  \"value\": {\n"
+                + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+                + "    \"optionalInt32\": 1234\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
 
     // 2. Wrappers in Any.
-    anyMessage = Any.pack(Int32Value.newBuilder().setValue(12345).build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
-            + "  \"value\": 12345\n"
-            + "}",
-        printer.print(anyMessage));
+    anyMessage = Any.pack(Int32Value.of(12345));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
+                + "  \"value\": 12345\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
-    anyMessage = Any.pack(UInt32Value.newBuilder().setValue(12345).build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt32Value\",\n"
-            + "  \"value\": 12345\n"
-            + "}",
-        printer.print(anyMessage));
+    anyMessage = Any.pack(UInt32Value.of(12345));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt32Value\",\n"
+                + "  \"value\": 12345\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
-    anyMessage = Any.pack(Int64Value.newBuilder().setValue(12345).build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
-            + "  \"value\": \"12345\"\n"
-            + "}",
-        printer.print(anyMessage));
+    anyMessage = Any.pack(Int64Value.of(12345));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
+                + "  \"value\": \"12345\"\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(UInt64Value.newBuilder().setValue(12345).build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt64Value\",\n"
-            + "  \"value\": \"12345\"\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt64Value\",\n"
+                + "  \"value\": \"12345\"\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(FloatValue.newBuilder().setValue(12345).build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.FloatValue\",\n"
-            + "  \"value\": 12345.0\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.FloatValue\",\n"
+                + "  \"value\": 12345.0\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(DoubleValue.newBuilder().setValue(12345).build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.DoubleValue\",\n"
-            + "  \"value\": 12345.0\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.DoubleValue\",\n"
+                + "  \"value\": 12345.0\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
-    anyMessage = Any.pack(BoolValue.newBuilder().setValue(true).build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n"
-            + "  \"value\": true\n"
-            + "}",
-        printer.print(anyMessage));
+    anyMessage = Any.pack(BoolValue.of(true));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n"
+                + "  \"value\": true\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
-    anyMessage = Any.pack(StringValue.newBuilder().setValue("Hello").build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.StringValue\",\n"
-            + "  \"value\": \"Hello\"\n"
-            + "}",
-        printer.print(anyMessage));
+    anyMessage = Any.pack(StringValue.of("Hello"));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.StringValue\",\n"
+                + "  \"value\": \"Hello\"\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
-    anyMessage =
-        Any.pack(BytesValue.newBuilder().setValue(ByteString.copyFrom(new byte[] {1, 2})).build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.BytesValue\",\n"
-            + "  \"value\": \"AQI=\"\n"
-            + "}",
-        printer.print(anyMessage));
+    anyMessage = Any.pack(BytesValue.of(ByteString.copyFrom(new byte[] {1, 2})));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.BytesValue\",\n"
+                + "  \"value\": \"AQI=\"\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
 
     // 3. Timestamp in Any.
     anyMessage = Any.pack(Timestamps.parse("1969-12-31T23:59:59Z"));
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
-            + "  \"value\": \"1969-12-31T23:59:59Z\"\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
+                + "  \"value\": \"1969-12-31T23:59:59Z\"\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
 
     // 4. Duration in Any
     anyMessage = Any.pack(Durations.parse("12345.10s"));
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
-            + "  \"value\": \"12345.100s\"\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
+                + "  \"value\": \"12345.100s\"\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
 
     // 5. FieldMask in Any
     anyMessage = Any.pack(FieldMaskUtil.fromString("foo.bar,baz"));
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
-            + "  \"value\": \"foo.bar,baz\"\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
+                + "  \"value\": \"foo.bar,baz\"\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
 
     // 6. Struct in Any
     Struct.Builder structBuilder = Struct.newBuilder();
     structBuilder.putFields("number", Value.newBuilder().setNumberValue(1.125).build());
     anyMessage = Any.pack(structBuilder.build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
-            + "  \"value\": {\n"
-            + "    \"number\": 1.125\n"
-            + "  }\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
+                + "  \"value\": {\n"
+                + "    \"number\": 1.125\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
 
     // 7. Value (number type) in Any
     Value.Builder valueBuilder = Value.newBuilder();
     valueBuilder.setNumberValue(1);
     anyMessage = Any.pack(valueBuilder.build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
-            + "  \"value\": 1.0\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+                + "  \"value\": 1.0\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
 
     // 8. Value (null type) in Any
     anyMessage = Any.pack(Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build());
-    assertEquals(
-        "{\n"
-            + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
-            + "  \"value\": null\n"
-            + "}",
-        printer.print(anyMessage));
+    assertThat(printer.print(anyMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+                + "  \"value\": null\n"
+                + "}");
     assertRoundTripEquals(anyMessage, registry);
   }
 
+  @Test
   public void testAnyInMaps() throws Exception {
     JsonFormat.TypeRegistry registry =
         JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build();
     JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
 
     TestAny.Builder testAny = TestAny.newBuilder();
-    testAny.putAnyMap("int32_wrapper", Any.pack(Int32Value.newBuilder().setValue(123).build()));
-    testAny.putAnyMap("int64_wrapper", Any.pack(Int64Value.newBuilder().setValue(456).build()));
+    testAny.putAnyMap("int32_wrapper", Any.pack(Int32Value.of(123)));
+    testAny.putAnyMap("int64_wrapper", Any.pack(Int64Value.of(456)));
     testAny.putAnyMap("timestamp", Any.pack(Timestamps.parse("1969-12-31T23:59:59Z")));
     testAny.putAnyMap("duration", Any.pack(Durations.parse("12345.1s")));
     testAny.putAnyMap("field_mask", Any.pack(FieldMaskUtil.fromString("foo.bar,baz")));
@@ -1116,71 +1148,73 @@
     testAny.putAnyMap("any_value_default", Any.pack(Any.getDefaultInstance()));
     testAny.putAnyMap("default", Any.getDefaultInstance());
 
-    assertEquals(
-        "{\n"
-            + "  \"anyMap\": {\n"
-            + "    \"int32_wrapper\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
-            + "      \"value\": 123\n"
-            + "    },\n"
-            + "    \"int64_wrapper\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
-            + "      \"value\": \"456\"\n"
-            + "    },\n"
-            + "    \"timestamp\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
-            + "      \"value\": \"1969-12-31T23:59:59Z\"\n"
-            + "    },\n"
-            + "    \"duration\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
-            + "      \"value\": \"12345.100s\"\n"
-            + "    },\n"
-            + "    \"field_mask\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
-            + "      \"value\": \"foo.bar,baz\"\n"
-            + "    },\n"
-            + "    \"struct\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
-            + "      \"value\": {\n"
-            + "        \"number\": 1.125\n"
-            + "      }\n"
-            + "    },\n"
-            + "    \"list_value\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.ListValue\",\n"
-            + "      \"value\": [1.125, null]\n"
-            + "    },\n"
-            + "    \"number_value\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
-            + "      \"value\": 1.125\n"
-            + "    },\n"
-            + "    \"any_value_number\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
-            + "      \"value\": {\n"
-            + "        \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
-            + "        \"value\": 1.125\n"
-            + "      }\n"
-            + "    },\n"
-            + "    \"any_value_default\": {\n"
-            + "      \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
-            + "      \"value\": {}\n"
-            + "    },\n"
-            + "    \"default\": {}\n"
-            + "  }\n"
-            + "}",
-        printer.print(testAny.build()));
+    assertThat(printer.print(testAny.build()))
+        .isEqualTo(
+            "{\n"
+                + "  \"anyMap\": {\n"
+                + "    \"int32_wrapper\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
+                + "      \"value\": 123\n"
+                + "    },\n"
+                + "    \"int64_wrapper\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
+                + "      \"value\": \"456\"\n"
+                + "    },\n"
+                + "    \"timestamp\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
+                + "      \"value\": \"1969-12-31T23:59:59Z\"\n"
+                + "    },\n"
+                + "    \"duration\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
+                + "      \"value\": \"12345.100s\"\n"
+                + "    },\n"
+                + "    \"field_mask\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
+                + "      \"value\": \"foo.bar,baz\"\n"
+                + "    },\n"
+                + "    \"struct\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
+                + "      \"value\": {\n"
+                + "        \"number\": 1.125\n"
+                + "      }\n"
+                + "    },\n"
+                + "    \"list_value\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.ListValue\",\n"
+                + "      \"value\": [1.125, null]\n"
+                + "    },\n"
+                + "    \"number_value\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+                + "      \"value\": 1.125\n"
+                + "    },\n"
+                + "    \"any_value_number\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+                + "      \"value\": {\n"
+                + "        \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+                + "        \"value\": 1.125\n"
+                + "      }\n"
+                + "    },\n"
+                + "    \"any_value_default\": {\n"
+                + "      \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+                + "      \"value\": {}\n"
+                + "    },\n"
+                + "    \"default\": {}\n"
+                + "  }\n"
+                + "}");
     assertRoundTripEquals(testAny.build(), registry);
   }
 
+  @Test
   public void testParserMissingTypeUrl() throws Exception {
     try {
       Any.Builder builder = Any.newBuilder();
       mergeFromJson("{\n" + "  \"optionalInt32\": 1234\n" + "}", builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IOException e) {
       // Expected.
     }
   }
 
+  @Test
   public void testParserUnexpectedTypeUrl() throws Exception {
     try {
       Any.Builder builder = Any.newBuilder();
@@ -1190,17 +1224,18 @@
               + "  \"optionalInt32\": 12345\n"
               + "}",
           builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IOException e) {
       // Expected.
     }
   }
 
+    @Test
   public void testParserRejectTrailingComma() throws Exception {
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       mergeFromJson("{\n" + "  \"optionalInt32\": 12345,\n" + "}", builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IOException e) {
       // Expected.
     }
@@ -1221,225 +1256,241 @@
     // }
   }
 
+  @Test
   public void testParserRejectInvalidBase64() throws Exception {
     assertRejects("optionalBytes", "!@#$");
   }
 
+  @Test
   public void testParserAcceptBase64Variants() throws Exception {
     assertAccepts("optionalBytes", "AQI"); // No padding
     assertAccepts("optionalBytes", "-_w"); // base64Url, no padding
   }
 
+  @Test
   public void testParserRejectInvalidEnumValue() throws Exception {
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       mergeFromJson("{\n" + "  \"optionalNestedEnum\": \"XXX\"\n" + "}", builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (InvalidProtocolBufferException e) {
       // Expected.
     }
   }
 
+  @Test
   public void testParserUnknownFields() throws Exception {
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       String json = "{\n" + "  \"unknownField\": \"XXX\"\n" + "}";
       JsonFormat.parser().merge(json, builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (InvalidProtocolBufferException e) {
       // Expected.
     }
   }
 
+  @Test
   public void testParserIgnoringUnknownFields() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     String json = "{\n" + "  \"unknownField\": \"XXX\"\n" + "}";
     JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
   }
 
+  @Test
   public void testParserIgnoringUnknownEnums() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     String json = "{\n" + "  \"optionalNestedEnum\": \"XXX\"\n" + "}";
     JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
-    assertEquals(0, builder.getOptionalNestedEnumValue());
+    assertThat(builder.getOptionalNestedEnumValue()).isEqualTo(0);
   }
 
+  @Test
   public void testParserSupportAliasEnums() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     String json = "{\n" + "  \"optionalAliasedEnum\": \"QUX\"\n" + "}";
     JsonFormat.parser().merge(json, builder);
-    assertEquals(AliasedEnum.ALIAS_BAZ, builder.getOptionalAliasedEnum());
+    assertThat(builder.getOptionalAliasedEnum()).isEqualTo(AliasedEnum.ALIAS_BAZ);
 
     builder = TestAllTypes.newBuilder();
     json = "{\n" + "  \"optionalAliasedEnum\": \"qux\"\n" + "}";
     JsonFormat.parser().merge(json, builder);
-    assertEquals(AliasedEnum.ALIAS_BAZ, builder.getOptionalAliasedEnum());
+    assertThat(builder.getOptionalAliasedEnum()).isEqualTo(AliasedEnum.ALIAS_BAZ);
 
     builder = TestAllTypes.newBuilder();
     json = "{\n" + "  \"optionalAliasedEnum\": \"bAz\"\n" + "}";
     JsonFormat.parser().merge(json, builder);
-    assertEquals(AliasedEnum.ALIAS_BAZ, builder.getOptionalAliasedEnum());
+    assertThat(builder.getOptionalAliasedEnum()).isEqualTo(AliasedEnum.ALIAS_BAZ);
   }
 
+  @Test
   public void testUnknownEnumMap() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     JsonFormat.parser()
         .ignoringUnknownFields()
         .merge("{\n" + "  \"int32ToEnumMap\": {1: XXX, 2: FOO}" + "}", builder);
 
-    assertEquals(NestedEnum.FOO, builder.getInt32ToEnumMapMap().get(2));
-    assertEquals(1, builder.getInt32ToEnumMapMap().size());
+    assertThat(builder.getInt32ToEnumMapMap()).containsEntry(2, NestedEnum.FOO);
+    assertThat(builder.getInt32ToEnumMapMap()).hasSize(1);
   }
 
+  @Test
   public void testRepeatedUnknownEnum() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     JsonFormat.parser()
         .ignoringUnknownFields()
         .merge("{\n" + "  \"repeatedNestedEnum\": [XXX, FOO, BAR, BAZ]" + "}", builder);
 
-    assertEquals(NestedEnum.FOO, builder.getRepeatedNestedEnum(0));
-    assertEquals(NestedEnum.BAR, builder.getRepeatedNestedEnum(1));
-    assertEquals(NestedEnum.BAZ, builder.getRepeatedNestedEnum(2));
-    assertEquals(3, builder.getRepeatedNestedEnumList().size());
+    assertThat(builder.getRepeatedNestedEnum(0)).isEqualTo(NestedEnum.FOO);
+    assertThat(builder.getRepeatedNestedEnum(1)).isEqualTo(NestedEnum.BAR);
+    assertThat(builder.getRepeatedNestedEnum(2)).isEqualTo(NestedEnum.BAZ);
+    assertThat(builder.getRepeatedNestedEnumList()).hasSize(3);
   }
 
+  @Test
   public void testParserIntegerEnumValue() throws Exception {
     TestAllTypes.Builder actualBuilder = TestAllTypes.newBuilder();
     mergeFromJson("{\n" + "  \"optionalNestedEnum\": 2\n" + "}", actualBuilder);
 
     TestAllTypes expected = TestAllTypes.newBuilder().setOptionalNestedEnum(NestedEnum.BAZ).build();
-    assertEquals(expected, actualBuilder.build());
+    assertThat(actualBuilder.build()).isEqualTo(expected);
   }
 
+  @Test
   public void testCustomJsonName() throws Exception {
     TestCustomJsonName message = TestCustomJsonName.newBuilder().setValue(12345).build();
-    assertEquals("{\n" + "  \"@value\": 12345\n" + "}", JsonFormat.printer().print(message));
+    assertThat(JsonFormat.printer().print(message))
+        .isEqualTo("{\n" + "  \"@value\": 12345\n" + "}");
     assertRoundTripEquals(message);
   }
 
   // Regression test for b/73832901. Make sure html tags are escaped.
+  @Test
   public void testHtmlEscape() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("</script>").build();
-    assertEquals("{\n  \"optionalString\": \"\\u003c/script\\u003e\"\n}", toJsonString(message));
+    assertThat(toJsonString(message))
+        .isEqualTo("{\n  \"optionalString\": \"\\u003c/script\\u003e\"\n}");
 
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     JsonFormat.parser().merge(toJsonString(message), builder);
-    assertEquals(message.getOptionalString(), builder.getOptionalString());
+    assertThat(builder.getOptionalString()).isEqualTo(message.getOptionalString());
   }
 
+  @Test
   public void testIncludingDefaultValueFields() throws Exception {
     TestAllTypes message = TestAllTypes.getDefaultInstance();
-    assertEquals("{\n}", JsonFormat.printer().print(message));
-    assertEquals(
-        "{\n"
-            + "  \"optionalInt32\": 0,\n"
-            + "  \"optionalInt64\": \"0\",\n"
-            + "  \"optionalUint32\": 0,\n"
-            + "  \"optionalUint64\": \"0\",\n"
-            + "  \"optionalSint32\": 0,\n"
-            + "  \"optionalSint64\": \"0\",\n"
-            + "  \"optionalFixed32\": 0,\n"
-            + "  \"optionalFixed64\": \"0\",\n"
-            + "  \"optionalSfixed32\": 0,\n"
-            + "  \"optionalSfixed64\": \"0\",\n"
-            + "  \"optionalFloat\": 0.0,\n"
-            + "  \"optionalDouble\": 0.0,\n"
-            + "  \"optionalBool\": false,\n"
-            + "  \"optionalString\": \"\",\n"
-            + "  \"optionalBytes\": \"\",\n"
-            + "  \"optionalNestedEnum\": \"FOO\",\n"
-            + "  \"repeatedInt32\": [],\n"
-            + "  \"repeatedInt64\": [],\n"
-            + "  \"repeatedUint32\": [],\n"
-            + "  \"repeatedUint64\": [],\n"
-            + "  \"repeatedSint32\": [],\n"
-            + "  \"repeatedSint64\": [],\n"
-            + "  \"repeatedFixed32\": [],\n"
-            + "  \"repeatedFixed64\": [],\n"
-            + "  \"repeatedSfixed32\": [],\n"
-            + "  \"repeatedSfixed64\": [],\n"
-            + "  \"repeatedFloat\": [],\n"
-            + "  \"repeatedDouble\": [],\n"
-            + "  \"repeatedBool\": [],\n"
-            + "  \"repeatedString\": [],\n"
-            + "  \"repeatedBytes\": [],\n"
-            + "  \"repeatedNestedMessage\": [],\n"
-            + "  \"repeatedNestedEnum\": [],\n"
-            + "  \"optionalAliasedEnum\": \"ALIAS_FOO\"\n"
-            + "}",
-        JsonFormat.printer().includingDefaultValueFields().print(message));
+    assertThat(JsonFormat.printer().print(message)).isEqualTo("{\n}");
+    assertThat(JsonFormat.printer().includingDefaultValueFields().print(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"optionalInt32\": 0,\n"
+                + "  \"optionalInt64\": \"0\",\n"
+                + "  \"optionalUint32\": 0,\n"
+                + "  \"optionalUint64\": \"0\",\n"
+                + "  \"optionalSint32\": 0,\n"
+                + "  \"optionalSint64\": \"0\",\n"
+                + "  \"optionalFixed32\": 0,\n"
+                + "  \"optionalFixed64\": \"0\",\n"
+                + "  \"optionalSfixed32\": 0,\n"
+                + "  \"optionalSfixed64\": \"0\",\n"
+                + "  \"optionalFloat\": 0.0,\n"
+                + "  \"optionalDouble\": 0.0,\n"
+                + "  \"optionalBool\": false,\n"
+                + "  \"optionalString\": \"\",\n"
+                + "  \"optionalBytes\": \"\",\n"
+                + "  \"optionalNestedEnum\": \"FOO\",\n"
+                + "  \"repeatedInt32\": [],\n"
+                + "  \"repeatedInt64\": [],\n"
+                + "  \"repeatedUint32\": [],\n"
+                + "  \"repeatedUint64\": [],\n"
+                + "  \"repeatedSint32\": [],\n"
+                + "  \"repeatedSint64\": [],\n"
+                + "  \"repeatedFixed32\": [],\n"
+                + "  \"repeatedFixed64\": [],\n"
+                + "  \"repeatedSfixed32\": [],\n"
+                + "  \"repeatedSfixed64\": [],\n"
+                + "  \"repeatedFloat\": [],\n"
+                + "  \"repeatedDouble\": [],\n"
+                + "  \"repeatedBool\": [],\n"
+                + "  \"repeatedString\": [],\n"
+                + "  \"repeatedBytes\": [],\n"
+                + "  \"repeatedNestedMessage\": [],\n"
+                + "  \"repeatedNestedEnum\": [],\n"
+                + "  \"optionalAliasedEnum\": \"ALIAS_FOO\"\n"
+                + "}");
 
-    Set<FieldDescriptor> fixedFields = new HashSet<FieldDescriptor>();
+    Set<FieldDescriptor> fixedFields = new HashSet<>();
     for (FieldDescriptor fieldDesc : TestAllTypes.getDescriptor().getFields()) {
       if (fieldDesc.getName().contains("_fixed")) {
         fixedFields.add(fieldDesc);
       }
     }
 
-    assertEquals(
-        "{\n"
-            + "  \"optionalFixed32\": 0,\n"
-            + "  \"optionalFixed64\": \"0\",\n"
-            + "  \"repeatedFixed32\": [],\n"
-            + "  \"repeatedFixed64\": []\n"
-            + "}",
-        JsonFormat.printer().includingDefaultValueFields(fixedFields).print(message));
+    assertThat(JsonFormat.printer().includingDefaultValueFields(fixedFields).print(message))
+        .isEqualTo(
+            "{\n"
+                + "  \"optionalFixed32\": 0,\n"
+                + "  \"optionalFixed64\": \"0\",\n"
+                + "  \"repeatedFixed32\": [],\n"
+                + "  \"repeatedFixed64\": []\n"
+                + "}");
 
     TestAllTypes messageNonDefaults =
         message.toBuilder().setOptionalInt64(1234).setOptionalFixed32(3232).build();
-    assertEquals(
-        "{\n"
-            + "  \"optionalInt64\": \"1234\",\n"
-            + "  \"optionalFixed32\": 3232,\n"
-            + "  \"optionalFixed64\": \"0\",\n"
-            + "  \"repeatedFixed32\": [],\n"
-            + "  \"repeatedFixed64\": []\n"
-            + "}",
-        JsonFormat.printer().includingDefaultValueFields(fixedFields).print(messageNonDefaults));
+    assertThat(
+            JsonFormat.printer().includingDefaultValueFields(fixedFields).print(messageNonDefaults))
+        .isEqualTo(
+            "{\n"
+                + "  \"optionalInt64\": \"1234\",\n"
+                + "  \"optionalFixed32\": 3232,\n"
+                + "  \"optionalFixed64\": \"0\",\n"
+                + "  \"repeatedFixed32\": [],\n"
+                + "  \"repeatedFixed64\": []\n"
+                + "}");
 
     try {
       JsonFormat.printer().includingDefaultValueFields().includingDefaultValueFields();
-      fail("IllegalStateException is expected.");
+      assertWithMessage("IllegalStateException is expected.").fail();
     } catch (IllegalStateException e) {
       // Expected.
-      assertTrue(
-          "Exception message should mention includingDefaultValueFields.",
-          e.getMessage().contains("includingDefaultValueFields"));
+      assertWithMessage("Exception message should mention includingDefaultValueFields.")
+          .that(e.getMessage().contains("includingDefaultValueFields"))
+          .isTrue();
     }
 
     try {
       JsonFormat.printer().includingDefaultValueFields().includingDefaultValueFields(fixedFields);
-      fail("IllegalStateException is expected.");
+      assertWithMessage("IllegalStateException is expected.").fail();
     } catch (IllegalStateException e) {
       // Expected.
-      assertTrue(
-          "Exception message should mention includingDefaultValueFields.",
-          e.getMessage().contains("includingDefaultValueFields"));
+      assertWithMessage("Exception message should mention includingDefaultValueFields.")
+          .that(e.getMessage().contains("includingDefaultValueFields"))
+          .isTrue();
     }
 
     try {
       JsonFormat.printer().includingDefaultValueFields(fixedFields).includingDefaultValueFields();
-      fail("IllegalStateException is expected.");
+      assertWithMessage("IllegalStateException is expected.").fail();
     } catch (IllegalStateException e) {
       // Expected.
-      assertTrue(
-          "Exception message should mention includingDefaultValueFields.",
-          e.getMessage().contains("includingDefaultValueFields"));
+      assertWithMessage("Exception message should mention includingDefaultValueFields.")
+          .that(e.getMessage().contains("includingDefaultValueFields"))
+          .isTrue();
     }
 
     try {
       JsonFormat.printer()
           .includingDefaultValueFields(fixedFields)
           .includingDefaultValueFields(fixedFields);
-      fail("IllegalStateException is expected.");
+      assertWithMessage("IllegalStateException is expected.").fail();
     } catch (IllegalStateException e) {
       // Expected.
-      assertTrue(
-          "Exception message should mention includingDefaultValueFields.",
-          e.getMessage().contains("includingDefaultValueFields"));
+      assertWithMessage("Exception message should mention includingDefaultValueFields.")
+          .that(e.getMessage().contains("includingDefaultValueFields"))
+          .isTrue();
     }
 
-    Set<FieldDescriptor> intFields = new HashSet<FieldDescriptor>();
+    Set<FieldDescriptor> intFields = new HashSet<>();
     for (FieldDescriptor fieldDesc : TestAllTypes.getDescriptor().getFields()) {
       if (fieldDesc.getName().contains("_int")) {
         intFields.add(fieldDesc);
@@ -1450,203 +1501,205 @@
       JsonFormat.printer()
           .includingDefaultValueFields(intFields)
           .includingDefaultValueFields(fixedFields);
-      fail("IllegalStateException is expected.");
+      assertWithMessage("IllegalStateException is expected.").fail();
     } catch (IllegalStateException e) {
       // Expected.
-      assertTrue(
-          "Exception message should mention includingDefaultValueFields.",
-          e.getMessage().contains("includingDefaultValueFields"));
+      assertWithMessage("Exception message should mention includingDefaultValueFields.")
+          .that(e.getMessage().contains("includingDefaultValueFields"))
+          .isTrue();
     }
 
     try {
       JsonFormat.printer().includingDefaultValueFields(null);
-      fail("IllegalArgumentException is expected.");
+      assertWithMessage("IllegalArgumentException is expected.").fail();
     } catch (IllegalArgumentException e) {
       // Expected.
-      assertTrue(
-          "Exception message should mention includingDefaultValueFields.",
-          e.getMessage().contains("includingDefaultValueFields"));
+      assertWithMessage("Exception message should mention includingDefaultValueFields.")
+          .that(e.getMessage().contains("includingDefaultValueFields"))
+          .isTrue();
     }
 
     try {
       JsonFormat.printer().includingDefaultValueFields(Collections.<FieldDescriptor>emptySet());
-      fail("IllegalArgumentException is expected.");
+      assertWithMessage("IllegalArgumentException is expected.").fail();
     } catch (IllegalArgumentException e) {
       // Expected.
-      assertTrue(
-          "Exception message should mention includingDefaultValueFields.",
-          e.getMessage().contains("includingDefaultValueFields"));
+      assertWithMessage("Exception message should mention includingDefaultValueFields.")
+          .that(e.getMessage().contains("includingDefaultValueFields"))
+          .isTrue();
     }
 
     TestMap mapMessage = TestMap.getDefaultInstance();
-    assertEquals("{\n}", JsonFormat.printer().print(mapMessage));
-    assertEquals(
-        "{\n"
-            + "  \"int32ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"int64ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"uint32ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"uint64ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"sint32ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"sint64ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"fixed32ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"fixed64ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"sfixed32ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"sfixed64ToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"boolToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"stringToInt32Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToInt64Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToUint32Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToUint64Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToSint32Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToSint64Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToFixed32Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToFixed64Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToSfixed32Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToSfixed64Map\": {\n"
-            + "  },\n"
-            + "  \"int32ToFloatMap\": {\n"
-            + "  },\n"
-            + "  \"int32ToDoubleMap\": {\n"
-            + "  },\n"
-            + "  \"int32ToBoolMap\": {\n"
-            + "  },\n"
-            + "  \"int32ToStringMap\": {\n"
-            + "  },\n"
-            + "  \"int32ToBytesMap\": {\n"
-            + "  },\n"
-            + "  \"int32ToMessageMap\": {\n"
-            + "  },\n"
-            + "  \"int32ToEnumMap\": {\n"
-            + "  }\n"
-            + "}",
-        JsonFormat.printer().includingDefaultValueFields().print(mapMessage));
+    assertThat(JsonFormat.printer().print(mapMessage)).isEqualTo("{\n}");
+    assertThat(JsonFormat.printer().includingDefaultValueFields().print(mapMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"int32ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"int64ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"uint32ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"uint64ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"sint32ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"sint64ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"fixed32ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"fixed64ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"sfixed32ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"sfixed64ToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"boolToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"stringToInt32Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToInt64Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToUint32Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToUint64Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToSint32Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToSint64Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToFixed32Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToFixed64Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToSfixed32Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToSfixed64Map\": {\n"
+                + "  },\n"
+                + "  \"int32ToFloatMap\": {\n"
+                + "  },\n"
+                + "  \"int32ToDoubleMap\": {\n"
+                + "  },\n"
+                + "  \"int32ToBoolMap\": {\n"
+                + "  },\n"
+                + "  \"int32ToStringMap\": {\n"
+                + "  },\n"
+                + "  \"int32ToBytesMap\": {\n"
+                + "  },\n"
+                + "  \"int32ToMessageMap\": {\n"
+                + "  },\n"
+                + "  \"int32ToEnumMap\": {\n"
+                + "  }\n"
+                + "}");
 
     TestOneof oneofMessage = TestOneof.getDefaultInstance();
-    assertEquals("{\n}", JsonFormat.printer().print(oneofMessage));
-    assertEquals("{\n}", JsonFormat.printer().includingDefaultValueFields().print(oneofMessage));
+    assertThat(JsonFormat.printer().print(oneofMessage)).isEqualTo("{\n}");
+    assertThat(JsonFormat.printer().includingDefaultValueFields().print(oneofMessage))
+        .isEqualTo("{\n}");
 
     oneofMessage = TestOneof.newBuilder().setOneofInt32(42).build();
-    assertEquals("{\n  \"oneofInt32\": 42\n}", JsonFormat.printer().print(oneofMessage));
-    assertEquals(
-        "{\n  \"oneofInt32\": 42\n}",
-        JsonFormat.printer().includingDefaultValueFields().print(oneofMessage));
+    assertThat(JsonFormat.printer().print(oneofMessage)).isEqualTo("{\n  \"oneofInt32\": 42\n}");
+    assertThat(JsonFormat.printer().includingDefaultValueFields().print(oneofMessage))
+        .isEqualTo("{\n  \"oneofInt32\": 42\n}");
 
     TestOneof.Builder oneofBuilder = TestOneof.newBuilder();
     mergeFromJson("{\n" + "  \"oneofNullValue\": null \n" + "}", oneofBuilder);
     oneofMessage = oneofBuilder.build();
-    assertEquals("{\n  \"oneofNullValue\": null\n}", JsonFormat.printer().print(oneofMessage));
-    assertEquals(
-        "{\n  \"oneofNullValue\": null\n}",
-        JsonFormat.printer().includingDefaultValueFields().print(oneofMessage));
+    assertThat(JsonFormat.printer().print(oneofMessage))
+        .isEqualTo("{\n  \"oneofNullValue\": null\n}");
+    assertThat(JsonFormat.printer().includingDefaultValueFields().print(oneofMessage))
+        .isEqualTo("{\n  \"oneofNullValue\": null\n}");
   }
 
+  @Test
   public void testPreservingProtoFieldNames() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build();
-    assertEquals("{\n" + "  \"optionalInt32\": 12345\n" + "}", JsonFormat.printer().print(message));
-    assertEquals(
-        "{\n" + "  \"optional_int32\": 12345\n" + "}",
-        JsonFormat.printer().preservingProtoFieldNames().print(message));
+    assertThat(JsonFormat.printer().print(message))
+        .isEqualTo("{\n" + "  \"optionalInt32\": 12345\n" + "}");
+    assertThat(JsonFormat.printer().preservingProtoFieldNames().print(message))
+        .isEqualTo("{\n" + "  \"optional_int32\": 12345\n" + "}");
 
     // The json_name field option is ignored when configured to use original proto field names.
     TestCustomJsonName messageWithCustomJsonName =
         TestCustomJsonName.newBuilder().setValue(12345).build();
-    assertEquals(
-        "{\n" + "  \"value\": 12345\n" + "}",
-        JsonFormat.printer().preservingProtoFieldNames().print(messageWithCustomJsonName));
+    assertThat(JsonFormat.printer().preservingProtoFieldNames().print(messageWithCustomJsonName))
+        .isEqualTo("{\n" + "  \"value\": 12345\n" + "}");
 
     // Parsers accept both original proto field names and lowerCamelCase names.
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     JsonFormat.parser().merge("{\"optionalInt32\": 12345}", builder);
-    assertEquals(12345, builder.getOptionalInt32());
+    assertThat(builder.getOptionalInt32()).isEqualTo(12345);
     builder.clear();
     JsonFormat.parser().merge("{\"optional_int32\": 54321}", builder);
-    assertEquals(54321, builder.getOptionalInt32());
+    assertThat(builder.getOptionalInt32()).isEqualTo(54321);
   }
 
+  @Test
   public void testPrintingEnumsAsInts() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalNestedEnum(NestedEnum.BAR).build();
-    assertEquals(
-        "{\n" + "  \"optionalNestedEnum\": 1\n" + "}",
-        JsonFormat.printer().printingEnumsAsInts().print(message));
+    assertThat(JsonFormat.printer().printingEnumsAsInts().print(message))
+        .isEqualTo("{\n" + "  \"optionalNestedEnum\": 1\n" + "}");
   }
 
+  @Test
   public void testOmittingInsignificantWhiteSpace() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build();
-    assertEquals(
-        "{" + "\"optionalInt32\":12345" + "}",
-        JsonFormat.printer().omittingInsignificantWhitespace().print(message));
+    assertThat(JsonFormat.printer().omittingInsignificantWhitespace().print(message))
+        .isEqualTo("{" + "\"optionalInt32\":12345" + "}");
     TestAllTypes message1 = TestAllTypes.getDefaultInstance();
-    assertEquals("{}", JsonFormat.printer().omittingInsignificantWhitespace().print(message1));
+    assertThat(JsonFormat.printer().omittingInsignificantWhitespace().print(message1))
+        .isEqualTo("{}");
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     setAllFields(builder);
     TestAllTypes message2 = builder.build();
-    assertEquals(
-        "{"
-            + "\"optionalInt32\":1234,"
-            + "\"optionalInt64\":\"1234567890123456789\","
-            + "\"optionalUint32\":5678,"
-            + "\"optionalUint64\":\"2345678901234567890\","
-            + "\"optionalSint32\":9012,"
-            + "\"optionalSint64\":\"3456789012345678901\","
-            + "\"optionalFixed32\":3456,"
-            + "\"optionalFixed64\":\"4567890123456789012\","
-            + "\"optionalSfixed32\":7890,"
-            + "\"optionalSfixed64\":\"5678901234567890123\","
-            + "\"optionalFloat\":1.5,"
-            + "\"optionalDouble\":1.25,"
-            + "\"optionalBool\":true,"
-            + "\"optionalString\":\"Hello world!\","
-            + "\"optionalBytes\":\"AAEC\","
-            + "\"optionalNestedMessage\":{"
-            + "\"value\":100"
-            + "},"
-            + "\"optionalNestedEnum\":\"BAR\","
-            + "\"repeatedInt32\":[1234,234],"
-            + "\"repeatedInt64\":[\"1234567890123456789\",\"234567890123456789\"],"
-            + "\"repeatedUint32\":[5678,678],"
-            + "\"repeatedUint64\":[\"2345678901234567890\",\"345678901234567890\"],"
-            + "\"repeatedSint32\":[9012,10],"
-            + "\"repeatedSint64\":[\"3456789012345678901\",\"456789012345678901\"],"
-            + "\"repeatedFixed32\":[3456,456],"
-            + "\"repeatedFixed64\":[\"4567890123456789012\",\"567890123456789012\"],"
-            + "\"repeatedSfixed32\":[7890,890],"
-            + "\"repeatedSfixed64\":[\"5678901234567890123\",\"678901234567890123\"],"
-            + "\"repeatedFloat\":[1.5,11.5],"
-            + "\"repeatedDouble\":[1.25,11.25],"
-            + "\"repeatedBool\":[true,true],"
-            + "\"repeatedString\":[\"Hello world!\",\"ello world!\"],"
-            + "\"repeatedBytes\":[\"AAEC\",\"AQI=\"],"
-            + "\"repeatedNestedMessage\":[{"
-            + "\"value\":100"
-            + "},{"
-            + "\"value\":200"
-            + "}],"
-            + "\"repeatedNestedEnum\":[\"BAR\",\"BAZ\"]"
-            + "}",
-        toCompactJsonString(message2));
+    assertThat(toCompactJsonString(message2))
+        .isEqualTo(
+            "{"
+                + "\"optionalInt32\":1234,"
+                + "\"optionalInt64\":\"1234567890123456789\","
+                + "\"optionalUint32\":5678,"
+                + "\"optionalUint64\":\"2345678901234567890\","
+                + "\"optionalSint32\":9012,"
+                + "\"optionalSint64\":\"3456789012345678901\","
+                + "\"optionalFixed32\":3456,"
+                + "\"optionalFixed64\":\"4567890123456789012\","
+                + "\"optionalSfixed32\":7890,"
+                + "\"optionalSfixed64\":\"5678901234567890123\","
+                + "\"optionalFloat\":1.5,"
+                + "\"optionalDouble\":1.25,"
+                + "\"optionalBool\":true,"
+                + "\"optionalString\":\"Hello world!\","
+                + "\"optionalBytes\":\"AAEC\","
+                + "\"optionalNestedMessage\":{"
+                + "\"value\":100"
+                + "},"
+                + "\"optionalNestedEnum\":\"BAR\","
+                + "\"repeatedInt32\":[1234,234],"
+                + "\"repeatedInt64\":[\"1234567890123456789\",\"234567890123456789\"],"
+                + "\"repeatedUint32\":[5678,678],"
+                + "\"repeatedUint64\":[\"2345678901234567890\",\"345678901234567890\"],"
+                + "\"repeatedSint32\":[9012,10],"
+                + "\"repeatedSint64\":[\"3456789012345678901\",\"456789012345678901\"],"
+                + "\"repeatedFixed32\":[3456,456],"
+                + "\"repeatedFixed64\":[\"4567890123456789012\",\"567890123456789012\"],"
+                + "\"repeatedSfixed32\":[7890,890],"
+                + "\"repeatedSfixed64\":[\"5678901234567890123\",\"678901234567890123\"],"
+                + "\"repeatedFloat\":[1.5,11.5],"
+                + "\"repeatedDouble\":[1.25,11.25],"
+                + "\"repeatedBool\":[true,true],"
+                + "\"repeatedString\":[\"Hello world!\",\"ello world!\"],"
+                + "\"repeatedBytes\":[\"AAEC\",\"AQI=\"],"
+                + "\"repeatedNestedMessage\":[{"
+                + "\"value\":100"
+                + "},{"
+                + "\"value\":200"
+                + "}],"
+                + "\"repeatedNestedEnum\":[\"BAR\",\"BAZ\"]"
+                + "}");
   }
 
   // Regression test for b/29892357
+  @Test
   public void testEmptyWrapperTypesInAny() throws Exception {
     JsonFormat.TypeRegistry registry =
         JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build();
@@ -1660,40 +1713,42 @@
             + "}\n",
         builder);
     Any any = builder.build();
-    assertEquals(0, any.getValue().size());
+    assertThat(any.getValue().size()).isEqualTo(0);
   }
 
+  @Test
   public void testRecursionLimit() throws Exception {
     String input =
-        "{\n"
-            + "  \"nested\": {\n"
-            + "    \"nested\": {\n"
-            + "      \"nested\": {\n"
-            + "        \"nested\": {\n"
-            + "          \"value\": 1234\n"
-            + "        }\n"
-            + "      }\n"
-            + "    }\n"
-            + "  }\n"
-            + "}\n";
+      "{\n"
+          + "  \"nested\": {\n"
+          + "    \"nested\": {\n"
+          + "      \"nested\": {\n"
+          + "        \"nested\": {\n"
+          + "          \"value\": 1234\n"
+          + "        }\n"
+          + "      }\n"
+          + "    }\n"
+          + "  }\n"
+          + "}\n";
 
     JsonFormat.Parser parser = JsonFormat.parser();
     TestRecursive.Builder builder = TestRecursive.newBuilder();
     parser.merge(input, builder);
     TestRecursive message = builder.build();
-    assertEquals(1234, message.getNested().getNested().getNested().getNested().getValue());
+    assertThat(message.getNested().getNested().getNested().getNested().getValue()).isEqualTo(1234);
 
     parser = JsonFormat.parser().usingRecursionLimit(3);
     builder = TestRecursive.newBuilder();
     try {
       parser.merge(input, builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (InvalidProtocolBufferException e) {
       // Expected.
     }
   }
 
   // Test that we are not leaking out JSON exceptions.
+  @Test
   public void testJsonException() throws Exception {
     InputStream throwingInputStream =
         new InputStream() {
@@ -1708,9 +1763,9 @@
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       JsonFormat.parser().merge(throwingReader, builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (IOException e) {
-      assertEquals("12345", e.getMessage());
+      assertThat(e).hasMessageThat().isEqualTo("12345");
     }
 
     Reader invalidJsonReader = new StringReader("{ xxx - yyy }");
@@ -1719,13 +1774,14 @@
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       JsonFormat.parser().merge(invalidJsonReader, builder);
-      fail("Exception is expected.");
+      assertWithMessage("Exception is expected.").fail();
     } catch (InvalidProtocolBufferException e) {
       // Expected.
     }
   }
 
   // Test that an error is thrown if a nested JsonObject is parsed as a primitive field.
+  @Test
   public void testJsonObjectForPrimitiveField() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
@@ -1741,6 +1797,7 @@
     }
   }
 
+  @Test
   public void testSortedMapKeys() throws Exception {
     TestMap.Builder mapBuilder = TestMap.newBuilder();
     mapBuilder.putStringToInt32Map("\ud834\udd20", 3); // utf-8 F0 9D 84 A0
@@ -1759,43 +1816,45 @@
     mapBuilder.putInt32ToInt32Map(2, 2);
     mapBuilder.putInt32ToInt32Map(-3, -3);
     TestMap mapMessage = mapBuilder.build();
-    assertEquals(
-        "{\n"
-            + "  \"int32ToInt32Map\": {\n"
-            + "    \"-3\": -3,\n"
-            + "    \"1\": 1,\n"
-            + "    \"2\": 2,\n"
-            + "    \"3\": 3,\n"
-            + "    \"4\": 4,\n"
-            + "    \"5\": 5,\n"
-            + "    \"10\": 10\n"
-            + "  },\n"
-            + "  \"stringToInt32Map\": {\n"
-            + "    \"19\": 19,\n"
-            + "    \"8\": 8,\n"
-            + "    \"abc\": 20,\n"
-            + "    \"foo\": 99,\n"
-            + "    \"xxx\": 123,\n"
-            + "    \"\u20ac\": 1,\n"
-            + "    \"\ufb00\": 2,\n"
-            + "    \"\ud834\udd20\": 3\n"
-            + "  }\n"
-            + "}",
-        toSortedJsonString(mapMessage));
+    assertThat(toSortedJsonString(mapMessage))
+        .isEqualTo(
+            "{\n"
+                + "  \"int32ToInt32Map\": {\n"
+                + "    \"-3\": -3,\n"
+                + "    \"1\": 1,\n"
+                + "    \"2\": 2,\n"
+                + "    \"3\": 3,\n"
+                + "    \"4\": 4,\n"
+                + "    \"5\": 5,\n"
+                + "    \"10\": 10\n"
+                + "  },\n"
+                + "  \"stringToInt32Map\": {\n"
+                + "    \"19\": 19,\n"
+                + "    \"8\": 8,\n"
+                + "    \"abc\": 20,\n"
+                + "    \"foo\": 99,\n"
+                + "    \"xxx\": 123,\n"
+                + "    \"\u20ac\": 1,\n"
+                + "    \"\ufb00\": 2,\n"
+                + "    \"\ud834\udd20\": 3\n"
+                + "  }\n"
+                + "}");
 
     TestMap emptyMap = TestMap.getDefaultInstance();
-    assertEquals("{\n}", toSortedJsonString(emptyMap));
+    assertThat(toSortedJsonString(emptyMap)).isEqualTo("{\n}");
   }
 
+  @Test
   public void testPrintingEnumsAsIntsChainedAfterIncludingDefaultValueFields() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalBool(false).build();
 
-    assertEquals(
-        "{\n" + "  \"optionalBool\": false\n" + "}",
-        JsonFormat.printer()
-            .includingDefaultValueFields(
-                ImmutableSet.of(message.getDescriptorForType().findFieldByName("optional_bool")))
-            .printingEnumsAsInts()
-            .print(message));
+    assertThat(
+            JsonFormat.printer()
+                .includingDefaultValueFields(
+                    ImmutableSet.of(
+                        message.getDescriptorForType().findFieldByName("optional_bool")))
+                .printingEnumsAsInts()
+                .print(message))
+        .isEqualTo("{\n" + "  \"optionalBool\": false\n" + "}");
   }
 }
diff --git a/java/util/src/test/java/com/google/protobuf/util/StructsTest.java b/java/util/src/test/java/com/google/protobuf/util/StructsTest.java
index 265aff5..9eb4cc6 100644
--- a/java/util/src/test/java/com/google/protobuf/util/StructsTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/StructsTest.java
@@ -33,22 +33,28 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.google.protobuf.Struct;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public final class StructsTest extends TestCase {
+@RunWith(JUnit4.class)
+public final class StructsTest {
 
+  @Test
   public void test1pair_constructsObject() throws Exception {
     Struct.Builder expected = Struct.newBuilder();
     JsonFormat.parser().merge("{\"k1\": 1}", expected);
     assertThat(Structs.of("k1", Values.of(1))).isEqualTo(expected.build());
   }
 
+  @Test
   public void test2pair_constructsObject() throws Exception {
     Struct.Builder expected = Struct.newBuilder();
     JsonFormat.parser().merge("{\"k1\": 1, \"k2\": 2}", expected);
     assertThat(Structs.of("k1", Values.of(1), "k2", Values.of(2))).isEqualTo(expected.build());
   }
 
+  @Test
   public void test3pair_constructsObject() throws Exception {
     Struct.Builder expected = Struct.newBuilder();
     JsonFormat.parser().merge("{\"k1\": 1, \"k2\": 2, \"k3\": 3}", expected);
diff --git a/java/util/src/test/java/com/google/protobuf/util/ValuesTest.java b/java/util/src/test/java/com/google/protobuf/util/ValuesTest.java
index d646e97..9e172c8 100644
--- a/java/util/src/test/java/com/google/protobuf/util/ValuesTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/ValuesTest.java
@@ -38,19 +38,25 @@
 import com.google.protobuf.Value;
 import java.util.ArrayList;
 import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public final class ValuesTest extends TestCase {
+@RunWith(JUnit4.class)
+public final class ValuesTest {
+  @Test
   public void testOfNull_IsNullValue() throws Exception {
     assertThat(Values.ofNull())
         .isEqualTo(Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build());
   }
 
+  @Test
   public void testOfBoolean_ConstructsValue() {
     assertThat(Values.of(true)).isEqualTo(Value.newBuilder().setBoolValue(true).build());
     assertThat(Values.of(false)).isEqualTo(Value.newBuilder().setBoolValue(false).build());
   }
 
+  @Test
   public void testOfNumeric_ConstructsValue() {
     assertThat(Values.of(100)).isEqualTo(Value.newBuilder().setNumberValue(100).build());
     assertThat(Values.of(1000L)).isEqualTo(Value.newBuilder().setNumberValue(1000).build());
@@ -58,11 +64,13 @@
     assertThat(Values.of(10000.23)).isEqualTo(Value.newBuilder().setNumberValue(10000.23).build());
   }
 
+  @Test
   public void testOfString_ConstructsValue() {
     assertThat(Values.of("")).isEqualTo(Value.newBuilder().setStringValue("").build());
     assertThat(Values.of("foo")).isEqualTo(Value.newBuilder().setStringValue("foo").build());
   }
 
+  @Test
   public void testOfStruct_ConstructsValue() {
     Struct.Builder builder = Struct.newBuilder();
     builder.putFields("a", Values.of("a"));
@@ -72,6 +80,7 @@
         .isEqualTo(Value.newBuilder().setStructValue(builder.build()).build());
   }
 
+  @Test
   public void testOfListValue_ConstructsInstance() {
     ListValue.Builder builder = ListValue.newBuilder();
     builder.addValues(Values.of(1));
@@ -81,6 +90,7 @@
         .isEqualTo(Value.newBuilder().setListValue(builder.build()).build());
   }
 
+  @Test
   public void testOfIterable_ReturnsTheValue() {
     ListValue.Builder builder = ListValue.newBuilder();
     builder.addValues(Values.of(1));
diff --git a/python/google/protobuf/internal/api_implementation.py b/python/google/protobuf/internal/api_implementation.py
index be1af7d..a366731 100644
--- a/python/google/protobuf/internal/api_implementation.py
+++ b/python/google/protobuf/internal/api_implementation.py
@@ -80,8 +80,7 @@
       # and Python 3 default to `_api_version = 2` (C++ implementation V2).
       pass
 
-_default_implementation_type = (
-    'python' if _api_version <= 0 else 'cpp')
+_default_implementation_type = ('python' if _api_version <= 0 else 'cpp')
 
 # This environment variable can be used to switch to a certain implementation
 # of the Python API, overriding the compile-time constants in the
diff --git a/python/google/protobuf/internal/more_extensions.proto b/python/google/protobuf/internal/more_extensions.proto
index 5038fd2..5340a70 100644
--- a/python/google/protobuf/internal/more_extensions.proto
+++ b/python/google/protobuf/internal/more_extensions.proto
@@ -34,11 +34,14 @@
 
 package google.protobuf.internal;
 
-
 message TopLevelMessage {
-  optional ExtendedMessage submessage = 1;
+  optional ExtendedMessage submessage = 1 [lazy = true];
+  optional NestedMessage nested_message = 2 [lazy = true];
 }
 
+message NestedMessage {
+  optional ExtendedMessage submessage = 1 [lazy = true];
+}
 
 message ExtendedMessage {
   optional int32 optional_int32 = 1001;
@@ -46,12 +49,10 @@
   extensions 1 to 999;
 }
 
-
 message ForeignMessage {
   optional int32 foreign_message_int = 1;
 }
 
-
 extend ExtendedMessage {
   optional int32 optional_int_extension = 1;
   optional ForeignMessage optional_message_extension = 2;
diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py
index 3ee14e4..d7d63c8 100755
--- a/python/google/protobuf/internal/proto_builder_test.py
+++ b/python/google/protobuf/internal/proto_builder_test.py
@@ -32,16 +32,13 @@
 
 """Tests for google.protobuf.proto_builder."""
 
-try:
-    from collections import OrderedDict
-except ImportError:
-    from ordereddict import OrderedDict  #PY26
+import collections
 try:
   import unittest2 as unittest
 except ImportError:
   import unittest
 
-from google.protobuf import descriptor_pb2
+from google.protobuf import descriptor_pb2  # pylint: disable=g-import-not-at-top
 from google.protobuf import descriptor
 from google.protobuf import descriptor_pool
 from google.protobuf import proto_builder
@@ -51,7 +48,7 @@
 class ProtoBuilderTest(unittest.TestCase):
 
   def setUp(self):
-    self.ordered_fields = OrderedDict([
+    self.ordered_fields = collections.OrderedDict([
         ('foo', descriptor_pb2.FieldDescriptorProto.TYPE_INT64),
         ('bar', descriptor_pb2.FieldDescriptorProto.TYPE_STRING),
         ])
diff --git a/python/google/protobuf/proto_api.h b/python/google/protobuf/proto_api.h
index c869bce..2e2156a 100644
--- a/python/google/protobuf/proto_api.h
+++ b/python/google/protobuf/proto_api.h
@@ -78,6 +78,18 @@
   // With the current implementation, only empty messages are in this case.
   virtual Message* GetMutableMessagePointer(PyObject* msg) const = 0;
 
+  // If the passed object is a Python Message Descriptor, returns its internal
+  // pointer.
+  // Otherwise, returns NULL with an exception set.
+  virtual const Descriptor* MessageDescriptor_AsDescriptor(
+      PyObject* desc) const = 0;
+
+  // If the passed object is a Python Enum Descriptor, returns its internal
+  // pointer.
+  // Otherwise, returns NULL with an exception set.
+  virtual const EnumDescriptor* EnumDescriptor_AsDescriptor(
+      PyObject* enum_desc) const = 0;
+
   // Expose the underlying DescriptorPool and MessageFactory to enable C++ code
   // to create Python-compatible message.
   virtual const DescriptorPool* GetDefaultDescriptorPool() const = 0;
@@ -108,6 +120,15 @@
   // python objects referencing the same C++ object.
   virtual PyObject* NewMessageOwnedExternally(
       Message* msg, PyObject* py_message_factory) const = 0;
+
+  // Returns a new reference for the given DescriptorPool.
+  // The returned object does not manage the C++ DescriptorPool: it is the
+  // responsibility of the caller to keep it alive.
+  // As long as the returned Python DescriptorPool object is kept alive,
+  // functions that process C++ descriptors or messages created from this pool
+  // can work and return their Python counterparts.
+  virtual PyObject* DescriptorPool_FromPool(
+      const google::protobuf::DescriptorPool* pool) const = 0;
 };
 
 inline const char* PyProtoAPICapsuleName() {
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
index b607956..7154d31 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -111,6 +111,8 @@
   cpool->error_collector = nullptr;
   cpool->underlay = NULL;
   cpool->database = NULL;
+  cpool->is_owned = false;
+  cpool->is_mutable = false;
 
   cpool->descriptor_options = new std::unordered_map<const void*, PyObject*>();
 
@@ -138,6 +140,8 @@
     return NULL;
   }
   cpool->pool = new DescriptorPool(underlay);
+  cpool->is_owned = true;
+  cpool->is_mutable = true;
   cpool->underlay = underlay;
 
   if (!descriptor_pool_map->insert(
@@ -159,10 +163,13 @@
   if (database != NULL) {
     cpool->error_collector = new BuildFileErrorCollector();
     cpool->pool = new DescriptorPool(database, cpool->error_collector);
+    cpool->is_mutable = false;
     cpool->database = database;
   } else {
     cpool->pool = new DescriptorPool();
+    cpool->is_mutable = true;
   }
+  cpool->is_owned = true;
 
   if (!descriptor_pool_map->insert(std::make_pair(cpool->pool, cpool)).second) {
     // Should never happen -- would indicate an internal error / bug.
@@ -201,7 +208,9 @@
   }
   delete self->descriptor_options;
   delete self->database;
-  delete self->pool;
+  if (self->is_owned) {
+    delete self->pool;
+  }
   delete self->error_collector;
   Py_TYPE(self)->tp_free(pself);
 }
@@ -582,6 +591,12 @@
         "Add your file to the underlying database.");
     return NULL;
   }
+  if (!self->is_mutable) {
+    PyErr_SetString(
+        PyExc_ValueError,
+        "This DescriptorPool is not mutable and cannot add new definitions.");
+    return nullptr;
+  }
 
   if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
     return NULL;
@@ -606,8 +621,9 @@
 
   BuildFileErrorCollector error_collector;
   const FileDescriptor* descriptor =
-      self->pool->BuildFileCollectingErrors(file_proto,
-                                            &error_collector);
+      // Pool is mutable, we can remove the "const".
+      const_cast<DescriptorPool*>(self->pool)
+          ->BuildFileCollectingErrors(file_proto, &error_collector);
   if (descriptor == NULL) {
     PyErr_Format(PyExc_TypeError,
                  "Couldn't build proto file into descriptor pool!\n%s",
@@ -615,6 +631,7 @@
     return NULL;
   }
 
+
   return PyFileDescriptor_FromDescriptorWithSerializedPb(
       descriptor, serialized_pb);
 }
@@ -768,6 +785,33 @@
   return it->second;
 }
 
+PyObject* PyDescriptorPool_FromPool(const DescriptorPool* pool) {
+  PyDescriptorPool* existing_pool = GetDescriptorPool_FromPool(pool);
+  if (existing_pool != nullptr) {
+    Py_INCREF(existing_pool);
+    return reinterpret_cast<PyObject*>(existing_pool);
+  } else {
+    PyErr_Clear();
+  }
+
+  PyDescriptorPool* cpool = cdescriptor_pool::_CreateDescriptorPool();
+  if (cpool == nullptr) {
+    return nullptr;
+  }
+  cpool->pool = const_cast<DescriptorPool*>(pool);
+  cpool->is_owned = false;
+  cpool->is_mutable = false;
+  cpool->underlay = nullptr;
+
+  if (!descriptor_pool_map->insert(std::make_pair(cpool->pool, cpool)).second) {
+    // Should never happen -- We already checked the existence above.
+    PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
+    return nullptr;
+  }
+
+  return reinterpret_cast<PyObject*>(cpool);
+}
+
 }  // namespace python
 }  // namespace protobuf
 }  // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h
index 2d456f9..48658d3 100644
--- a/python/google/protobuf/pyext/descriptor_pool.h
+++ b/python/google/protobuf/pyext/descriptor_pool.h
@@ -54,10 +54,18 @@
 // "Methods" that interacts with this DescriptorPool are in the cdescriptor_pool
 // namespace.
 typedef struct PyDescriptorPool {
-  PyObject_HEAD
+  PyObject_HEAD;
 
   // The C++ pool containing Descriptors.
-  DescriptorPool* pool;
+  const DescriptorPool* pool;
+
+  // True if we should free the pointer above.
+  bool is_owned;
+
+  // True if this pool accepts new proto definitions.
+  // In this case it is allowed to const_cast<DescriptorPool*>(pool).
+  bool is_mutable;
+
 
   // The error collector to store error info. Can be NULL. This pointer is
   // owned.
@@ -116,16 +124,20 @@
 
 }  // namespace cdescriptor_pool
 
-// Retrieve the global descriptor pool owned by the _message module.
+// Retrieves the global descriptor pool owned by the _message module.
 // This is the one used by pb2.py generated modules.
 // Returns a *borrowed* reference.
 // "Default" pool used to register messages from _pb2.py modules.
 PyDescriptorPool* GetDefaultDescriptorPool();
 
-// Retrieve the python descriptor pool owning a C++ descriptor pool.
+// Retrieves an existing python descriptor pool owning the C++ descriptor pool.
 // Returns a *borrowed* reference.
 PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool);
 
+// Wraps a C++ descriptor pool in a Python object, creates it if necessary.
+// Returns a new reference.
+PyObject* PyDescriptorPool_FromPool(const DescriptorPool* pool);
+
 // Initialize objects used by this module.
 bool InitDescriptorPool();
 
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 125df32..34816ee 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -110,6 +110,10 @@
       const std::vector<const FieldDescriptor*>& fields) {
     lhs->GetReflection()->UnsafeShallowSwapFields(lhs, rhs, fields);
   }
+  static bool IsLazyField(const Reflection* reflection,
+                          const FieldDescriptor* field) {
+    return reflection->IsLazyField(field);
+  }
 };
 
 static PyObject* kDESCRIPTOR;
@@ -482,6 +486,18 @@
 
 }  // namespace message_meta
 
+// Protobuf has a 64MB limit built in, this variable will override this. Please
+// do not enable this unless you fully understand the implications: protobufs
+// must all be kept in memory at the same time, so if they grow too big you may
+// get OOM errors. The protobuf APIs do not provide any tools for processing
+// protobufs in chunks.  If you have protos this big you should break them up if
+// it is at all convenient to do so.
+#ifdef PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS
+static bool allow_oversize_protos = true;
+#else
+static bool allow_oversize_protos = false;
+#endif
+
 static PyTypeObject _CMessageClass_Type = {
     PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
     ".MessageMeta",                       // tp_name
@@ -877,6 +893,7 @@
   if (!self->composite_fields) {
     return 0;
   }
+  PyMessageFactory* factory = GetFactoryForMessage(self);
   for (const auto& item : *self->composite_fields) {
     const FieldDescriptor* descriptor = item.first;
     if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
@@ -890,8 +907,8 @@
       if (reflection->HasField(*message, descriptor)) {
         // Message used to be read_only, but is no longer. Get the new pointer
         // and record it.
-        Message* mutable_message =
-            reflection->MutableMessage(message, descriptor, nullptr);
+        Message* mutable_message = reflection->MutableMessage(
+            message, descriptor, factory->message_factory);
         cmsg->message = mutable_message;
         cmsg->read_only = false;
         if (FixupMessageAfterMerge(cmsg) < 0) {
@@ -1052,6 +1069,9 @@
     }
   }
 
+  Arena* arena = Arena::InternalHelper<Message>::GetArenaForAllocation(message);
+  GOOGLE_DCHECK_EQ(arena, nullptr)
+      << "python protobuf is expected to be allocated from heap";
   // Remove items, starting from the end.
   for (; length > to; length--) {
     if (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
@@ -1060,7 +1080,18 @@
     }
     // It seems that RemoveLast() is less efficient for sub-messages, and
     // the memory is not completely released. Prefer ReleaseLast().
-    Message* sub_message = reflection->ReleaseLast(message, field_descriptor);
+    //
+    // To work around a debug hardening (PROTOBUF_FORCE_COPY_IN_RELEASE),
+    // explicitly use UnsafeArenaReleaseLast. To not break rare use cases where
+    // arena is used, we fallback to ReleaseLast (but GOOGLE_DCHECK to find/fix it).
+    //
+    // Note that arena is likely null and GOOGLE_DCHECK and ReleaesLast might be
+    // redundant. The current approach takes extra cautious path not to disrupt
+    // production.
+    Message* sub_message =
+        (arena == nullptr)
+            ? reflection->UnsafeArenaReleaseLast(message, field_descriptor)
+            : reflection->ReleaseLast(message, field_descriptor);
     // If there is a live weak reference to an item being removed, we "Release"
     // it, and it takes ownership of the message.
     if (CMessage* released = self->MaybeReleaseSubMessage(sub_message)) {
@@ -1914,18 +1945,6 @@
   Py_RETURN_NONE;
 }
 
-// Protobuf has a 64MB limit built in, this variable will override this. Please
-// do not enable this unless you fully understand the implications: protobufs
-// must all be kept in memory at the same time, so if they grow too big you may
-// get OOM errors. The protobuf APIs do not provide any tools for processing
-// protobufs in chunks.  If you have protos this big you should break them up if
-// it is at all convenient to do so.
-#ifdef PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS
-static bool allow_oversize_protos = true;
-#else
-static bool allow_oversize_protos = false;
-#endif
-
 // Provide a method in the module to set allow_oversize_protos to a boolean
 // value. This method returns the newly value of allow_oversize_protos.
 PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg) {
@@ -2267,8 +2286,6 @@
     CMessage* self, const FieldDescriptor* field_descriptor) {
   const Reflection* reflection = self->message->GetReflection();
   PyMessageFactory* factory = GetFactoryForMessage(self);
-  const Message& sub_message = reflection->GetMessage(
-      *self->message, field_descriptor, factory->message_factory);
 
   CMessageClass* message_class = message_factory::GetOrCreateMessageClass(
       factory, field_descriptor->message_type());
@@ -2286,7 +2303,20 @@
   Py_INCREF(self);
   cmsg->parent = self;
   cmsg->parent_field_descriptor = field_descriptor;
-  cmsg->read_only = !reflection->HasField(*self->message, field_descriptor);
+  if (reflection->HasField(*self->message, field_descriptor)) {
+    // Force triggering MutableMessage to set the lazy message 'Dirty'
+    if (MessageReflectionFriend::IsLazyField(reflection, field_descriptor)) {
+      Message* sub_message = reflection->MutableMessage(
+          self->message, field_descriptor, factory->message_factory);
+      cmsg->read_only = false;
+      cmsg->message = sub_message;
+      return cmsg;
+    }
+  } else {
+    cmsg->read_only = true;
+  }
+  const Message& sub_message = reflection->GetMessage(
+      *self->message, field_descriptor, factory->message_factory);
   cmsg->message = const_cast<Message*>(&sub_message);
   return cmsg;
 }
@@ -2869,20 +2899,36 @@
   return cmsg->message;
 }
 
-PyObject* PyMessage_New(const Descriptor* descriptor,
-                        PyObject* py_message_factory) {
+// Returns a new reference to the MessageClass to use for message creation.
+// - if a PyMessageFactory is passed, use it.
+// - Otherwise, if a PyDescriptorPool was created, use its factory.
+static CMessageClass* GetMessageClassFromDescriptor(
+    const Descriptor* descriptor, PyObject* py_message_factory) {
   PyMessageFactory* factory = nullptr;
   if (py_message_factory == nullptr) {
-    factory = GetDescriptorPool_FromPool(descriptor->file()->pool())
-                  ->py_message_factory;
+    PyDescriptorPool* pool =
+        GetDescriptorPool_FromPool(descriptor->file()->pool());
+    if (pool == nullptr) {
+      PyErr_SetString(PyExc_TypeError,
+                      "Unknown descriptor pool; C++ users should call "
+                      "DescriptorPool_FromPool and keep it alive");
+      return nullptr;
+    }
+    factory = pool->py_message_factory;
   } else if (PyObject_TypeCheck(py_message_factory, &PyMessageFactory_Type)) {
     factory = reinterpret_cast<PyMessageFactory*>(py_message_factory);
   } else {
     PyErr_SetString(PyExc_TypeError, "Expected a MessageFactory");
     return nullptr;
   }
-  auto* message_class =
-      message_factory::GetOrCreateMessageClass(factory, descriptor);
+
+  return message_factory::GetOrCreateMessageClass(factory, descriptor);
+}
+
+PyObject* PyMessage_New(const Descriptor* descriptor,
+                        PyObject* py_message_factory) {
+  CMessageClass* message_class =
+      GetMessageClassFromDescriptor(descriptor, py_message_factory);
   if (message_class == nullptr) {
     return nullptr;
   }
@@ -2897,20 +2943,8 @@
 
 PyObject* PyMessage_NewMessageOwnedExternally(Message* message,
                                               PyObject* py_message_factory) {
-  if (py_message_factory) {
-    PyErr_SetString(PyExc_NotImplementedError,
-                    "Default message_factory=NULL is the only supported value");
-    return nullptr;
-  }
-  if (message->GetReflection()->GetMessageFactory() !=
-      MessageFactory::generated_factory()) {
-    PyErr_SetString(PyExc_TypeError,
-                    "Message pointer was not created from the default factory");
-    return nullptr;
-  }
-
-  CMessageClass* message_class = message_factory::GetOrCreateMessageClass(
-      GetDefaultDescriptorPool()->py_message_factory, message->GetDescriptor());
+  CMessageClass* message_class = GetMessageClassFromDescriptor(
+      message->GetDescriptor(), py_message_factory);
   if (message_class == nullptr) {
     return nullptr;
   }
diff --git a/python/google/protobuf/pyext/message_module.cc b/python/google/protobuf/pyext/message_module.cc
index b5975f7..4125dd7 100644
--- a/python/google/protobuf/pyext/message_module.cc
+++ b/python/google/protobuf/pyext/message_module.cc
@@ -31,6 +31,7 @@
 #include <Python.h>
 
 #include <google/protobuf/message_lite.h>
+#include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message_factory.h>
@@ -46,6 +47,15 @@
   google::protobuf::Message* GetMutableMessagePointer(PyObject* msg) const override {
     return google::protobuf::python::PyMessage_GetMutableMessagePointer(msg);
   }
+  const google::protobuf::Descriptor* MessageDescriptor_AsDescriptor(
+      PyObject* desc) const override {
+    return google::protobuf::python::PyMessageDescriptor_AsDescriptor(desc);
+  }
+  const google::protobuf::EnumDescriptor* EnumDescriptor_AsDescriptor(
+      PyObject* enum_desc) const override {
+    return google::protobuf::python::PyEnumDescriptor_AsDescriptor(enum_desc);
+  }
+
   const google::protobuf::DescriptorPool* GetDefaultDescriptorPool() const override {
     return google::protobuf::python::GetDefaultDescriptorPool()->pool;
   }
@@ -63,6 +73,10 @@
     return google::protobuf::python::PyMessage_NewMessageOwnedExternally(
         msg, py_message_factory);
   }
+  PyObject* DescriptorPool_FromPool(
+      const google::protobuf::DescriptorPool* pool) const override {
+    return google::protobuf::python::PyDescriptorPool_FromPool(pool);
+  }
 };
 
 }  // namespace
diff --git a/src/Makefile.am b/src/Makefile.am
index edd3660..0129741 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -107,6 +107,7 @@
   google/protobuf/generated_message_util.h                       \
   google/protobuf/has_bits.h                                     \
   google/protobuf/implicit_weak_message.h                        \
+  google/protobuf/inlined_string_field.h                         \
   google/protobuf/io/io_win32.h                                \
   google/protobuf/map_entry.h                                    \
   google/protobuf/map_entry_lite.h                               \
@@ -128,6 +129,7 @@
   google/protobuf/repeated_field.h                               \
   google/protobuf/service.h                                      \
   google/protobuf/source_context.pb.h                            \
+  google/protobuf/string_member_robber.h                         \
   google/protobuf/struct.pb.h                                    \
   google/protobuf/text_format.h                                  \
   google/protobuf/timestamp.pb.h                                 \
@@ -212,6 +214,7 @@
   google/protobuf/generated_message_table_driven_lite.h        \
   google/protobuf/generated_message_table_driven_lite.cc       \
   google/protobuf/implicit_weak_message.cc                     \
+  google/protobuf/inlined_string_field.cc                      \
   google/protobuf/map.cc                                       \
   google/protobuf/message_lite.cc                              \
   google/protobuf/parse_context.cc                             \
@@ -703,6 +706,8 @@
   google/protobuf/map_test_util.inc                            \
   google/protobuf/map_test_util.h                              \
   google/protobuf/map_test_util_impl.h                         \
+  google/protobuf/reflection_tester.cc                         \
+  google/protobuf/reflection_tester.h                          \
   google/protobuf/test_util.cc                                 \
   google/protobuf/test_util.h                                  \
   google/protobuf/test_util.inc                                \
@@ -754,6 +759,7 @@
   google/protobuf/dynamic_message_unittest.cc                  \
   google/protobuf/extension_set_unittest.cc                    \
   google/protobuf/generated_message_reflection_unittest.cc     \
+  google/protobuf/inlined_string_field_unittest.cc             \
   google/protobuf/map_field_test.cc                            \
   google/protobuf/map_test.cc                                  \
   google/protobuf/message_unittest.cc                          \
@@ -771,6 +777,7 @@
   google/protobuf/unknown_field_set_unittest.cc                \
   google/protobuf/well_known_types_unittest.cc                 \
   google/protobuf/wire_format_unittest.cc                      \
+  google/protobuf/wire_format_unittest.inc                     \
   google/protobuf/io/coded_stream_unittest.cc                  \
   google/protobuf/io/printer_unittest.cc                       \
   google/protobuf/io/tokenizer_unittest.cc                     \
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index e371a67..7fc1219 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -42,11 +42,12 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Any, type_url_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Any, value_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::Any)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Any)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -175,7 +176,8 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Any.type_url"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // bytes value = 2;
       case 2:
@@ -183,28 +185,29 @@
           auto str = _internal_mutable_value();
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -260,13 +263,7 @@
         this->_internal_value());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Any::_class_data_ = {
@@ -275,8 +272,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Any::GetClassData() const { return &_class_data_; }
 
-void Any::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Any::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Any *>(to)->MergeFrom(
       static_cast<const Any &>(from));
 }
@@ -310,16 +307,18 @@
 
 void Any::InternalSwap(Any* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &type_url_, GetArenaForAllocation(),
-      &other->type_url_, other->GetArenaForAllocation()
+      &type_url_, lhs_arena,
+      &other->type_url_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &value_, GetArenaForAllocation(),
-      &other->value_, other->GetArenaForAllocation()
+      &value_, lhs_arena,
+      &other->value_, rhs_arena
   );
 }
 
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index 158da76..f727663 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -175,7 +175,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Any& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index b2e14d1..8d45b60 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -79,6 +79,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Api, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Api, methods_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Api, options_),
@@ -91,6 +92,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Method, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Method, request_type_url_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Method, request_streaming_),
@@ -103,13 +105,14 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Mixin, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Mixin, root_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::Api)},
-  { 12, -1, sizeof(PROTOBUF_NAMESPACE_ID::Method)},
-  { 24, -1, sizeof(PROTOBUF_NAMESPACE_ID::Mixin)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Api)},
+  { 13, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Method)},
+  { 26, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Mixin)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -280,7 +283,8 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Api.name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.Method methods = 2;
       case 2:
@@ -292,7 +296,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.Option options = 3;
       case 3:
@@ -304,7 +309,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // string version = 4;
       case 4:
@@ -313,14 +319,16 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Api.version"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.SourceContext source_context = 5;
       case 5:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 42)) {
           ptr = ctx->ParseMessage(_internal_mutable_source_context(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.Mixin mixins = 6;
       case 6:
@@ -332,7 +340,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.Syntax syntax = 7;
       case 7:
@@ -340,28 +349,29 @@
           ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
           _internal_set_syntax(static_cast<PROTOBUF_NAMESPACE_ID::Syntax>(val));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -494,13 +504,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_syntax());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Api::_class_data_ = {
@@ -509,8 +513,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Api::GetClassData() const { return &_class_data_; }
 
-void Api::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Api::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Api *>(to)->MergeFrom(
       static_cast<const Api &>(from));
 }
@@ -553,19 +557,21 @@
 
 void Api::InternalSwap(Api* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   methods_.InternalSwap(&other->methods_);
   options_.InternalSwap(&other->options_);
   mixins_.InternalSwap(&other->mixins_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &version_, GetArenaForAllocation(),
-      &other->version_, other->GetArenaForAllocation()
+      &version_, lhs_arena,
+      &other->version_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(Api, syntax_)
@@ -688,7 +694,8 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Method.name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // string request_type_url = 2;
       case 2:
@@ -697,14 +704,16 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Method.request_type_url"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // bool request_streaming = 3;
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 24)) {
           request_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // string response_type_url = 4;
       case 4:
@@ -713,14 +722,16 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Method.response_type_url"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // bool response_streaming = 5;
       case 5:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 40)) {
           response_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.Option options = 6;
       case 6:
@@ -732,7 +743,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.Syntax syntax = 7;
       case 7:
@@ -740,28 +752,29 @@
           ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
           _internal_set_syntax(static_cast<PROTOBUF_NAMESPACE_ID::Syntax>(val));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -888,13 +901,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_syntax());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Method::_class_data_ = {
@@ -903,8 +910,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Method::GetClassData() const { return &_class_data_; }
 
-void Method::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Method::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Method *>(to)->MergeFrom(
       static_cast<const Method &>(from));
 }
@@ -951,22 +958,24 @@
 
 void Method::InternalSwap(Method* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   options_.InternalSwap(&other->options_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &request_type_url_, GetArenaForAllocation(),
-      &other->request_type_url_, other->GetArenaForAllocation()
+      &request_type_url_, lhs_arena,
+      &other->request_type_url_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &response_type_url_, GetArenaForAllocation(),
-      &other->response_type_url_, other->GetArenaForAllocation()
+      &response_type_url_, lhs_arena,
+      &other->response_type_url_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(Method, syntax_)
@@ -1065,7 +1074,8 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Mixin.name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // string root = 2;
       case 2:
@@ -1074,28 +1084,29 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Mixin.root"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1155,13 +1166,7 @@
         this->_internal_root());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Mixin::_class_data_ = {
@@ -1170,8 +1175,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Mixin::GetClassData() const { return &_class_data_; }
 
-void Mixin::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Mixin::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Mixin *>(to)->MergeFrom(
       static_cast<const Mixin &>(from));
 }
@@ -1205,16 +1210,18 @@
 
 void Mixin::InternalSwap(Mixin* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &root_, GetArenaForAllocation(),
-      &other->root_, other->GetArenaForAllocation()
+      &root_, lhs_arena,
+      &other->root_, rhs_arena
   );
 }
 
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index 67e9d84..1708da8 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -152,7 +152,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Api& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -403,7 +403,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Method& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -632,7 +632,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Mixin& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index bd9516b..c12bf2b 100644
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -136,14 +136,14 @@
 SerialArena::AllocateAlignedWithCleanupFallback(
     size_t n, const AllocationPolicy* policy) {
   AllocateNewBlock(n + kCleanupSize, policy);
-  return AllocateAlignedWithCleanup(n, policy);
+  return AllocateFromExistingWithCleanupFallback(n);
 }
 
 PROTOBUF_NOINLINE
 void* SerialArena::AllocateAlignedFallback(size_t n,
                                            const AllocationPolicy* policy) {
   AllocateNewBlock(n, policy);
-  return AllocateAligned(n, policy);
+  return AllocateFromExisting(n);
 }
 
 void SerialArena::AllocateNewBlock(size_t n, const AllocationPolicy* policy) {
@@ -168,8 +168,8 @@
 #endif  // ADDRESS_SANITIZER
 }
 
-uint64 SerialArena::SpaceUsed() const {
-  uint64 space_used = ptr_ - head_->Pointer(kBlockHeaderSize);
+uint64_t SerialArena::SpaceUsed() const {
+  uint64_t space_used = ptr_ - head_->Pointer(kBlockHeaderSize);
   space_used += space_used_;
   // Remove the overhead of the SerialArena itself.
   space_used -= ThreadSafeArena::kSerialArenaSize;
@@ -263,11 +263,11 @@
   auto id = tc.next_lifecycle_id;
   // We increment lifecycle_id's by multiples of two so we can use bit 0 as
   // a tag.
-  constexpr uint64 kDelta = 2;
-  constexpr uint64 kInc = ThreadCache::kPerThreadIds * kDelta;
+  constexpr uint64_t kDelta = 2;
+  constexpr uint64_t kInc = ThreadCache::kPerThreadIds * kDelta;
   if (PROTOBUF_PREDICT_FALSE((id & (kInc - 1)) == 0)) {
     constexpr auto relaxed = std::memory_order_relaxed;
-    // On platforms that don't support uint64 atomics we can certainly not
+    // On platforms that don't support uint64_t atomics we can certainly not
     // afford to increment by large intervals and expect uniqueness due to
     // wrapping, hence we only add by 1.
     id = lifecycle_id_generator_.id.fetch_add(1, relaxed) * kInc;
@@ -316,7 +316,7 @@
   return mem;
 }
 
-uint64 ThreadSafeArena::Reset() {
+uint64_t ThreadSafeArena::Reset() {
   // Have to do this in a first pass, because some of the destructors might
   // refer to memory in other blocks.
   CleanupList();
@@ -406,18 +406,18 @@
       ->AddCleanup(elem, cleanup, AllocPolicy());
 }
 
-uint64 ThreadSafeArena::SpaceAllocated() const {
+uint64_t ThreadSafeArena::SpaceAllocated() const {
   SerialArena* serial = threads_.load(std::memory_order_acquire);
-  uint64 res = 0;
+  uint64_t res = 0;
   for (; serial; serial = serial->next()) {
     res += serial->SpaceAllocated();
   }
   return res;
 }
 
-uint64 ThreadSafeArena::SpaceUsed() const {
+uint64_t ThreadSafeArena::SpaceUsed() const {
   SerialArena* serial = threads_.load(std::memory_order_acquire);
-  uint64 space_used = 0;
+  uint64_t space_used = 0;
   for (; serial; serial = serial->next()) {
     space_used += serial->SpaceUsed();
   }
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index 897a70f..305a511 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -91,6 +91,7 @@
 namespace internal {
 
 struct ArenaStringPtr;  // defined in arenastring.h
+class InlinedStringField;  // defined in inlined_string_field.h
 class LazyField;        // defined in lazy_field.h
 class EpsCopyInputStream;  // defined in parse_context.h
 
@@ -350,19 +351,19 @@
   // policies. Do not use these in unit tests.
   // Returns the total space allocated by the arena, which is the sum of the
   // sizes of the underlying blocks.
-  uint64 SpaceAllocated() const { return impl_.SpaceAllocated(); }
+  uint64_t SpaceAllocated() const { return impl_.SpaceAllocated(); }
   // Returns the total space used by the arena. Similar to SpaceAllocated but
   // does not include free space and block overhead. The total space returned
   // may not include space used by other threads executing concurrently with
   // the call to this method.
-  uint64 SpaceUsed() const { return impl_.SpaceUsed(); }
+  uint64_t SpaceUsed() const { return impl_.SpaceUsed(); }
 
   // Frees all storage allocated by this arena after calling destructors
   // registered with OwnDestructor() and freeing objects registered with Own().
   // Any objects allocated on this arena are unusable after this call. It also
   // returns the total space used by the arena which is the sums of the sizes
   // of the allocated blocks. This method is not thread-safe.
-  uint64 Reset() { return impl_.Reset(); }
+  uint64_t Reset() { return impl_.Reset(); }
 
   // Adds |object| to a list of heap-allocated objects to be freed with |delete|
   // when the arena is destroyed or reset.
@@ -632,9 +633,11 @@
     CreateInArenaStorageInternal(ptr, arena,
                                  typename is_arena_constructable<T>::type(),
                                  std::forward<Args>(args)...);
-    RegisterDestructorInternal(
-        ptr, arena,
-        typename InternalHelper<T>::is_destructor_skippable::type());
+    if (arena != nullptr) {
+      RegisterDestructorInternal(
+          ptr, arena,
+          typename InternalHelper<T>::is_destructor_skippable::type());
+    }
   }
 
   template <typename T, typename... Args>
@@ -788,6 +791,7 @@
   template <typename Type>
   friend class internal::GenericTypeHandler;
   friend struct internal::ArenaStringPtr;  // For AllocateAligned.
+  friend class internal::InlinedStringField;  // For AllocateAligned.
   friend class internal::LazyField;        // For CreateMaybeMessage.
   friend class internal::EpsCopyInputStream;  // For parser performance
   friend class MessageLite;
diff --git a/src/google/protobuf/arena_impl.h b/src/google/protobuf/arena_impl.h
index 40608df..781d19c 100644
--- a/src/google/protobuf/arena_impl.h
+++ b/src/google/protobuf/arena_impl.h
@@ -66,11 +66,11 @@
   // Invoked when the arena is about to be destroyed. This method will
   // typically finalize any metric collection and delete the collector.
   // space_allocated is the space used by the arena.
-  virtual void OnDestroy(uint64 space_allocated) = 0;
+  virtual void OnDestroy(uint64_t space_allocated) = 0;
 
   // OnReset() is called when the associated arena is reset.
   // space_allocated is the space used by the arena just before the reset.
-  virtual void OnReset(uint64 space_allocated) = 0;
+  virtual void OnReset(uint64_t space_allocated) = 0;
 
   // OnAlloc is called when an allocation happens.
   // type_info is promised to be static - its lifetime extends to
@@ -79,7 +79,7 @@
   // intentionally want to avoid monitoring an allocation. (i.e. internal
   // allocations for managing the arena)
   virtual void OnAlloc(const std::type_info* allocated_type,
-                       uint64 alloc_size) = 0;
+                       uint64_t alloc_size) = 0;
 
   // Does OnAlloc() need to be called?  If false, metric collection overhead
   // will be reduced since we will not do extra work per allocation.
@@ -141,10 +141,10 @@
   Memory Free(Deallocator deallocator);
 
   void CleanupList();
-  uint64 SpaceAllocated() const {
+  uint64_t SpaceAllocated() const {
     return space_allocated_.load(std::memory_order_relaxed);
   }
-  uint64 SpaceUsed() const;
+  uint64_t SpaceUsed() const;
 
   bool HasSpace(size_t n) { return n <= static_cast<size_t>(limit_ - ptr_); }
 
@@ -154,6 +154,11 @@
     if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) {
       return AllocateAlignedFallback(n, policy);
     }
+    return AllocateFromExisting(n);
+  }
+
+ private:
+  void* AllocateFromExisting(size_t n) {
     void* ret = ptr_;
     ptr_ += n;
 #ifdef ADDRESS_SANITIZER
@@ -162,17 +167,13 @@
     return ret;
   }
 
+ public:
   // Allocate space if the current region provides enough space.
   bool MaybeAllocateAligned(size_t n, void** out) {
     GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
     GOOGLE_DCHECK_GE(limit_, ptr_);
     if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) return false;
-    void* ret = ptr_;
-    ptr_ += n;
-#ifdef ADDRESS_SANITIZER
-    ASAN_UNPOISON_MEMORY_REGION(ret, n);
-#endif  // ADDRESS_SANITIZER
-    *out = ret;
+    *out = AllocateFromExisting(n);
     return true;
   }
 
@@ -181,6 +182,12 @@
     if (PROTOBUF_PREDICT_FALSE(!HasSpace(n + kCleanupSize))) {
       return AllocateAlignedWithCleanupFallback(n, policy);
     }
+    return AllocateFromExistingWithCleanupFallback(n);
+  }
+
+ private:
+  std::pair<void*, CleanupNode*> AllocateFromExistingWithCleanupFallback(
+      size_t n) {
     void* ret = ptr_;
     ptr_ += n;
     limit_ -= kCleanupSize;
@@ -191,6 +198,7 @@
     return CreatePair(ret, reinterpret_cast<CleanupNode*>(limit_));
   }
 
+ public:
   void AddCleanup(void* elem, void (*cleanup)(void*),
                   const AllocationPolicy* policy) {
     auto res = AllocateAlignedWithCleanup(0, policy);
@@ -277,10 +285,10 @@
   // if it was passed in.
   ~ThreadSafeArena();
 
-  uint64 Reset();
+  uint64_t Reset();
 
-  uint64 SpaceAllocated() const;
-  uint64 SpaceUsed() const;
+  uint64_t SpaceAllocated() const;
+  uint64_t SpaceUsed() const;
 
   void* AllocateAligned(size_t n, const std::type_info* type) {
     SerialArena* arena;
@@ -312,7 +320,7 @@
 
  private:
   // Unique for each arena. Changes on Reset().
-  uint64 tag_and_id_;
+  uint64_t tag_and_id_;
   // The LSB of tag_and_id_ indicates if allocs in this arena are recorded.
   enum { kRecordAllocs = 1 };
 
@@ -343,7 +351,7 @@
 
   inline bool ShouldRecordAlloc() const { return tag_and_id_ & kRecordAllocs; }
 
-  inline uint64 LifeCycleId() const {
+  inline uint64_t LifeCycleId() const {
     return tag_and_id_ & (-kRecordAllocs - 1);
   }
 
@@ -362,7 +370,7 @@
     hint_.store(serial, std::memory_order_release);
   }
 
-  PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFast(uint64 lifecycle_id,
+  PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFast(uint64_t lifecycle_id,
                                                  SerialArena** arena) {
     if (GetSerialArenaFromThreadCache(lifecycle_id, arena)) return true;
     if (lifecycle_id & kRecordAllocs) return false;
@@ -379,7 +387,7 @@
   }
 
   PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFromThreadCache(
-      uint64 lifecycle_id, SerialArena** arena) {
+      uint64_t lifecycle_id, SerialArena** arena) {
     // If this thread already owns a block in this arena then try to use that.
     // This fast path optimizes the case where multiple threads allocate from
     // the same arena.
@@ -427,10 +435,10 @@
     static constexpr size_t kPerThreadIds = 256;
     // Next lifecycle ID available to this thread. We need to reserve a new
     // batch, if `next_lifecycle_id & (kPerThreadIds - 1) == 0`.
-    uint64 next_lifecycle_id;
+    uint64_t next_lifecycle_id;
     // The ThreadCache is considered valid as long as this matches the
     // lifecycle_id of the arena being used.
-    uint64 last_lifecycle_id_seen;
+    uint64_t last_lifecycle_id_seen;
     SerialArena* last_serial_arena;
   };
 
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index 03c3d8d..b6fbd1f 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -169,13 +169,13 @@
 
 TEST(ArenaTest, BasicCreate) {
   Arena arena;
-  EXPECT_TRUE(Arena::Create<int32>(&arena) != NULL);
-  EXPECT_TRUE(Arena::Create<int64>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<int32_t>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<int64_t>(&arena) != NULL);
   EXPECT_TRUE(Arena::Create<float>(&arena) != NULL);
   EXPECT_TRUE(Arena::Create<double>(&arena) != NULL);
   EXPECT_TRUE(Arena::Create<std::string>(&arena) != NULL);
-  arena.Own(new int32);
-  arena.Own(new int64);
+  arena.Own(new int32_t);
+  arena.Own(new int64_t);
   arena.Own(new float);
   arena.Own(new double);
   arena.Own(new std::string);
@@ -622,7 +622,7 @@
     TestAllTypes::NestedMessage* arena2_submessage =
         Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
     arena2_submessage->set_bb(42);
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
+#ifdef PROTOBUF_HAS_DEATH_TEST
     EXPECT_DEBUG_DEATH(arena1_message->set_allocated_optional_nested_message(
                            arena2_submessage),
                        "submessage_arena");
@@ -635,7 +635,7 @@
       Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena1);
   arena1_submessage->set_bb(42);
   TestAllTypes* heap_message = new TestAllTypes;
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
+#ifdef PROTOBUF_HAS_DEATH_TEST
   EXPECT_DEBUG_DEATH(
       heap_message->set_allocated_optional_nested_message(arena1_submessage),
       "submessage_arena");
@@ -691,7 +691,7 @@
     TestAllTypes::NestedMessage* arena2_submessage =
         Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
     arena2_submessage->set_bb(42);
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
+#ifdef PROTOBUF_HAS_DEATH_TEST
     EXPECT_DEBUG_DEATH(
         r->SetAllocatedMessage(arena1_message, arena2_submessage, msg_field),
         "GetOwningArena");
@@ -704,7 +704,7 @@
       Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena1);
   arena1_submessage->set_bb(42);
   TestAllTypes* heap_message = new TestAllTypes;
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
+#ifdef PROTOBUF_HAS_DEATH_TEST
   EXPECT_DEBUG_DEATH(
       r->SetAllocatedMessage(heap_message, arena1_submessage, msg_field),
       "GetOwningArena");
@@ -803,7 +803,7 @@
     TestAllTypes::NestedMessage* arena2_submessage =
         Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
     arena2_submessage->set_bb(42);
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
+#ifdef PROTOBUF_HAS_DEATH_TEST
     EXPECT_DEBUG_DEATH(
         arena1_message->mutable_repeated_nested_message()->AddAllocated(
             arena2_submessage),
@@ -820,7 +820,7 @@
     TestAllTypes::NestedMessage* arena2_submessage =
         Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
     arena2_submessage->set_bb(42);
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
+#ifdef PROTOBUF_HAS_DEATH_TEST
     EXPECT_DEBUG_DEATH(
         heap_message->mutable_repeated_nested_message()->AddAllocated(
             arena2_submessage),
@@ -925,7 +925,7 @@
     TestAllTypes::NestedMessage* arena2_submessage =
         Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
     arena2_submessage->set_bb(42);
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
+#ifdef PROTOBUF_HAS_DEATH_TEST
     EXPECT_DEBUG_DEATH(
         r->AddAllocatedMessage(arena1_message, fd, arena2_submessage),
         "value_arena");
@@ -941,7 +941,7 @@
     TestAllTypes::NestedMessage* arena2_submessage =
         Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
     arena2_submessage->set_bb(42);
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
+#ifdef PROTOBUF_HAS_DEATH_TEST
     EXPECT_DEBUG_DEATH(
         r->AddAllocatedMessage(heap_message, fd, arena2_submessage),
         "value_arena");
@@ -1339,7 +1339,7 @@
 }
 
 // Align n to next multiple of 8
-uint64 Align8(uint64 n) { return (n + 7) & -8; }
+uint64_t Align8(uint64_t n) { return (n + 7) & -8; }
 
 TEST(ArenaTest, SpaceAllocated_and_Used) {
   Arena arena_1;
@@ -1402,11 +1402,11 @@
     opt.start_block_size = opt.max_block_size = i;
     Arena arena(opt);
 
-    *Arena::Create<int64>(&arena) = 42;
+    *Arena::Create<int64_t>(&arena) = 42;
     EXPECT_GE(arena.SpaceAllocated(), 8);
     EXPECT_EQ(8, arena.SpaceUsed());
 
-    *Arena::Create<int64>(&arena) = 42;
+    *Arena::Create<int64_t>(&arena) = 42;
     EXPECT_GE(arena.SpaceAllocated(), 16);
     EXPECT_EQ(16, arena.SpaceUsed());
   }
@@ -1464,10 +1464,10 @@
 }
 
 namespace {
-uint32 hooks_num_init = 0;
-uint32 hooks_num_allocations = 0;
-uint32 hooks_num_reset = 0;
-uint32 hooks_num_destruct = 0;
+uint32_t hooks_num_init = 0;
+uint32_t hooks_num_allocations = 0;
+uint32_t hooks_num_reset = 0;
+uint32_t hooks_num_destruct = 0;
 
 void ClearHookCounts() {
   hooks_num_init = 0;
@@ -1502,13 +1502,13 @@
       : ArenaMetricsCollector(record_allocs) {
     ++hooks_num_init;
   }
-  void OnDestroy(uint64 space_allocated) override {
+  void OnDestroy(uint64_t space_allocated) override {
     ++hooks_num_destruct;
     delete this;
   }
-  void OnReset(uint64 space_allocated) override { ++hooks_num_reset; }
+  void OnReset(uint64_t space_allocated) override { ++hooks_num_reset; }
   void OnAlloc(const std::type_info* allocated_type,
-               uint64 alloc_size) override {
+               uint64_t alloc_size) override {
     ++hooks_num_allocations;
   }
 };
@@ -1523,8 +1523,8 @@
     Arena arena(options);
     EXPECT_EQ(1, hooks_num_init);
     EXPECT_EQ(0, hooks_num_allocations);
-    Arena::Create<uint64>(&arena);
-    if (std::is_trivially_destructible<uint64>::value) {
+    Arena::Create<uint64_t>(&arena);
+    if (std::is_trivially_destructible<uint64_t>::value) {
       EXPECT_EQ(1, hooks_num_allocations);
     } else {
       EXPECT_EQ(2, hooks_num_allocations);
@@ -1544,7 +1544,7 @@
 
   Arena arena(options);
   EXPECT_EQ(0, hooks_num_allocations);
-  Arena::Create<uint64>(&arena);
+  Arena::Create<uint64_t>(&arena);
   EXPECT_EQ(0, hooks_num_allocations);
 }
 
diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h
index 1fafa69..2477369 100644
--- a/src/google/protobuf/arenastring.h
+++ b/src/google/protobuf/arenastring.h
@@ -352,12 +352,15 @@
   tagged_ptr_.Set(const_cast<std::string*>(value));
 }
 
+// Make sure rhs_arena allocated rhs, and lhs_arena allocated lhs.
 inline PROTOBUF_NDEBUG_INLINE void ArenaStringPtr::InternalSwap(  //
     const std::string* default_value,                             //
     ArenaStringPtr* rhs, Arena* rhs_arena,                        //
     ArenaStringPtr* lhs, Arena* lhs_arena) {
+  // Silence unused variable warnings in release buildls.
   (void)default_value;
-  std::swap(lhs_arena, rhs_arena);
+  (void)rhs_arena;
+  (void)lhs_arena;
   std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
 #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
   auto force_realloc = [default_value](ArenaStringPtr* p, Arena* arena) {
@@ -370,8 +373,10 @@
     if (arena == nullptr) delete old_value;
     p->tagged_ptr_.Set(new_value);
   };
-  force_realloc(lhs, lhs_arena);
-  force_realloc(rhs, rhs_arena);
+  // Because, at this point, tagged_ptr_ has been swapped, arena should also be
+  // swapped.
+  force_realloc(lhs, rhs_arena);
+  force_realloc(rhs, lhs_arena);
 #endif  // PROTOBUF_FORCE_COPY_IN_SWAP
 }
 
diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h
index c8d9e49..2cbda27 100644
--- a/src/google/protobuf/compiler/code_generator.h
+++ b/src/google/protobuf/compiler/code_generator.h
@@ -103,14 +103,15 @@
                            GeneratorContext* generator_context,
                            std::string* error) const;
 
-  // Sync with plugin.proto.
+  // This must be kept in sync with plugin.proto. See that file for
+  // documentation on each value.
   enum Feature {
     FEATURE_PROTO3_OPTIONAL = 1,
   };
 
   // Implement this to indicate what features this code generator supports.
-  // This should be a bitwise OR of features from the Features enum in
-  // plugin.proto.
+  //
+  // This must be a bitwise OR of values from the Feature enum above (or zero).
   virtual uint64_t GetSupportedFeatures() const { return 0; }
 
   // This is no longer used, but this class is part of the opensource protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 3792db8..670c37f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -57,8 +57,9 @@
 }  // anonymous namespace
 
 ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
-                                       const Options& options)
-    : descriptor_(descriptor), options_(options) {
+                                       const Options& options,
+                                       MessageSCCAnalyzer* scc_analyzer)
+    : descriptor_(descriptor), options_(options), scc_analyzer_(scc_analyzer) {
   // Construct type_traits_.
   if (descriptor_->is_repeated()) {
     type_traits_ = "Repeated";
@@ -179,6 +180,18 @@
       "    ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
       "  $scoped_name$($constant_name$, $1$);\n",
       default_str);
+
+  // Register extension verify function if needed.
+  if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
+      ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_)) {
+    format(
+        "PROTOBUF_ATTRIBUTE_INIT_PRIORITY "
+        "::$proto_ns$::internal::RegisterExtensionVerify< $extendee$,\n"
+        "    $1$, $number$> $2$_$name$_register;\n",
+        ClassName(descriptor_->message_type(), true),
+        IsScoped() ? ClassName(descriptor_->extension_scope(), false) : "");
+  }
 }
 
 }  // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h
index 72413f6..bcc8018 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.h
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.h
@@ -55,6 +55,8 @@
 namespace compiler {
 namespace cpp {
 
+class MessageSCCAnalyzer;
+
 // Generates code for an extension, which may be within the scope of some
 // message or may be at file scope.  This is much simpler than FieldGenerator
 // since extensions are just simple identifiers with interesting types.
@@ -62,7 +64,8 @@
  public:
   // See generator.cc for the meaning of dllexport_decl.
   explicit ExtensionGenerator(const FieldDescriptor* descriptor,
-                              const Options& options);
+                              const Options& options,
+                              MessageSCCAnalyzer* scc_analyzer);
   ~ExtensionGenerator();
 
   // Header stuff.
@@ -77,6 +80,7 @@
   const FieldDescriptor* descriptor_;
   std::string type_traits_;
   Options options_;
+  MessageSCCAnalyzer* scc_analyzer_;
 
   std::map<std::string, std::string> variables_;
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index 82247ff..48ae290 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -61,37 +61,39 @@
 
 namespace {
 
-std::string GenerateAnnotation(StringPiece substitute_template_prefix,
-                               StringPiece prepared_template,
-                               StringPiece substitute_template_suffix,
-                               int field_index, StringPiece lambda_args,
-                               StringPiece access_type) {
-  return strings::Substitute(
-      StrCat(substitute_template_prefix, prepared_template,
-                   substitute_template_suffix),
-      field_index, access_type, lambda_args);
+void MaySetAnnotationVariable(const Options& options,
+                              StringPiece annotation_name,
+                              StringPiece substitute_template_prefix,
+                              StringPiece prepared_template,
+                              int field_index, StringPiece access_type,
+                              std::map<std::string, std::string>* variables) {
+  if (options.field_listener_options.forbidden_field_listener_events.count(
+          std::string(annotation_name)))
+    return;
+  (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute(
+      StrCat(substitute_template_prefix, prepared_template, ");\n"),
+      field_index, access_type);
 }
 
 std::string GenerateTemplateForOneofString(const FieldDescriptor* descriptor,
                                            StringPiece proto_ns,
                                            StringPiece field_member) {
+  std::string field_name = google::protobuf::compiler::cpp::FieldName(descriptor);
   std::string field_pointer =
       descriptor->options().ctype() == google::protobuf::FieldOptions::STRING
           ? "$0.GetPointer()"
           : "$0";
 
   if (descriptor->default_value_string().empty()) {
-    return strings::Substitute(
-        StrCat("_internal_has_",
-                     google::protobuf::compiler::cpp::FieldName(descriptor),
-                     "()? _listener_->ExtractFieldInfo(", field_pointer,
-                     "): ::", proto_ns, "::FieldAccessListener::AddressInfo()"),
-        field_member);
+    return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ",
+                                         field_pointer, ": nullptr"),
+                            field_member);
   }
 
   if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING_PIECE) {
-    return StrCat("_listener_->ExtractFieldInfo(_internal_",
-                        google::protobuf::compiler::cpp::FieldName(descriptor), "())");
+    return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ",
+                                         field_pointer, ": nullptr"),
+                            field_member);
   }
 
   std::string default_value_pointer =
@@ -99,26 +101,24 @@
           ? "&$1.get()"
           : "&$1";
   return strings::Substitute(
-      StrCat("_listener_->ExtractFieldInfo(_internal_has_",
-                   google::protobuf::compiler::cpp::FieldName(descriptor), "()? ",
-                   field_pointer, " : ", default_value_pointer, ")"),
+      StrCat("_internal_has_", field_name, "() ? ", field_pointer, " : ",
+                   default_value_pointer),
       field_member, MakeDefaultName(descriptor));
 }
 
 std::string GenerateTemplateForSingleString(const FieldDescriptor* descriptor,
                                             StringPiece field_member) {
   if (descriptor->default_value_string().empty()) {
-    return strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member);
+    return StrCat("&", field_member);
   }
 
   if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING) {
     return strings::Substitute(
-        "_listener_->ExtractFieldInfo($0.IsDefault("
-        "nullptr) ? &$1.get() : $0.GetPointer())",
-        field_member, MakeDefaultName(descriptor));
+        "$0.IsDefault(nullptr) ? &$1.get() : $0.GetPointer()", field_member,
+        MakeDefaultName(descriptor));
   }
 
-  return strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member);
+  return StrCat("&", field_member);
 }
 
 }  // namespace
@@ -143,7 +143,7 @@
           "  ", FieldName(descriptor), "_AccessedNoStrip = true;\n");
     }
   }
-  if (!options.inject_field_listener_events) {
+  if (!options.field_listener_options.inject_field_listener_events) {
     return;
   }
   if (descriptor->file()->options().optimize_for() ==
@@ -157,50 +157,29 @@
     field_member = StrCat(oneof_member->name(), "_.", field_member);
   }
   const std::string proto_ns = (*variables)["proto_ns"];
-  std::string lambda_args = "_listener_, this";
-  std::string lambda_flat_args = "_listener_, this";
-  const std::string substitute_template_prefix = StrCat(
-      "  {\n"
-      "    auto _listener_ = ::",
-      proto_ns,
-      "::FieldAccessListener::GetListener();\n"
-      "    if (_listener_) _listener_->OnFieldAccess([$2] { return ");
-  const std::string substitute_template_suffix = StrCat(
-      "; }, "
-      "GetDescriptor()->field($0), "
-      "::",
-      proto_ns,
-      "::FieldAccessListener::FieldAccessType::$1);\n"
-      "  }\n");
+  const std::string substitute_template_prefix = "  _tracker_.$1<$0>(this, ";
   std::string prepared_template;
 
   // Flat template is needed if the prepared one is introspecting the values
   // inside the returned values, for example, for repeated fields and maps.
   std::string prepared_flat_template;
   std::string prepared_add_template;
-  // TODO(jianzhouzh): Fix all forward declared messages and deal with the
-  // weak fields.
+  // TODO(b/190614678): Support fields with type Message or Map.
   if (descriptor->is_repeated() && !descriptor->is_map()) {
     if (descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
         descriptor->type() != FieldDescriptor::TYPE_GROUP) {
-      lambda_args = "_listener_, this, index";
-      prepared_template = strings::Substitute(
-          "_listener_->ExtractFieldInfo(&$0.Get(index))", field_member);
-      prepared_add_template = strings::Substitute(
-          "_listener_->ExtractFieldInfo(&$0.Get($0.size() - 1))", field_member);
-    } else {
-      prepared_template =
-          StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()");
+      prepared_template = strings::Substitute("&$0.Get(index)", field_member);
       prepared_add_template =
-          StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()");
+          strings::Substitute("&$0.Get($0.size() - 1)", field_member);
+    } else {
+      prepared_template = "nullptr";
+      prepared_add_template = "nullptr";
     }
   } else if (descriptor->is_map()) {
-    prepared_template =
-        StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()");
+    prepared_template = "nullptr";
   } else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
              !descriptor->options().lazy()) {
-    prepared_template =
-        StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()");
+    prepared_template = "nullptr";
   } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
     if (oneof_member) {
       prepared_template = GenerateTemplateForOneofString(
@@ -210,56 +189,49 @@
           GenerateTemplateForSingleString(descriptor, field_member);
     }
   } else {
-    prepared_template =
-        strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member);
+    prepared_template = StrCat("&", field_member);
   }
   if (descriptor->is_repeated() && !descriptor->is_map() &&
       descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
       descriptor->type() != FieldDescriptor::TYPE_GROUP) {
-    prepared_flat_template =
-        strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member);
+    prepared_flat_template = StrCat("&", field_member);
   } else {
     prepared_flat_template = prepared_template;
   }
-  (*variables)["annotate_get"] = GenerateAnnotation(
-      substitute_template_prefix, prepared_template, substitute_template_suffix,
-      descriptor->index(), lambda_args, "kGet");
-  (*variables)["annotate_set"] = GenerateAnnotation(
-      substitute_template_prefix, prepared_template, substitute_template_suffix,
-      descriptor->index(), lambda_args, "kSet");
-  (*variables)["annotate_has"] = GenerateAnnotation(
-      substitute_template_prefix, prepared_template, substitute_template_suffix,
-      descriptor->index(), lambda_args, "kHas");
-  (*variables)["annotate_mutable"] = GenerateAnnotation(
-      substitute_template_prefix, prepared_template, substitute_template_suffix,
-      descriptor->index(), lambda_args, "kMutable");
-  (*variables)["annotate_release"] = GenerateAnnotation(
-      substitute_template_prefix, prepared_template, substitute_template_suffix,
-      descriptor->index(), lambda_args, "kRelease");
-  (*variables)["annotate_clear"] =
-      GenerateAnnotation(substitute_template_prefix, prepared_flat_template,
-                         substitute_template_suffix, descriptor->index(),
-                         lambda_flat_args, "kClear");
-  (*variables)["annotate_size"] =
-      GenerateAnnotation(substitute_template_prefix, prepared_flat_template,
-                         substitute_template_suffix, descriptor->index(),
-                         lambda_flat_args, "kSize");
-  (*variables)["annotate_list"] =
-      GenerateAnnotation(substitute_template_prefix, prepared_flat_template,
-                         substitute_template_suffix, descriptor->index(),
-                         lambda_flat_args, "kList");
-  (*variables)["annotate_mutable_list"] =
-      GenerateAnnotation(substitute_template_prefix, prepared_flat_template,
-                         substitute_template_suffix, descriptor->index(),
-                         lambda_flat_args, "kMutableList");
-  (*variables)["annotate_add"] =
-      GenerateAnnotation(substitute_template_prefix, prepared_add_template,
-                         substitute_template_suffix, descriptor->index(),
-                         lambda_flat_args, "kAdd");
-  (*variables)["annotate_add_mutable"] =
-      GenerateAnnotation(substitute_template_prefix, prepared_add_template,
-                         substitute_template_suffix, descriptor->index(),
-                         lambda_flat_args, "kAddMutable");
+
+  MaySetAnnotationVariable(options, "get", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnGet",
+                           variables);
+  MaySetAnnotationVariable(options, "set", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnSet",
+                           variables);
+  MaySetAnnotationVariable(options, "has", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnHas",
+                           variables);
+  MaySetAnnotationVariable(options, "mutable", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnMutable",
+                           variables);
+  MaySetAnnotationVariable(options, "release", substitute_template_prefix,
+                           prepared_template, descriptor->index(), "OnRelease",
+                           variables);
+  MaySetAnnotationVariable(options, "clear", substitute_template_prefix,
+                           prepared_flat_template, descriptor->index(),
+                           "OnClear", variables);
+  MaySetAnnotationVariable(options, "size", substitute_template_prefix,
+                           prepared_flat_template, descriptor->index(),
+                           "OnSize", variables);
+  MaySetAnnotationVariable(options, "list", substitute_template_prefix,
+                           prepared_flat_template, descriptor->index(),
+                           "OnList", variables);
+  MaySetAnnotationVariable(options, "mutable_list", substitute_template_prefix,
+                           prepared_flat_template, descriptor->index(),
+                           "OnMutableList", variables);
+  MaySetAnnotationVariable(options, "add", substitute_template_prefix,
+                           prepared_add_template, descriptor->index(), "OnAdd",
+                           variables);
+  MaySetAnnotationVariable(options, "add_mutable", substitute_template_prefix,
+                           prepared_add_template, descriptor->index(),
+                           "OnAddMutable", variables);
 }
 
 void SetCommonFieldVariables(const FieldDescriptor* descriptor,
@@ -310,6 +282,22 @@
       strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;");
 }
 
+void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) {
+  if (!IsStringInlined(descriptor_, options_)) {
+    GOOGLE_CHECK_EQ(inlined_string_index, -1);
+    return;
+  }
+  variables_["inlined_string_donated"] = StrCat(
+      "(_inlined_string_donated_[", inlined_string_index / 32, "] & 0x",
+      strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8),
+      "u) != 0;");
+  variables_["donating_states_word"] =
+      StrCat("_inlined_string_donated_[", inlined_string_index / 32, "]");
+  variables_["mask_for_undonate"] = StrCat(
+      "~0x", strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8),
+      "u");
+}
+
 void SetCommonOneofFieldVariables(
     const FieldDescriptor* descriptor,
     std::map<std::string, std::string>* variables) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index b210ef9..185fa8c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -181,7 +181,10 @@
   // are placed in the message's ByteSize() method.
   virtual void GenerateByteSize(io::Printer* printer) const = 0;
 
+  virtual bool IsInlined() const { return false; }
+
   void SetHasBitIndex(int32_t has_bit_index);
+  void SetInlinedStringIndex(int32_t inlined_string_index);
 
  protected:
   const FieldDescriptor* descriptor_;
@@ -207,6 +210,12 @@
     }
   }
 
+  void SetInlinedStringIndices(const std::vector<int>& inlined_string_indices) {
+    for (int i = 0; i < descriptor_->field_count(); ++i) {
+      field_generators_[i]->SetInlinedStringIndex(inlined_string_indices[i]);
+    }
+  }
+
  private:
   const Descriptor* descriptor_;
   std::vector<std::unique_ptr<FieldGenerator>> field_generators_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 0c23947..1f20c4d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -130,7 +130,7 @@
   }
   for (int i = 0; i < file->extension_count(); i++) {
     extension_generators_.emplace_back(
-        new ExtensionGenerator(file->extension(i), options));
+        new ExtensionGenerator(file->extension(i), options, &scc_analyzer_));
   }
   for (int i = 0; i < file->weak_dependency_count(); ++i) {
     weak_deps_.insert(file->weak_dependency(i));
@@ -463,6 +463,19 @@
          DefaultInstanceType(generator->descriptor_, options_),
          DefaultInstanceName(generator->descriptor_, options_));
 
+  for (int i = 0; i < generator->descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = generator->descriptor_->field(i);
+    if (IsStringInlined(field, options_)) {
+      // Force the initialization of the inlined string in the default instance.
+      format(
+          "PROTOBUF_ATTRIBUTE_INIT_PRIORITY std::true_type "
+          "$1$::_init_inline_$2$_ = "
+          "($3$._instance.$2$_.Init(), std::true_type{});\n",
+          ClassName(generator->descriptor_), FieldName(field),
+          DefaultInstanceName(generator->descriptor_, options_));
+    }
+  }
+
   if (options_.lite_implicit_weak_fields) {
     format("$1$* $2$ = &$3$;\n",
            DefaultInstanceType(generator->descriptor_, options_),
@@ -578,6 +591,13 @@
       "// @@protoc_insertion_point(global_scope)\n");
 }
 
+void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) {
+  Formatter format(printer, variables_);
+  GenerateSourceIncludes(printer);
+  NamespaceOpener ns(Namespace(file_, options_), format);
+  extension_generators_[idx]->GenerateDefinition(printer);
+}
+
 void FileGenerator::GenerateGlobalSource(io::Printer* printer) {
   Formatter format(printer, variables_);
   GenerateSourceIncludes(printer);
@@ -598,21 +618,6 @@
   for (int i = 0; i < enum_generators_.size(); i++) {
     enum_generators_[i]->GenerateMethods(i, printer);
   }
-
-  // Define extensions.
-  for (int i = 0; i < extension_generators_.size(); i++) {
-    extension_generators_[i]->GenerateDefinition(printer);
-  }
-
-  if (HasGenericServices(file_, options_)) {
-    // Generate services.
-    for (int i = 0; i < service_generators_.size(); i++) {
-      if (i == 0) format("\n");
-      format(kThickSeparator);
-      format("\n");
-      service_generators_[i]->GenerateImplementation(printer);
-    }
-  }
 }
 
 void FileGenerator::GenerateSource(io::Printer* printer) {
@@ -1143,6 +1148,9 @@
     GOOGLE_CHECK(!options_.opensource_runtime);
     IncludeFile("net/proto2/public/lazy_field.h", printer);
   }
+  if (ShouldVerify(file_, options_, &scc_analyzer_)) {
+    IncludeFile("net/proto2/public/wire_format_verify.h", printer);
+  }
 
   if (options_.opensource_runtime) {
     // Verify the protobuf library header version is compatible with the protoc
@@ -1170,6 +1178,9 @@
   IncludeFile("net/proto2/io/public/coded_stream.h", printer);
   IncludeFile("net/proto2/public/arena.h", printer);
   IncludeFile("net/proto2/public/arenastring.h", printer);
+  if (options_.force_inline_string || options_.profile_driven_inline_string) {
+    IncludeFile("net/proto2/public/inlined_string_field.h", printer);
+  }
   IncludeFile("net/proto2/public/generated_message_table_driven.h", printer);
   if (HasGeneratedMethods(file_, options_) &&
       options_.tctable_mode != Options::kTCTableNever) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index 35a9085..e881602 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -82,9 +82,20 @@
   void GeneratePBHeader(io::Printer* printer, const std::string& info_path);
   void GenerateSource(io::Printer* printer);
 
+  // The following member functions are used when the lite_implicit_weak_fields
+  // option is set. In this mode the code is organized a bit differently to
+  // promote better linker stripping of unused code. In particular, we generate
+  // one .cc file per message, one .cc file per extension, and a main pb.cc file
+  // containing everything else.
+
   int NumMessages() const { return message_generators_.size(); }
-  // Similar to GenerateSource but generates only one message
+  int NumExtensions() const { return extension_generators_.size(); }
+  // Generates the source file for one message.
   void GenerateSourceForMessage(int idx, io::Printer* printer);
+  // Generates the source file for one extension.
+  void GenerateSourceForExtension(int idx, io::Printer* printer);
+  // Generates a source file containing everything except messages and
+  // extensions.
   void GenerateGlobalSource(io::Printer* printer);
 
  private:
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 2a6087e..0851571 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -35,6 +35,7 @@
 #include <google/protobuf/compiler/cpp/cpp_generator.h>
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -53,6 +54,12 @@
 CppGenerator::CppGenerator() {}
 CppGenerator::~CppGenerator() {}
 
+namespace {
+std::string NumberedCcFileName(const std::string& basename, int number) {
+  return StrCat(basename, ".out/", number, ".cc");
+}
+}  // namespace
+
 bool CppGenerator::Generate(const FileDescriptor* file,
                             const std::string& parameter,
                             GeneratorContext* generator_context,
@@ -107,7 +114,19 @@
     } else if (options[i].first == "annotate_accessor") {
       file_options.annotate_accessor = true;
     } else if (options[i].first == "inject_field_listener_events") {
-      file_options.inject_field_listener_events = true;
+      file_options.field_listener_options.inject_field_listener_events = true;
+    } else if (options[i].first == "forbidden_field_listener_events") {
+      std::size_t pos = 0;
+      do {
+        std::size_t next_pos = options[i].second.find_first_of("+", pos);
+        if (next_pos == std::string::npos) {
+          next_pos = options[i].second.size();
+        }
+        if (next_pos > pos)
+          file_options.field_listener_options.forbidden_field_listener_events
+              .insert(options[i].second.substr(pos, next_pos - pos));
+        pos = next_pos + 1;
+      } while (pos < options[i].second.size());
     } else if (options[i].first == "eagerly_verified_lazy") {
       file_options.eagerly_verified_lazy = true;
     } else if (options[i].first == "force_eagerly_verified_lazy") {
@@ -204,24 +223,37 @@
       file_generator.GenerateGlobalSource(&printer);
     }
 
-    int num_cc_files = file_generator.NumMessages();
+    int num_cc_files =
+        file_generator.NumMessages() + file_generator.NumExtensions();
 
     // If we're using implicit weak fields then we allow the user to
     // optionally specify how many files to generate, not counting the global
     // pb.cc file. If we have more files than messages, then some files will
     // be generated as empty placeholders.
     if (file_options.num_cc_files > 0) {
-      GOOGLE_CHECK_LE(file_generator.NumMessages(), file_options.num_cc_files)
-          << "There must be at least as many numbered .cc files as messages.";
+      GOOGLE_CHECK_LE(num_cc_files, file_options.num_cc_files)
+          << "There must be at least as many numbered .cc files as messages "
+             "and extensions.";
       num_cc_files = file_options.num_cc_files;
     }
-    for (int i = 0; i < num_cc_files; i++) {
-      std::unique_ptr<io::ZeroCopyOutputStream> output(
-          generator_context->Open(StrCat(basename, ".out/", i, ".cc")));
+    int cc_file_number = 0;
+    for (int i = 0; i < file_generator.NumMessages(); i++) {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open(
+          NumberedCcFileName(basename, cc_file_number++)));
       io::Printer printer(output.get(), '$');
-      if (i < file_generator.NumMessages()) {
-        file_generator.GenerateSourceForMessage(i, &printer);
-      }
+      file_generator.GenerateSourceForMessage(i, &printer);
+    }
+    for (int i = 0; i < file_generator.NumExtensions(); i++) {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open(
+          NumberedCcFileName(basename, cc_file_number++)));
+      io::Printer printer(output.get(), '$');
+      file_generator.GenerateSourceForExtension(i, &printer);
+    }
+    // Create empty placeholder files if necessary to match the expected number
+    // of files.
+    for (; cc_file_number < num_cc_files; ++cc_file_number) {
+      std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open(
+          NumberedCcFileName(basename, cc_file_number)));
     }
   } else {
     std::unique_ptr<io::ZeroCopyOutputStream> output(
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index c25de21..25206db 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -430,9 +430,14 @@
 
 std::string SuperClassName(const Descriptor* descriptor,
                            const Options& options) {
-  return "::" + ProtobufNamespace(options) +
-         (HasDescriptorMethods(descriptor->file(), options) ? "::Message"
-                                                            : "::MessageLite");
+  if (!HasDescriptorMethods(descriptor->file(), options)) {
+    return "::" + ProtobufNamespace(options) + "::MessageLite";
+  }
+  auto simple_base = SimpleBaseClass(descriptor, options);
+  if (simple_base.empty()) {
+    return "::" + ProtobufNamespace(options) + "::Message";
+  }
+  return "::" + ProtobufNamespace(options) + "::internal::" + simple_base;
 }
 
 std::string ResolveKeyword(const std::string& name) {
@@ -772,6 +777,11 @@
   return function_name;
 }
 
+bool IsStringInlined(const FieldDescriptor* descriptor,
+                     const Options& options) {
+  return false;
+}
+
 static bool HasLazyFields(const Descriptor* descriptor, const Options& options,
                           MessageSCCAnalyzer* scc_analyzer) {
   for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) {
@@ -929,6 +939,16 @@
   return false;
 }
 
+bool ShouldVerify(const Descriptor* descriptor, const Options& options,
+                  MessageSCCAnalyzer* scc_analyzer) {
+  return false;
+}
+
+bool ShouldVerify(const FileDescriptor* file, const Options& options,
+                  MessageSCCAnalyzer* scc_analyzer) {
+  return false;
+}
+
 bool IsStringOrMessage(const FieldDescriptor* field) {
   switch (field->cpp_type()) {
     case FieldDescriptor::CPPTYPE_INT32:
@@ -1075,21 +1095,12 @@
                         "VerifyUTF8CordNamedField", format);
 }
 
-namespace {
-
-void Flatten(const Descriptor* descriptor,
-             std::vector<const Descriptor*>* flatten) {
-  for (int i = 0; i < descriptor->nested_type_count(); i++)
-    Flatten(descriptor->nested_type(i), flatten);
-  flatten->push_back(descriptor);
-}
-
-}  // namespace
-
 void FlattenMessagesInFile(const FileDescriptor* file,
                            std::vector<const Descriptor*>* result) {
   for (int i = 0; i < file->message_type_count(); i++) {
-    Flatten(file->message_type(i), result);
+    ForEachMessage(file->message_type(i), [&](const Descriptor* descriptor) {
+      result->push_back(descriptor);
+    });
   }
 }
 
@@ -1457,6 +1468,10 @@
   return FileOptions::SPEED;
 }
 
+bool EnableMessageOwnedArena(const Descriptor* desc) {
+  return false;
+}
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 8c07e47..88befc0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -315,6 +315,8 @@
   return false;
 }
 
+bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options);
+
 // For a string field, returns the effective ctype.  If the actual ctype is
 // not supported, returns the default of STRING.
 FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
@@ -325,6 +327,11 @@
          EffectiveStringCType(field, options) == FieldOptions::CORD;
 }
 
+inline bool IsString(const FieldDescriptor* field, const Options& options) {
+  return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+         EffectiveStringCType(field, options) == FieldOptions::STRING;
+}
+
 inline bool IsStringPiece(const FieldDescriptor* field,
                           const Options& options) {
   return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
@@ -533,6 +540,19 @@
   return result;
 }
 
+template <typename F>
+void ForEachMessage(const Descriptor* descriptor, F&& func) {
+  for (int i = 0; i < descriptor->nested_type_count(); i++)
+    ForEachMessage(descriptor->nested_type(i), std::forward<F&&>(func));
+  func(descriptor);
+}
+
+template <typename F>
+void ForEachMessage(const FileDescriptor* descriptor, F&& func) {
+  for (int i = 0; i < descriptor->message_type_count(); i++)
+    ForEachMessage(descriptor->message_type(i), std::forward<F&&>(func));
+}
+
 bool HasWeakFields(const Descriptor* desc, const Options& options);
 bool HasWeakFields(const FileDescriptor* desc, const Options& options);
 
@@ -630,6 +650,27 @@
 bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
                          MessageSCCAnalyzer* scc_analyzer);
 
+inline bool HasSimpleBaseClass(const Descriptor* desc, const Options& options) {
+  if (!HasDescriptorMethods(desc->file(), options)) return false;
+  if (desc->extension_range_count() != 0) return false;
+  if (desc->field_count() == 0) return true;
+  // TODO(jorg): Support additional common message types with only one
+  // or two fields
+  return false;
+}
+
+inline std::string SimpleBaseClass(const Descriptor* desc,
+                                   const Options& options) {
+  if (!HasDescriptorMethods(desc->file(), options)) return "";
+  if (desc->extension_range_count() != 0) return "";
+  if (desc->field_count() == 0) {
+    return "ZeroFieldsBase";
+  }
+  // TODO(jorg): Support additional common message types with only one
+  // or two fields
+  return "";
+}
+
 // Formatter is a functor class which acts as a closure around printer and
 // the variable map. It's much like printer->Print except it supports both named
 // variables that are substituted using a key value map and direct arguments. In
@@ -884,8 +925,12 @@
 
 PROTOC_EXPORT std::string StripProto(const std::string& filename);
 
-inline bool EnableMessageOwnedArena(const Descriptor* /* desc */ ) { return false; }
+bool EnableMessageOwnedArena(const Descriptor* desc);
 
+bool ShouldVerify(const Descriptor* descriptor, const Options& options,
+                  MessageSCCAnalyzer* scc_analyzer);
+bool ShouldVerify(const FileDescriptor* file, const Options& options,
+                  MessageSCCAnalyzer* scc_analyzer);
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index ff8b308..d15f9b6 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -43,6 +43,7 @@
 #include <utility>
 #include <vector>
 
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
 #include <google/protobuf/compiler/cpp/cpp_extension.h>
 #include <google/protobuf/compiler/cpp/cpp_field.h>
@@ -52,6 +53,7 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
 #include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/map_entry_lite.h>
@@ -181,6 +183,10 @@
   return ret;
 }
 
+bool StrContains(const std::string& haystack, const std::string& needle) {
+  return haystack.find(needle) != std::string::npos;
+}
+
 // Finds runs of fields for which `predicate` is true.
 // RunMap maps from fields that start each run to the number of fields in that
 // run.  This is optimized for the common case that there are very few runs in
@@ -295,15 +301,6 @@
   return true;
 }
 
-bool ShouldMarkClearAsFinal(const Descriptor* descriptor,
-                            const Options& options) {
-  static std::set<std::string> exclusions{
-  };
-
-  const std::string name = ClassName(descriptor, true);
-  return exclusions.find(name) == exclusions.end() ||
-         options.opensource_runtime;
-}
 
 // Returns true to make the message serialize in order, decided by the following
 // factors in the order of precedence.
@@ -397,6 +394,16 @@
   return v.front()->is_required();
 }
 
+bool HasSingularString(const Descriptor* desc, const Options& options) {
+  for (const auto* field : FieldRange(desc)) {
+    if (IsString(field, options) && !IsStringInlined(field, options) &&
+        !field->is_repeated() && !field->real_containing_oneof()) {
+      return true;
+    }
+  }
+  return false;
+}
+
 // Collects neighboring fields based on a given criteria (equivalent predicate).
 template <typename Predicate>
 std::vector<std::vector<const FieldDescriptor*>> CollectFields(
@@ -553,6 +560,88 @@
   return true;
 }
 
+void MaySetAnnotationVariable(const Options& options,
+                              StringPiece annotation_name,
+                              StringPiece injector_template_prefix,
+                              StringPiece injector_template_suffix,
+                              std::map<std::string, std::string>* variables) {
+  if (options.field_listener_options.forbidden_field_listener_events.count(
+          std::string(annotation_name)))
+    return;
+  (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute(
+      StrCat(injector_template_prefix, injector_template_suffix),
+      (*variables)["classtype"]);
+}
+
+void GenerateExtensionAnnotations(
+    const Descriptor* descriptor, const Options& options,
+    std::map<std::string, std::string>* variables) {
+  const std::map<std::string, std::string> accessor_annotations_to_hooks = {
+      {"annotate_extension_has", "OnHasExtension"},
+      {"annotate_extension_clear", "OnClearExtension"},
+      {"annotate_extension_repeated_size", "OnExtensionSize"},
+      {"annotate_extension_get", "OnGetExtension"},
+      {"annotate_extension_mutable", "OnMutableExtension"},
+      {"annotate_extension_set", "OnSetExtension"},
+      {"annotate_extension_release", "OnReleaseExtension"},
+      {"annotate_repeated_extension_get", "OnGetExtension"},
+      {"annotate_repeated_extension_mutable", "OnMutableExtension"},
+      {"annotate_repeated_extension_set", "OnSetExtension"},
+      {"annotate_repeated_extension_add", "OnAddExtension"},
+      {"annotate_repeated_extension_add_mutable", "OnAddMutableExtension"},
+      {"annotate_repeated_extension_list", "OnListExtension"},
+      {"annotate_repeated_extension_list_mutable", "OnMutableListExtension"},
+  };
+  for (const auto& annotation : accessor_annotations_to_hooks) {
+    (*variables)[annotation.first] = "";
+  }
+  if (!options.field_listener_options.inject_field_listener_events ||
+      descriptor->file()->options().optimize_for() ==
+          google::protobuf::FileOptions::LITE_RUNTIME) {
+    return;
+  }
+  for (const auto& annotation : accessor_annotations_to_hooks) {
+    const std::string& annotation_name = annotation.first;
+    const std::string& listener_call = annotation.second;
+    if (!StrContains(annotation_name, "repeated") &&
+        !StrContains(annotation_name, "size") &&
+        !StrContains(annotation_name, "clear")) {
+      // Primitive fields accessors.
+      // "Has" is here as users calling "has" on a repeated field is a mistake.
+      (*variables)[annotation_name] = StrCat(
+          "  _tracker_.", listener_call,
+          "(this, id.number(), _proto_TypeTraits::GetPtr(id.number(), "
+          "_extensions_, id.default_value_ref()));");
+    } else if (StrContains(annotation_name, "repeated") &&
+               !StrContains(annotation_name, "list") &&
+               !StrContains(annotation_name, "size")) {
+      // Repeated index accessors.
+      std::string str_index = "index";
+      if (StrContains(annotation_name, "add")) {
+        str_index = "_extensions_.ExtensionSize(id.number()) - 1";
+      }
+      (*variables)[annotation_name] =
+          StrCat("  _tracker_.", listener_call,
+                       "(this, id.number(), "
+                       "_proto_TypeTraits::GetPtr(id.number(), _extensions_, ",
+                       str_index, "));");
+    } else if (StrContains(annotation_name, "list") ||
+               StrContains(annotation_name, "size")) {
+      // Repeated full accessors.
+      (*variables)[annotation_name] = StrCat(
+          "  _tracker_.", listener_call,
+          "(this, id.number(), _proto_TypeTraits::GetRepeatedPtr(id.number(), "
+          "_extensions_));");
+    } else {
+      // Generic accessors such as "clear".
+      // TODO(b/190614678): Generalize clear from both repeated and non repeated
+      // calls, currently their underlying memory interfaces are very different.
+      // Or think of removing clear callback as no usages are needed and no
+      // memory exist after calling clear().
+    }
+  }
+}
+
 }  // anonymous namespace
 
 // ===================================================================
@@ -567,6 +656,7 @@
       options_(options),
       field_generators_(descriptor, options, scc_analyzer),
       max_has_bit_index_(0),
+      max_inlined_string_index_(0),
       num_weak_fields_(0),
       scc_analyzer_(scc_analyzer),
       variables_(vars) {
@@ -583,36 +673,31 @@
   variables_["annotate_deserialize"] = "";
   variables_["annotate_reflection"] = "";
   variables_["annotate_bytesize"] = "";
+  variables_["annotate_mergefrom"] = "";
 
-  if (options.inject_field_listener_events &&
+  if (options.field_listener_options.inject_field_listener_events &&
       descriptor->file()->options().optimize_for() !=
           google::protobuf::FileOptions::LITE_RUNTIME) {
-    const std::string injector_template = StrCat(
-        "  {\n"
-        "    auto _listener_ = ::",
-        variables_["proto_ns"],
-        "::FieldAccessListener::GetListener();\n"
-        "    if (_listener_) ");
+    const std::string injector_template = "  _tracker_.";
 
-    StrAppend(&variables_["annotate_serialize"], injector_template,
-                    "_listener_->OnSerializationAccess(this);\n"
-                    "  }\n");
-    StrAppend(&variables_["annotate_deserialize"], injector_template,
-                    " _listener_->OnDeserializationAccess(this);\n"
-                    "  }\n");
+    MaySetAnnotationVariable(options, "serialize", injector_template,
+                             "OnSerialize(this);\n", &variables_);
+    MaySetAnnotationVariable(options, "deserialize", injector_template,
+                             "OnDeserialize(this);\n", &variables_);
     // TODO(danilak): Ideally annotate_reflection should not exist and we need
     // to annotate all reflective calls on our own, however, as this is a cause
     // for side effects, i.e. reading values dynamically, we want the users know
     // that dynamic access can happen.
-    StrAppend(&variables_["annotate_reflection"], injector_template,
-                    "_listener_->OnReflectionAccess(default_instance()"
-                    ".GetMetadata().descriptor);\n"
-                    "  }\n");
-    StrAppend(&variables_["annotate_bytesize"], injector_template,
-                    "_listener_->OnByteSizeAccess(this);\n"
-                    "  }\n");
+    MaySetAnnotationVariable(options, "reflection", injector_template,
+                             "OnGetMetadata();\n", &variables_);
+    MaySetAnnotationVariable(options, "bytesize", injector_template,
+                             "OnByteSize(this);\n", &variables_);
+    MaySetAnnotationVariable(options, "mergefrom", injector_template,
+                             "OnMergeFrom(this, &from);\n", &variables_);
   }
 
+  GenerateExtensionAnnotations(descriptor_, options_, &variables_);
+
   SetUnknownFieldsVariable(descriptor_, options_, &variables_);
 
   // Compute optimized field order to be used for layout and initialization
@@ -640,12 +725,22 @@
       }
       has_bit_indices_[field->index()] = max_has_bit_index_++;
     }
+    if (IsStringInlined(field, options_)) {
+      if (inlined_string_indices_.empty()) {
+        inlined_string_indices_.resize(descriptor_->field_count(), kNoHasbit);
+      }
+      inlined_string_indices_[field->index()] = max_inlined_string_index_++;
+    }
   }
 
   if (!has_bit_indices_.empty()) {
     field_generators_.SetHasBitIndices(has_bit_indices_);
   }
 
+  if (!inlined_string_indices_.empty()) {
+    field_generators_.SetInlinedStringIndices(inlined_string_indices_);
+  }
+
   num_required_fields_ = 0;
   for (int i = 0; i < descriptor->field_count(); i++) {
     if (descriptor->field(i)->is_required()) {
@@ -656,8 +751,8 @@
   table_driven_ =
       TableDrivenParsingEnabled(descriptor_, options_, scc_analyzer_);
   parse_function_generator_.reset(new ParseFunctionGenerator(
-      descriptor_, max_has_bit_index_, has_bit_indices_, options_,
-      scc_analyzer_, variables_));
+      descriptor_, max_has_bit_index_, has_bit_indices_,
+      inlined_string_indices_, options_, scc_analyzer_, variables_));
 }
 
 MessageGenerator::~MessageGenerator() = default;
@@ -666,6 +761,10 @@
   return (max_has_bit_index_ + 31) / 32;
 }
 
+size_t MessageGenerator::InlinedStringDonatedSize() const {
+  return (max_inlined_string_index_ + 31) / 32;
+}
+
 int MessageGenerator::HasBitIndex(const FieldDescriptor* field) const {
   return has_bit_indices_.empty() ? kNoHasbit
                                   : has_bit_indices_[field->index()];
@@ -690,8 +789,8 @@
     enum_generators_.push_back(enum_generators->back().get());
   }
   for (int i = 0; i < descriptor_->extension_count(); i++) {
-    extension_generators->emplace_back(
-        new ExtensionGenerator(descriptor_->extension(i), options_));
+    extension_generators->emplace_back(new ExtensionGenerator(
+        descriptor_->extension(i), options_, scc_analyzer_));
     extension_generators_.push_back(extension_generators->back().get());
   }
 }
@@ -777,9 +876,206 @@
   }
 
   if (descriptor_->extension_range_count() > 0) {
-    // Generate accessors for extensions.  We just call a macro located in
-    // extension_set.h since the accessors about 80 lines of static code.
-    format("$GOOGLE_PROTOBUF$_EXTENSION_ACCESSORS($classname$)\n");
+    // Generate accessors for extensions.
+    // We use "_proto_TypeTraits" as a type name below because "TypeTraits"
+    // causes problems if the class has a nested message or enum type with that
+    // name and "_TypeTraits" is technically reserved for the C++ library since
+    // it starts with an underscore followed by a capital letter.
+    //
+    // For similar reason, we use "_field_type" and "_is_packed" as parameter
+    // names below, so that "field_type" and "is_packed" can be used as field
+    // names.
+    format(R"(
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline bool HasExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+$annotate_extension_has$
+  return _extensions_.Has(id.number());
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void ClearExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+  _extensions_.ClearExtension(id.number());
+$annotate_extension_clear$
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline int ExtensionSize(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+$annotate_extension_repeated_size$
+  return _extensions_.ExtensionSize(id.number());
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+$annotate_extension_get$
+  return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                id.default_value());
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+$annotate_extension_mutable$
+  return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                    &_extensions_);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void SetExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    typename _proto_TypeTraits::Singular::ConstType value) {
+  _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+$annotate_extension_set$
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void SetAllocatedExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    typename _proto_TypeTraits::Singular::MutableType value) {
+  _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                  &_extensions_);
+$annotate_extension_set$
+}
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void UnsafeArenaSetAllocatedExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    typename _proto_TypeTraits::Singular::MutableType value) {
+  _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                             value, &_extensions_);
+$annotate_extension_set$
+}
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline PROTOBUF_MUST_USE_RESULT
+    typename _proto_TypeTraits::Singular::MutableType
+    ReleaseExtension(
+        const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+            $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+$annotate_extension_release$
+  return _proto_TypeTraits::Release(id.number(), _field_type,
+                                    &_extensions_);
+}
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Singular::MutableType
+UnsafeArenaReleaseExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+$annotate_extension_release$
+  return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                               &_extensions_);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    int index) const {
+$annotate_repeated_extension_get$
+  return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    int index) {
+$annotate_repeated_extension_mutable$
+  return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void SetExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+  _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+$annotate_repeated_extension_set$
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+  typename _proto_TypeTraits::Repeated::MutableType to_add =
+      _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+$annotate_repeated_extension_add_mutable$
+  return to_add;
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline void AddExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id,
+    typename _proto_TypeTraits::Repeated::ConstType value) {
+  _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                         &_extensions_);
+$annotate_repeated_extension_add$
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+GetRepeatedExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+$annotate_repeated_extension_list$
+  return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+}
+
+template <typename _proto_TypeTraits,
+          ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+          bool _is_packed>
+inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+MutableRepeatedExtension(
+    const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+        $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) {
+$annotate_repeated_extension_list_mutable$
+  return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                            _is_packed, &_extensions_);
+}
+
+)");
     // Generate MessageSet specific APIs for proto2 MessageSet.
     // For testing purposes we don't check for bridge.MessageSet, so
     // we don't use IsProto2MessageSet
@@ -1145,8 +1441,10 @@
   } else {
     format("inline $classname$() : $classname$(nullptr) {}\n");
   }
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    format("~$classname$() override;\n");
+  }
   format(
-      "~$classname$() override;\n"
       "explicit constexpr "
       "$classname$(::$proto_ns$::internal::ConstantInitialized);\n"
       "\n"
@@ -1213,7 +1511,6 @@
         "  return default_instance().GetMetadata().descriptor;\n"
         "}\n"
         "static const ::$proto_ns$::Reflection* GetReflection() {\n"
-        "$annotate_reflection$"
         "  return default_instance().GetMetadata().reflection;\n"
         "}\n");
   }
@@ -1362,22 +1659,36 @@
 
   if (HasGeneratedMethods(descriptor_->file(), options_)) {
     if (HasDescriptorMethods(descriptor_->file(), options_)) {
-      format(
-          // Use Message's built-in MergeFrom and CopyFrom when the passed-in
-          // argument is a generic Message instance, and only define the custom
-          // MergeFrom and CopyFrom instances when the source of the merge/copy
-          // is known to be the same class as the destination.
-          // TODO(jorg): Define MergeFrom in terms of MergeImpl, rather than the
-          // other way around, to save even more code size.
-          "using $superclass$::CopyFrom;\n"
-          "void CopyFrom(const $classname$& from);\n"
-          ""
-          "using $superclass$::MergeFrom;\n"
-          "void MergeFrom(const $classname$& from);\n"
-          "private:\n"
-          "static void MergeImpl(::$proto_ns$::Message*to, const "
-          "::$proto_ns$::Message&from);\n"
-          "public:\n");
+      if (!HasSimpleBaseClass(descriptor_, options_)) {
+        format(
+            // Use Message's built-in MergeFrom and CopyFrom when the passed-in
+            // argument is a generic Message instance, and only define the
+            // custom MergeFrom and CopyFrom instances when the source of the
+            // merge/copy is known to be the same class as the destination.
+            // TODO(jorg): Define MergeFrom in terms of MergeImpl, rather than
+            // the other way around, to save even more code size.
+            "using $superclass$::CopyFrom;\n"
+            "void CopyFrom(const $classname$& from);\n"
+            ""
+            "using $superclass$::MergeFrom;\n"
+            "void MergeFrom(const $classname$& from);\n"
+            "private:\n"
+            "static void MergeImpl(::$proto_ns$::Message* to, const "
+            "::$proto_ns$::Message& from);\n"
+            "public:\n");
+      } else {
+        format(
+            "using $superclass$::CopyFrom;\n"
+            "inline void CopyFrom(const $classname$& from) {\n"
+            "  $superclass$::CopyImpl(this, from);\n"
+            "}\n"
+            ""
+            "using $superclass$::MergeFrom;\n"
+            "void MergeFrom(const $classname$& from) {\n"
+            "  $superclass$::MergeImpl(this, from);\n"
+            "}\n"
+            "public:\n");
+      }
     } else {
       format(
           "void CheckTypeAndMergeFrom(const ::$proto_ns$::MessageLite& from)"
@@ -1386,36 +1697,42 @@
           "void MergeFrom(const $classname$& from);\n");
     }
 
-    format.Set("clear_final",
-               ShouldMarkClearAsFinal(descriptor_, options_) ? "final" : "");
+    if (!HasSimpleBaseClass(descriptor_, options_)) {
+      format(
+          "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;\n"
+          "bool IsInitialized() const final;\n"
+          "\n"
+          "size_t ByteSizeLong() const final;\n");
 
-    format(
-        "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear()$ clear_final$;\n"
-        "bool IsInitialized() const final;\n"
-        "\n"
-        "size_t ByteSizeLong() const final;\n");
+      parse_function_generator_->GenerateMethodDecls(printer);
 
-    parse_function_generator_->GenerateMethodDecls(printer);
+      format(
+          "$uint8$* _InternalSerialize(\n"
+          "    $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
+          "const final;\n");
 
-    format(
-        "$uint8$* _InternalSerialize(\n"
-        "    $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
-        "const final;\n");
-
-    // DiscardUnknownFields() is implemented in message.cc using reflections. We
-    // need to implement this function in generated code for messages.
-    if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
-      format("void DiscardUnknownFields()$ full_final$;\n");
+      // DiscardUnknownFields() is implemented in message.cc using reflections.
+      // We need to implement this function in generated code for messages.
+      if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
+        format("void DiscardUnknownFields()$ full_final$;\n");
+      }
     }
   }
 
-  format(
-      "int GetCachedSize() const final { return _cached_size_.Get(); }"
-      "\n\nprivate:\n"
-      "void SharedCtor();\n"
-      "void SharedDtor();\n"
-      "void SetCachedSize(int size) const$ full_final$;\n"
-      "void InternalSwap($classname$* other);\n");
+  if (options_.field_listener_options.inject_field_listener_events) {
+    format("static constexpr int _kInternalFieldNumber = $1$;\n",
+           descriptor_->field_count());
+  }
+
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    format(
+        "int GetCachedSize() const final { return _cached_size_.Get(); }"
+        "\n\nprivate:\n"
+        "void SharedCtor();\n"
+        "void SharedDtor();\n"
+        "void SetCachedSize(int size) const$ full_final$;\n"
+        "void InternalSwap($classname$* other);\n");
+  }
 
   format(
       // Friend AnyMetadata so that it can call this FullMessageName() method.
@@ -1433,9 +1750,13 @@
       "protected:\n"
       "explicit $classname$(::$proto_ns$::Arena* arena,\n"
       "                     bool is_message_owned = false);\n"
-      "private:\n"
-      "static void ArenaDtor(void* object);\n"
-      "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n");
+      "private:\n");
+
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    format(
+        "static void ArenaDtor(void* object);\n"
+        "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n");
+  }
 
   format(
       "public:\n"
@@ -1562,6 +1883,21 @@
         "\n");
   }
 
+  if (options_.field_listener_options.inject_field_listener_events &&
+      descriptor_->file()->options().optimize_for() !=
+          google::protobuf::FileOptions::LITE_RUNTIME) {
+    format("static ::$proto_ns$::AccessListener<$1$> _tracker_;\n",
+           ClassName(descriptor_));
+  }
+
+  // Generate _inlined_string_donated_ for inlined string type.
+  // TODO(congliu): To avoid affecting the locality of `_has_bits_`, should this
+  // be below or above `_has_bits_`?
+  if (!inlined_string_indices_.empty()) {
+    format("::$proto_ns$::internal::HasBits<$1$> _inlined_string_donated_;\n",
+           InlinedStringDonatedSize());
+  }
+
   format(
       "template <typename T> friend class "
       "::$proto_ns$::Arena::InternalHelper;\n"
@@ -1731,8 +2067,17 @@
   has_offset = !has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)
                    ? offset + has_offset
                    : -1;
+  int inlined_string_indices_offset;
+  if (inlined_string_indices_.empty()) {
+    inlined_string_indices_offset = -1;
+  } else {
+    GOOGLE_DCHECK_NE(has_offset, -1);
+    GOOGLE_DCHECK(!IsMapEntryMessage(descriptor_));
+    inlined_string_indices_offset = has_offset + has_bit_indices_.size();
+  }
 
-  format("{ $1$, $2$, sizeof($classtype$)},\n", offset, has_offset);
+  format("{ $1$, $2$, $3$, sizeof($classtype$)},\n", offset, has_offset,
+         inlined_string_indices_offset);
 }
 
 namespace {
@@ -1746,7 +2091,9 @@
   if (type == FieldDescriptor::TYPE_STRING ||
       type == FieldDescriptor::TYPE_BYTES) {
     // string field
-    if (IsCord(field, options)) {
+    if (generator.IsInlined()) {
+      type = internal::FieldMetadata::kInlinedType;
+    } else if (IsCord(field, options)) {
       type = internal::FieldMetadata::kCordType;
     } else if (IsStringPiece(field, options)) {
       type = internal::FieldMetadata::kStringPieceType;
@@ -1956,13 +2303,24 @@
         "  MergeFromInternal(other);\n"
         "}\n");
     if (HasDescriptorMethods(descriptor_->file(), options_)) {
-      format(
-          "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
-          "  return ::$proto_ns$::internal::AssignDescriptors(\n"
-          "      &$desc_table$_getter, &$desc_table$_once,\n"
-          "      $file_level_metadata$[$1$]);\n"
-          "}\n",
-          index_in_file_messages_);
+      if (!descriptor_->options().map_entry()) {
+        format(
+            "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+            "$annotate_reflection$"
+            "  return ::$proto_ns$::internal::AssignDescriptors(\n"
+            "      &$desc_table$_getter, &$desc_table$_once,\n"
+            "      $file_level_metadata$[$1$]);\n"
+            "}\n",
+            index_in_file_messages_);
+      } else {
+        format(
+            "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+            "  return ::$proto_ns$::internal::AssignDescriptors(\n"
+            "      &$desc_table$_getter, &$desc_table$_once,\n"
+            "      $file_level_metadata$[$1$]);\n"
+            "}\n",
+            index_in_file_messages_);
+      }
     }
     return;
   }
@@ -2059,10 +2417,12 @@
     GenerateClear(printer);
     format("\n");
 
-    parse_function_generator_->GenerateMethodImpls(printer);
-    format("\n");
+    if (!HasSimpleBaseClass(descriptor_, options_)) {
+      parse_function_generator_->GenerateMethodImpls(printer);
+      format("\n");
 
-    parse_function_generator_->GenerateDataDefinitions(printer);
+      parse_function_generator_->GenerateDataDefinitions(printer);
+    }
 
     GenerateSerializeWithCachedSizesToArray(printer);
     format("\n");
@@ -2083,6 +2443,8 @@
     format("\n");
   }
 
+  GenerateVerify(printer);
+
   GenerateSwap(printer);
   format("\n");
 
@@ -2095,13 +2457,24 @@
         index_in_file_messages_);
   }
   if (HasDescriptorMethods(descriptor_->file(), options_)) {
-    format(
-        "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
-        "  return ::$proto_ns$::internal::AssignDescriptors(\n"
-        "      &$desc_table$_getter, &$desc_table$_once,\n"
-        "      $file_level_metadata$[$1$]);\n"
-        "}\n",
-        index_in_file_messages_);
+    if (!descriptor_->options().map_entry()) {
+      format(
+          "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+          "$annotate_reflection$"
+          "  return ::$proto_ns$::internal::AssignDescriptors(\n"
+          "      &$desc_table$_getter, &$desc_table$_once,\n"
+          "      $file_level_metadata$[$1$]);\n"
+          "}\n",
+          index_in_file_messages_);
+    } else {
+      format(
+          "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+          "  return ::$proto_ns$::internal::AssignDescriptors(\n"
+          "      &$desc_table$_getter, &$desc_table$_once,\n"
+          "      $file_level_metadata$[$1$]);\n"
+          "}\n",
+          index_in_file_messages_);
+    }
   } else {
     format(
         "std::string $classname$::GetTypeName() const {\n"
@@ -2110,6 +2483,14 @@
         "\n");
   }
 
+  if (options_.field_listener_options.inject_field_listener_events &&
+      descriptor_->file()->options().optimize_for() !=
+          google::protobuf::FileOptions::LITE_RUNTIME) {
+    format(
+        "::$proto_ns$::AccessListener<$classtype$> "
+        "$1$::_tracker_(&FullMessageName);\n",
+        ClassName(descriptor_));
+  }
 }
 
 size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
@@ -2148,9 +2529,13 @@
     }
 
     processing_type = static_cast<unsigned>(field->type());
+    const FieldGenerator& generator = field_generators_.get(field);
     if (field->type() == FieldDescriptor::TYPE_STRING) {
       switch (EffectiveStringCType(field, options_)) {
         case FieldOptions::STRING:
+          if (generator.IsInlined()) {
+            processing_type = internal::TYPE_STRING_INLINED;
+          }
           break;
         case FieldOptions::CORD:
           processing_type = internal::TYPE_STRING_CORD;
@@ -2162,6 +2547,9 @@
     } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
       switch (EffectiveStringCType(field, options_)) {
         case FieldOptions::STRING:
+          if (generator.IsInlined()) {
+            processing_type = internal::TYPE_BYTES_INLINED;
+          }
           break;
         case FieldOptions::CORD:
           processing_type = internal::TYPE_BYTES_CORD;
@@ -2326,7 +2714,12 @@
   } else {
     format("~0u,  // no _weak_field_map_\n");
   }
-  const int kNumGenericOffsets = 5;  // the number of fixed offsets above
+  if (!inlined_string_indices_.empty()) {
+    format("PROTOBUF_FIELD_OFFSET($classtype$, _inlined_string_donated_),\n");
+  } else {
+    format("~0u,  // no _inlined_string_donated_\n");
+  }
+  const int kNumGenericOffsets = 6;  // the number of fixed offsets above
   const size_t offsets = kNumGenericOffsets + descriptor_->field_count() +
                          descriptor_->real_oneof_decl_count();
   size_t entries = offsets;
@@ -2345,10 +2738,18 @@
       format("PROTOBUF_FIELD_OFFSET($classtype$, $1$_)", FieldName(field));
     }
 
+    // Some information about a field is in the pdproto profile. The profile is
+    // only available at compile time. So we embed such information in the
+    // offset of the field, so that the information is available when reflective
+    // accessing the field at run time.
+    //
+    // Embed whether the field is used to the MSB of the offset.
     if (!IsFieldUsed(field, options_)) {
       format(" | 0x80000000u, // unused\n");
     } else if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) {
       format(" | 0x1u, // eagerly verified lazy\n");
+    } else if (IsStringInlined(field, options_)) {
+      format(" | 0x1u, // inlined\n");
     } else {
       format(",\n");
     }
@@ -2374,11 +2775,21 @@
       format("$1$,\n", index);
     }
   }
+  if (!inlined_string_indices_.empty()) {
+    entries += inlined_string_indices_.size();
+    for (int inlined_string_indice : inlined_string_indices_) {
+      const std::string index = inlined_string_indice >= 0
+                                    ? StrCat(inlined_string_indice)
+                                    : "~0u";
+      format("$1$,\n", index);
+    }
+  }
 
   return std::make_pair(entries, offsets);
 }
 
 void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
 
   format("void $classname$::SharedCtor() {\n");
@@ -2394,6 +2805,7 @@
 }
 
 void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
 
   format("inline void $classname$::SharedDtor() {\n");
@@ -2424,6 +2836,7 @@
 }
 
 void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
 
   // Generate the ArenaDtor() method. Track whether any fields actually produced
@@ -2593,7 +3006,8 @@
     bool has_arena_constructor = field->is_repeated();
     if (!field->real_containing_oneof() &&
         (IsLazy(field, options_, scc_analyzer_) ||
-         IsStringPiece(field, options_))) {
+         IsStringPiece(field, options_) ||
+         (IsString(field, options_) && IsStringInlined(field, options_)))) {
       has_arena_constructor = true;
     }
     if (has_arena_constructor) {
@@ -2620,15 +3034,29 @@
   format(
       "$classname$::$classname$(::$proto_ns$::Arena* arena,\n"
       "                         bool is_message_owned)\n"
-      "  : $1$ {\n"
-      "  SharedCtor();\n"
-      "  if (!is_message_owned) {\n"
-      "    RegisterArenaDtor(arena);\n"
-      "  }\n"
-      "  // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
-      "}\n",
+      "  : $1$ {\n",
       initializer_with_arena);
 
+  if (!inlined_string_indices_.empty()) {
+    // Donate inline string fields.
+    format("  if (arena != nullptr) {\n");
+    for (size_t i = 0; i < InlinedStringDonatedSize(); ++i) {
+      format("    _inlined_string_donated_[$1$] = ~0u;\n", i);
+    }
+    format("  }\n");
+  }
+
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    format(
+        "  SharedCtor();\n"
+        "  if (!is_message_owned) {\n"
+        "    RegisterArenaDtor(arena);\n"
+        "  }\n");
+  }
+  format(
+      "  // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
+      "}\n");
+
   std::map<std::string, std::string> vars;
   SetUnknownFieldsVariable(descriptor_, options_, &vars);
   format.AddMap(vars);
@@ -2652,6 +3080,9 @@
     format.Indent();
     format.Indent();
 
+    // Do not copy inlined_string_donated_, because this is not an arena
+    // constructor.
+
     if (!has_bit_indices_.empty()) {
       format(",\n_has_bits_(from._has_bits_)");
     }
@@ -2726,14 +3157,22 @@
   GenerateSharedConstructorCode(printer);
 
   // Generate the destructor.
-  format(
-      "$classname$::~$classname$() {\n"
-      "  // @@protoc_insertion_point(destructor:$full_name$)\n"
-      "  if (GetArenaForAllocation() != nullptr) return;\n"
-      "  SharedDtor();\n"
-      "  _internal_metadata_.Delete<$unknown_fields_type$>();\n"
-      "}\n"
-      "\n");
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    format(
+        "$classname$::~$classname$() {\n"
+        "  // @@protoc_insertion_point(destructor:$full_name$)\n"
+        "  if (GetArenaForAllocation() != nullptr) return;\n"
+        "  SharedDtor();\n"
+        "  _internal_metadata_.Delete<$unknown_fields_type$>();\n"
+        "}\n"
+        "\n");
+  } else {
+    // For messages using simple base classes, having no destructor
+    // allows our vtable to share the same destructor as every other
+    // message with a simple base class.  This works only as long as
+    // we have no fields needing destruction, of course.  (No strings
+    // or extensions)
+  }
 
   // Generate the shared destructor code.
   GenerateSharedDestructorCode(printer);
@@ -2741,11 +3180,13 @@
   // Generate the arena-specific destructor code.
   GenerateArenaDestructorCode(printer);
 
-  // Generate SetCachedSize.
-  format(
-      "void $classname$::SetCachedSize(int size) const {\n"
-      "  _cached_size_.Set(size);\n"
-      "}\n");
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    // Generate SetCachedSize.
+    format(
+        "void $classname$::SetCachedSize(int size) const {\n"
+        "  _cached_size_.Set(size);\n"
+        "}\n");
+  }
 }
 
 void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) {
@@ -2759,6 +3200,7 @@
 }
 
 void MessageGenerator::GenerateClear(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
 
   // The maximum number of bytes we will memset to zero without checking their
@@ -2916,6 +3358,8 @@
     format("_weak_field_map_.ClearAll();\n");
   }
 
+  // We don't clear donated status.
+
   if (!has_bit_indices_.empty()) {
     // Step 5: Everything else.
     format("_has_bits_.Clear();\n");
@@ -2975,6 +3419,7 @@
 }
 
 void MessageGenerator::GenerateSwap(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
 
   format("void $classname$::InternalSwap($classname$* other) {\n");
@@ -2989,6 +3434,11 @@
     std::map<std::string, std::string> vars;
     SetUnknownFieldsVariable(descriptor_, options_, &vars);
     format.AddMap(vars);
+    if (HasSingularString(descriptor_, options_)) {
+      format(
+          "auto* lhs_arena = GetArenaForAllocation();\n"
+          "auto* rhs_arena = other->GetArenaForAllocation();\n");
+    }
     format("_internal_metadata_.InternalSwap(&other->_internal_metadata_);\n");
 
     if (!has_bit_indices_.empty()) {
@@ -3056,47 +3506,64 @@
 
 void MessageGenerator::GenerateMergeFrom(io::Printer* printer) {
   Formatter format(printer, variables_);
-  if (HasDescriptorMethods(descriptor_->file(), options_)) {
-    // We don't override the generalized MergeFrom (aka that which
-    // takes in the Message base class as a parameter); instead we just
-    // let the base Message::MergeFrom take care of it.  The base MergeFrom
-    // knows how to quickly confirm the types exactly match, and if so, will
-    // use GetClassData() to retrieve the address of MergeImpl, which calls
-    // the fast MergeFrom overload.  Most callers avoid all this by passing
-    // a "from" message that is the same type as the message being merged
-    // into, rather than a generic Message.
+  if (!HasSimpleBaseClass(descriptor_, options_)) {
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      // We don't override the generalized MergeFrom (aka that which
+      // takes in the Message base class as a parameter); instead we just
+      // let the base Message::MergeFrom take care of it.  The base MergeFrom
+      // knows how to quickly confirm the types exactly match, and if so, will
+      // use GetClassData() to retrieve the address of MergeImpl, which calls
+      // the fast MergeFrom overload.  Most callers avoid all this by passing
+      // a "from" message that is the same type as the message being merged
+      // into, rather than a generic Message.
 
+      format(
+          "const ::$proto_ns$::Message::ClassData "
+          "$classname$::_class_data_ = {\n"
+          "    ::$proto_ns$::Message::CopyWithSizeCheck,\n"
+          "    $classname$::MergeImpl\n"
+          "};\n"
+          "const ::$proto_ns$::Message::ClassData*"
+          "$classname$::GetClassData() const { return &_class_data_; }\n"
+          "\n"
+          "void $classname$::MergeImpl(::$proto_ns$::Message* to,\n"
+          "                      const ::$proto_ns$::Message& from) {\n"
+          "  static_cast<$classname$ *>(to)->MergeFrom(\n"
+          "      static_cast<const $classname$ &>(from));\n"
+          "}\n"
+          "\n");
+    } else {
+      // Generate CheckTypeAndMergeFrom().
+      format(
+          "void $classname$::CheckTypeAndMergeFrom(\n"
+          "    const ::$proto_ns$::MessageLite& from) {\n"
+          "  MergeFrom(*::$proto_ns$::internal::DownCast<const $classname$*>(\n"
+          "      &from));\n"
+          "}\n");
+    }
+  } else {
+    // In the simple case, we just define ClassData that vectors back to the
+    // simple implementation of Copy and Merge.
     format(
         "const ::$proto_ns$::Message::ClassData "
         "$classname$::_class_data_ = {\n"
-        "    ::$proto_ns$::Message::CopyWithSizeCheck,\n"
-        "    $classname$::MergeImpl\n"
+        "    $superclass$::CopyImpl,\n"
+        "    $superclass$::MergeImpl,\n"
         "};\n"
         "const ::$proto_ns$::Message::ClassData*"
         "$classname$::GetClassData() const { return &_class_data_; }\n"
         "\n"
-        "void $classname$::MergeImpl(::$proto_ns$::Message*to,\n"
-        "                      const ::$proto_ns$::Message&from) {\n"
-        "  static_cast<$classname$ *>(to)->MergeFrom(\n"
-        "      static_cast<const $classname$ &>(from));\n"
-        "}\n"
         "\n");
-  } else {
-    // Generate CheckTypeAndMergeFrom().
-    format(
-        "void $classname$::CheckTypeAndMergeFrom(\n"
-        "    const ::$proto_ns$::MessageLite& from) {\n"
-        "  MergeFrom(*::$proto_ns$::internal::DownCast<const $classname$*>(\n"
-        "      &from));\n"
-        "}\n");
   }
 }
 
 void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast.
   Formatter format(printer, variables_);
   format(
       "void $classname$::MergeFrom(const $classname$& from) {\n"
+      "$annotate_mergefrom$"
       "// @@protoc_insertion_point(class_specific_merge_from_start:"
       "$full_name$)\n"
       "  $DCHK$_NE(&from, this);\n");
@@ -3255,6 +3722,7 @@
 }
 
 void MessageGenerator::GenerateCopyFrom(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
   if (HasDescriptorMethods(descriptor_->file(), options_)) {
     // We don't override the generalized CopyFrom (aka that which
@@ -3301,6 +3769,9 @@
   format("}\n");
 }
 
+void MessageGenerator::GenerateVerify(io::Printer* printer) {
+}
+
 void MessageGenerator::GenerateSerializeOneofFields(
     io::Printer* printer, const std::vector<const FieldDescriptor*>& fields) {
   Formatter format(printer, variables_);
@@ -3376,11 +3847,12 @@
   format("// Extension range [$start$, $end$)\n");
   format(
       "target = _extensions_._InternalSerialize(\n"
-      "    $start$, $end$, target, stream);\n\n");
+      "internal_default_instance(), $start$, $end$, target, stream);\n\n");
 }
 
 void MessageGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
   if (descriptor_->options().message_set_wire_format()) {
     // Special-case MessageSet.
@@ -3390,7 +3862,8 @@
         "const {\n"
         "$annotate_serialize$"
         "  target = _extensions_."
-        "InternalSerializeMessageSetWithCachedSizesToArray(target, stream);\n");
+        "InternalSerializeMessageSetWithCachedSizesToArray(\n"  //
+        "internal_default_instance(), target, stream);\n");
     std::map<std::string, std::string> vars;
     SetUnknownFieldsVariable(descriptor_, options_, &vars);
     format.AddMap(vars);
@@ -3443,6 +3916,7 @@
 
 void MessageGenerator::GenerateSerializeWithCachedSizesBody(
     io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
   // If there are multiple fields in a row from the same oneof then we
   // coalesce them and emit a switch statement.  This is more efficient
@@ -3759,6 +4233,7 @@
 }
 
 void MessageGenerator::GenerateByteSize(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
 
   if (descriptor_->options().message_set_wire_format()) {
@@ -3987,37 +4462,37 @@
     format("total_size += _weak_field_map_.ByteSizeLong();\n");
   }
 
-  format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n");
   if (UseUnknownFieldSet(descriptor_->file(), options_)) {
     // We go out of our way to put the computation of the uncommon path of
     // unknown fields in tail position. This allows for better code generation
     // of this function for simple protos.
     format(
-        "  return ::$proto_ns$::internal::ComputeUnknownFieldsSize(\n"
-        "      _internal_metadata_, total_size, &_cached_size_);\n");
+        "return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);\n");
   } else {
+    format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n");
     format("  total_size += $unknown_fields$.size();\n");
-  }
-  format("}\n");
+    format("}\n");
 
-  // We update _cached_size_ even though this is a const method.  Because
-  // const methods might be called concurrently this needs to be atomic
-  // operations or the program is undefined.  In practice, since any concurrent
-  // writes will be writing the exact same value, normal writes will work on
-  // all common processors. We use a dedicated wrapper class to abstract away
-  // the underlying atomic. This makes it easier on platforms where even relaxed
-  // memory order might have perf impact to replace it with ordinary loads and
-  // stores.
-  format(
-      "int cached_size = ::$proto_ns$::internal::ToCachedSize(total_size);\n"
-      "SetCachedSize(cached_size);\n"
-      "return total_size;\n");
+    // We update _cached_size_ even though this is a const method.  Because
+    // const methods might be called concurrently this needs to be atomic
+    // operations or the program is undefined.  In practice, since any
+    // concurrent writes will be writing the exact same value, normal writes
+    // will work on all common processors. We use a dedicated wrapper class to
+    // abstract away the underlying atomic. This makes it easier on platforms
+    // where even relaxed memory order might have perf impact to replace it with
+    // ordinary loads and stores.
+    format(
+        "int cached_size = ::$proto_ns$::internal::ToCachedSize(total_size);\n"
+        "SetCachedSize(cached_size);\n"
+        "return total_size;\n");
+  }
 
   format.Outdent();
   format("}\n");
 }
 
 void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
+  if (HasSimpleBaseClass(descriptor_, options_)) return;
   Formatter format(printer, variables_);
   format("bool $classname$::IsInitialized() const {\n");
   format.Indent();
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 339d6e7..64af2bf 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -134,6 +134,7 @@
   // Generate standard Message methods.
   void GenerateClear(io::Printer* printer);
   void GenerateOneofClear(io::Printer* printer);
+  void GenerateVerify(io::Printer* printer);
   void GenerateSerializeWithCachedSizes(io::Printer* printer);
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer);
   void GenerateSerializeWithCachedSizesBody(io::Printer* printer);
@@ -177,6 +178,7 @@
                                bool copy_constructor) const;
 
   size_t HasBitsSize() const;
+  size_t InlinedStringDonatedSize() const;
   int HasBitIndex(const FieldDescriptor* a) const;
   int HasByteIndex(const FieldDescriptor* a) const;
   int HasWordIndex(const FieldDescriptor* a) const;
@@ -196,6 +198,13 @@
   std::vector<const FieldDescriptor*> optimized_order_;
   std::vector<int> has_bit_indices_;
   int max_has_bit_index_;
+
+  // A map from field index to inlined_string index. For non-inlined-string
+  // fields, the element is -1.
+  std::vector<int> inlined_string_indices_;
+  // The count of inlined_string fields in the message.
+  int max_inlined_string_index_;
+
   std::vector<const EnumGenerator*> enum_generators_;
   std::vector<const ExtensionGenerator*> extension_generators_;
   int num_required_fields_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 2e97c3d..57cef2f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -33,6 +33,7 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
 
+#include <set>
 #include <string>
 
 namespace google {
@@ -49,6 +50,11 @@
   kLiteRuntime,
 };
 
+struct FieldListenerOptions {
+  bool inject_field_listener_events = false;
+  std::set<std::string> forbidden_field_listener_events;
+};
+
 // Generator options (see generator.cc for a description of each):
 struct Options {
   std::string dllexport_decl;
@@ -64,6 +70,8 @@
   bool opensource_runtime = false;
   bool annotate_accessor = false;
   bool unused_field_stripping = false;
+  bool profile_driven_inline_string = false;
+  bool force_inline_string = false;
   std::string runtime_include_base;
   int num_cc_files = 0;
   std::string annotation_pragma_name;
@@ -74,7 +82,7 @@
     kTCTableGuarded,
     kTCTableAlways
   } tctable_mode = kTCTableNever;
-  bool inject_field_listener_events = false;
+  FieldListenerOptions field_listener_options;
   bool eagerly_verified_lazy = false;
   bool force_eagerly_verified_lazy = false;
 };
diff --git a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
index 6886b4f..3991d12 100644
--- a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
@@ -30,7 +30,9 @@
 
 #include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h>
 
+#include <algorithm>
 #include <limits>
+#include <string>
 
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/wire_format.h>
@@ -64,16 +66,6 @@
   return ctype == FieldOptions::STRING || ctype == FieldOptions::CORD;
 }
 
-bool IsTcTableEnabled(const Options& options) {
-  return options.tctable_mode == Options::kTCTableAlways;
-}
-bool IsTcTableGuarded(const Options& options) {
-  return options.tctable_mode == Options::kTCTableGuarded;
-}
-bool IsTcTableDisabled(const Options& options) {
-  return options.tctable_mode == Options::kTCTableNever;
-}
-
 int TagSize(uint32_t field_number) {
   if (field_number < 16) return 1;
   GOOGLE_CHECK_LT(field_number, (1 << 14))
@@ -81,22 +73,38 @@
   return 2;
 }
 
+const char* CodedTagType(int tag_size) {
+  return tag_size == 1 ? "uint8_t" : "uint16_t";
+}
+
 const char* TagType(const FieldDescriptor* field) {
   return CodedTagType(TagSize(field->number()));
 }
 
-std::string MessageParseFunctionName(const FieldDescriptor* field,
-                                     const Options& options) {
-  std::string name =
-      "::" + ProtobufNamespace(options) + "::internal::TcParserBase::";
-  if (field->is_repeated()) {
-    name.append("Repeated");
-  } else {
-    name.append("Singular");
+std::string TcParserBaseName(const Options& options) {
+  return StrCat("::", ProtobufNamespace(options),
+                      "::internal::TcParserBase::");
+}
+
+std::string MessageTcParseFunctionName(const FieldDescriptor* field,
+                                       const Options& options) {
+  if (field->message_type()->field_count() == 0 ||
+      !HasGeneratedMethods(field->message_type()->file(), options)) {
+    // For files with `option optimize_for = CODE_SIZE`, or which derive from
+    // `ZeroFieldsBase`, we need to call the `_InternalParse` function, because
+    // there is no generated tailcall function. For tailcall parsing, this is
+    // done by helpers in TcParserBase.
+    return StrCat(TcParserBaseName(options),
+                        (field->is_repeated() ? "Repeated" : "Singular"),
+                        "ParseMessage<",
+                        QualifiedClassName(field->message_type()),  //
+                        ", ", TagType(field), ">");
   }
-  name.append("ParseMessage<" + QualifiedClassName(field->message_type()) +
-              ", " + TagType(field) + ">");
-  return name;
+  // This matches macros in generated_message_tctable_impl.h:
+  return StrCat("PROTOBUF_TC_PARSE_",
+                      (field->is_repeated() ? "REPEATED" : "SINGULAR"),
+                      TagSize(field->number()), "(",
+                      QualifiedClassName(field->message_type()), ")");
 }
 
 std::string FieldParseFunctionName(const FieldDescriptor* field,
@@ -105,10 +113,6 @@
 
 }  // namespace
 
-const char* CodedTagType(int tag_size) {
-  return tag_size == 1 ? "uint8_t" : "uint16_t";
-}
-
 TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor,
                                      const Options& options,
                                      const std::vector<int>& has_bit_indices,
@@ -139,9 +143,9 @@
     // Anything difficult slow path:
     if (field->is_map()) continue;
     if (field->real_containing_oneof()) continue;
-    if (field->options().lazy()) continue;
     if (field->options().weak()) continue;
     if (IsImplicitWeakField(field, options, scc_analyzer)) continue;
+    if (IsLazy(field, options, scc_analyzer)) continue;
 
     // The largest tag that can be read by the tailcall parser is two bytes
     // when varint-coded. This allows 14 bits for the numeric tag value:
@@ -189,7 +193,7 @@
 
     switch (field->type()) {
       case FieldDescriptor::TYPE_MESSAGE:
-        name = MessageParseFunctionName(field, options);
+        name = MessageTcParseFunctionName(field, options);
         break;
 
       case FieldDescriptor::TYPE_FIXED64:
@@ -230,16 +234,6 @@
     fast_path_fields[idx].field = field;
   }
 
-  // Construct a mask of has-bits for required fields numbered <= 32.
-  has_hasbits_required_mask = 0;
-  for (auto field : FieldRange(descriptor)) {
-    if (field->is_required()) {
-      int idx = has_bit_indices[field->index()];
-      if (idx >= 32) continue;
-      has_hasbits_required_mask |= 1u << idx;
-    }
-  }
-
   // If there are no fallback fields, and at most one extension range, the
   // parser can use a generic fallback function. Otherwise, a message-specific
   // fallback routine is needed.
@@ -249,15 +243,17 @@
 
 ParseFunctionGenerator::ParseFunctionGenerator(
     const Descriptor* descriptor, int max_has_bit_index,
-    const std::vector<int>& has_bit_indices, const Options& options,
+    const std::vector<int>& has_bit_indices,
+    const std::vector<int>& inlined_string_indices, const Options& options,
     MessageSCCAnalyzer* scc_analyzer,
     const std::map<std::string, std::string>& vars)
     : descriptor_(descriptor),
       scc_analyzer_(scc_analyzer),
       options_(options),
       variables_(vars),
+      inlined_string_indices_(inlined_string_indices),
       num_hasbits_(max_has_bit_index) {
-  if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
+  if (should_generate_tctable()) {
     tc_table_info_.reset(new TailCallTableInfo(descriptor_, options_,
                                                has_bit_indices, scc_analyzer));
   }
@@ -268,28 +264,46 @@
 
 void ParseFunctionGenerator::GenerateMethodDecls(io::Printer* printer) {
   Formatter format(printer, variables_);
-  if (IsTcTableGuarded(options_)) {
-    format.Outdent();
-    format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
-    format.Indent();
-  }
-  if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
-    if (tc_table_info_->use_generated_fallback) {
-      format(
-          "static const char* Tct_ParseFallback(\n"
-          "    ::$proto_ns$::MessageLite *msg, const char *ptr,\n"
-          "    ::$proto_ns$::internal::ParseContext *ctx,\n"
-          "    const ::$proto_ns$::internal::TailCallParseTableBase *table,\n"
-          "    uint64_t hasbits, ::$proto_ns$::internal::TcFieldData data);\n"
-          "inline const char* Tct_FallbackImpl(\n"
-          "    const char* ptr, ::$proto_ns$::internal::ParseContext* ctx,\n"
-          "    const void*, $uint64$ hasbits);\n");
+  if (should_generate_tctable()) {
+    auto declare_function = [&format](const char* name,
+                                      const std::string& guard) {
+      if (!guard.empty()) {
+        format.Outdent();
+        format("#if $1$\n", guard);
+        format.Indent();
+      }
+      format("static const char* $1$(PROTOBUF_TC_PARAM_DECL);\n", name);
+      if (!guard.empty()) {
+        format.Outdent();
+        format("#endif  // $1$\n", guard);
+        format.Indent();
+      }
+    };
+    if (should_generate_guarded_tctable()) {
+      format.Outdent();
+      format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
+      format.Indent();
     }
-  }
-  if (IsTcTableGuarded(options_)) {
-    format.Outdent();
-    format("#endif\n");
-    format.Indent();
+    format("// The Tct_* functions are internal to the protobuf runtime:\n");
+    // These guards are defined in port_def.inc:
+    declare_function("Tct_ParseS1", "PROTOBUF_TC_STATIC_PARSE_SINGULAR1");
+    declare_function("Tct_ParseS2", "PROTOBUF_TC_STATIC_PARSE_SINGULAR2");
+    declare_function("Tct_ParseR1", "PROTOBUF_TC_STATIC_PARSE_REPEATED1");
+    declare_function("Tct_ParseR2", "PROTOBUF_TC_STATIC_PARSE_REPEATED2");
+    if (tc_table_info_->use_generated_fallback) {
+      format.Outdent();
+      format(
+          " private:\n"
+          "  ");
+      declare_function("Tct_ParseFallback", "");
+      format(" public:\n");
+      format.Indent();
+    }
+    if (should_generate_guarded_tctable()) {
+      format.Outdent();
+      format("#endif\n");
+      format.Indent();
+    }
   }
   format(
       "const char* _InternalParse(const char* ptr, "
@@ -298,8 +312,10 @@
 
 void ParseFunctionGenerator::GenerateMethodImpls(io::Printer* printer) {
   Formatter format(printer, variables_);
+  bool need_parse_function = true;
   if (descriptor_->options().message_set_wire_format()) {
     // Special-case MessageSet.
+    need_parse_function = false;
     format(
         "const char* $classname$::_InternalParse(const char* ptr,\n"
         "                  ::$proto_ns$::internal::ParseContext* ctx) {\n"
@@ -307,85 +323,157 @@
         "  return _extensions_.ParseMessageSet(ptr, \n"
         "      internal_default_instance(), &_internal_metadata_, ctx);\n"
         "}\n");
+  }
+  if (!should_generate_tctable()) {
+    if (need_parse_function) {
+      GenerateLoopingParseFunction(format);
+    }
     return;
   }
-  if (IsTcTableGuarded(options_)) {
+  if (should_generate_guarded_tctable()) {
     format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
   }
-  if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
-    format(
-        "const char* $classname$::_InternalParse(\n"
-        "    const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n"
-        "  return ::$proto_ns$::internal::TcParser<$1$>::ParseLoop(\n"
-        "      this, ptr, ctx, &_table_.header);\n"
-        "}\n"
-        "\n",
-        tc_table_info_->table_size_log2);
-    if (tc_table_info_->use_generated_fallback) {
-      GenerateTailcallFallbackFunction(format);
+  if (need_parse_function) {
+    GenerateTailcallParseFunction(format);
+  }
+  if (tc_table_info_->use_generated_fallback) {
+    GenerateTailcallFallbackFunction(format);
+  }
+  GenerateTailcallFieldParseFunctions(format);
+  if (should_generate_guarded_tctable()) {
+    if (need_parse_function) {
+      format("\n#else  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
+      GenerateLoopingParseFunction(format);
     }
-  }
-  if (IsTcTableGuarded(options_)) {
-    format("\n#else  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
-  }
-  if (IsTcTableGuarded(options_) || IsTcTableDisabled(options_)) {
-    GenerateLoopingParseFunction(format);
-  }
-  if (IsTcTableGuarded(options_)) {
     format("\n#endif  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
   }
 }
 
+bool ParseFunctionGenerator::should_generate_tctable() const {
+  if (options_.tctable_mode == Options::kTCTableNever) {
+    return false;
+  }
+  return true;
+}
+
+void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) {
+  GOOGLE_CHECK(should_generate_tctable());
+
+  // Generate an `_InternalParse` that starts the tail-calling loop.
+  format(
+      "const char* $classname$::_InternalParse(\n"
+      "    const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n"
+      "$annotate_deserialize$"
+      "  ptr = ::$proto_ns$::internal::TcParser<$1$>::ParseLoop(\n"
+      "      this, ptr, ctx, &_table_.header);\n",
+      tc_table_info_->table_size_log2);
+  format(
+      "  return ptr;\n"
+      "}\n\n");
+}
+
 void ParseFunctionGenerator::GenerateTailcallFallbackFunction(
     Formatter& format) {
+  GOOGLE_CHECK(should_generate_tctable());
   format(
       "const char* $classname$::Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL) {\n"
-      "  return static_cast<$classname$*>(msg)->Tct_FallbackImpl(ptr, ctx, "
-      "table, hasbits);\n"
-      "}\n\n");
-
-  format(
-      "const char* $classname$::Tct_FallbackImpl(const char* ptr, "
-      "::$proto_ns$::internal::ParseContext* ctx, const void*, "
-      "$uint64$ hasbits) {\n"
       "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr\n");
   format.Indent();
+  format("auto* typed_msg = static_cast<$classname$*>(msg);\n");
 
   if (num_hasbits_ > 0) {
     // Sync hasbits
-    format("_has_bits_[0] = hasbits;\n");
+    format("typed_msg->_has_bits_[0] = hasbits;\n");
   }
 
-  format.Set("has_bits", "_has_bits_");
-  format.Set("continue", "goto success");
+  format.Set("msg", "typed_msg->");
+  format.Set("this", "typed_msg");
+  format.Set("has_bits", "typed_msg->_has_bits_");
+  format.Set("next_tag", "goto next_tag");
   GenerateParseIterationBody(format, descriptor_,
                              tc_table_info_->fallback_fields);
 
   format.Outdent();
-  format("success:\n");
-  format("  return ptr;\n");
   format(
+      "next_tag:\n"
+      "message_done:\n"
+      "  return ptr;\n"
       "#undef CHK_\n"
       "}\n");
 }
 
+void ParseFunctionGenerator::GenerateTailcallFieldParseFunctions(
+    Formatter& format) {
+  GOOGLE_CHECK(should_generate_tctable());
+  // There are four cases where a tailcall target are needed for messages:
+  //   {singular, repeated} x {1, 2}-byte tag
+  struct {
+    const char* type;
+    int size;
+  } const kTagLayouts[] = {
+      {"uint8_t", 1},
+      {"uint16_t", 2},
+  };
+  // Singular:
+  for (const auto& layout : kTagLayouts) {
+    // Guard macros are defined in port_def.inc.
+    format(
+        "#if PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n"
+        "const char* $classname$::Tct_ParseS$1$(PROTOBUF_TC_PARAM_DECL) {\n"
+        "  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0))\n"
+        "    PROTOBUF_MUSTTAIL "
+        "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
+        "  ptr += $1$;\n"
+        "  hasbits |= (uint64_t{1} << data.hasbit_idx());\n"
+        "  ::$proto_ns$::internal::TcParserBase::SyncHasbits"
+        "(msg, hasbits, table);\n"
+        "  auto& field = ::$proto_ns$::internal::TcParserBase::"
+        "RefAt<$classtype$*>(msg, data.offset());\n"
+        "  if (field == nullptr)\n"
+        "    field = CreateMaybeMessage<$classtype$>(ctx->data().arena);\n"
+        "  return ctx->ParseMessage(field, ptr);\n"
+        "}\n"
+        "#endif  // PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n",
+        layout.size, layout.type);
+  }
+  // Repeated:
+  for (const auto& layout : kTagLayouts) {
+    // Guard macros are defined in port_def.inc.
+    format(
+        "#if PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n"
+        "const char* $classname$::Tct_ParseR$1$(PROTOBUF_TC_PARAM_DECL) {\n"
+        "  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0)) {\n"
+        "    PROTOBUF_MUSTTAIL "
+        "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
+        "  }\n"
+        "  ptr += $1$;\n"
+        "  auto& field = ::$proto_ns$::internal::TcParserBase::RefAt<"
+        "::$proto_ns$::RepeatedPtrField<$classname$>>(msg, data.offset());\n"
+        "  ::$proto_ns$::internal::TcParserBase::SyncHasbits"
+        "(msg, hasbits, table);\n"
+        "  ptr = ctx->ParseMessage(field.Add(), ptr);\n"
+        "  return ptr;\n"
+        "}\n"
+        "#endif  // PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n",
+        layout.size, layout.type);
+  }
+}
+
 void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) {
-  if (descriptor_->options().message_set_wire_format()) {
+  if (!should_generate_tctable()) {
     return;
   }
   Formatter format(printer, variables_);
-  if (IsTcTableGuarded(options_)) {
+  if (should_generate_guarded_tctable()) {
     format.Outdent();
     format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
     format.Indent();
   }
-  if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
-    format(
-        "static const ::$proto_ns$::internal::TailCallParseTable<$1$>\n"
-        "    _table_;\n",
-        tc_table_info_->table_size_log2);
-  }
-  if (IsTcTableGuarded(options_)) {
+  format(
+      "static const ::$proto_ns$::internal::TailCallParseTable<$1$>\n"
+      "    _table_;\n",
+      tc_table_info_->table_size_log2);
+  if (should_generate_guarded_tctable()) {
     format.Outdent();
     format("#endif  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
     format.Indent();
@@ -393,17 +481,15 @@
 }
 
 void ParseFunctionGenerator::GenerateDataDefinitions(io::Printer* printer) {
-  if (descriptor_->options().message_set_wire_format()) {
+  if (!should_generate_tctable()) {
     return;
   }
   Formatter format(printer, variables_);
-  if (IsTcTableGuarded(options_)) {
+  if (should_generate_guarded_tctable()) {
     format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
   }
-  if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
-    GenerateTailCallTable(format);
-  }
-  if (IsTcTableGuarded(options_)) {
+  GenerateTailCallTable(format);
+  if (should_generate_guarded_tctable()) {
     format("#endif  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
   }
 }
@@ -415,6 +501,8 @@
       "$annotate_deserialize$"
       "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure\n");
   format.Indent();
+  format.Set("msg", "");
+  format.Set("this", "this");
   int hasbits_size = 0;
   if (num_hasbits_ > 0) {
     hasbits_size = (num_hasbits_ + 31) / 32;
@@ -427,7 +515,7 @@
   } else {
     format.Set("has_bits", "_has_bits_");
   }
-  format.Set("continue", "continue");
+  format.Set("next_tag", "continue");
   format("while (!ctx->Done(&ptr)) {\n");
   format.Indent();
 
@@ -438,26 +526,26 @@
   format("}  // while\n");
 
   format.Outdent();
-  format("success:\n");
+  format("message_done:\n");
   if (hasbits_size) format("  _has_bits_.Or(has_bits);\n");
 
   format(
       "  return ptr;\n"
       "failure:\n"
       "  ptr = nullptr;\n"
-      "  goto success;\n"
+      "  goto message_done;\n"
       "#undef CHK_\n"
       "}\n");
 }
 
 void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) {
+  GOOGLE_CHECK(should_generate_tctable());
   // All entries without a fast-path parsing function need a fallback.
   std::string fallback;
   if (tc_table_info_->use_generated_fallback) {
     fallback = ClassName(descriptor_) + "::Tct_ParseFallback";
   } else {
-    fallback = "::" + ProtobufNamespace(options_) +
-               "::internal::TcParserBase::GenericFallback";
+    fallback = TcParserBaseName(options_) + "GenericFallback";
     if (GetOptimizeFor(descriptor_->file(), options_) ==
         FileOptions::LITE_RUNTIME) {
       fallback += "Lite";
@@ -493,10 +581,8 @@
     format("0, 0, 0,  // no _extensions_\n");
   }
   format(
-      "$1$,  // has_bits_required_mask\n"
-      "&$2$._instance,\n"
-      "$3$  // fallback\n",
-      tc_table_info_->has_hasbits_required_mask,
+      "&$1$._instance,\n"
+      "$2$  // fallback\n",
       DefaultInstanceName(descriptor_, options_), fallback);
   format.Outdent();
   format("}, {\n");
@@ -536,13 +622,25 @@
                 "::" + MakeDefaultName(field) + ".get()";
   format(
       "if (arena != nullptr) {\n"
-      "  ptr = ctx->ReadArenaString(ptr, &$1$_, arena);\n"
+      "  ptr = ctx->ReadArenaString(ptr, &$msg$$name$_, arena");
+  if (IsStringInlined(field, options_)) {
+    GOOGLE_DCHECK(!inlined_string_indices_.empty());
+    int inlined_string_index = inlined_string_indices_[field->index()];
+    GOOGLE_DCHECK_GE(inlined_string_index, 0);
+    format(
+        ", $msg$_internal_$name$_donated(), &_inlined_string_donated_[$1$], "
+        "~0x$2$u",
+        inlined_string_index / 32,
+        strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8));
+  }
+  format(
+      ");\n"
       "} else {\n"
       "  ptr = ::$proto_ns$::internal::InlineGreedyStringParser("
-      "$1$_.MutableNoArenaNoDefault(&$2$), ptr, ctx);\n"
+      "$msg$$name$_.MutableNoArenaNoDefault(&$1$), ptr, ctx);\n"
       "}\n"
-      "const std::string* str = &$1$_.Get(); (void)str;\n",
-      FieldName(field), default_string);
+      "const std::string* str = &$msg$$name$_.Get(); (void)str;\n",
+      default_string);
 }
 
 void ParseFunctionGenerator::GenerateStrings(Formatter& format,
@@ -560,24 +658,24 @@
       !field->real_containing_oneof() && ctype == FieldOptions::STRING) {
     GenerateArenaString(format, field);
   } else {
-    std::string name;
+    std::string parser_name;
     switch (ctype) {
       case FieldOptions::STRING:
-        name = "GreedyStringParser";
+        parser_name = "GreedyStringParser";
         break;
       case FieldOptions::CORD:
-        name = "CordParser";
+        parser_name = "CordParser";
         break;
       case FieldOptions::STRING_PIECE:
-        name = "StringPieceParser";
+        parser_name = "StringPieceParser";
         break;
     }
     format(
-        "auto str = $1$$2$_$3$();\n"
-        "ptr = ::$proto_ns$::internal::Inline$4$(str, ptr, ctx);\n",
+        "auto str = $msg$$1$$2$_$name$();\n"
+        "ptr = ::$proto_ns$::internal::Inline$3$(str, ptr, ctx);\n",
         HasInternalAccessors(ctype) ? "_internal_" : "",
         field->is_repeated() && !field->is_packable() ? "add" : "mutable",
-        FieldName(field), name);
+        parser_name);
   }
   if (!check_utf8) return;  // return if this is a bytes field
   auto level = GetUtf8CheckMode(field, options_);
@@ -614,24 +712,20 @@
 void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format,
                                                  const FieldDescriptor* field) {
   if (field->is_packable()) {
-    std::string enum_validator;
     if (field->type() == FieldDescriptor::TYPE_ENUM &&
         !HasPreservingUnknownEnumSemantics(field)) {
-      enum_validator =
-          StrCat(", ", QualifiedClassName(field->enum_type(), options_),
-                       "_IsValid, &_internal_metadata_, ", field->number());
+      std::string enum_type = QualifiedClassName(field->enum_type(), options_);
       format(
           "ptr = "
           "::$proto_ns$::internal::Packed$1$Parser<$unknown_fields_type$>("
-          "_internal_mutable_$2$(), ptr, ctx$3$);\n",
-          DeclaredTypeMethodName(field->type()), FieldName(field),
-          enum_validator);
+          "$msg$_internal_mutable_$name$(), ptr, ctx, $2$_IsValid, "
+          "&$msg$_internal_metadata_, $3$);\n",
+          DeclaredTypeMethodName(field->type()), enum_type, field->number());
     } else {
       format(
           "ptr = ::$proto_ns$::internal::Packed$1$Parser("
-          "_internal_mutable_$2$(), ptr, ctx$3$);\n",
-          DeclaredTypeMethodName(field->type()), FieldName(field),
-          enum_validator);
+          "$msg$_internal_mutable_$name$(), ptr, ctx);\n",
+          DeclaredTypeMethodName(field->type()));
     }
   } else {
     auto field_type = field->type();
@@ -651,61 +745,59 @@
               !HasPreservingUnknownEnumSemantics(field)) {
             format(
                 "auto object = "
-                "::$proto_ns$::internal::InitEnumParseWrapper<$unknown_"
-                "fields_type$>("
-                "&$1$_, $2$_IsValid, $3$, &_internal_metadata_);\n"
+                "::$proto_ns$::internal::InitEnumParseWrapper<"
+                "$unknown_fields_type$>(&$msg$$name$_, $1$_IsValid, "
+                "$2$, &$msg$_internal_metadata_);\n"
                 "ptr = ctx->ParseMessage(&object, ptr);\n",
-                FieldName(field), QualifiedClassName(val->enum_type()),
+                QualifiedClassName(val->enum_type(), options_),
                 field->number());
           } else {
-            format("ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field));
+            format("ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n");
           }
         } else if (IsLazy(field, options_, scc_analyzer_)) {
           if (field->real_containing_oneof()) {
             format(
-                "if (!_internal_has_$1$()) {\n"
-                "  clear_$2$();\n"
-                "  $2$_.$1$_ = ::$proto_ns$::Arena::CreateMessage<\n"
+                "if (!$msg$_internal_has_$name$()) {\n"
+                "  $msg$clear_$1$();\n"
+                "  $msg$$1$_.$name$_ = ::$proto_ns$::Arena::CreateMessage<\n"
                 "      ::$proto_ns$::internal::LazyField>("
-                "GetArenaForAllocation());\n"
-                "  set_has_$1$();\n"
+                "$msg$GetArenaForAllocation());\n"
+                "  $msg$set_has_$name$();\n"
                 "}\n"
-                "ptr = ctx->ParseMessage($2$_.$1$_, ptr);\n",
-                FieldName(field), field->containing_oneof()->name());
+                "ptr = ctx->ParseMessage($msg$$1$_.$name$_, ptr);\n",
+                field->containing_oneof()->name());
           } else if (HasHasbit(field)) {
             format(
-                "_Internal::set_has_$1$(&$has_bits$);\n"
-                "ptr = ctx->ParseMessage(&$1$_, ptr);\n",
-                FieldName(field));
+                "_Internal::set_has_$name$(&$has_bits$);\n"
+                "ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n");
           } else {
-            format("ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field));
+            format("ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n");
           }
         } else if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
           if (!field->is_repeated()) {
             format(
-                "ptr = ctx->ParseMessage(_Internal::mutable_$1$(this), "
-                "ptr);\n",
-                FieldName(field));
+                "ptr = ctx->ParseMessage(_Internal::mutable_$name$($this$), "
+                "ptr);\n");
           } else {
             format(
-                "ptr = ctx->ParseMessage($1$_.AddWeak(reinterpret_cast<const "
-                "::$proto_ns$::MessageLite*>($2$::_$3$_default_instance_ptr_)"
+                "ptr = ctx->ParseMessage($msg$$name$_.AddWeak("
+                "reinterpret_cast<const ::$proto_ns$::MessageLite*>($1$ptr_)"
                 "), ptr);\n",
-                FieldName(field), Namespace(field->message_type(), options_),
-                ClassName(field->message_type()));
+                QualifiedDefaultInstanceName(field->message_type(), options_));
           }
         } else if (IsWeak(field, options_)) {
           format(
               "{\n"
               "  auto* default_ = &reinterpret_cast<const Message&>($1$);\n"
-              "  ptr = ctx->ParseMessage(_weak_field_map_.MutableMessage($2$,"
-              " default_), ptr);\n"
+              "  ptr = ctx->ParseMessage($msg$_weak_field_map_.MutableMessage("
+              "$2$, default_), ptr);\n"
               "}\n",
               QualifiedDefaultInstanceName(field->message_type(), options_),
               field->number());
         } else {
-          format("ptr = ctx->ParseMessage(_internal_$1$_$2$(), ptr);\n",
-                 field->is_repeated() ? "add" : "mutable", FieldName(field));
+          format(
+              "ptr = ctx->ParseMessage($msg$_internal_$mutable_field$(), "
+              "ptr);\n");
         }
         break;
       }
@@ -728,29 +820,39 @@
 void ParseFunctionGenerator::GenerateFieldBody(
     Formatter& format, WireFormatLite::WireType wiretype,
     const FieldDescriptor* field) {
+  Formatter::SaveState formatter_state(&format);
+  format.AddMap(
+      {{"name", FieldName(field)},
+       {"primitive_type", PrimitiveTypeName(options_, field->cpp_type())}});
+  if (field->is_repeated()) {
+    format.AddMap({{"put_field", StrCat("add_", FieldName(field))},
+                   {"mutable_field", StrCat("add_", FieldName(field))}});
+  } else {
+    format.AddMap(
+        {{"put_field", StrCat("set_", FieldName(field))},
+         {"mutable_field", StrCat("mutable_", FieldName(field))}});
+  }
   uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype);
   switch (wiretype) {
     case WireFormatLite::WIRETYPE_VARINT: {
       std::string type = PrimitiveTypeName(options_, field->cpp_type());
-      std::string prefix = field->is_repeated() ? "add" : "set";
       if (field->type() == FieldDescriptor::TYPE_ENUM) {
+        format.Set("enum_type",
+                   QualifiedClassName(field->enum_type(), options_));
         format(
             "$uint64$ val = ::$proto_ns$::internal::ReadVarint64(&ptr);\n"
             "CHK_(ptr);\n");
         if (!HasPreservingUnknownEnumSemantics(field)) {
-          format("if (PROTOBUF_PREDICT_TRUE($1$_IsValid(val))) {\n",
-                 QualifiedClassName(field->enum_type(), options_));
+          format("if (PROTOBUF_PREDICT_TRUE($enum_type$_IsValid(val))) {\n");
           format.Indent();
         }
-        format("_internal_$1$_$2$(static_cast<$3$>(val));\n", prefix,
-               FieldName(field),
-               QualifiedClassName(field->enum_type(), options_));
+        format("$msg$_internal_$put_field$(static_cast<$enum_type$>(val));\n");
         if (!HasPreservingUnknownEnumSemantics(field)) {
           format.Outdent();
           format(
               "} else {\n"
               "  ::$proto_ns$::internal::WriteVarint("
-              "$1$, val, mutable_unknown_fields());\n"
+              "$1$, val, $msg$mutable_unknown_fields());\n"
               "}\n",
               field->number());
         }
@@ -765,42 +867,38 @@
           zigzag = "ZigZag";
         }
         if (field->is_repeated() || field->real_containing_oneof()) {
-          std::string prefix = field->is_repeated() ? "add" : "set";
           format(
-              "_internal_$1$_$2$("
-              "::$proto_ns$::internal::ReadVarint$3$$4$(&ptr));\n"
+              "$msg$_internal_$put_field$("
+              "::$proto_ns$::internal::ReadVarint$1$$2$(&ptr));\n"
               "CHK_(ptr);\n",
-              prefix, FieldName(field), zigzag, size);
+              zigzag, size);
         } else {
           if (HasHasbit(field)) {
-            format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field));
+            format("_Internal::set_has_$name$(&$has_bits$);\n");
           }
           format(
-              "$1$_ = ::$proto_ns$::internal::ReadVarint$2$$3$(&ptr);\n"
+              "$msg$$name$_ = ::$proto_ns$::internal::ReadVarint$1$$2$(&ptr);\n"
               "CHK_(ptr);\n",
-              FieldName(field), zigzag, size);
+              zigzag, size);
         }
       }
       break;
     }
     case WireFormatLite::WIRETYPE_FIXED32:
     case WireFormatLite::WIRETYPE_FIXED64: {
-      std::string type = PrimitiveTypeName(options_, field->cpp_type());
       if (field->is_repeated() || field->real_containing_oneof()) {
-        std::string prefix = field->is_repeated() ? "add" : "set";
         format(
-            "_internal_$1$_$2$("
-            "::$proto_ns$::internal::UnalignedLoad<$3$>(ptr));\n"
-            "ptr += sizeof($3$);\n",
-            prefix, FieldName(field), type);
+            "$msg$_internal_$put_field$("
+            "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr));\n"
+            "ptr += sizeof($primitive_type$);\n");
       } else {
         if (HasHasbit(field)) {
-          format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field));
+          format("_Internal::set_has_$name$(&$has_bits$);\n");
         }
         format(
-            "$1$_ = ::$proto_ns$::internal::UnalignedLoad<$2$>(ptr);\n"
-            "ptr += sizeof($2$);\n",
-            FieldName(field), type);
+            "$msg$$name$_ = "
+            "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr);\n"
+            "ptr += sizeof($primitive_type$);\n");
       }
       break;
     }
@@ -811,9 +909,9 @@
     }
     case WireFormatLite::WIRETYPE_START_GROUP: {
       format(
-          "ptr = ctx->ParseGroup(_internal_$1$_$2$(), ptr, $3$);\n"
+          "ptr = ctx->ParseGroup($msg$_internal_$mutable_field$(), ptr, $1$);\n"
           "CHK_(ptr);\n",
-          field->is_repeated() ? "add" : "mutable", FieldName(field), tag);
+          tag);
       break;
     }
     case WireFormatLite::WIRETYPE_END_GROUP: {
@@ -845,14 +943,90 @@
   return expected_tag;
 }
 
+// These variables are used by the generated parse iteration, and must already
+// be defined in the generated code:
+// - `const char* ptr`: the input buffer.
+// - `ParseContext* ctx`: the associated context for `ptr`.
+// - implicit `this`: i.e., we must be in a non-static member function.
+//
+// The macro `CHK_(x)` must be defined. It should return an error condition if
+// the macro parameter is false.
+//
+// Whenever an END_GROUP tag was read, or tag 0 was read, the generated code
+// branches to the label `message_done`.
+//
+// These formatter variables are used:
+// - `next_tag`: a single statement to begin parsing the next tag.
+//
+// At the end of the generated code, the enclosing function should proceed to
+// parse the next tag in the stream.
 void ParseFunctionGenerator::GenerateParseIterationBody(
     Formatter& format, const Descriptor* descriptor,
     const std::vector<const FieldDescriptor*>& ordered_fields) {
   format(
       "$uint32$ tag;\n"
       "ptr = ::$proto_ns$::internal::ReadTag(ptr, &tag);\n");
-  if (!ordered_fields.empty()) format("switch (tag >> 3) {\n");
 
+  if (!ordered_fields.empty()) {
+    GenerateFieldSwitch(format, ordered_fields);
+    // Each field `case` only considers field number. Field numbers that are
+    // not defined in the message, or tags with an incompatible wire type, are
+    // considered "unusual" cases. They will be handled by the logic below.
+    format.Outdent();
+    format("handle_unusual:\n");
+    format.Indent();
+  }
+
+  // Unusual/extension/unknown case:
+  format(
+      "if ((tag == 0) || ((tag & 7) == 4)) {\n"
+      "  CHK_(ptr);\n"
+      "  ctx->SetLastTag(tag);\n"
+      "  goto message_done;\n"
+      "}\n");
+  if (IsMapEntryMessage(descriptor)) {
+    format("$next_tag$;\n");
+  } else {
+    if (descriptor->extension_range_count() > 0) {
+      format("if (");
+      for (int i = 0; i < descriptor->extension_range_count(); i++) {
+        const Descriptor::ExtensionRange* range =
+            descriptor->extension_range(i);
+        if (i > 0) format(" ||\n    ");
+
+        uint32_t start_tag = WireFormatLite::MakeTag(
+            range->start, static_cast<WireFormatLite::WireType>(0));
+        uint32_t end_tag = WireFormatLite::MakeTag(
+            range->end, static_cast<WireFormatLite::WireType>(0));
+
+        if (range->end > FieldDescriptor::kMaxNumber) {
+          format("($1$u <= tag)", start_tag);
+        } else {
+          format("($1$u <= tag && tag < $2$u)", start_tag, end_tag);
+        }
+      }
+      format(
+          ") {\n"
+          "  ptr = $msg$_extensions_.ParseField(tag, ptr, "
+          "internal_default_instance(), &$msg$_internal_metadata_, ctx);\n"
+          "  CHK_(ptr != nullptr);\n"
+          "  $next_tag$;\n"
+          "}\n");
+    }
+    format(
+        "ptr = UnknownFieldParse(\n"
+        "    tag,\n"
+        "    $msg$_internal_metadata_.mutable_unknown_fields<"
+        "$unknown_fields_type$>(),\n"
+        "    ptr, ctx);\n"
+        "CHK_(ptr != nullptr);\n");
+  }
+}
+
+void ParseFunctionGenerator::GenerateFieldSwitch(
+    Formatter& format,
+    const std::vector<const FieldDescriptor*>& ordered_fields) {
+  format("switch (tag >> 3) {\n");
   format.Indent();
 
   for (const auto* field : ordered_fields) {
@@ -893,61 +1067,18 @@
                         field);
       format.Outdent();
     }
-    format.Outdent();
     format(
-        "  } else goto handle_unusual;\n"
-        "  $continue$;\n");
+        "} else\n"
+        "  goto handle_unusual;\n"
+        "$next_tag$;\n");
+    format.Outdent();
   }  // for loop over ordered fields
 
-  // Default case
-  if (!ordered_fields.empty()) format("default: {\n");
-  if (!ordered_fields.empty()) format("handle_unusual:\n");
   format(
-      "  if ((tag == 0) || ((tag & 7) == 4)) {\n"
-      "    CHK_(ptr);\n"
-      "    ctx->SetLastTag(tag);\n"
-      "    goto success;\n"
-      "  }\n");
-  if (IsMapEntryMessage(descriptor)) {
-    format("  $continue$;\n");
-  } else {
-    if (descriptor->extension_range_count() > 0) {
-      format("if (");
-      for (int i = 0; i < descriptor->extension_range_count(); i++) {
-        const Descriptor::ExtensionRange* range =
-            descriptor->extension_range(i);
-        if (i > 0) format(" ||\n    ");
-
-        uint32_t start_tag = WireFormatLite::MakeTag(
-            range->start, static_cast<WireFormatLite::WireType>(0));
-        uint32_t end_tag = WireFormatLite::MakeTag(
-            range->end, static_cast<WireFormatLite::WireType>(0));
-
-        if (range->end > FieldDescriptor::kMaxNumber) {
-          format("($1$u <= tag)", start_tag);
-        } else {
-          format("($1$u <= tag && tag < $2$u)", start_tag, end_tag);
-        }
-      }
-      format(") {\n");
-      format(
-          "  ptr = _extensions_.ParseField(tag, ptr,\n"
-          "      internal_default_instance(), &_internal_metadata_, ctx);\n"
-          "  CHK_(ptr != nullptr);\n"
-          "  $continue$;\n"
-          "}\n");
-    }
-    format(
-        "  ptr = UnknownFieldParse(tag,\n"
-        "      _internal_metadata_.mutable_unknown_fields<$unknown_"
-        "fields_type$>(),\n"
-        "      ptr, ctx);\n"
-        "  CHK_(ptr != nullptr);\n"
-        "  $continue$;\n");
-  }
-  if (!ordered_fields.empty()) format("}\n");  // default case
+      "default:\n"
+      "  goto handle_unusual;\n");
   format.Outdent();
-  if (!ordered_fields.empty()) format("}  // switch\n");
+  format("}  // switch\n");
 }
 
 namespace {
@@ -1137,31 +1268,30 @@
 
   name.append(CodedTagType(tag_length_bytes));
 
-  std::string tcpb =
-      StrCat(ProtobufNamespace(options), "::internal::TcParserBase");
-
   switch (type_format) {
     case TypeFormat::kVar64:
     case TypeFormat::kVar32:
     case TypeFormat::kBool:
-      name.append(StrCat(", ::", tcpb, "::kNoConversion"));
+      name.append(
+          StrCat(", ", TcParserBaseName(options), "kNoConversion"));
       break;
 
     case TypeFormat::kSInt64:
     case TypeFormat::kSInt32:
-      name.append(StrCat(", ::", tcpb, "::kZigZag"));
+      name.append(StrCat(", ", TcParserBaseName(options), "kZigZag"));
       break;
 
     case TypeFormat::kBytes:
-      name.append(StrCat(", ::", tcpb, "::kNoUtf8"));
+      name.append(StrCat(", ", TcParserBaseName(options), "kNoUtf8"));
       break;
 
     case TypeFormat::kString:
-      name.append(StrCat(", ::", tcpb, "::kUtf8"));
+      name.append(StrCat(", ", TcParserBaseName(options), "kUtf8"));
       break;
 
     case TypeFormat::kStringValidateOnly:
-      name.append(StrCat(", ::", tcpb, "::kUtf8ValidateOnly"));
+      name.append(
+          StrCat(", ", TcParserBaseName(options), "kUtf8ValidateOnly"));
       break;
 
     default:
diff --git a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h
index 116353a..793e6ae 100644
--- a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h
+++ b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h
@@ -76,6 +76,7 @@
  public:
   ParseFunctionGenerator(const Descriptor* descriptor, int max_has_bit_index,
                          const std::vector<int>& has_bit_indices,
+                         const std::vector<int>& inlined_string_indices,
                          const Options& options,
                          MessageSCCAnalyzer* scc_analyzer,
                          const std::map<std::string, std::string>& vars);
@@ -93,9 +94,25 @@
   void GenerateDataDefinitions(io::Printer* printer);
 
  private:
+  // Returns true if tailcall table code should be generated.
+  bool should_generate_tctable() const;
+
+  // Returns true if tailcall table code should be generated, but inside an
+  // #ifdef guard.
+  bool should_generate_guarded_tctable() const {
+    return should_generate_tctable() &&
+           options_.tctable_mode == Options::kTCTableGuarded;
+  }
+
+  // Generates a tail-calling `_InternalParse` function.
+  void GenerateTailcallParseFunction(Formatter& format);
+
   // Generates a fallback function for tailcall table-based parsing.
   void GenerateTailcallFallbackFunction(Formatter& format);
 
+  // Generates functions for parsing this message as a field.
+  void GenerateTailcallFieldParseFunctions(Formatter& format);
+
   // Generates a looping `_InternalParse` function.
   void GenerateLoopingParseFunction(Formatter& format);
 
@@ -123,18 +140,20 @@
       Formatter& format, const Descriptor* descriptor,
       const std::vector<const FieldDescriptor*>& ordered_fields);
 
+  // Generates a `switch` statement to parse each of `ordered_fields`.
+  void GenerateFieldSwitch(
+      Formatter& format,
+      const std::vector<const FieldDescriptor*>& ordered_fields);
+
   const Descriptor* descriptor_;
   MessageSCCAnalyzer* scc_analyzer_;
   const Options& options_;
   std::map<std::string, std::string> variables_;
   std::unique_ptr<TailCallTableInfo> tc_table_info_;
+  std::vector<int> inlined_string_indices_;
   int num_hasbits_;
 };
 
-// Returns the integer type that holds a tag of the given length (in bytes) when
-// wire-encoded.
-const char* CodedTagType(int tag_size);
-
 enum class ParseCardinality {
   kSingular,
   kOneof,
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 9664586..ffccf08 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -209,10 +209,19 @@
   Formatter format(printer, variables_);
   int fixed_size = FixedSize(descriptor_->type());
   if (fixed_size == -1) {
-    format(
-        "total_size += $tag_size$ +\n"
-        "  ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
-        "    this->_internal_$name$());\n");
+    if (internal::WireFormat::TagSize(descriptor_->number(),
+                                      descriptor_->type()) == 1) {
+      // Adding one is very common and it turns out it can be done for
+      // free inside of WireFormatLite, so we can save an instruction here.
+      format(
+          "total_size += ::$proto_ns$::internal::WireFormatLite::"
+          "$declared_type$SizePlusOne(this->_internal_$name$());\n");
+    } else {
+      format(
+          "total_size += $tag_size$ +\n"
+          "  ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
+          "    this->_internal_$name$());\n");
+    }
   } else {
     format("total_size += $tag_size$ + $fixed_size$;\n");
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 5c7bb68..be19310 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -104,7 +104,8 @@
 
 StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor,
                                            const Options& options)
-    : FieldGenerator(descriptor, options) {
+    : FieldGenerator(descriptor, options),
+      inlined_(IsStringInlined(descriptor, options)) {
   SetStringVariables(descriptor, &variables_, options);
 }
 
@@ -112,7 +113,14 @@
 
 void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
   Formatter format(printer, variables_);
-  format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
+  if (!inlined_) {
+    format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
+  } else {
+    // `_init_inline_xxx` is used for initializing default instances.
+    format(
+        "::$proto_ns$::internal::InlinedStringField $name$_;\n"
+        "static std::true_type _init_inline_$name$_;\n");
+  }
 }
 
 void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const {
@@ -172,8 +180,13 @@
       "const std::string& _internal_$name$() const;\n"
       "inline PROTOBUF_ALWAYS_INLINE void "
       "_internal_set_$name$(const std::string& value);\n"
-      "std::string* _internal_mutable_$name$();\n"
-      "public:\n");
+      "std::string* _internal_mutable_$name$();\n");
+  if (inlined_) {
+    format(
+        "inline PROTOBUF_ALWAYS_INLINE bool _internal_$name$_donated() "
+        "const;\n");
+  }
+  format("public:\n");
 
   if (unknown_ctype) {
     format.Outdent();
@@ -196,16 +209,36 @@
   }
   format(
       "  return _internal_$name$();\n"
-      "}\n"
-      "template <typename ArgT0, typename... ArgT>\n"
-      "inline PROTOBUF_ALWAYS_INLINE\n"
-      "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
-      " $set_hasbit$\n"
-      " $name$_.$setter$($default_value_tag$, static_cast<ArgT0 &&>(arg0),"
-      " args..., GetArenaForAllocation());\n"
-      "$annotate_set$"
-      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
-      "}\n"
+      "}\n");
+  if (!inlined_) {
+    format(
+        "template <typename ArgT0, typename... ArgT>\n"
+        "inline PROTOBUF_ALWAYS_INLINE\n"
+        "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
+        " $set_hasbit$\n"
+        " $name$_.$setter$($default_value_tag$, static_cast<ArgT0 &&>(arg0),"
+        " args..., GetArenaForAllocation());\n"
+        "$annotate_set$"
+        "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+        "}\n");
+  } else {
+    format(
+        "template <typename ArgT0, typename... ArgT>\n"
+        "inline PROTOBUF_ALWAYS_INLINE\n"
+        "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
+        " $set_hasbit$\n"
+        " $name$_.$setter$(nullptr, static_cast<ArgT0 &&>(arg0),"
+        " args..., GetArenaForAllocation(), _internal_$name$_donated(), "
+        "&$donating_states_word$, $mask_for_undonate$);\n"
+        "$annotate_set$"
+        "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+        "}\n"
+        "inline bool $classname$::_internal_$name$_donated() const {\n"
+        "  bool value = $inlined_string_donated$\n"
+        "  return value;\n"
+        "}\n");
+  }
+  format(
       "inline std::string* $classname$::mutable_$name$() {\n"
       "  std::string* _s = _internal_mutable_$name$();\n"
       "$annotate_mutable$"
@@ -217,15 +250,34 @@
       "}\n"
       "inline void $classname$::_internal_set_$name$(const std::string& "
       "value) {\n"
-      "  $set_hasbit$\n"
-      "  $name$_.Set($default_value_tag$, value, GetArenaForAllocation());\n"
-      "}\n");
+      "  $set_hasbit$\n");
+  if (!inlined_) {
+    format(
+        "  $name$_.Set($default_value_tag$, value, GetArenaForAllocation());\n"
+        "}\n");
+  } else {
+    format(
+        "  $name$_.Set(nullptr, value, GetArenaForAllocation(),\n"
+        "    _internal_$name$_donated(), &$donating_states_word$, "
+        "$mask_for_undonate$);\n"
+        "}\n");
+  }
   format(
       "inline std::string* $classname$::_internal_mutable_$name$() {\n"
-      "  $set_hasbit$\n"
-      "  return $name$_.Mutable($default_variable_or_tag$, "
-      "GetArenaForAllocation());\n"
-      "}\n"
+      "  $set_hasbit$\n");
+  if (!inlined_) {
+    format(
+        "  return $name$_.Mutable($default_variable_or_tag$, "
+        "GetArenaForAllocation());\n"
+        "}\n");
+  } else {
+    format(
+        "  return $name$_.Mutable($default_variable_or_tag$, "
+        "GetArenaForAllocation(), _internal_$name$_donated(), "
+        "&$donating_states_word$, $mask_for_undonate$);\n"
+        "}\n");
+  }
+  format(
       "inline std::string* $classname$::$release_name$() {\n"
       "$annotate_release$"
       "  // @@protoc_insertion_point(field_release:$full_name$)\n");
@@ -235,9 +287,16 @@
         "  if (!_internal_has_$name$()) {\n"
         "    return nullptr;\n"
         "  }\n"
-        "  $clear_hasbit$\n"
-        "  return $name$_.ReleaseNonDefault($init_value$, "
-        "GetArenaForAllocation());\n");
+        "  $clear_hasbit$\n");
+    if (!inlined_) {
+      format(
+          "  return $name$_.ReleaseNonDefault($init_value$, "
+          "GetArenaForAllocation());\n");
+    } else {
+      format(
+          "  return $name$_.Release(nullptr, GetArenaForAllocation(), "
+          "_internal_$name$_donated());\n");
+    }
   } else {
     format(
         "  return $name$_.Release($init_value$, GetArenaForAllocation());\n");
@@ -250,9 +309,19 @@
       "    $set_hasbit$\n"
       "  } else {\n"
       "    $clear_hasbit$\n"
-      "  }\n"
-      "  $name$_.SetAllocated($init_value$, $name$,\n"
-      "      GetArenaForAllocation());\n"
+      "  }\n");
+  if (!inlined_) {
+    format(
+        "  $name$_.SetAllocated($init_value$, $name$,\n"
+        "      GetArenaForAllocation());\n");
+  } else {
+    // Currently, string fields with default value can't be inlined.
+    format(
+        "    $name$_.SetAllocated(nullptr, $name$, GetArenaForAllocation(), "
+        "_internal_$name$_donated(), &$donating_states_word$, "
+        "$mask_for_undonate$);\n");
+  }
+  format(
       "$annotate_set$"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "}\n");
@@ -274,6 +343,7 @@
   if (descriptor_->default_value_string().empty()) {
     format("$name$_.ClearToEmpty();\n");
   } else {
+    GOOGLE_DCHECK(!inlined_);
     format(
         "$name$_.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n");
   }
@@ -292,6 +362,18 @@
   // checks against the default variable.
   const bool must_be_present = HasHasbit(descriptor_);
 
+  if (inlined_ && must_be_present) {
+    // Calling mutable_$name$() gives us a string reference and sets the has bit
+    // for $name$ (in proto2).  We may get here when the string field is inlined
+    // but the string's contents have not been changed by the user, so we cannot
+    // make an assertion about the contents of the string and could never make
+    // an assertion about the string instance.
+    //
+    // For non-inlined strings, we distinguish from non-default by comparing
+    // instances, rather than contents.
+    format("$DCHK$(!$name$_.IsDefault(nullptr));\n");
+  }
+
   if (descriptor_->default_value_string().empty()) {
     if (must_be_present) {
       format("$name$_.ClearNonDefaultToEmpty();\n");
@@ -314,16 +396,31 @@
 
 void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
   Formatter format(printer, variables_);
-  format(
-      "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n"
-      "    $init_value$,\n"
-      "    &$name$_, GetArenaForAllocation(),\n"
-      "    &other->$name$_, other->GetArenaForAllocation()\n"
-      ");\n");
+  if (!inlined_) {
+    format(
+        "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n"
+        "    $init_value$,\n"
+        "    &$name$_, lhs_arena,\n"
+        "    &other->$name$_, rhs_arena\n"
+        ");\n");
+  } else {
+    // At this point, it's guaranteed that the two fields being swapped are on
+    // the same arena.
+    format(
+        "$name$_.Swap(&other->$name$_, nullptr, GetArenaForAllocation(), "
+        "_internal_$name$_donated(), other->_internal_$name$_donated(), "
+        "&$donating_states_word$, &(other->$donating_states_word$), "
+        "$mask_for_undonate$);\n");
+  }
 }
 
 void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
   Formatter format(printer, variables_);
+  if (inlined_ && descriptor_->default_value_string().empty()) {
+    // Automatic initialization will construct the string.
+    return;
+  }
+  GOOGLE_DCHECK(!inlined_);
   format("$name$_.UnsafeSetDefault($init_value$);\n");
 }
 
@@ -340,10 +437,16 @@
 
   format.Indent();
 
-  // TODO(gpike): improve this
-  format(
-      "$name$_.Set($default_value_tag$, from._internal_$name$(), \n"
-      "  GetArenaForAllocation());\n");
+  if (!inlined_) {
+    format(
+        "$name$_.Set($default_value_tag$, from._internal_$name$(), \n"
+        "  GetArenaForAllocation());\n");
+  } else {
+    format(
+        "$name$_.Set(nullptr, from._internal_$name$(),\n"
+        "  GetArenaForAllocation(), _internal_$name$_donated(), "
+        "&$donating_states_word$, $mask_for_undonate$);\n");
+  }
 
   format.Outdent();
   format("}\n");
@@ -351,6 +454,11 @@
 
 void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
   Formatter format(printer, variables_);
+  if (inlined_) {
+    // The destructor is automatically invoked.
+    return;
+  }
+
   format("$name$_.DestroyNoArena($init_value$);\n");
 }
 
@@ -380,6 +488,10 @@
 void StringFieldGenerator::GenerateConstinitInitializer(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
+  if (inlined_) {
+    format("$name$_(nullptr, false)");
+    return;
+  }
   if (descriptor_->default_value_string().empty()) {
     format("$name$_(&::$proto_ns$::internal::fixed_address_empty_string)");
   } else {
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index f35cff1..85689bb 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -66,8 +66,10 @@
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const override;
   void GenerateByteSize(io::Printer* printer) const override;
   void GenerateConstinitInitializer(io::Printer* printer) const override;
+  bool IsInlined() const override { return inlined_; }
 
  private:
+  bool inlined_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
 };
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.inc b/src/google/protobuf/compiler/cpp/cpp_unittest.inc
index e929da2..24104db 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.inc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.inc
@@ -90,6 +90,8 @@
 namespace cpp_unittest {
 
 
+void DoNothing() {}
+
 class MockErrorCollector : public MultiFileErrorCollector {
  public:
   MockErrorCollector() {}
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
index dd442fe..f154f95 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -569,9 +569,14 @@
   WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
   printer->Print(
       variables_,
+      // NB: Do not use the "$name$_converter_" field; the usage of generics
+      // (and requisite upcasts to Object) prevent optimizations.  Even
+      // without any optimizations, the below code is cheaper because it
+      // avoids boxing an int and a checkcast from the generics.
       "@java.lang.Override\n"
       "$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
-      "  return $name$_converter_.convert($name$_.getInt(index));\n"
+      "  $type$ result = $type$.forNumber($name$_.getInt(index));\n"
+      "  return result == null ? $unknown$ : result;\n"
       "}\n");
   printer->Annotate("{", "}", descriptor_);
   if (SupportUnknownEnumValue(descriptor_->file())) {
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 336a08f..ebd57a7 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -1457,7 +1457,7 @@
     io::Printer* printer) const {
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> Unit): "
+      "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> kotlin.Unit): "
       "$message$ "
       "=\n"
       "  $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
@@ -1482,7 +1482,7 @@
     io::Printer* printer) const {
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "inline fun $message$.copy(block: $message_kt$.Dsl.() -> Unit): "
+      "inline fun $message$.copy(block: $message_kt$.Dsl.() -> kotlin.Unit): "
       "$message$ =\n"
       "  $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
       "}._build()\n",
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index 13f003b..8f93499 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -780,7 +780,7 @@
     io::Printer* printer) const {
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> Unit): "
+      "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> kotlin.Unit): "
       "$message$ =\n"
       "  $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
       "}._build()\n",
@@ -803,7 +803,7 @@
 void ImmutableMessageLiteGenerator::GenerateTopLevelKotlinMembers(
     io::Printer* printer) const {
   printer->Print(
-      "inline fun $message$.copy(block: $message_kt$.Dsl.() -> Unit): "
+      "inline fun $message$.copy(block: $message_kt$.Dsl.() -> kotlin.Unit): "
       "$message$ =\n"
       "  $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
       "}._build()\n",
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 1db96f8..cfd0e03 100644
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -1408,24 +1408,17 @@
 // were the final one for a given filename.
 class FileDeduplicator {
  public:
-  explicit FileDeduplicator(const GeneratorOptions& options)
-      : error_on_conflict_(options.error_on_name_conflict) {}
+  explicit FileDeduplicator(const GeneratorOptions& options) {}
 
   // params:
   //   filenames: a pair of {short filename, full filename}
   //              (short filename don't have extra information, full filename
   //               contains extra information)
   //   desc: The Descriptor or SCC pointer or EnumDescriptor.
-  //   error: The returned error information.
   bool AddFile(const std::pair<std::string, std::string> filenames,
-               const void* desc, std::string* error) {
+               const void* desc) {
     if (descs_by_shortname_.find(filenames.first) !=
         descs_by_shortname_.end()) {
-      if (error_on_conflict_) {
-        *error = "Name conflict: file name " + filenames.first +
-                 " would be generated by two descriptors";
-        return false;
-      }
       // Change old pointer's actual name to full name.
       auto short_name_desc = descs_by_shortname_[filenames.first];
       allowed_descs_actual_name_[short_name_desc] =
@@ -1443,7 +1436,6 @@
   }
 
  private:
-  bool error_on_conflict_;
   // The map that restores all the descs that are using short name as filename.
   std::map<std::string, const void*> descs_by_shortname_;
   // The final actual filename map.
@@ -1537,8 +1529,7 @@
 bool GenerateJspbAllowedMap(const GeneratorOptions& options,
                             const std::vector<const FileDescriptor*>& files,
                             std::map<const void*, std::string>* allowed_set,
-                            SCCAnalyzer<DepsGenerator>* analyzer,
-                            std::string* error) {
+                            SCCAnalyzer<DepsGenerator>* analyzer) {
   std::vector<const FileDescriptor*> files_ordered;
   GenerateJspbFileOrder(files, &files_ordered);
 
@@ -1553,7 +1544,7 @@
               std::make_pair(
                   GetMessagesFileName(options, analyzer->GetSCC(desc), false),
                   GetMessagesFileName(options, analyzer->GetSCC(desc), true)),
-              analyzer->GetSCC(desc), error)) {
+              analyzer->GetSCC(desc))) {
         return false;
       }
     }
@@ -1561,7 +1552,7 @@
       const EnumDescriptor* desc = files_ordered[i]->enum_type(j);
       if (!dedup.AddFile(std::make_pair(GetEnumFileName(options, desc, false),
                                         GetEnumFileName(options, desc, true)),
-                         desc, error)) {
+                         desc)) {
         return false;
       }
     }
@@ -1580,7 +1571,7 @@
               std::make_pair(
                   GetExtensionFileName(options, files_ordered[i], false),
                   GetExtensionFileName(options, files_ordered[i], true)),
-              files_ordered[i], error)) {
+              files_ordered[i])) {
         return false;
       }
     }
@@ -3473,12 +3464,10 @@
         return false;
       }
       testonly = true;
+
     } else if (options[i].first == "error_on_name_conflict") {
-      if (options[i].second != "") {
-        *error = "Unexpected option value for error_on_name_conflict";
-        return false;
-      }
-      error_on_name_conflict = true;
+      GOOGLE_LOG(WARNING) << "Ignoring error_on_name_conflict option, this "
+                             "will be removed in a future release";
     } else if (options[i].first == "output_dir") {
       output_dir = options[i].second;
     } else if (options[i].first == "namespace_prefix") {
@@ -3527,11 +3516,10 @@
 
   if (import_style != kImportClosure &&
       (add_require_for_enums || testonly || !library.empty() ||
-       error_on_name_conflict || extension != ".js" ||
-       one_output_file_per_input_file)) {
+       extension != ".js" || one_output_file_per_input_file)) {
     *error =
-        "The add_require_for_enums, testonly, library, error_on_name_conflict, "
-        "extension, and one_output_file_per_input_file options should only be "
+        "The add_require_for_enums, testonly, library, extension, and "
+        "one_output_file_per_input_file options should only be "
         "used for import_style=closure";
     return false;
   }
@@ -3766,8 +3754,7 @@
     std::set<const Descriptor*> have_printed;
     SCCAnalyzer<DepsGenerator> analyzer;
     std::map<const void*, std::string> allowed_map;
-    if (!GenerateJspbAllowedMap(options, files, &allowed_map, &analyzer,
-                                error)) {
+    if (!GenerateJspbAllowedMap(options, files, &allowed_map, &analyzer)) {
       return false;
     }
 
diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h
index e452020..cd9631a 100644
--- a/src/google/protobuf/compiler/js/js_generator.h
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -83,7 +83,6 @@
         add_require_for_enums(false),
         testonly(false),
         library(""),
-        error_on_name_conflict(false),
         extension(".js"),
         one_output_file_per_input_file(false),
         annotate_code(false) {}
@@ -119,8 +118,6 @@
   // Create a library with name <name>_lib.js rather than a separate .js file
   // per type?
   std::string library;
-  // Error if there are two types that would generate the same output file?
-  bool error_on_name_conflict;
   // The extension to use for output file names.
   std::string extension;
   // Create a separate output file for each input file?
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index e1dacae..a8e40cd 100644
--- a/src/google/protobuf/compiler/plugin.cc
+++ b/src/google/protobuf/compiler/plugin.cc
@@ -175,6 +175,7 @@
     return 1;
   }
 
+
   std::string error_msg;
   CodeGeneratorResponse response;
 
diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h
index de581c1..7d1bf45 100644
--- a/src/google/protobuf/compiler/plugin.h
+++ b/src/google/protobuf/compiler/plugin.h
@@ -78,6 +78,7 @@
 PROTOC_EXPORT int PluginMain(int argc, char* argv[],
                              const CodeGenerator* generator);
 
+
 // Generates code using the given code generator. Returns true if the code
 // generation is successful. If the code generation fails, error_msg may be
 // populated to describe the failure cause.
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index f66f854..9f35b1c 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -89,6 +89,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::Version, major_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::Version, minor_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::Version, patch_),
@@ -102,6 +103,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, file_to_generate_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, parameter_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest, proto_file_),
@@ -115,6 +117,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, insertion_point_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File, content_),
@@ -128,6 +131,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, error_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, supported_features_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse, file_),
@@ -136,10 +140,10 @@
   ~0u,
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, 9, sizeof(PROTOBUF_NAMESPACE_ID::compiler::Version)},
-  { 13, 22, sizeof(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest)},
-  { 26, 35, sizeof(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File)},
-  { 39, 47, sizeof(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse)},
+  { 0, 10, -1, sizeof(PROTOBUF_NAMESPACE_ID::compiler::Version)},
+  { 14, 24, -1, sizeof(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest)},
+  { 28, 38, -1, sizeof(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File)},
+  { 42, 51, -1, sizeof(PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -316,7 +320,8 @@
           _Internal::set_has_major(&has_bits);
           major_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 minor = 2;
       case 2:
@@ -324,7 +329,8 @@
           _Internal::set_has_minor(&has_bits);
           minor_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 patch = 3;
       case 3:
@@ -332,7 +338,8 @@
           _Internal::set_has_patch(&has_bits);
           patch_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string suffix = 4;
       case 4:
@@ -343,29 +350,30 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.Version.suffix");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -431,33 +439,21 @@
 
     // optional int32 major = 1;
     if (cached_has_bits & 0x00000002u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_major());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_major());
     }
 
     // optional int32 minor = 2;
     if (cached_has_bits & 0x00000004u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_minor());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_minor());
     }
 
     // optional int32 patch = 3;
     if (cached_has_bits & 0x00000008u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_patch());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_patch());
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Version::_class_data_ = {
@@ -466,8 +462,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Version::GetClassData() const { return &_class_data_; }
 
-void Version::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Version::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Version *>(to)->MergeFrom(
       static_cast<const Version &>(from));
 }
@@ -511,12 +507,14 @@
 
 void Version::InternalSwap(Version* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &suffix_, GetArenaForAllocation(),
-      &other->suffix_, other->GetArenaForAllocation()
+      &suffix_, lhs_arena,
+      &other->suffix_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(Version, patch_)
@@ -654,7 +652,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string parameter = 2;
       case 2:
@@ -665,14 +664,16 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorRequest.parameter");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.compiler.Version compiler_version = 3;
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 26)) {
           ptr = ctx->ParseMessage(_internal_mutable_compiler_version(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
       case 15:
@@ -684,29 +685,30 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<122>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -801,13 +803,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData CodeGeneratorRequest::_class_data_ = {
@@ -816,8 +812,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorRequest::GetClassData() const { return &_class_data_; }
 
-void CodeGeneratorRequest::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void CodeGeneratorRequest::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<CodeGeneratorRequest *>(to)->MergeFrom(
       static_cast<const CodeGeneratorRequest &>(from));
 }
@@ -857,14 +853,16 @@
 
 void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   file_to_generate_.InternalSwap(&other->file_to_generate_);
   proto_file_.InternalSwap(&other->proto_file_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &parameter_, GetArenaForAllocation(),
-      &other->parameter_, other->GetArenaForAllocation()
+      &parameter_, lhs_arena,
+      &other->parameter_, rhs_arena
   );
   swap(compiler_version_, other->compiler_version_);
 }
@@ -1013,7 +1011,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string insertion_point = 2;
       case 2:
@@ -1024,7 +1023,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string content = 15;
       case 15:
@@ -1035,36 +1035,38 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.content");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16;
       case 16:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 130)) {
           ptr = ctx->ParseMessage(_internal_mutable_generated_code_info(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1160,13 +1162,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData CodeGeneratorResponse_File::_class_data_ = {
@@ -1175,8 +1171,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse_File::GetClassData() const { return &_class_data_; }
 
-void CodeGeneratorResponse_File::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void CodeGeneratorResponse_File::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<CodeGeneratorResponse_File *>(to)->MergeFrom(
       static_cast<const CodeGeneratorResponse_File &>(from));
 }
@@ -1219,22 +1215,24 @@
 
 void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &insertion_point_, GetArenaForAllocation(),
-      &other->insertion_point_, other->GetArenaForAllocation()
+      &insertion_point_, lhs_arena,
+      &other->insertion_point_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &content_, GetArenaForAllocation(),
-      &other->content_, other->GetArenaForAllocation()
+      &content_, lhs_arena,
+      &other->content_, rhs_arena
   );
   swap(generated_code_info_, other->generated_code_info_);
 }
@@ -1341,7 +1339,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.error");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional uint64 supported_features = 2;
       case 2:
@@ -1349,7 +1348,8 @@
           _Internal::set_has_supported_features(&has_bits);
           supported_features_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
       case 15:
@@ -1361,29 +1361,30 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<122>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1452,19 +1453,11 @@
 
     // optional uint64 supported_features = 2;
     if (cached_has_bits & 0x00000002u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64Size(
-          this->_internal_supported_features());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64SizePlusOne(this->_internal_supported_features());
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData CodeGeneratorResponse::_class_data_ = {
@@ -1473,8 +1466,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse::GetClassData() const { return &_class_data_; }
 
-void CodeGeneratorResponse::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void CodeGeneratorResponse::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<CodeGeneratorResponse *>(to)->MergeFrom(
       static_cast<const CodeGeneratorResponse &>(from));
 }
@@ -1513,13 +1506,15 @@
 
 void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   file_.InternalSwap(&other->file_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &error_, GetArenaForAllocation(),
-      &other->error_, other->GetArenaForAllocation()
+      &error_, lhs_arena,
+      &other->error_, rhs_arena
   );
   swap(supported_features_, other->supported_features_);
 }
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index e1ede97..d230cd4 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -195,7 +195,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Version& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -396,7 +396,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const CodeGeneratorRequest& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -618,7 +618,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const CodeGeneratorResponse_File& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -834,7 +834,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const CodeGeneratorResponse& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index bedb5b3..408caf8 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -35,6 +35,7 @@
 #include <google/protobuf/descriptor.h>
 
 #include <algorithm>
+#include <array>
 #include <functional>
 #include <limits>
 #include <map>
@@ -75,7 +76,8 @@
 namespace google {
 namespace protobuf {
 
-struct Symbol {
+class Symbol {
+ public:
   enum Type {
     NULL_SYMBOL,
     MESSAGE,
@@ -83,69 +85,177 @@
     ONEOF,
     ENUM,
     ENUM_VALUE,
+    ENUM_VALUE_OTHER_PARENT,
     SERVICE,
     METHOD,
-    PACKAGE
-  };
-  Type type;
-  union {
-    const Descriptor* descriptor;
-    const FieldDescriptor* field_descriptor;
-    const OneofDescriptor* oneof_descriptor;
-    const EnumDescriptor* enum_descriptor;
-    const EnumValueDescriptor* enum_value_descriptor;
-    const ServiceDescriptor* service_descriptor;
-    const MethodDescriptor* method_descriptor;
-    const FileDescriptor* package_file_descriptor;
+    PACKAGE,
+    QUERY_KEY
   };
 
-  inline Symbol() : type(NULL_SYMBOL) { descriptor = nullptr; }
-  inline bool IsNull() const { return type == NULL_SYMBOL; }
-  inline bool IsType() const { return type == MESSAGE || type == ENUM; }
-  inline bool IsAggregate() const {
-    return type == MESSAGE || type == PACKAGE || type == ENUM ||
-           type == SERVICE;
+  Symbol() : ptr_(nullptr) {}
+
+  // Every object we store derives from internal::SymbolBase, where we store the
+  // symbol type enum.
+  // Storing in the object can be done without using more space in most cases,
+  // while storing it in the Symbol type would require 8 bytes.
+#define DEFINE_MEMBERS(TYPE, TYPE_CONSTANT, FIELD)                             \
+  explicit Symbol(TYPE* value) : ptr_(value) {                                 \
+    value->symbol_type_ = TYPE_CONSTANT;                                       \
+  }                                                                            \
+  const TYPE* FIELD() const {                                                  \
+    return type() == TYPE_CONSTANT ? static_cast<const TYPE*>(ptr_) : nullptr; \
   }
 
-#define CONSTRUCTOR(TYPE, TYPE_CONSTANT, FIELD) \
-  inline explicit Symbol(const TYPE* value) {   \
-    type = TYPE_CONSTANT;                       \
-    this->FIELD = value;                        \
+  DEFINE_MEMBERS(Descriptor, MESSAGE, descriptor)
+  DEFINE_MEMBERS(FieldDescriptor, FIELD, field_descriptor)
+  DEFINE_MEMBERS(OneofDescriptor, ONEOF, oneof_descriptor)
+  DEFINE_MEMBERS(EnumDescriptor, ENUM, enum_descriptor)
+  DEFINE_MEMBERS(ServiceDescriptor, SERVICE, service_descriptor)
+  DEFINE_MEMBERS(MethodDescriptor, METHOD, method_descriptor)
+
+  // We use a special node for FileDescriptor.
+  // It is potentially added to the table with multiple different names, so we
+  // need a separate place to put the name.
+  struct Package : internal::SymbolBase {
+    const std::string* name;
+    const FileDescriptor* file;
+  };
+  DEFINE_MEMBERS(Package, PACKAGE, package_file_descriptor)
+
+  // Enum values have two different parents.
+  // We use two different identitied for the same object to determine the two
+  // different insertions in the map.
+  static Symbol EnumValue(EnumValueDescriptor* value, int n) {
+    Symbol s;
+    internal::SymbolBase* ptr;
+    if (n == 0) {
+      ptr = static_cast<internal::SymbolBaseN<0>*>(value);
+      ptr->symbol_type_ = ENUM_VALUE;
+    } else {
+      ptr = static_cast<internal::SymbolBaseN<1>*>(value);
+      ptr->symbol_type_ = ENUM_VALUE_OTHER_PARENT;
+    }
+    s.ptr_ = ptr;
+    return s;
   }
 
-  CONSTRUCTOR(Descriptor, MESSAGE, descriptor)
-  CONSTRUCTOR(FieldDescriptor, FIELD, field_descriptor)
-  CONSTRUCTOR(OneofDescriptor, ONEOF, oneof_descriptor)
-  CONSTRUCTOR(EnumDescriptor, ENUM, enum_descriptor)
-  CONSTRUCTOR(EnumValueDescriptor, ENUM_VALUE, enum_value_descriptor)
-  CONSTRUCTOR(ServiceDescriptor, SERVICE, service_descriptor)
-  CONSTRUCTOR(MethodDescriptor, METHOD, method_descriptor)
-  CONSTRUCTOR(FileDescriptor, PACKAGE, package_file_descriptor)
-#undef CONSTRUCTOR
+  const EnumValueDescriptor* enum_value_descriptor() const {
+    return type() == ENUM_VALUE
+               ? static_cast<const EnumValueDescriptor*>(
+                     static_cast<const internal::SymbolBaseN<0>*>(ptr_))
+           : type() == ENUM_VALUE_OTHER_PARENT
+               ? static_cast<const EnumValueDescriptor*>(
+                     static_cast<const internal::SymbolBaseN<1>*>(ptr_))
+               : nullptr;
+  }
+
+  // Not a real symbol.
+  // Only used for heterogeneous lookups and never actually inserted in the
+  // tables.
+  struct QueryKey : internal::SymbolBase {
+    StringPiece name;
+    const void* parent;
+  };
+  DEFINE_MEMBERS(QueryKey, QUERY_KEY, query_key);
+#undef DEFINE_MEMBERS
+
+  Type type() const {
+    return ptr_ == nullptr ? NULL_SYMBOL
+                           : static_cast<Type>(ptr_->symbol_type_);
+  }
+  bool IsNull() const { return type() == NULL_SYMBOL; }
+  bool IsType() const { return type() == MESSAGE || type() == ENUM; }
+  bool IsAggregate() const {
+    return type() == MESSAGE || type() == PACKAGE || type() == ENUM ||
+           type() == SERVICE;
+  }
 
   const FileDescriptor* GetFile() const {
-    switch (type) {
-      case NULL_SYMBOL:
-        return nullptr;
+    switch (type()) {
       case MESSAGE:
-        return descriptor->file();
+        return descriptor()->file();
       case FIELD:
-        return field_descriptor->file();
+        return field_descriptor()->file();
       case ONEOF:
-        return oneof_descriptor->containing_type()->file();
+        return oneof_descriptor()->containing_type()->file();
       case ENUM:
-        return enum_descriptor->file();
+        return enum_descriptor()->file();
       case ENUM_VALUE:
-        return enum_value_descriptor->type()->file();
+        return enum_value_descriptor()->type()->file();
       case SERVICE:
-        return service_descriptor->file();
+        return service_descriptor()->file();
       case METHOD:
-        return method_descriptor->service()->file();
+        return method_descriptor()->service()->file();
       case PACKAGE:
-        return package_file_descriptor;
+        return package_file_descriptor()->file;
+      default:
+        return nullptr;
     }
-    return nullptr;
   }
+
+  StringPiece full_name() const {
+    switch (type()) {
+      case MESSAGE:
+        return descriptor()->full_name();
+      case FIELD:
+        return field_descriptor()->full_name();
+      case ONEOF:
+        return oneof_descriptor()->full_name();
+      case ENUM:
+        return enum_descriptor()->full_name();
+      case ENUM_VALUE:
+        return enum_value_descriptor()->full_name();
+      case SERVICE:
+        return service_descriptor()->full_name();
+      case METHOD:
+        return method_descriptor()->full_name();
+      case PACKAGE:
+        return *package_file_descriptor()->name;
+      case QUERY_KEY:
+        return query_key()->name;
+      default:
+        GOOGLE_CHECK(false);
+    }
+    return "";
+  }
+
+  std::pair<const void*, StringPiece> parent_key() const {
+    const auto or_file = [&](const void* p) { return p ? p : GetFile(); };
+    switch (type()) {
+      case MESSAGE:
+        return {or_file(descriptor()->containing_type()), descriptor()->name()};
+      case FIELD: {
+        auto* field = field_descriptor();
+        return {or_file(field->is_extension() ? field->extension_scope()
+                                              : field->containing_type()),
+                field->name()};
+      }
+      case ONEOF:
+        return {oneof_descriptor()->containing_type(),
+                oneof_descriptor()->name()};
+      case ENUM:
+        return {or_file(enum_descriptor()->containing_type()),
+                enum_descriptor()->name()};
+      case ENUM_VALUE:
+        return {or_file(enum_value_descriptor()->type()->containing_type()),
+                enum_value_descriptor()->name()};
+      case ENUM_VALUE_OTHER_PARENT:
+        return {enum_value_descriptor()->type(),
+                enum_value_descriptor()->name()};
+      case SERVICE:
+        return {GetFile(), service_descriptor()->name()};
+      case METHOD:
+        return {method_descriptor()->service(), method_descriptor()->name()};
+      case QUERY_KEY:
+        return {query_key()->parent, query_key()->name};
+      default:
+        GOOGLE_CHECK(false);
+    }
+    return {};
+  }
+
+ private:
+  const internal::SymbolBase* ptr_;
 };
 
 const FieldDescriptor::CppType
@@ -435,11 +545,31 @@
 
 const Symbol kNullSymbol;
 
-typedef HASH_MAP<StringPiece, Symbol, HASH_FXN<StringPiece>>
-    SymbolsByNameMap;
+struct SymbolByFullNameHash {
+  size_t operator()(Symbol s) const {
+    return HASH_FXN<StringPiece>{}(s.full_name());
+  }
+};
+struct SymbolByFullNameEq {
+  bool operator()(Symbol a, Symbol b) const {
+    return a.full_name() == b.full_name();
+  }
+};
+using SymbolsByNameSet =
+    HASH_SET<Symbol, SymbolByFullNameHash, SymbolByFullNameEq>;
 
-typedef HASH_MAP<PointerStringPair, Symbol, PointerStringPairHash>
-    SymbolsByParentMap;
+struct SymbolByParentHash {
+  size_t operator()(Symbol s) const {
+    return PointerStringPairHash{}(s.parent_key());
+  }
+};
+struct SymbolByParentEq {
+  bool operator()(Symbol a, Symbol b) const {
+    return a.parent_key() == b.parent_key();
+  }
+};
+using SymbolsByParentSet =
+    HASH_SET<Symbol, SymbolByParentHash, SymbolByParentEq>;
 
 typedef HASH_MAP<StringPiece, const FileDescriptor*,
                  HASH_FXN<StringPiece>>
@@ -496,6 +626,403 @@
          allowed_proto3_extendees->end();
 }
 
+// This bump allocator arena is optimized for the use case of this file. It is
+// mostly optimized for memory usage, since these objects are expected to live
+// for the entirety of the program.
+//
+// Some differences from other arenas:
+//  - It has a fixed number of non-trivial types it can hold. This allows
+//    tracking the allocations with a single byte. In contrast, google::protobuf::Arena
+//    uses 16 bytes per non-trivial object created.
+//  - It has some extra metadata for rollbacks. This is necessary for
+//    implementing the API below. This metadata is flushed at the end and would
+//    not cause persistent memory usage.
+//  - It tries to squeeze every byte of out the blocks. If an allocation is too
+//    large for the current block we move the block to a secondary area where we
+//    can still use it for smaller objects. This complicates rollback logic but
+//    makes it much more memory efficient.
+//
+//  The allocation strategy is as follows:
+//   - Memory is allocated from the front, with a forced 8 byte alignment.
+//   - Metadata is allocated from the back, one byte per element.
+//   - The metadata encodes one of two things:
+//     * For types we want to track, the index into KnownTypes.
+//     * For raw memory blocks, the size of the block (in 8 byte increments
+//       to allow for a larger limit).
+//   - When the raw data is too large to represent in the metadata byte, we
+//     allocate this memory separately in the heap and store an OutOfLineAlloc
+//     object instead. These come from large array allocations and alike.
+//
+//  Blocks are kept in 3 areas:
+//   - `current_` is the one we are currently allocating from. When we need to
+//     allocate a block that doesn't fit there, we make a new block and move the
+//     old `current_` to one of the areas below.
+//   - Blocks that have no more usable space left (ie less than 9 bytes) are
+//     stored in `full_blocks_`.
+//   - Blocks that have some usable space are categorized in
+//     `small_size_blocks_` depending on how much space they have left.
+//     See `kSmallSizes` to see which sizes we track.
+//
+class TableArena {
+ public:
+  // Allocate a block on `n` bytes, with no destructor information saved.
+  void* AllocateMemory(uint32_t n) {
+    uint32_t tag = SizeToRawTag(n) + kFirstRawTag;
+    if (tag > 255) {
+      // We can't fit the size, use an OutOfLineAlloc.
+      return Create<OutOfLineAlloc>(OutOfLineAlloc{::operator new(n), n})->ptr;
+    }
+
+    return AllocRawInternal(n, static_cast<Tag>(tag));
+  }
+
+  // Allocate and construct an element of type `T` as if by
+  // `T(std::forward<Args>(args...))`.
+  // The object is registered for destruction, if its destructor is not trivial.
+  template <typename T, typename... Args>
+  T* Create(Args&&... args) {
+    static_assert(alignof(T) <= 8, "");
+    return ::new (AllocRawInternal(sizeof(T), TypeTag<T>(KnownTypes{})))
+        T(std::forward<Args>(args)...);
+  }
+
+  TableArena() {}
+
+  TableArena(const TableArena&) = delete;
+  TableArena& operator=(const TableArena&) = delete;
+
+  ~TableArena() {
+    // Uncomment this to debug usage statistics of the arena blocks.
+    // PrintUsageInfo();
+
+    for (Block* list : GetLists()) {
+      while (list != nullptr) {
+        Block* b = list;
+        list = list->next;
+        b->VisitBlock(DestroyVisitor{});
+        b->Destroy();
+      }
+    }
+  }
+
+
+  // This function exists for debugging only.
+  // It can be called from the destructor to dump some info in the tests to
+  // inspect the usage of the arena.
+  void PrintUsageInfo() const {
+    const auto print_histogram = [](Block* b, int size) {
+      std::map<uint32_t, uint32_t> unused_space_count;
+      int count = 0;
+      for (; b != nullptr; b = b->next) {
+        ++unused_space_count[b->space_left()];
+        ++count;
+      }
+      if (size > 0) {
+        fprintf(stderr, "  Blocks `At least %d`", size);
+      } else {
+        fprintf(stderr, "  Blocks `full`");
+      }
+      fprintf(stderr, ": %d blocks.\n", count);
+      for (auto p : unused_space_count) {
+        fprintf(stderr, "    space=%4u, count=%3u\n", p.first, p.second);
+      }
+    };
+
+    fprintf(stderr, "TableArena unused space histogram:\n");
+    fprintf(stderr, "  Current: %u\n",
+            current_ != nullptr ? current_->space_left() : 0);
+    print_histogram(full_blocks_, 0);
+    for (size_t i = 0; i < kSmallSizes.size(); ++i) {
+      print_histogram(small_size_blocks_[i], kSmallSizes[i]);
+    }
+  }
+
+  // Current allocation count.
+  // This can be used for checkpointing.
+  size_t num_allocations() const { return num_allocations_; }
+
+  // Rollback the latest allocations until we reach back to `checkpoint`
+  // num_allocations.
+  void RollbackTo(size_t checkpoint) {
+    while (num_allocations_ > checkpoint) {
+      GOOGLE_DCHECK(!rollback_info_.empty());
+      auto& info = rollback_info_.back();
+      Block* b = info.block;
+
+      VisitAlloc(b->data(), &b->start_offset, &b->end_offset, DestroyVisitor{},
+                 KnownTypes{});
+      if (--info.count == 0) {
+        rollback_info_.pop_back();
+      }
+      --num_allocations_;
+    }
+
+    // Reconstruct the lists and destroy empty blocks.
+    auto lists = GetLists();
+    current_ = full_blocks_ = nullptr;
+    small_size_blocks_.fill(nullptr);
+
+    for (Block* list : lists) {
+      while (list != nullptr) {
+        Block* b = list;
+        list = list->next;
+
+        if (b->start_offset == 0) {
+          // This is empty, free it.
+          b->Destroy();
+        } else {
+          RelocateToUsedList(b);
+        }
+      }
+    }
+  }
+
+  // Clear all rollback information. Reduces memory usage.
+  // Trying to rollback past num_allocations() is now impossible.
+  void ClearRollbackData() {
+    rollback_info_.clear();
+    rollback_info_.shrink_to_fit();
+  }
+
+ private:
+  static constexpr size_t RoundUp(size_t n) { return (n + 7) & ~7; }
+
+  using Tag = unsigned char;
+
+  void* AllocRawInternal(uint32_t size, Tag tag) {
+    GOOGLE_DCHECK_GT(size, 0);
+    size = RoundUp(size);
+
+    Block* to_relocate = nullptr;
+    Block* to_use;
+
+    for (size_t i = 0; i < kSmallSizes.size(); ++i) {
+      if (small_size_blocks_[i] != nullptr && size <= kSmallSizes[i]) {
+        to_use = to_relocate = PopBlock(small_size_blocks_[i]);
+        break;
+      }
+    }
+
+    if (to_relocate != nullptr) {
+      // We found one in the loop.
+    } else if (current_ != nullptr && size + 1 <= current_->space_left()) {
+      to_use = current_;
+    } else {
+      // No space left anywhere, make a new block.
+      to_relocate = current_;
+      // For now we hardcode the size to one page. Note that the maximum we can
+      // allocate in the block according to the limits of Tag is less than 2k,
+      // so this can fit anything that Tag can represent.
+      constexpr size_t kBlockSize = 4096;
+      to_use = current_ = ::new (::operator new(kBlockSize)) Block(kBlockSize);
+      GOOGLE_DCHECK_GE(current_->space_left(), size + 1);
+    }
+
+    ++num_allocations_;
+    if (!rollback_info_.empty() && rollback_info_.back().block == to_use) {
+      ++rollback_info_.back().count;
+    } else {
+      rollback_info_.push_back({to_use, 1});
+    }
+
+    void* p = to_use->Allocate(size, tag);
+    if (to_relocate != nullptr) {
+      RelocateToUsedList(to_relocate);
+    }
+    return p;
+  }
+
+  static void OperatorDelete(void* p, size_t s) {
+#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
+    ::operator delete(p, s);
+#else
+    ::operator delete(p);
+#endif
+  }
+
+  struct OutOfLineAlloc {
+    void* ptr;
+    uint32_t size;
+  };
+
+  template <typename... T>
+  struct TypeList {
+    static constexpr Tag kSize = static_cast<Tag>(sizeof...(T));
+  };
+
+  template <typename T, typename Visitor>
+  static void RunVisitor(char* p, uint16_t* start, Visitor visit) {
+    *start -= RoundUp(sizeof(T));
+    visit(reinterpret_cast<T*>(p + *start));
+  }
+
+  // Visit the allocation at the passed location.
+  // It updates start/end to be after the visited object.
+  // This allows visiting a whole block by calling the function in a loop.
+  template <typename Visitor, typename... T>
+  static void VisitAlloc(char* p, uint16_t* start, uint16_t* end, Visitor visit,
+                         TypeList<T...>) {
+    const Tag tag = static_cast<Tag>(p[*end]);
+    if (tag >= kFirstRawTag) {
+      // Raw memory. Skip it.
+      *start -= TagToSize(tag);
+    } else {
+      using F = void (*)(char*, uint16_t*, Visitor);
+      static constexpr F kFuncs[] = {&RunVisitor<T, Visitor>...};
+      kFuncs[tag](p, start, visit);
+    }
+    ++*end;
+  }
+
+  template <typename U, typename... Ts>
+  static constexpr Tag TypeTag(TypeList<U, Ts...>) {
+    return 0;
+  }
+
+  template <
+      typename U, typename T, typename... Ts,
+      typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
+  static constexpr Tag TypeTag(TypeList<T, Ts...>) {
+    return 1 + TypeTag<U>(TypeList<Ts...>{});
+  }
+
+  template <typename U>
+  static constexpr Tag TypeTag(TypeList<>) {
+    static_assert(std::is_trivially_destructible<U>::value, "");
+    return SizeToRawTag(sizeof(U));
+  }
+
+  using KnownTypes =
+      TypeList<OutOfLineAlloc, std::string,
+               // For name arrays
+               std::array<std::string, 2>, std::array<std::string, 3>,
+               std::array<std::string, 4>, std::array<std::string, 5>,
+               FileDescriptorTables, SourceCodeInfo, FileOptions,
+               MessageOptions, FieldOptions, ExtensionRangeOptions,
+               OneofOptions, EnumOptions, EnumValueOptions, ServiceOptions,
+               MethodOptions>;
+  static constexpr Tag kFirstRawTag = KnownTypes::kSize;
+
+
+  struct DestroyVisitor {
+    template <typename T>
+    void operator()(T* p) {
+      p->~T();
+    }
+    void operator()(OutOfLineAlloc* p) { OperatorDelete(p->ptr, p->size); }
+  };
+
+  static uint32_t SizeToRawTag(size_t n) { return (RoundUp(n) / 8) - 1; }
+
+  static uint32_t TagToSize(Tag tag) {
+    GOOGLE_DCHECK_GE(tag, kFirstRawTag);
+    return static_cast<uint32_t>(tag - kFirstRawTag + 1) * 8;
+  }
+
+  struct Block {
+    uint16_t start_offset;
+    uint16_t end_offset;
+    uint16_t capacity;
+    Block* next;
+
+    // `allocated_size` is the total size of the memory block allocated.
+    // The `Block` structure is constructed at the start and the rest of the
+    // memory is used as the payload of the `Block`.
+    explicit Block(uint32_t allocated_size) {
+      start_offset = 0;
+      end_offset = capacity =
+          reinterpret_cast<char*>(this) + allocated_size - data();
+      next = nullptr;
+    }
+
+    char* data() {
+      return reinterpret_cast<char*>(this) + RoundUp(sizeof(Block));
+    }
+
+    uint32_t memory_used() {
+      return data() + capacity - reinterpret_cast<char*>(this);
+    }
+    uint32_t space_left() const { return end_offset - start_offset; }
+
+    void* Allocate(uint32_t n, Tag tag) {
+      GOOGLE_DCHECK_LE(n + 1, space_left());
+      void* p = data() + start_offset;
+      start_offset += n;
+      data()[--end_offset] = tag;
+      return p;
+    }
+
+    void Destroy() { OperatorDelete(this, memory_used()); }
+
+    void PrependTo(Block*& list) {
+      next = list;
+      list = this;
+    }
+
+    template <typename Visitor>
+    void VisitBlock(Visitor visit) {
+      for (uint16_t s = start_offset, e = end_offset; s != 0;) {
+        VisitAlloc(data(), &s, &e, visit, KnownTypes{});
+      }
+    }
+  };
+
+  Block* PopBlock(Block*& list) {
+    Block* res = list;
+    list = list->next;
+    return res;
+  }
+
+  void RelocateToUsedList(Block* to_relocate) {
+    if (current_ == nullptr) {
+      current_ = to_relocate;
+      current_->next = nullptr;
+      return;
+    } else if (current_->space_left() < to_relocate->space_left()) {
+      std::swap(current_, to_relocate);
+      current_->next = nullptr;
+    }
+
+    for (int i = kSmallSizes.size(); --i >= 0;) {
+      if (to_relocate->space_left() >= 1 + kSmallSizes[i]) {
+        to_relocate->PrependTo(small_size_blocks_[i]);
+        return;
+      }
+    }
+
+    to_relocate->PrependTo(full_blocks_);
+  }
+
+  static constexpr std::array<uint8_t, 6> kSmallSizes = {
+      // Sizes for pointer arrays.
+      8, 16, 24, 32,
+      // Sizes for string arrays (for descriptor names).
+      // The most common array sizes are 2 and 3.
+      2 * sizeof(std::string), 3 * sizeof(std::string)};
+
+  // Helper function to iterate all lists.
+  std::array<Block*, 2 + kSmallSizes.size()> GetLists() const {
+    std::array<Block*, 2 + kSmallSizes.size()> res;
+    res[0] = current_;
+    res[1] = full_blocks_;
+    std::copy(small_size_blocks_.begin(), small_size_blocks_.end(), &res[2]);
+    return res;
+  }
+
+  Block* current_ = nullptr;
+  std::array<Block*, kSmallSizes.size()> small_size_blocks_{};
+  Block* full_blocks_ = nullptr;
+
+  size_t num_allocations_ = 0;
+  struct RollbackInfo {
+    Block* block;
+    size_t count;
+  };
+  std::vector<RollbackInfo> rollback_info_;
+};
+
+constexpr std::array<uint8_t, 6> TableArena::kSmallSizes;
+
 }  // anonymous namespace
 
 // ===================================================================
@@ -619,14 +1146,31 @@
 
   // Allocate a string which will be destroyed when the pool is destroyed.
   // The string is initialized to the given value for convenience.
-  std::string* AllocateString(StringPiece value);
+  const std::string* AllocateString(StringPiece value);
 
-  // Allocate empty string which will be destroyed when the pool is destroyed.
-  std::string* AllocateEmptyString();
+  // Allocates an array of strings which will be destroyed when the pool is
+  // destroyed. The array is initialized with the input values.
+  template <typename... In>
+  const std::string* AllocateStringArray(In&&... values);
 
-  // Allocate a internal::call_once which will be destroyed when the pool is
+  struct FieldNamesResult {
+    std::string* array;
+    int lowercase_index;
+    int camelcase_index;
+    int json_index;
+  };
+  // Allocate all 5 names of the field:
+  // name, full name, lowercase, camelcase and json.
+  // This function will dedup the strings when possible.
+  // The resulting array contains `name` at index 0, `full_name` at index 1 and
+  // the other 3 indices are specified in the result.
+  FieldNamesResult AllocateFieldNames(const std::string& name,
+                                      const std::string& scope,
+                                      const std::string* opt_json_name);
+
+  // Allocate a LazyInitData which will be destroyed when the pool is
   // destroyed.
-  internal::once_flag* AllocateOnceDynamic();
+  internal::LazyInitData* AllocateLazyInit();
 
   // Allocate a protocol message object.  Some older versions of GCC have
   // trouble understanding explicit template instantiations in some cases, so
@@ -641,34 +1185,22 @@
  private:
   // All other memory allocated in the pool.  Must be first as other objects can
   // point into these.
-  std::vector<std::vector<char>> allocations_;
-  std::vector<std::unique_ptr<std::string>> strings_;
-  std::vector<std::unique_ptr<Message>> messages_;
-  std::vector<std::unique_ptr<internal::once_flag>> once_dynamics_;
-  std::vector<std::unique_ptr<FileDescriptorTables>> file_tables_;
+  TableArena arena_;
 
-  SymbolsByNameMap symbols_by_name_;
+  SymbolsByNameSet symbols_by_name_;
   FilesByNameMap files_by_name_;
   ExtensionsGroupedByDescriptorMap extensions_;
 
   struct CheckPoint {
     explicit CheckPoint(const Tables* tables)
-        : strings_before_checkpoint(tables->strings_.size()),
-          messages_before_checkpoint(tables->messages_.size()),
-          once_dynamics_before_checkpoint(tables->once_dynamics_.size()),
-          file_tables_before_checkpoint(tables->file_tables_.size()),
-          allocations_before_checkpoint(tables->allocations_.size()),
+        : arena_before_checkpoint(tables->arena_.num_allocations()),
           pending_symbols_before_checkpoint(
               tables->symbols_after_checkpoint_.size()),
           pending_files_before_checkpoint(
               tables->files_after_checkpoint_.size()),
           pending_extensions_before_checkpoint(
               tables->extensions_after_checkpoint_.size()) {}
-    int strings_before_checkpoint;
-    int messages_before_checkpoint;
-    int once_dynamics_before_checkpoint;
-    int file_tables_before_checkpoint;
-    int allocations_before_checkpoint;
+    int arena_before_checkpoint;
     int pending_symbols_before_checkpoint;
     int pending_files_before_checkpoint;
     int pending_extensions_before_checkpoint;
@@ -703,13 +1235,9 @@
   // -----------------------------------------------------------------
   // Finding items.
 
-  // Find symbols.  These return a null Symbol (symbol.IsNull() is true)
-  // if not found.
+  // Returns a null Symbol (symbol.IsNull() is true) if not found.
   inline Symbol FindNestedSymbol(const void* parent,
                                  StringPiece name) const;
-  inline Symbol FindNestedSymbolOfType(const void* parent,
-                                       StringPiece name,
-                                       const Symbol::Type type) const;
 
   // These return nullptr if not found.
   inline const FieldDescriptor* FindFieldByNumber(const Descriptor* parent,
@@ -765,7 +1293,7 @@
       const FileDescriptorTables* tables);
   void FieldsByCamelcaseNamesLazyInitInternal() const;
 
-  SymbolsByParentMap symbols_by_parent_;
+  SymbolsByParentSet symbols_by_parent_;
   mutable FieldsByNameMap fields_by_lowercase_name_;
   std::unique_ptr<FieldsByNameMap> fields_by_lowercase_name_tmp_;
   mutable internal::once_flag fields_by_lowercase_name_once_;
@@ -834,6 +1362,7 @@
     symbols_after_checkpoint_.clear();
     files_after_checkpoint_.clear();
     extensions_after_checkpoint_.clear();
+    arena_.ClearRollbackData();
   }
 }
 
@@ -843,7 +1372,9 @@
 
   for (size_t i = checkpoint.pending_symbols_before_checkpoint;
        i < symbols_after_checkpoint_.size(); i++) {
-    symbols_by_name_.erase(symbols_after_checkpoint_[i]);
+    Symbol::QueryKey name;
+    name.name = symbols_after_checkpoint_[i];
+    symbols_by_name_.erase(Symbol(&name));
   }
   for (size_t i = checkpoint.pending_files_before_checkpoint;
        i < files_after_checkpoint_.size(); i++) {
@@ -860,41 +1391,26 @@
   extensions_after_checkpoint_.resize(
       checkpoint.pending_extensions_before_checkpoint);
 
-  strings_.resize(checkpoint.strings_before_checkpoint);
-  messages_.resize(checkpoint.messages_before_checkpoint);
-  once_dynamics_.resize(checkpoint.once_dynamics_before_checkpoint);
-  file_tables_.resize(checkpoint.file_tables_before_checkpoint);
-  allocations_.resize(checkpoint.allocations_before_checkpoint);
+  arena_.RollbackTo(checkpoint.arena_before_checkpoint);
   checkpoints_.pop_back();
 }
 
 // -------------------------------------------------------------------
 
 inline Symbol DescriptorPool::Tables::FindSymbol(StringPiece key) const {
-  const Symbol* result = FindOrNull(symbols_by_name_, key);
-  if (result == nullptr) {
-    return kNullSymbol;
-  } else {
-    return *result;
-  }
+  Symbol::QueryKey name;
+  name.name = key;
+  auto it = symbols_by_name_.find(Symbol(&name));
+  return it == symbols_by_name_.end() ? kNullSymbol : *it;
 }
 
 inline Symbol FileDescriptorTables::FindNestedSymbol(
     const void* parent, StringPiece name) const {
-  const Symbol* result =
-      FindOrNull(symbols_by_parent_, PointerStringPair(parent, name));
-  if (result == nullptr) {
-    return kNullSymbol;
-  } else {
-    return *result;
-  }
-}
-
-inline Symbol FileDescriptorTables::FindNestedSymbolOfType(
-    const void* parent, StringPiece name, const Symbol::Type type) const {
-  Symbol result = FindNestedSymbol(parent, name);
-  if (result.type != type) return kNullSymbol;
-  return result;
+  Symbol::QueryKey query;
+  query.name = name;
+  query.parent = parent;
+  auto it = symbols_by_parent_.find(Symbol(&query));
+  return it == symbols_by_parent_.end() ? kNullSymbol : *it;
 }
 
 Symbol DescriptorPool::Tables::FindByNameHelper(const DescriptorPool* pool,
@@ -1045,9 +1561,9 @@
     DescriptorPool::Tables* tables = const_cast<DescriptorPool::Tables*>(
         DescriptorPool::generated_pool()->tables_.get());
     EnumValueDescriptor* result = tables->Allocate<EnumValueDescriptor>();
-    result->name_ = tables->AllocateString(enum_value_name);
-    result->full_name_ =
-        tables->AllocateString(parent->full_name() + "." + enum_value_name);
+    result->all_names_ = tables->AllocateStringArray(
+        enum_value_name,
+        StrCat(parent->full_name(), ".", enum_value_name));
     result->number_ = number;
     result->type_ = parent;
     result->options_ = &EnumValueOptions::default_instance();
@@ -1076,7 +1592,8 @@
 
 bool DescriptorPool::Tables::AddSymbol(const std::string& full_name,
                                        Symbol symbol) {
-  if (InsertIfNotPresent(&symbols_by_name_, full_name, symbol)) {
+  GOOGLE_DCHECK_EQ(full_name, symbol.full_name());
+  if (symbols_by_name_.insert(symbol).second) {
     symbols_after_checkpoint_.push_back(full_name.c_str());
     return true;
   } else {
@@ -1087,8 +1604,9 @@
 bool FileDescriptorTables::AddAliasUnderParent(const void* parent,
                                                const std::string& name,
                                                Symbol symbol) {
-  PointerStringPair by_parent_key(parent, name.c_str());
-  return InsertIfNotPresent(&symbols_by_parent_, by_parent_key, symbol);
+  GOOGLE_DCHECK_EQ(name, symbol.parent_key().second);
+  GOOGLE_DCHECK_EQ(parent, symbol.parent_key().first);
+  return symbols_by_parent_.insert(symbol).second;
 }
 
 bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) {
@@ -1167,46 +1685,107 @@
   return reinterpret_cast<Type*>(AllocateBytes(sizeof(Type) * count));
 }
 
-std::string* DescriptorPool::Tables::AllocateString(StringPiece value) {
-  std::string* result = new std::string(value);
-  strings_.emplace_back(result);
+const std::string* DescriptorPool::Tables::AllocateString(
+    StringPiece value) {
+  return arena_.Create<std::string>(value);
+}
+
+template <typename... In>
+const std::string* DescriptorPool::Tables::AllocateStringArray(In&&... values) {
+  auto& array = *arena_.Create<std::array<std::string, sizeof...(In)>>();
+  array = {{std::string(std::forward<In>(values))...}};
+  return array.data();
+}
+
+DescriptorPool::Tables::FieldNamesResult
+DescriptorPool::Tables::AllocateFieldNames(const std::string& name,
+                                           const std::string& scope,
+                                           const std::string* opt_json_name) {
+  std::string lowercase_name = name;
+  LowerString(&lowercase_name);
+
+  std::string camelcase_name = ToCamelCase(name, /* lower_first = */ true);
+  std::string json_name;
+  if (opt_json_name != nullptr) {
+    json_name = *opt_json_name;
+  } else {
+    json_name = ToJsonName(name);
+  }
+
+  const bool lower_eq_name = lowercase_name == name;
+  const bool camel_eq_name = camelcase_name == name;
+  const bool json_eq_name = json_name == name;
+  const bool json_eq_camel = json_name == camelcase_name;
+
+  const int total_count = 2 + (lower_eq_name ? 0 : 1) +
+                          (camel_eq_name ? 0 : 1) +
+                          (json_eq_name || json_eq_camel ? 0 : 1);
+  FieldNamesResult result;
+  // We use std::array to allow handling of the destruction of the strings.
+  switch (total_count) {
+    case 2:
+      result.array = arena_.Create<std::array<std::string, 2>>()->data();
+      break;
+    case 3:
+      result.array = arena_.Create<std::array<std::string, 3>>()->data();
+      break;
+    case 4:
+      result.array = arena_.Create<std::array<std::string, 4>>()->data();
+      break;
+    case 5:
+      result.array = arena_.Create<std::array<std::string, 5>>()->data();
+      break;
+  }
+
+  result.array[0] = name;
+  if (scope.empty()) {
+    result.array[1] = name;
+  } else {
+    result.array[1] = StrCat(scope, ".", name);
+  }
+  int index = 2;
+  if (lower_eq_name) {
+    result.lowercase_index = 0;
+  } else {
+    result.lowercase_index = index;
+    result.array[index++] = std::move(lowercase_name);
+  }
+
+  if (camel_eq_name) {
+    result.camelcase_index = 0;
+  } else {
+    result.camelcase_index = index;
+    result.array[index++] = std::move(camelcase_name);
+  }
+
+  if (json_eq_name) {
+    result.json_index = 0;
+  } else if (json_eq_camel) {
+    result.json_index = result.camelcase_index;
+  } else {
+    result.json_index = index;
+    result.array[index] = std::move(json_name);
+  }
+
   return result;
 }
 
-std::string* DescriptorPool::Tables::AllocateEmptyString() {
-  std::string* result = new std::string();
-  strings_.emplace_back(result);
-  return result;
-}
-
-internal::once_flag* DescriptorPool::Tables::AllocateOnceDynamic() {
-  internal::once_flag* result = new internal::once_flag();
-  once_dynamics_.emplace_back(result);
-  return result;
+internal::LazyInitData* DescriptorPool::Tables::AllocateLazyInit() {
+  return arena_.Create<internal::LazyInitData>();
 }
 
 template <typename Type>
 Type* DescriptorPool::Tables::AllocateMessage(Type* /* dummy */) {
-  Type* result = new Type;
-  messages_.emplace_back(result);
-  return result;
+  return arena_.Create<Type>();
 }
 
 FileDescriptorTables* DescriptorPool::Tables::AllocateFileTables() {
-  FileDescriptorTables* result = new FileDescriptorTables;
-  file_tables_.emplace_back(result);
-  return result;
+  return arena_.Create<FileDescriptorTables>();
 }
 
 void* DescriptorPool::Tables::AllocateBytes(int size) {
-  // TODO(kenton):  Would it be worthwhile to implement this in some more
-  // sophisticated way?  Probably not for the open source release, but for
-  // internal use we could easily plug in one of our existing memory pool
-  // allocators...
   if (size == 0) return nullptr;
-
-  allocations_.emplace_back(size);
-  return allocations_.back().data();
+  return arena_.AllocateMemory(size);
 }
 
 void FileDescriptorTables::BuildLocationsByPath(
@@ -1407,60 +1986,54 @@
 
 const Descriptor* DescriptorPool::FindMessageTypeByName(
     ConstStringParam name) const {
-  Symbol result = tables_->FindByNameHelper(this, name);
-  return (result.type == Symbol::MESSAGE) ? result.descriptor : nullptr;
+  return tables_->FindByNameHelper(this, name).descriptor();
 }
 
 const FieldDescriptor* DescriptorPool::FindFieldByName(
     ConstStringParam name) const {
-  Symbol result = tables_->FindByNameHelper(this, name);
-  if (result.type == Symbol::FIELD &&
-      !result.field_descriptor->is_extension()) {
-    return result.field_descriptor;
-  } else {
-    return nullptr;
+  if (const FieldDescriptor* field =
+          tables_->FindByNameHelper(this, name).field_descriptor()) {
+    if (!field->is_extension()) {
+      return field;
+    }
   }
+  return nullptr;
 }
 
 const FieldDescriptor* DescriptorPool::FindExtensionByName(
     ConstStringParam name) const {
-  Symbol result = tables_->FindByNameHelper(this, name);
-  if (result.type == Symbol::FIELD && result.field_descriptor->is_extension()) {
-    return result.field_descriptor;
-  } else {
-    return nullptr;
+  if (const FieldDescriptor* field =
+          tables_->FindByNameHelper(this, name).field_descriptor()) {
+    if (field->is_extension()) {
+      return field;
+    }
   }
+  return nullptr;
 }
 
 const OneofDescriptor* DescriptorPool::FindOneofByName(
     ConstStringParam name) const {
-  Symbol result = tables_->FindByNameHelper(this, name);
-  return (result.type == Symbol::ONEOF) ? result.oneof_descriptor : nullptr;
+  return tables_->FindByNameHelper(this, name).oneof_descriptor();
 }
 
 const EnumDescriptor* DescriptorPool::FindEnumTypeByName(
     ConstStringParam name) const {
-  Symbol result = tables_->FindByNameHelper(this, name);
-  return (result.type == Symbol::ENUM) ? result.enum_descriptor : nullptr;
+  return tables_->FindByNameHelper(this, name).enum_descriptor();
 }
 
 const EnumValueDescriptor* DescriptorPool::FindEnumValueByName(
     ConstStringParam name) const {
-  Symbol result = tables_->FindByNameHelper(this, name);
-  return (result.type == Symbol::ENUM_VALUE) ? result.enum_value_descriptor
-                                             : nullptr;
+  return tables_->FindByNameHelper(this, name).enum_value_descriptor();
 }
 
 const ServiceDescriptor* DescriptorPool::FindServiceByName(
     ConstStringParam name) const {
-  Symbol result = tables_->FindByNameHelper(this, name);
-  return (result.type == Symbol::SERVICE) ? result.service_descriptor : nullptr;
+  return tables_->FindByNameHelper(this, name).service_descriptor();
 }
 
 const MethodDescriptor* DescriptorPool::FindMethodByName(
     ConstStringParam name) const {
-  Symbol result = tables_->FindByNameHelper(this, name);
-  return (result.type == Symbol::METHOD) ? result.method_descriptor : nullptr;
+  return tables_->FindByNameHelper(this, name).method_descriptor();
 }
 
 const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
@@ -1607,34 +2180,20 @@
 }
 
 const FieldDescriptor* Descriptor::FindFieldByName(ConstStringParam key) const {
-  Symbol result =
-      file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD);
-  if (!result.IsNull() && !result.field_descriptor->is_extension()) {
-    return result.field_descriptor;
-  } else {
-    return nullptr;
-  }
+  const FieldDescriptor* field =
+      file()->tables_->FindNestedSymbol(this, key).field_descriptor();
+  return field != nullptr && !field->is_extension() ? field : nullptr;
 }
 
 const OneofDescriptor* Descriptor::FindOneofByName(ConstStringParam key) const {
-  Symbol result =
-      file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ONEOF);
-  if (!result.IsNull()) {
-    return result.oneof_descriptor;
-  } else {
-    return nullptr;
-  }
+  return file()->tables_->FindNestedSymbol(this, key).oneof_descriptor();
 }
 
 const FieldDescriptor* Descriptor::FindExtensionByName(
     ConstStringParam key) const {
-  Symbol result =
-      file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD);
-  if (!result.IsNull() && result.field_descriptor->is_extension()) {
-    return result.field_descriptor;
-  } else {
-    return nullptr;
-  }
+  const FieldDescriptor* field =
+      file()->tables_->FindNestedSymbol(this, key).field_descriptor();
+  return field != nullptr && field->is_extension() ? field : nullptr;
 }
 
 const FieldDescriptor* Descriptor::FindExtensionByLowercaseName(
@@ -1660,35 +2219,17 @@
 }
 
 const Descriptor* Descriptor::FindNestedTypeByName(ConstStringParam key) const {
-  Symbol result =
-      file()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE);
-  if (!result.IsNull()) {
-    return result.descriptor;
-  } else {
-    return nullptr;
-  }
+  return file()->tables_->FindNestedSymbol(this, key).descriptor();
 }
 
 const EnumDescriptor* Descriptor::FindEnumTypeByName(
     ConstStringParam key) const {
-  Symbol result =
-      file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM);
-  if (!result.IsNull()) {
-    return result.enum_descriptor;
-  } else {
-    return nullptr;
-  }
+  return file()->tables_->FindNestedSymbol(this, key).enum_descriptor();
 }
 
 const EnumValueDescriptor* Descriptor::FindEnumValueByName(
     ConstStringParam key) const {
-  Symbol result =
-      file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE);
-  if (!result.IsNull()) {
-    return result.enum_value_descriptor;
-  } else {
-    return nullptr;
-  }
+  return file()->tables_->FindNestedSymbol(this, key).enum_value_descriptor();
 }
 
 const FieldDescriptor* Descriptor::map_key() const {
@@ -1705,13 +2246,7 @@
 
 const EnumValueDescriptor* EnumDescriptor::FindValueByName(
     ConstStringParam key) const {
-  Symbol result =
-      file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE);
-  if (!result.IsNull()) {
-    return result.enum_value_descriptor;
-  } else {
-    return nullptr;
-  }
+  return file()->tables_->FindNestedSymbol(this, key).enum_value_descriptor();
 }
 
 const EnumValueDescriptor* EnumDescriptor::FindValueByNumber(int key) const {
@@ -1725,64 +2260,34 @@
 
 const MethodDescriptor* ServiceDescriptor::FindMethodByName(
     ConstStringParam key) const {
-  Symbol result =
-      file()->tables_->FindNestedSymbolOfType(this, key, Symbol::METHOD);
-  if (!result.IsNull()) {
-    return result.method_descriptor;
-  } else {
-    return nullptr;
-  }
+  return file()->tables_->FindNestedSymbol(this, key).method_descriptor();
 }
 
 const Descriptor* FileDescriptor::FindMessageTypeByName(
     ConstStringParam key) const {
-  Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE);
-  if (!result.IsNull()) {
-    return result.descriptor;
-  } else {
-    return nullptr;
-  }
+  return tables_->FindNestedSymbol(this, key).descriptor();
 }
 
 const EnumDescriptor* FileDescriptor::FindEnumTypeByName(
     ConstStringParam key) const {
-  Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM);
-  if (!result.IsNull()) {
-    return result.enum_descriptor;
-  } else {
-    return nullptr;
-  }
+  return tables_->FindNestedSymbol(this, key).enum_descriptor();
 }
 
 const EnumValueDescriptor* FileDescriptor::FindEnumValueByName(
     ConstStringParam key) const {
-  Symbol result =
-      tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE);
-  if (!result.IsNull()) {
-    return result.enum_value_descriptor;
-  } else {
-    return nullptr;
-  }
+  return tables_->FindNestedSymbol(this, key).enum_value_descriptor();
 }
 
 const ServiceDescriptor* FileDescriptor::FindServiceByName(
     ConstStringParam key) const {
-  Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::SERVICE);
-  if (!result.IsNull()) {
-    return result.service_descriptor;
-  } else {
-    return nullptr;
-  }
+  return tables_->FindNestedSymbol(this, key).service_descriptor();
 }
 
 const FieldDescriptor* FileDescriptor::FindExtensionByName(
     ConstStringParam key) const {
-  Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD);
-  if (!result.IsNull() && result.field_descriptor->is_extension()) {
-    return result.field_descriptor;
-  } else {
-    return nullptr;
-  }
+  const FieldDescriptor* field =
+      tables_->FindNestedSymbol(this, key).field_descriptor();
+  return field != nullptr && field->is_extension() ? field : nullptr;
 }
 
 const FieldDescriptor* FileDescriptor::FindExtensionByLowercaseName(
@@ -1879,7 +2384,7 @@
     Symbol symbol = tables_->FindSymbol(prefix);
     // If the symbol type is anything other than PACKAGE, then its complete
     // definition is already known.
-    if (!symbol.IsNull() && symbol.type != Symbol::PACKAGE) {
+    if (!symbol.IsNull() && symbol.type() != Symbol::PACKAGE) {
       return true;
     }
   }
@@ -1968,16 +2473,16 @@
   GOOGLE_CHECK(has_default_value()) << "No default value";
   switch (cpp_type()) {
     case CPPTYPE_INT32:
-      return StrCat(default_value_int32());
+      return StrCat(default_value_int32_t());
       break;
     case CPPTYPE_INT64:
-      return StrCat(default_value_int64());
+      return StrCat(default_value_int64_t());
       break;
     case CPPTYPE_UINT32:
-      return StrCat(default_value_uint32());
+      return StrCat(default_value_uint32_t());
       break;
     case CPPTYPE_UINT64:
-      return StrCat(default_value_uint64());
+      return StrCat(default_value_uint64_t());
       break;
     case CPPTYPE_FLOAT:
       return SimpleFtoa(default_value_float());
@@ -2276,6 +2781,7 @@
       if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
         std::string tmp;
         TextFormat::Printer printer;
+        printer.SetExpandAny(true);
         printer.SetInitialIndentLevel(depth + 1);
         printer.PrintFieldValueToString(options, field, repeated ? j : -1,
                                         &tmp);
@@ -2954,7 +3460,7 @@
   if (source_code_info_) {
     if (const SourceCodeInfo_Location* loc =
             tables_->GetSourceLocation(path, source_code_info_)) {
-      const RepeatedField<int32>& span = loc->span();
+      const RepeatedField<int32_t>& span = loc->span();
       if (span.size() == 3 || span.size() == 4) {
         out_location->start_line = span.Get(0);
         out_location->start_column = span.Get(1);
@@ -3253,7 +3759,7 @@
   // package to the symbol table (e.g. AddPackage("foo.bar", ...) will add
   // "foo.bar" and "foo" to the table).
   void AddPackage(const std::string& name, const Message& proto,
-                  const FileDescriptor* file);
+                  FileDescriptor* file);
 
   // Checks that the symbol name contains only alphanumeric characters and
   // underscores.  Records an error otherwise.
@@ -3287,11 +3793,12 @@
       DescriptorT* descriptor, const std::vector<int>& options_path,
       const std::string& option_name);
 
-  // Allocate string on the string pool and initialize it to full proto name.
+  // Allocates an array of two strings, the first one is a copy of `proto_name`,
+  // and the second one is the full name.
   // Full proto name is "scope.proto_name" if scope is non-empty and
   // "proto_name" otherwise.
-  std::string* AllocateNameString(const std::string& scope,
-                                  const std::string& proto_name);
+  const std::string* AllocateNameStrings(const std::string& scope,
+                                         const std::string& proto_name);
 
   // These methods all have the same signature for the sake of the BUILD_ARRAY
   // macro, below.
@@ -3419,13 +3926,13 @@
 
     // Convenience functions to set an int field the right way, depending on
     // its wire type (a single int CppType can represent multiple wire types).
-    void SetInt32(int number, int32 value, FieldDescriptor::Type type,
+    void SetInt32(int number, int32_t value, FieldDescriptor::Type type,
                   UnknownFieldSet* unknown_fields);
-    void SetInt64(int number, int64 value, FieldDescriptor::Type type,
+    void SetInt64(int number, int64_t value, FieldDescriptor::Type type,
                   UnknownFieldSet* unknown_fields);
-    void SetUInt32(int number, uint32 value, FieldDescriptor::Type type,
+    void SetUInt32(int number, uint32_t value, FieldDescriptor::Type type,
                    UnknownFieldSet* unknown_fields);
-    void SetUInt64(int number, uint64 value, FieldDescriptor::Type type,
+    void SetUInt64(int number, uint64_t value, FieldDescriptor::Type type,
                    UnknownFieldSet* unknown_fields);
 
     // A helper function that adds an error at the specified location of the
@@ -3440,7 +3947,11 @@
     // A helper function that adds an error at the location of the option name
     // and returns false.
     bool AddNameError(const std::string& msg) {
+#ifdef PROTOBUF_INTERNAL_IGNORE_FIELD_NAME_ERRORS_
+      return true;
+#else   // PROTOBUF_INTERNAL_IGNORE_FIELD_NAME_ERRORS_
       return AddOptionError(DescriptorPool::ErrorCollector::OPTION_NAME, msg);
+#endif  // PROTOBUF_INTERNAL_IGNORE_FIELD_NAME_ERRORS_
     }
 
     // A helper function that adds an error at the location of the option name
@@ -3739,7 +4250,7 @@
     return result;
   }
 
-  if (result.type == Symbol::PACKAGE) {
+  if (result.type() == Symbol::PACKAGE) {
     // Arg, this is overcomplicated.  The symbol is a package name.  It could
     // be that the package was defined in multiple files.  result.GetFile()
     // returns the first file we saw that used this package.  We've determined
@@ -3882,24 +4393,23 @@
     mutex_->AssertHeld();
   }
   // Compute names.
-  const std::string* placeholder_full_name;
-  const std::string* placeholder_name;
+  StringPiece placeholder_full_name;
+  StringPiece placeholder_name;
   const std::string* placeholder_package;
 
   if (!ValidateQualifiedName(name)) return kNullSymbol;
   if (name[0] == '.') {
     // Fully-qualified.
-    placeholder_full_name = tables_->AllocateString(name.substr(1));
+    placeholder_full_name = name.substr(1);
   } else {
-    placeholder_full_name = tables_->AllocateString(name);
+    placeholder_full_name = name;
   }
 
-  std::string::size_type dotpos = placeholder_full_name->find_last_of('.');
+  std::string::size_type dotpos = placeholder_full_name.find_last_of('.');
   if (dotpos != std::string::npos) {
     placeholder_package =
-        tables_->AllocateString(placeholder_full_name->substr(0, dotpos));
-    placeholder_name =
-        tables_->AllocateString(placeholder_full_name->substr(dotpos + 1));
+        tables_->AllocateString(placeholder_full_name.substr(0, dotpos));
+    placeholder_name = placeholder_full_name.substr(dotpos + 1);
   } else {
     placeholder_package = &internal::GetEmptyString();
     placeholder_name = placeholder_full_name;
@@ -3907,7 +4417,7 @@
 
   // Create the placeholders.
   FileDescriptor* placeholder_file = NewPlaceholderFileWithMutexHeld(
-      *placeholder_full_name + ".placeholder.proto");
+      StrCat(placeholder_full_name, ".placeholder.proto"));
   placeholder_file->package_ = placeholder_package;
 
   if (placeholder_type == PLACEHOLDER_ENUM) {
@@ -3917,8 +4427,8 @@
     EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0];
     memset(static_cast<void*>(placeholder_enum), 0, sizeof(*placeholder_enum));
 
-    placeholder_enum->full_name_ = placeholder_full_name;
-    placeholder_enum->name_ = placeholder_name;
+    placeholder_enum->all_names_ =
+        tables_->AllocateStringArray(placeholder_name, placeholder_full_name);
     placeholder_enum->file_ = placeholder_file;
     placeholder_enum->options_ = &EnumOptions::default_instance();
     placeholder_enum->is_placeholder_ = true;
@@ -3932,13 +4442,11 @@
     memset(static_cast<void*>(placeholder_value), 0,
            sizeof(*placeholder_value));
 
-    placeholder_value->name_ = tables_->AllocateString("PLACEHOLDER_VALUE");
     // Note that enum value names are siblings of their type, not children.
-    placeholder_value->full_name_ =
-        placeholder_package->empty()
-            ? placeholder_value->name_
-            : tables_->AllocateString(*placeholder_package +
-                                      ".PLACEHOLDER_VALUE");
+    placeholder_value->all_names_ = tables_->AllocateStringArray(
+        "PLACEHOLDER_VALUE", placeholder_package->empty()
+                                 ? "PLACEHOLDER_VALUE"
+                                 : *placeholder_package + ".PLACEHOLDER_VALUE");
 
     placeholder_value->number_ = 0;
     placeholder_value->type_ = placeholder_enum;
@@ -3953,8 +4461,8 @@
     memset(static_cast<void*>(placeholder_message), 0,
            sizeof(*placeholder_message));
 
-    placeholder_message->full_name_ = placeholder_full_name;
-    placeholder_message->name_ = placeholder_name;
+    placeholder_message->all_names_ =
+        tables_->AllocateStringArray(placeholder_name, placeholder_full_name);
     placeholder_message->file_ = placeholder_file;
     placeholder_message->options_ = &MessageOptions::default_instance();
     placeholder_message->is_placeholder_ = true;
@@ -3968,6 +4476,7 @@
       // kMaxNumber + 1 because ExtensionRange::end is exclusive.
       placeholder_message->extension_ranges_->end =
           FieldDescriptor::kMaxNumber + 1;
+      placeholder_message->extension_ranges_->options_ = nullptr;
     }
 
     return Symbol(placeholder_message);
@@ -4052,37 +4561,40 @@
 }
 
 void DescriptorBuilder::AddPackage(const std::string& name,
-                                   const Message& proto,
-                                   const FileDescriptor* file) {
+                                   const Message& proto, FileDescriptor* file) {
   if (name.find('\0') != std::string::npos) {
     AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
              "\"" + name + "\" contains null character.");
     return;
   }
-  if (tables_->AddSymbol(name, Symbol(file))) {
-    // Success.  Also add parent package, if any.
+
+  Symbol existing_symbol = tables_->FindSymbol(name);
+  // It's OK to redefine a package.
+  if (existing_symbol.IsNull()) {
+    auto* package = tables_->AllocateArray<Symbol::Package>(1);
+    // If the name is the package name, then it is already in the arena.
+    // If not, copy it there. It came from the call to AddPackage below.
+    package->name =
+        &name == &file->package() ? &name : tables_->AllocateString(name);
+    package->file = file;
+    tables_->AddSymbol(*package->name, Symbol(package));
+    // Also add parent package, if any.
     std::string::size_type dot_pos = name.find_last_of('.');
     if (dot_pos == std::string::npos) {
       // No parents.
       ValidateSymbolName(name, name, proto);
     } else {
       // Has parent.
-      std::string* parent_name =
-          tables_->AllocateString(name.substr(0, dot_pos));
-      AddPackage(*parent_name, proto, file);
+      AddPackage(name.substr(0, dot_pos), proto, file);
       ValidateSymbolName(name.substr(dot_pos + 1), name, proto);
     }
-  } else {
-    Symbol existing_symbol = tables_->FindSymbol(name);
-    // It's OK to redefine a package.
-    if (existing_symbol.type != Symbol::PACKAGE) {
-      // Symbol seems to have been defined in a different file.
-      AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
-               "\"" + name +
-                   "\" is already defined (as something other than "
-                   "a package) in file \"" +
-                   existing_symbol.GetFile()->name() + "\".");
-    }
+  } else if (existing_symbol.type() != Symbol::PACKAGE) {
+    // Symbol seems to have been defined in a different file.
+    AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+             "\"" + name +
+                 "\" is already defined (as something other than "
+                 "a package) in file \"" +
+                 existing_symbol.GetFile()->name() + "\".");
   }
 }
 
@@ -4177,12 +4689,12 @@
   if (!unknown_fields.empty()) {
     // Can not use options->GetDescriptor() which may case deadlock.
     Symbol msg_symbol = tables_->FindSymbol(option_name);
-    if (msg_symbol.type == Symbol::MESSAGE) {
+    if (msg_symbol.type() == Symbol::MESSAGE) {
       for (int i = 0; i < unknown_fields.field_count(); ++i) {
         assert_mutex_held(pool_);
         const FieldDescriptor* field =
             pool_->InternalFindExtensionByNumberNoLock(
-                msg_symbol.descriptor, unknown_fields.field(i).number());
+                msg_symbol.descriptor(), unknown_fields.field(i).number());
         if (field) {
           unused_dependency_.erase(field->file());
         }
@@ -4395,18 +4907,7 @@
   result->dependency_count_ = proto.dependency_size();
   result->dependencies_ =
       tables_->AllocateArray<const FileDescriptor*>(proto.dependency_size());
-  if (pool_->lazily_build_dependencies_) {
-    result->dependencies_once_ = tables_->AllocateOnceDynamic();
-    result->dependencies_names_ =
-        tables_->AllocateArray<const std::string*>(proto.dependency_size());
-    if (proto.dependency_size() > 0) {
-      memset(result->dependencies_names_, 0,
-             sizeof(*result->dependencies_names_) * proto.dependency_size());
-    }
-  } else {
-    result->dependencies_once_ = nullptr;
-    result->dependencies_names_ = nullptr;
-  }
+  result->dependencies_once_ = nullptr;
   unused_dependency_.clear();
   std::set<int> weak_deps;
   for (int i = 0; i < proto.weak_dependency_size(); ++i) {
@@ -4452,7 +4953,17 @@
 
     result->dependencies_[i] = dependency;
     if (pool_->lazily_build_dependencies_ && !dependency) {
-      result->dependencies_names_[i] =
+      if (result->dependencies_once_ == nullptr) {
+        result->dependencies_once_ = tables_->AllocateLazyInit();
+        result->dependencies_once_->file.dependencies_names =
+            tables_->AllocateArray<const std::string*>(proto.dependency_size());
+        if (proto.dependency_size() > 0) {
+          std::fill_n(result->dependencies_once_->file.dependencies_names,
+                      proto.dependency_size(), nullptr);
+        }
+      }
+
+      result->dependencies_once_->file.dependencies_names[i] =
           tables_->AllocateString(proto.dependency(i));
     }
   }
@@ -4570,16 +5081,14 @@
 }
 
 
-std::string* DescriptorBuilder::AllocateNameString(
+const std::string* DescriptorBuilder::AllocateNameStrings(
     const std::string& scope, const std::string& proto_name) {
-  std::string* full_name;
   if (scope.empty()) {
-    full_name = tables_->AllocateString(proto_name);
+    return tables_->AllocateStringArray(proto_name, proto_name);
   } else {
-    full_name = tables_->AllocateEmptyString();
-    *full_name = StrCat(scope, ".", proto_name);
+    return tables_->AllocateStringArray(proto_name,
+                                        StrCat(scope, ".", proto_name));
   }
-  return full_name;
 }
 
 void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
@@ -4587,18 +5096,16 @@
                                      Descriptor* result) {
   const std::string& scope =
       (parent == nullptr) ? file_->package() : parent->full_name();
-  std::string* full_name = AllocateNameString(scope, proto.name());
-  ValidateSymbolName(proto.name(), *full_name, proto);
+  result->all_names_ = AllocateNameStrings(scope, proto.name());
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
 
-  result->name_ = tables_->AllocateString(proto.name());
-  result->full_name_ = full_name;
   result->file_ = file_;
   result->containing_type_ = parent;
   result->is_placeholder_ = false;
   result->is_unqualified_placeholder_ = false;
   result->well_known_type_ = Descriptor::WELLKNOWNTYPE_UNSPECIFIED;
 
-  auto it = pool_->tables_->well_known_types_.find(*full_name);
+  auto it = pool_->tables_->well_known_types_.find(result->full_name());
   if (it != pool_->tables_->well_known_types_.end()) {
     result->well_known_type_ = it->second;
   }
@@ -4726,11 +5233,19 @@
                                               bool is_extension) {
   const std::string& scope =
       (parent == nullptr) ? file_->package() : parent->full_name();
-  std::string* full_name = AllocateNameString(scope, proto.name());
-  ValidateSymbolName(proto.name(), *full_name, proto);
 
-  result->name_ = tables_->AllocateString(proto.name());
-  result->full_name_ = full_name;
+  // We allocate all names in a single array, and dedup them.
+  // We remember the indices for the potentially deduped values.
+  auto all_names = tables_->AllocateFieldNames(
+      proto.name(), scope,
+      proto.has_json_name() ? &proto.json_name() : nullptr);
+  result->all_names_ = all_names.array;
+  result->lowercase_name_index_ = all_names.lowercase_index;
+  result->camelcase_name_index_ = all_names.camelcase_index;
+  result->json_name_index_ = all_names.json_index;
+
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
   result->file_ = file_;
   result->number_ = proto.number();
   result->is_extension_ = is_extension;
@@ -4744,31 +5259,7 @@
                  result->full_name());
   }
 
-  // If .proto files follow the style guide then the name should already be
-  // lower-cased.  If that's the case we can just reuse the string we
-  // already allocated rather than allocate a new one.
-  std::string lowercase_name(proto.name());
-  LowerString(&lowercase_name);
-  if (lowercase_name == proto.name()) {
-    result->lowercase_name_ = result->name_;
-  } else {
-    result->lowercase_name_ = tables_->AllocateString(lowercase_name);
-  }
-
-  // Don't bother with the above optimization for camel-case names since
-  // .proto files that follow the guide shouldn't be using names in this
-  // format, so the optimization wouldn't help much.
-  result->camelcase_name_ =
-      tables_->AllocateString(ToCamelCase(proto.name(),
-                                          /* lower_first = */ true));
-
-  if (proto.has_json_name()) {
-    result->has_json_name_ = true;
-    result->json_name_ = tables_->AllocateString(proto.json_name());
-  } else {
-    result->has_json_name_ = false;
-    result->json_name_ = tables_->AllocateString(ToJsonName(proto.name()));
-  }
+  result->has_json_name_ = proto.has_json_name();
 
   // Some compilers do not allow static_cast directly between two enum types,
   // so we must cast to int first.
@@ -4796,10 +5287,8 @@
   result->extension_scope_ = nullptr;
   result->message_type_ = nullptr;
   result->enum_type_ = nullptr;
-  result->type_name_ = nullptr;
   result->type_once_ = nullptr;
   result->default_value_enum_ = nullptr;
-  result->default_value_enum_name_ = nullptr;
 
   result->has_default_value_ = proto.has_default_value();
   if (proto.has_default_value() && result->is_repeated()) {
@@ -4813,19 +5302,19 @@
       char* end_pos = nullptr;
       switch (result->cpp_type()) {
         case FieldDescriptor::CPPTYPE_INT32:
-          result->default_value_int32_ =
+          result->default_value_int32_t_ =
               strtol(proto.default_value().c_str(), &end_pos, 0);
           break;
         case FieldDescriptor::CPPTYPE_INT64:
-          result->default_value_int64_ =
+          result->default_value_int64_t_ =
               strto64(proto.default_value().c_str(), &end_pos, 0);
           break;
         case FieldDescriptor::CPPTYPE_UINT32:
-          result->default_value_uint32_ =
+          result->default_value_uint32_t_ =
               strtoul(proto.default_value().c_str(), &end_pos, 0);
           break;
         case FieldDescriptor::CPPTYPE_UINT64:
-          result->default_value_uint64_ =
+          result->default_value_uint64_t_ =
               strtou64(proto.default_value().c_str(), &end_pos, 0);
           break;
         case FieldDescriptor::CPPTYPE_FLOAT:
@@ -4906,16 +5395,16 @@
       // No explicit default value
       switch (result->cpp_type()) {
         case FieldDescriptor::CPPTYPE_INT32:
-          result->default_value_int32_ = 0;
+          result->default_value_int32_t_ = 0;
           break;
         case FieldDescriptor::CPPTYPE_INT64:
-          result->default_value_int64_ = 0;
+          result->default_value_int64_t_ = 0;
           break;
         case FieldDescriptor::CPPTYPE_UINT32:
-          result->default_value_uint32_ = 0;
+          result->default_value_uint32_t_ = 0;
           break;
         case FieldDescriptor::CPPTYPE_UINT64:
-          result->default_value_uint64_ = 0;
+          result->default_value_uint64_t_ = 0;
           break;
         case FieldDescriptor::CPPTYPE_FLOAT:
           result->default_value_float_ = 0.0f;
@@ -5083,12 +5572,8 @@
 void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
                                    Descriptor* parent,
                                    OneofDescriptor* result) {
-  std::string* full_name =
-      AllocateNameString(parent->full_name(), proto.name());
-  ValidateSymbolName(proto.name(), *full_name, proto);
-
-  result->name_ = tables_->AllocateString(proto.name());
-  result->full_name_ = full_name;
+  result->all_names_ = AllocateNameStrings(parent->full_name(), proto.name());
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
 
   result->containing_type_ = parent;
 
@@ -5178,11 +5663,9 @@
                                   EnumDescriptor* result) {
   const std::string& scope =
       (parent == nullptr) ? file_->package() : parent->full_name();
-  std::string* full_name = AllocateNameString(scope, proto.name());
-  ValidateSymbolName(proto.name(), *full_name, proto);
 
-  result->name_ = tables_->AllocateString(proto.name());
-  result->full_name_ = full_name;
+  result->all_names_ = AllocateNameStrings(scope, proto.name());
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
   result->file_ = file_;
   result->containing_type_ = parent;
   result->is_placeholder_ = false;
@@ -5272,20 +5755,20 @@
 void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto,
                                        const EnumDescriptor* parent,
                                        EnumValueDescriptor* result) {
-  result->name_ = tables_->AllocateString(proto.name());
+  // Note:  full_name for enum values is a sibling to the parent's name, not a
+  //   child of it.
+  std::string full_name;
+  size_t scope_len = parent->full_name().size() - parent->name().size();
+  full_name.reserve(scope_len + proto.name().size());
+  full_name.append(parent->full_name().data(), scope_len);
+  full_name.append(proto.name());
+
+  result->all_names_ =
+      tables_->AllocateStringArray(proto.name(), std::move(full_name));
   result->number_ = proto.number();
   result->type_ = parent;
 
-  // Note:  full_name for enum values is a sibling to the parent's name, not a
-  //   child of it.
-  std::string* full_name = tables_->AllocateEmptyString();
-  size_t scope_len = parent->full_name_->size() - parent->name_->size();
-  full_name->reserve(scope_len + result->name_->size());
-  full_name->append(parent->full_name_->data(), scope_len);
-  full_name->append(*result->name_);
-  result->full_name_ = full_name;
-
-  ValidateSymbolName(proto.name(), *full_name, proto);
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
 
   // Copy options.
   result->options_ = nullptr;  // Set to default_instance later if necessary.
@@ -5300,14 +5783,14 @@
   // parent->containing_type() as the value's parent.
   bool added_to_outer_scope =
       AddSymbol(result->full_name(), parent->containing_type(), result->name(),
-                proto, Symbol(result));
+                proto, Symbol::EnumValue(result, 0));
 
   // However, we also want to be able to search for values within a single
   // enum type, so we add it as a child of the enum type itself, too.
   // Note:  This could fail, but if it does, the error has already been
   //   reported by the above AddSymbol() call, so we ignore the return code.
-  bool added_to_inner_scope =
-      file_tables_->AddAliasUnderParent(parent, result->name(), Symbol(result));
+  bool added_to_inner_scope = file_tables_->AddAliasUnderParent(
+      parent, result->name(), Symbol::EnumValue(result, 1));
 
   if (added_to_inner_scope && !added_to_outer_scope) {
     // This value did not conflict with any values defined in the same enum,
@@ -5343,12 +5826,9 @@
 void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto,
                                      const void* /* dummy */,
                                      ServiceDescriptor* result) {
-  std::string* full_name = AllocateNameString(file_->package(), proto.name());
-  ValidateSymbolName(proto.name(), *full_name, proto);
-
-  result->name_ = tables_->AllocateString(proto.name());
-  result->full_name_ = full_name;
+  result->all_names_ = AllocateNameStrings(file_->package(), proto.name());
   result->file_ = file_;
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
 
   BUILD_ARRAY(proto, result, method, BuildMethod, result);
 
@@ -5367,14 +5847,10 @@
 void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto,
                                     const ServiceDescriptor* parent,
                                     MethodDescriptor* result) {
-  result->name_ = tables_->AllocateString(proto.name());
   result->service_ = parent;
+  result->all_names_ = AllocateNameStrings(parent->full_name(), proto.name());
 
-  std::string* full_name =
-      AllocateNameString(parent->full_name(), *result->name_);
-  result->full_name_ = full_name;
-
-  ValidateSymbolName(proto.name(), *full_name, proto);
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
 
   // These will be filled in when cross-linking.
   result->input_type_.Init();
@@ -5570,13 +6046,13 @@
                          DescriptorPool::ErrorCollector::EXTENDEE,
                          proto.extendee());
       return;
-    } else if (extendee.type != Symbol::MESSAGE) {
+    } else if (extendee.type() != Symbol::MESSAGE) {
       AddError(field->full_name(), proto,
                DescriptorPool::ErrorCollector::EXTENDEE,
                "\"" + proto.extendee() + "\" is not a message type.");
       return;
     }
-    field->containing_type_ = extendee.descriptor;
+    field->containing_type_ = extendee.descriptor();
 
     const Descriptor::ExtensionRange* extension_range =
         field->containing_type()->FindExtensionRangeContainingNumber(
@@ -5637,10 +6113,10 @@
         // Save the symbol names for later for lookup, and allocate the once
         // object needed for the accessors.
         std::string name = proto.type_name();
-        field->type_once_ = tables_->AllocateOnceDynamic();
-        field->type_name_ = tables_->AllocateString(name);
+        field->type_once_ = tables_->AllocateLazyInit();
+        field->type_once_->field.type_name = tables_->AllocateString(name);
         if (proto.has_default_value()) {
-          field->default_value_enum_name_ =
+          field->type_once_->field.default_value_enum_name =
               tables_->AllocateString(proto.default_value());
         }
         // AddFieldByNumber and AddExtension are done later in this function,
@@ -5670,9 +6146,9 @@
 
     if (!proto.has_type()) {
       // Choose field type based on symbol.
-      if (type.type == Symbol::MESSAGE) {
+      if (type.type() == Symbol::MESSAGE) {
         field->type_ = FieldDescriptor::TYPE_MESSAGE;
-      } else if (type.type == Symbol::ENUM) {
+      } else if (type.type() == Symbol::ENUM) {
         field->type_ = FieldDescriptor::TYPE_ENUM;
       } else {
         AddError(field->full_name(), proto,
@@ -5683,13 +6159,13 @@
     }
 
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      if (type.type != Symbol::MESSAGE) {
+      field->message_type_ = type.descriptor();
+      if (field->message_type_ == nullptr) {
         AddError(field->full_name(), proto,
                  DescriptorPool::ErrorCollector::TYPE,
                  "\"" + proto.type_name() + "\" is not a message type.");
         return;
       }
-      field->message_type_ = type.descriptor;
 
       if (field->has_default_value()) {
         AddError(field->full_name(), proto,
@@ -5697,13 +6173,13 @@
                  "Messages can't have default values.");
       }
     } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
-      if (type.type != Symbol::ENUM) {
+      field->enum_type_ = type.enum_descriptor();
+      if (field->enum_type_ == nullptr) {
         AddError(field->full_name(), proto,
                  DescriptorPool::ErrorCollector::TYPE,
                  "\"" + proto.type_name() + "\" is not an enum type.");
         return;
       }
-      field->enum_type_ = type.enum_descriptor;
 
       if (field->enum_type()->is_placeholder_) {
         // We can't look up default values for placeholder types.  We'll have
@@ -5725,13 +6201,14 @@
           // We can't just use field->enum_type()->FindValueByName() here
           // because that locks the pool's mutex, which we have already locked
           // at this point.
-          Symbol default_value = LookupSymbolNoPlaceholder(
-              proto.default_value(), field->enum_type()->full_name());
+          const EnumValueDescriptor* default_value =
+              LookupSymbolNoPlaceholder(proto.default_value(),
+                                        field->enum_type()->full_name())
+                  .enum_value_descriptor();
 
-          if (default_value.type == Symbol::ENUM_VALUE &&
-              default_value.enum_value_descriptor->type() ==
-                  field->enum_type()) {
-            field->default_value_enum_ = default_value.enum_value_descriptor;
+          if (default_value != nullptr &&
+              default_value->type() == field->enum_type()) {
+            field->default_value_enum_ = default_value;
           } else {
             AddError(field->full_name(), proto,
                      DescriptorPool::ErrorCollector::DEFAULT_VALUE,
@@ -5859,12 +6336,12 @@
     } else {
       method->input_type_.SetLazy(proto.input_type(), file_);
     }
-  } else if (input_type.type != Symbol::MESSAGE) {
+  } else if (input_type.type() != Symbol::MESSAGE) {
     AddError(method->full_name(), proto,
              DescriptorPool::ErrorCollector::INPUT_TYPE,
              "\"" + proto.input_type() + "\" is not a message type.");
   } else {
-    method->input_type_.Set(input_type.descriptor);
+    method->input_type_.Set(input_type.descriptor());
   }
 
   Symbol output_type =
@@ -5879,12 +6356,12 @@
     } else {
       method->output_type_.SetLazy(proto.output_type(), file_);
     }
-  } else if (output_type.type != Symbol::MESSAGE) {
+  } else if (output_type.type() != Symbol::MESSAGE) {
     AddError(method->full_name(), proto,
              DescriptorPool::ErrorCollector::OUTPUT_TYPE,
              "\"" + proto.output_type() + "\" is not a message type.");
   } else {
-    method->output_type_.Set(output_type.descriptor);
+    method->output_type_.Set(output_type.descriptor());
   }
 }
 
@@ -6056,10 +6533,10 @@
   VALIDATE_OPTIONS_FROM_ARRAY(message, enum_type, Enum);
   VALIDATE_OPTIONS_FROM_ARRAY(message, extension, Field);
 
-  const int64 max_extension_range =
-      static_cast<int64>(message->options().message_set_wire_format()
-                             ? kint32max
-                             : FieldDescriptor::kMaxNumber);
+  const int64_t max_extension_range =
+      static_cast<int64_t>(message->options().message_set_wire_format()
+                               ? kint32max
+                               : FieldDescriptor::kMaxNumber);
   for (int i = 0; i < message->extension_range_count(); ++i) {
     if (message->extension_range(i)->end > max_extension_range + 1) {
       AddError(message->full_name(), proto.extension_range(i),
@@ -6497,9 +6974,8 @@
   // the file that defines the option, not descriptor.proto itself.
   Symbol symbol = builder_->FindSymbolNotEnforcingDeps(
       options->GetDescriptor()->full_name());
-  if (!symbol.IsNull() && symbol.type == Symbol::MESSAGE) {
-    options_descriptor = symbol.descriptor;
-  } else {
+  options_descriptor = symbol.descriptor();
+  if (options_descriptor == nullptr) {
     // The options message's descriptor was not in the builder's pool, so use
     // the standard version from the generated pool. We're not holding the
     // generated pool's mutex, so we can search it the straightforward way.
@@ -6535,9 +7011,7 @@
       // mutex, and the latter method locks it again.
       symbol =
           builder_->LookupSymbol(name_part, options_to_interpret_->name_scope);
-      if (!symbol.IsNull() && symbol.type == Symbol::FIELD) {
-        field = symbol.field_descriptor;
-      }
+      field = symbol.field_descriptor();
       // If we don't find the field then the field's descriptor was not in the
       // builder's pool, but there's no point in looking in the generated
       // pool. We require that you import the file that defines any extensions
@@ -6708,7 +7182,7 @@
     if (matched) {
       // see if this location is in the range to remove
       bool loc_matches = true;
-      if (loc->path_size() < static_cast<int64>(pathv.size())) {
+      if (loc->path_size() < static_cast<int64_t>(pathv.size())) {
         loc_matches = false;
       } else {
         for (size_t j = 0; j < pathv.size(); j++) {
@@ -6851,7 +7325,7 @@
     case FieldDescriptor::CPPTYPE_INT32:
       if (uninterpreted_option_->has_positive_int_value()) {
         if (uninterpreted_option_->positive_int_value() >
-            static_cast<uint64>(kint32max)) {
+            static_cast<uint64_t>(kint32max)) {
           return AddValueError("Value out of range for int32 option \"" +
                                option_field->full_name() + "\".");
         } else {
@@ -6861,7 +7335,7 @@
         }
       } else if (uninterpreted_option_->has_negative_int_value()) {
         if (uninterpreted_option_->negative_int_value() <
-            static_cast<int64>(kint32min)) {
+            static_cast<int64_t>(kint32min)) {
           return AddValueError("Value out of range for int32 option \"" +
                                option_field->full_name() + "\".");
         } else {
@@ -6878,7 +7352,7 @@
     case FieldDescriptor::CPPTYPE_INT64:
       if (uninterpreted_option_->has_positive_int_value()) {
         if (uninterpreted_option_->positive_int_value() >
-            static_cast<uint64>(kint64max)) {
+            static_cast<uint64_t>(kint64max)) {
           return AddValueError("Value out of range for int64 option \"" +
                                option_field->full_name() + "\".");
         } else {
@@ -6962,7 +7436,7 @@
     }
 
     case FieldDescriptor::CPPTYPE_BOOL:
-      uint64 value;
+      uint64_t value;
       if (!uninterpreted_option_->has_identifier_value()) {
         return AddValueError(
             "Value must be identifier for boolean option "
@@ -7007,15 +7481,15 @@
         // the pool's mutex, and the latter method locks it again.
         Symbol symbol =
             builder_->FindSymbolNotEnforcingDeps(fully_qualified_name);
-        if (!symbol.IsNull() && symbol.type == Symbol::ENUM_VALUE) {
-          if (symbol.enum_value_descriptor->type() != enum_type) {
+        if (auto* candicate_descriptor = symbol.enum_value_descriptor()) {
+          if (candicate_descriptor->type() != enum_type) {
             return AddValueError(
                 "Enum type \"" + enum_type->full_name() +
                 "\" has no value named \"" + value_name + "\" for option \"" +
                 option_field->full_name() +
                 "\". This appears to be a value from a sibling type.");
           } else {
-            enum_value = symbol.enum_value_descriptor;
+            enum_value = candicate_descriptor;
           }
         }
       } else {
@@ -7032,11 +7506,11 @@
                              "option \"" +
                              option_field->full_name() + "\".");
       } else {
-        // Sign-extension is not a problem, since we cast directly from int32 to
-        // uint64, without first going through uint32.
+        // Sign-extension is not a problem, since we cast directly from int32_t
+        // to uint64_t, without first going through uint32_t.
         unknown_fields->AddVarint(
             option_field->number(),
-            static_cast<uint64>(static_cast<int64>(enum_value->number())));
+            static_cast<uint64_t>(static_cast<int64_t>(enum_value->number())));
       }
       break;
     }
@@ -7076,8 +7550,7 @@
       return nullptr;
     }
     assert_mutex_held(builder_->pool_);
-    Symbol result = builder_->FindSymbol(name);
-    return result.type == Symbol::MESSAGE ? result.descriptor : nullptr;
+    return builder_->FindSymbol(name).descriptor();
   }
 
   const FieldDescriptor* FindExtension(Message* message,
@@ -7086,12 +7559,11 @@
     const Descriptor* descriptor = message->GetDescriptor();
     Symbol result =
         builder_->LookupSymbolNoPlaceholder(name, descriptor->full_name());
-    if (result.type == Symbol::FIELD &&
-        result.field_descriptor->is_extension()) {
-      return result.field_descriptor;
-    } else if (result.type == Symbol::MESSAGE &&
+    if (auto* field = result.field_descriptor()) {
+      return field;
+    } else if (result.type() == Symbol::MESSAGE &&
                descriptor->options().message_set_wire_format()) {
-      const Descriptor* foreign_type = result.descriptor;
+      const Descriptor* foreign_type = result.descriptor();
       // The text format allows MessageSet items to be specified using
       // the type name, rather than the extension identifier. If the symbol
       // lookup returned a Message, and the enclosing Message has
@@ -7180,16 +7652,16 @@
 }
 
 void DescriptorBuilder::OptionInterpreter::SetInt32(
-    int number, int32 value, FieldDescriptor::Type type,
+    int number, int32_t value, FieldDescriptor::Type type,
     UnknownFieldSet* unknown_fields) {
   switch (type) {
     case FieldDescriptor::TYPE_INT32:
-      unknown_fields->AddVarint(number,
-                                static_cast<uint64>(static_cast<int64>(value)));
+      unknown_fields->AddVarint(
+          number, static_cast<uint64_t>(static_cast<int64_t>(value)));
       break;
 
     case FieldDescriptor::TYPE_SFIXED32:
-      unknown_fields->AddFixed32(number, static_cast<uint32>(value));
+      unknown_fields->AddFixed32(number, static_cast<uint32_t>(value));
       break;
 
     case FieldDescriptor::TYPE_SINT32:
@@ -7204,15 +7676,15 @@
 }
 
 void DescriptorBuilder::OptionInterpreter::SetInt64(
-    int number, int64 value, FieldDescriptor::Type type,
+    int number, int64_t value, FieldDescriptor::Type type,
     UnknownFieldSet* unknown_fields) {
   switch (type) {
     case FieldDescriptor::TYPE_INT64:
-      unknown_fields->AddVarint(number, static_cast<uint64>(value));
+      unknown_fields->AddVarint(number, static_cast<uint64_t>(value));
       break;
 
     case FieldDescriptor::TYPE_SFIXED64:
-      unknown_fields->AddFixed64(number, static_cast<uint64>(value));
+      unknown_fields->AddFixed64(number, static_cast<uint64_t>(value));
       break;
 
     case FieldDescriptor::TYPE_SINT64:
@@ -7227,15 +7699,15 @@
 }
 
 void DescriptorBuilder::OptionInterpreter::SetUInt32(
-    int number, uint32 value, FieldDescriptor::Type type,
+    int number, uint32_t value, FieldDescriptor::Type type,
     UnknownFieldSet* unknown_fields) {
   switch (type) {
     case FieldDescriptor::TYPE_UINT32:
-      unknown_fields->AddVarint(number, static_cast<uint64>(value));
+      unknown_fields->AddVarint(number, static_cast<uint64_t>(value));
       break;
 
     case FieldDescriptor::TYPE_FIXED32:
-      unknown_fields->AddFixed32(number, static_cast<uint32>(value));
+      unknown_fields->AddFixed32(number, static_cast<uint32_t>(value));
       break;
 
     default:
@@ -7245,7 +7717,7 @@
 }
 
 void DescriptorBuilder::OptionInterpreter::SetUInt64(
-    int number, uint64 value, FieldDescriptor::Type type,
+    int number, uint64_t value, FieldDescriptor::Type type,
     UnknownFieldSet* unknown_fields) {
   switch (type) {
     case FieldDescriptor::TYPE_UINT64:
@@ -7300,33 +7772,32 @@
 // enum_type_, message_type_, and default_value_enum_ appropriately.
 void FieldDescriptor::InternalTypeOnceInit() const {
   GOOGLE_CHECK(file()->finished_building_ == true);
-  if (type_name_) {
+  if (type_once_->field.type_name) {
     Symbol result = file()->pool()->CrossLinkOnDemandHelper(
-        *type_name_, type_ == FieldDescriptor::TYPE_ENUM);
-    if (result.type == Symbol::MESSAGE) {
+        *type_once_->field.type_name, type_ == FieldDescriptor::TYPE_ENUM);
+    if (result.type() == Symbol::MESSAGE) {
       type_ = FieldDescriptor::TYPE_MESSAGE;
-      message_type_ = result.descriptor;
-    } else if (result.type == Symbol::ENUM) {
+      message_type_ = result.descriptor();
+    } else if (result.type() == Symbol::ENUM) {
       type_ = FieldDescriptor::TYPE_ENUM;
-      enum_type_ = result.enum_descriptor;
+      enum_type_ = result.enum_descriptor();
     }
   }
   if (enum_type_ && !default_value_enum_) {
-    if (default_value_enum_name_) {
+    if (type_once_->field.default_value_enum_name) {
       // Have to build the full name now instead of at CrossLink time,
       // because enum_type_ may not be known at the time.
       std::string name = enum_type_->full_name();
       // Enum values reside in the same scope as the enum type.
       std::string::size_type last_dot = name.find_last_of('.');
       if (last_dot != std::string::npos) {
-        name = name.substr(0, last_dot) + "." + *default_value_enum_name_;
+        name = name.substr(0, last_dot) + "." +
+               *type_once_->field.default_value_enum_name;
       } else {
-        name = *default_value_enum_name_;
+        name = *type_once_->field.default_value_enum_name;
       }
       Symbol result = file()->pool()->CrossLinkOnDemandHelper(name, true);
-      if (result.type == Symbol::ENUM_VALUE) {
-        default_value_enum_ = result.enum_value_descriptor;
-      }
+      default_value_enum_ = result.enum_value_descriptor();
     }
     if (!default_value_enum_) {
       // We use the first defined value as the default
@@ -7346,21 +7817,21 @@
 // import building and cross linking of a field of a message.
 const Descriptor* FieldDescriptor::message_type() const {
   if (type_once_) {
-    internal::call_once(*type_once_, FieldDescriptor::TypeOnceInit, this);
+    internal::call_once(type_once_->once, FieldDescriptor::TypeOnceInit, this);
   }
   return message_type_;
 }
 
 const EnumDescriptor* FieldDescriptor::enum_type() const {
   if (type_once_) {
-    internal::call_once(*type_once_, FieldDescriptor::TypeOnceInit, this);
+    internal::call_once(type_once_->once, FieldDescriptor::TypeOnceInit, this);
   }
   return enum_type_;
 }
 
 const EnumValueDescriptor* FieldDescriptor::default_value_enum() const {
   if (type_once_) {
-    internal::call_once(*type_once_, FieldDescriptor::TypeOnceInit, this);
+    internal::call_once(type_once_->once, FieldDescriptor::TypeOnceInit, this);
   }
   return default_value_enum_;
 }
@@ -7376,9 +7847,10 @@
 
 void FileDescriptor::InternalDependenciesOnceInit() const {
   GOOGLE_CHECK(finished_building_ == true);
+  auto* names = dependencies_once_->file.dependencies_names;
   for (int i = 0; i < dependency_count(); i++) {
-    if (dependencies_names_[i]) {
-      dependencies_[i] = pool_->FindFileByName(*dependencies_names_[i]);
+    if (names[i]) {
+      dependencies_[i] = pool_->FindFileByName(*names[i]);
     }
   }
 }
@@ -7391,7 +7863,7 @@
   if (dependencies_once_) {
     // Do once init for all indices, as it's unlikely only a single index would
     // be called, and saves on internal::call_once allocations.
-    internal::call_once(*dependencies_once_,
+    internal::call_once(dependencies_once_->once,
                         FileDescriptor::DependenciesOnceInit, this);
   }
   return dependencies_[index];
@@ -7408,9 +7880,7 @@
 
 namespace internal {
 void LazyDescriptor::Set(const Descriptor* descriptor) {
-  GOOGLE_CHECK(!name_);
   GOOGLE_CHECK(!once_);
-  GOOGLE_CHECK(!file_);
   descriptor_ = descriptor;
 }
 
@@ -7418,31 +7888,32 @@
                              const FileDescriptor* file) {
   // verify Init() has been called and Set hasn't been called yet.
   GOOGLE_CHECK(!descriptor_);
-  GOOGLE_CHECK(!file_);
-  GOOGLE_CHECK(!name_);
   GOOGLE_CHECK(!once_);
   GOOGLE_CHECK(file && file->pool_);
   GOOGLE_CHECK(file->pool_->lazily_build_dependencies_);
   GOOGLE_CHECK(!file->finished_building_);
-  file_ = file;
-  name_ = file->pool_->tables_->AllocateString(name);
-  once_ = file->pool_->tables_->AllocateOnceDynamic();
+  once_ = file->pool_->tables_->AllocateLazyInit();
+  once_->descriptor.file = file;
+  once_->descriptor.name = file->pool_->tables_->AllocateString(name);
 }
 
 void LazyDescriptor::Once() {
   if (once_) {
-    internal::call_once(*once_, LazyDescriptor::OnceStatic, this);
+    internal::call_once(once_->once, LazyDescriptor::OnceStatic, this);
   }
 }
 
 void LazyDescriptor::OnceStatic(LazyDescriptor* lazy) { lazy->OnceInternal(); }
 
 void LazyDescriptor::OnceInternal() {
-  GOOGLE_CHECK(file_->finished_building_);
-  if (!descriptor_ && name_) {
-    Symbol result = file_->pool_->CrossLinkOnDemandHelper(*name_, false);
-    if (!result.IsNull() && result.type == Symbol::MESSAGE) {
-      descriptor_ = result.descriptor;
+  auto* file = once_->descriptor.file;
+  auto* name = once_->descriptor.name;
+  GOOGLE_CHECK(file->finished_building_);
+  if (!descriptor_ && name) {
+    auto* descriptor =
+        file->pool_->CrossLinkOnDemandHelper(*name, false).descriptor();
+    if (descriptor != nullptr) {
+      descriptor_ = descriptor;
     }
   }
 }
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index 0625b50..d2bf86e 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -121,7 +121,7 @@
 // Defined in descriptor.cc
 class DescriptorBuilder;
 class FileDescriptorTables;
-struct Symbol;
+class Symbol;
 
 // Defined in unknown_field_set.h.
 class UnknownField;
@@ -182,15 +182,37 @@
 // which is needed when a pool has lazily_build_dependencies_ set.
 // Must be instantiated as mutable in a descriptor.
 namespace internal {
+
+// Data required to do lazy initialization.
+struct PROTOBUF_EXPORT LazyInitData {
+#ifndef SWIG
+  internal::once_flag once;
+#endif
+  struct Field {
+    const std::string* type_name;
+    const std::string* default_value_enum_name;
+  };
+  struct Descriptor {
+    const std::string* name;
+    const FileDescriptor* file;
+  };
+  struct File {
+    const std::string** dependencies_names;
+  };
+  union {
+    Field field;
+    Descriptor descriptor;
+    File file;
+  };
+};
+
 class PROTOBUF_EXPORT LazyDescriptor {
  public:
   // Init function to be called at init time of a descriptor containing
   // a LazyDescriptor.
   void Init() {
     descriptor_ = nullptr;
-    name_ = nullptr;
     once_ = nullptr;
-    file_ = nullptr;
   }
 
   // Sets the value of the descriptor if it is known during the descriptor
@@ -220,10 +242,22 @@
   void Once();
 
   const Descriptor* descriptor_;
-  const std::string* name_;
-  internal::once_flag* once_;
-  const FileDescriptor* file_;
+  LazyInitData* once_;
 };
+
+class PROTOBUF_EXPORT SymbolBase {
+ private:
+  friend class google::protobuf::Symbol;
+  uint8_t symbol_type_;
+};
+
+// Some types have more than one SymbolBase because they have multiple
+// identities in the table. We can't have duplicate direct bases, so we use this
+// intermediate base to do so.
+// See BuildEnumValue for details.
+template <int N>
+class PROTOBUF_EXPORT SymbolBaseN : public SymbolBase {};
+
 }  // namespace internal
 
 // Describes a type of protocol message, or a particular group within a
@@ -231,7 +265,7 @@
 // Message::GetDescriptor().  Generated message classes also have a
 // static method called descriptor() which returns the type's descriptor.
 // Use DescriptorPool to construct your own descriptors.
-class PROTOBUF_EXPORT Descriptor {
+class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
  public:
   typedef DescriptorProto Proto;
 
@@ -500,6 +534,7 @@
   const FieldDescriptor* map_value() const;
 
  private:
+  friend class Symbol;
   typedef MessageOptions OptionsType;
 
   // Allows tests to test CopyTo(proto, true).
@@ -524,8 +559,16 @@
   // to this descriptor from the file root.
   void GetLocationPath(std::vector<int>* output) const;
 
-  const std::string* name_;
-  const std::string* full_name_;
+  // True if this is a placeholder for an unknown type.
+  bool is_placeholder_ : 1;
+  // True if this is a placeholder and the type name wasn't fully-qualified.
+  bool is_unqualified_placeholder_ : 1;
+  // Well known type.  Stored as char to conserve space.
+  char well_known_type_;
+  int field_count_;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
   const FileDescriptor* file_;
   const Descriptor* containing_type_;
   const MessageOptions* options_;
@@ -540,7 +583,6 @@
   ReservedRange* reserved_ranges_;
   const std::string** reserved_names_;
 
-  int field_count_;
   int oneof_decl_count_;
   int real_oneof_decl_count_;
   int nested_type_count_;
@@ -550,13 +592,6 @@
   int reserved_range_count_;
   int reserved_name_count_;
 
-  // True if this is a placeholder for an unknown type.
-  bool is_placeholder_;
-  // True if this is a placeholder and the type name wasn't fully-qualified.
-  bool is_unqualified_placeholder_;
-  // Well known type.  Stored as char to conserve space.
-  char well_known_type_;
-
   // IMPORTANT:  If you add a new field, make sure to search for all instances
   // of Allocate<Descriptor>() and AllocateArray<Descriptor>() in descriptor.cc
   // and update them to initialize the field.
@@ -584,7 +619,7 @@
 // - Given a DescriptorPool, call DescriptorPool::FindExtensionByNumber() or
 //   DescriptorPool::FindExtensionByPrintableName().
 // Use DescriptorPool to construct your own descriptors.
-class PROTOBUF_EXPORT FieldDescriptor {
+class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase {
  public:
   typedef FieldDescriptorProto Proto;
 
@@ -727,16 +762,20 @@
 
   // Get the field default value if cpp_type() == CPPTYPE_INT32.  If no
   // explicit default was defined, the default is 0.
-  int32 default_value_int32() const;
+  int32_t default_value_int32_t() const;
+  int32_t default_value_int32() const { return default_value_int32_t(); }
   // Get the field default value if cpp_type() == CPPTYPE_INT64.  If no
   // explicit default was defined, the default is 0.
-  int64 default_value_int64() const;
+  int64_t default_value_int64_t() const;
+  int64_t default_value_int64() const { return default_value_int64_t(); }
   // Get the field default value if cpp_type() == CPPTYPE_UINT32.  If no
   // explicit default was defined, the default is 0.
-  uint32 default_value_uint32() const;
+  uint32_t default_value_uint32_t() const;
+  uint32_t default_value_uint32() const { return default_value_uint32_t(); }
   // Get the field default value if cpp_type() == CPPTYPE_UINT64.  If no
   // explicit default was defined, the default is 0.
-  uint64 default_value_uint64() const;
+  uint64_t default_value_uint64_t() const;
+  uint64_t default_value_uint64() const { return default_value_uint64_t(); }
   // Get the field default value if cpp_type() == CPPTYPE_FLOAT.  If no
   // explicit default was defined, the default is 0.0.
   float default_value_float() const;
@@ -835,6 +874,7 @@
   bool GetSourceLocation(SourceLocation* out_location) const;
 
  private:
+  friend class Symbol;
   typedef FieldOptions OptionsType;
 
   // Allows access to GetLocationPath for annotations.
@@ -864,25 +904,34 @@
   // Returns true if this is a map message type.
   bool is_map_message_type() const;
 
-  const std::string* name_;
-  const std::string* full_name_;
-  const std::string* lowercase_name_;
-  const std::string* camelcase_name_;
-  // If has_json_name_ is true, it's the value specified by the user.
-  // Otherwise, it has the same value as camelcase_name_.
-  const std::string* json_name_;
-  const FileDescriptor* file_;
-  internal::once_flag* type_once_;
-  static void TypeOnceInit(const FieldDescriptor* to_init);
-  void InternalTypeOnceInit() const;
-  mutable Type type_;
-  Label label_;
   bool has_default_value_;
   bool proto3_optional_;
   // Whether the user has specified the json_name field option in the .proto
   // file.
   bool has_json_name_;
   bool is_extension_;
+
+  // Actually a `Type`, but stored as uint8_t to save space.
+  mutable uint8_t type_;
+  // Actually a `Label` but stored as uint8_t to save space.
+  uint8_t label_;
+
+  // Logically:
+  //   all_names_ = [name, full_name, lower, camel, json]
+  // However:
+  //   duplicates will be omitted, so lower/camel/json might be in the same
+  //   position.
+  // We store the true offset for each name here, and the bit width must be
+  // large enough to account for the worst case where all names are present.
+  uint8_t lowercase_name_index_ : 2;
+  uint8_t camelcase_name_index_ : 2;
+  uint8_t json_name_index_ : 3;
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+
+  internal::LazyInitData* type_once_;
+  static void TypeOnceInit(const FieldDescriptor* to_init);
+  void InternalTypeOnceInit() const;
   int number_;
   int index_in_oneof_;
   const Descriptor* containing_type_;
@@ -891,17 +940,15 @@
   mutable const Descriptor* message_type_;
   mutable const EnumDescriptor* enum_type_;
   const FieldOptions* options_;
-  const std::string* type_name_;
-  const std::string* default_value_enum_name_;
   // IMPORTANT:  If you add a new field, make sure to search for all instances
   // of Allocate<FieldDescriptor>() and AllocateArray<FieldDescriptor>() in
   // descriptor.cc and update them to initialize the field.
 
   union {
-    int32 default_value_int32_;
-    int64 default_value_int64_;
-    uint32 default_value_uint32_;
-    uint64 default_value_uint64_;
+    int32_t default_value_int32_t_;
+    int64_t default_value_int64_t_;
+    uint32_t default_value_uint32_t_;
+    uint64_t default_value_uint64_t_;
     float default_value_float_;
     double default_value_double_;
     bool default_value_bool_;
@@ -930,7 +977,7 @@
 
 
 // Describes a oneof defined in a message type.
-class PROTOBUF_EXPORT OneofDescriptor {
+class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
  public:
   typedef OneofDescriptorProto Proto;
 
@@ -974,6 +1021,7 @@
   bool GetSourceLocation(SourceLocation* out_location) const;
 
  private:
+  friend class Symbol;
   typedef OneofOptions OptionsType;
 
   // Allows access to GetLocationPath for annotations.
@@ -988,10 +1036,11 @@
   // to this descriptor from the file root.
   void GetLocationPath(std::vector<int>* output) const;
 
-  const std::string* name_;
-  const std::string* full_name_;
-  const Descriptor* containing_type_;
   int field_count_;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const Descriptor* containing_type_;
   const FieldDescriptor** fields_;
   const OneofOptions* options_;
 
@@ -1009,7 +1058,7 @@
 // Describes an enum type defined in a .proto file.  To get the EnumDescriptor
 // for a generated enum type, call TypeName_descriptor().  Use DescriptorPool
 // to construct your own descriptors.
-class PROTOBUF_EXPORT EnumDescriptor {
+class PROTOBUF_EXPORT EnumDescriptor : private internal::SymbolBase {
  public:
   typedef EnumDescriptorProto Proto;
 
@@ -1101,6 +1150,7 @@
   bool GetSourceLocation(SourceLocation* out_location) const;
 
  private:
+  friend class Symbol;
   typedef EnumOptions OptionsType;
 
   // Allows access to GetLocationPath for annotations.
@@ -1126,18 +1176,18 @@
   // to this descriptor from the file root.
   void GetLocationPath(std::vector<int>* output) const;
 
-  const std::string* name_;
-  const std::string* full_name_;
-  const FileDescriptor* file_;
-  const Descriptor* containing_type_;
-  const EnumOptions* options_;
-
   // True if this is a placeholder for an unknown type.
   bool is_placeholder_;
   // True if this is a placeholder and the type name wasn't fully-qualified.
   bool is_unqualified_placeholder_;
 
   int value_count_;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+  const Descriptor* containing_type_;
+  const EnumOptions* options_;
   EnumValueDescriptor* values_;
 
   int reserved_range_count_;
@@ -1166,7 +1216,8 @@
 // for its type, then use EnumDescriptor::FindValueByName() or
 // EnumDescriptor::FindValueByNumber().  Use DescriptorPool to construct
 // your own descriptors.
-class PROTOBUF_EXPORT EnumValueDescriptor {
+class PROTOBUF_EXPORT EnumValueDescriptor : private internal::SymbolBaseN<0>,
+                                            private internal::SymbolBaseN<1> {
  public:
   typedef EnumValueDescriptorProto Proto;
 
@@ -1209,6 +1260,7 @@
   bool GetSourceLocation(SourceLocation* out_location) const;
 
  private:
+  friend class Symbol;
   typedef EnumValueOptions OptionsType;
 
   // Allows access to GetLocationPath for annotations.
@@ -1223,9 +1275,9 @@
   // to this descriptor from the file root.
   void GetLocationPath(std::vector<int>* output) const;
 
-  const std::string* name_;
-  const std::string* full_name_;
   int number_;
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
   const EnumDescriptor* type_;
   const EnumValueOptions* options_;
   // IMPORTANT:  If you add a new field, make sure to search for all instances
@@ -1244,7 +1296,7 @@
 
 // Describes an RPC service. Use DescriptorPool to construct your own
 // descriptors.
-class PROTOBUF_EXPORT ServiceDescriptor {
+class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase {
  public:
   typedef ServiceDescriptorProto Proto;
 
@@ -1289,6 +1341,7 @@
   bool GetSourceLocation(SourceLocation* out_location) const;
 
  private:
+  friend class Symbol;
   typedef ServiceOptions OptionsType;
 
   // Allows access to GetLocationPath for annotations.
@@ -1303,8 +1356,8 @@
   // to this descriptor from the file root.
   void GetLocationPath(std::vector<int>* output) const;
 
-  const std::string* name_;
-  const std::string* full_name_;
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
   const FileDescriptor* file_;
   const ServiceOptions* options_;
   MethodDescriptor* methods_;
@@ -1326,7 +1379,7 @@
 // a service, first get its ServiceDescriptor, then call
 // ServiceDescriptor::FindMethodByName().  Use DescriptorPool to construct your
 // own descriptors.
-class PROTOBUF_EXPORT MethodDescriptor {
+class PROTOBUF_EXPORT MethodDescriptor : private internal::SymbolBase {
  public:
   typedef MethodDescriptorProto Proto;
 
@@ -1375,6 +1428,7 @@
   bool GetSourceLocation(SourceLocation* out_location) const;
 
  private:
+  friend class Symbol;
   typedef MethodOptions OptionsType;
 
   // Allows access to GetLocationPath for annotations.
@@ -1389,14 +1443,14 @@
   // to this descriptor from the file root.
   void GetLocationPath(std::vector<int>* output) const;
 
-  const std::string* name_;
-  const std::string* full_name_;
+  bool client_streaming_;
+  bool server_streaming_;
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
   const ServiceDescriptor* service_;
   mutable internal::LazyDescriptor input_type_;
   mutable internal::LazyDescriptor output_type_;
   const MethodOptions* options_;
-  bool client_streaming_;
-  bool server_streaming_;
   // IMPORTANT:  If you add a new field, make sure to search for all instances
   // of Allocate<MethodDescriptor>() and AllocateArray<MethodDescriptor>() in
   // descriptor.cc and update them to initialize the field.
@@ -1554,7 +1608,7 @@
   const std::string* name_;
   const std::string* package_;
   const DescriptorPool* pool_;
-  internal::once_flag* dependencies_once_;
+  internal::LazyInitData* dependencies_once_;
   static void DependenciesOnceInit(const FileDescriptor* to_init);
   void InternalDependenciesOnceInit() const;
 
@@ -1565,17 +1619,18 @@
   int message_type_count_;
   int enum_type_count_;
   int service_count_;
-  int extension_count_;
-  Syntax syntax_;
-  bool is_placeholder_;
 
+  bool is_placeholder_;
   // Indicates the FileDescriptor is completed building. Used to verify
   // that type accessor functions that can possibly build a dependent file
   // aren't called during the process of building the file.
   bool finished_building_;
+  // Actually a `Syntax` but stored as uint8_t to save space.
+  uint8_t syntax_;
+  // This one is here to fill the padding.
+  int extension_count_;
 
   mutable const FileDescriptor** dependencies_;
-  const std::string** dependencies_names_;
   int* public_dependencies_;
   int* weak_dependencies_;
   Descriptor* message_types_;
@@ -1988,6 +2043,11 @@
 #define PROTOBUF_DEFINE_STRING_ACCESSOR(CLASS, FIELD) \
   inline const std::string& CLASS::FIELD() const { return *FIELD##_; }
 
+// Name and full name are stored in a single array to save space.
+#define PROTOBUF_DEFINE_NAME_ACCESSOR(CLASS)                              \
+  inline const std::string& CLASS::name() const { return all_names_[0]; } \
+  inline const std::string& CLASS::full_name() const { return all_names_[1]; }
+
 // Arrays take an index parameter, obviously.
 #define PROTOBUF_DEFINE_ARRAY_ACCESSOR(CLASS, FIELD, TYPE) \
   inline TYPE CLASS::FIELD(int index) const { return FIELD##s_ + index; }
@@ -1995,8 +2055,7 @@
 #define PROTOBUF_DEFINE_OPTIONS_ACCESSOR(CLASS, TYPE) \
   inline const TYPE& CLASS::options() const { return *options_; }
 
-PROTOBUF_DEFINE_STRING_ACCESSOR(Descriptor, name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(Descriptor, full_name)
+PROTOBUF_DEFINE_NAME_ACCESSOR(Descriptor)
 PROTOBUF_DEFINE_ACCESSOR(Descriptor, file, const FileDescriptor*)
 PROTOBUF_DEFINE_ACCESSOR(Descriptor, containing_type, const Descriptor*)
 
@@ -2025,15 +2084,10 @@
 PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
 PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool)
 
-PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, json_name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name)
+PROTOBUF_DEFINE_NAME_ACCESSOR(FieldDescriptor)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool)
-PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, label, FieldDescriptor::Label)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_type, const Descriptor*)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_oneof,
                          const OneofDescriptor*)
@@ -2042,23 +2096,21 @@
 PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_json_name, bool)
-PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32, int32)
-PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64, int64)
-PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint32, uint32)
-PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint64, uint64)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32_t, int32_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64_t, int64_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint32_t, uint32_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint64_t, uint64_t)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_float, float)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_double, double)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_bool, bool)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, default_value_string)
 
-PROTOBUF_DEFINE_STRING_ACCESSOR(OneofDescriptor, name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(OneofDescriptor, full_name)
+PROTOBUF_DEFINE_NAME_ACCESSOR(OneofDescriptor)
 PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, containing_type, const Descriptor*)
 PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, field_count, int)
 PROTOBUF_DEFINE_OPTIONS_ACCESSOR(OneofDescriptor, OneofOptions)
 
-PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, full_name)
+PROTOBUF_DEFINE_NAME_ACCESSOR(EnumDescriptor)
 PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, file, const FileDescriptor*)
 PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, containing_type, const Descriptor*)
 PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
@@ -2071,22 +2123,19 @@
                                const EnumDescriptor::ReservedRange*)
 PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, reserved_name_count, int)
 
-PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, full_name)
+PROTOBUF_DEFINE_NAME_ACCESSOR(EnumValueDescriptor)
 PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int)
 PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*)
 PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
 
-PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, full_name)
+PROTOBUF_DEFINE_NAME_ACCESSOR(ServiceDescriptor)
 PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, file, const FileDescriptor*)
 PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method,
                                const MethodDescriptor*)
 PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
 
-PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, name)
-PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, full_name)
+PROTOBUF_DEFINE_NAME_ACCESSOR(MethodDescriptor)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
 PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool)
@@ -2164,11 +2213,27 @@
   return *reserved_names_[index];
 }
 
+inline const std::string& FieldDescriptor::lowercase_name() const {
+  return all_names_[lowercase_name_index_];
+}
+
+inline const std::string& FieldDescriptor::camelcase_name() const {
+  return all_names_[camelcase_name_index_];
+}
+
+inline const std::string& FieldDescriptor::json_name() const {
+  return all_names_[json_name_index_];
+}
+
+inline FieldDescriptor::Label FieldDescriptor::label() const {
+  return static_cast<Label>(label_);
+}
+
 inline FieldDescriptor::Type FieldDescriptor::type() const {
   if (type_once_) {
-    internal::call_once(*type_once_, &FieldDescriptor::TypeOnceInit, this);
+    internal::call_once(type_once_->once, &FieldDescriptor::TypeOnceInit, this);
   }
-  return type_;
+  return static_cast<Type>(type_);
 }
 
 inline bool FieldDescriptor::is_required() const {
@@ -2309,7 +2374,9 @@
   return dependency(weak_dependencies_[index]);
 }
 
-inline FileDescriptor::Syntax FileDescriptor::syntax() const { return syntax_; }
+inline FileDescriptor::Syntax FileDescriptor::syntax() const {
+  return static_cast<Syntax>(syntax_);
+}
 
 // Can't use PROTOBUF_DEFINE_ARRAY_ACCESSOR because fields_ is actually an array
 // of pointers rather than the usual array of objects.
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 2e91b7c..6e2afc0 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -459,12 +459,14 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileDescriptorSet, file_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _has_bits_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileDescriptorProto, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileDescriptorProto, package_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileDescriptorProto, dependency_),
@@ -494,6 +496,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, start_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, end_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, options_),
@@ -505,6 +508,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, start_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, end_),
   0,
@@ -514,6 +518,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::DescriptorProto, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::DescriptorProto, field_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::DescriptorProto, extension_),
@@ -539,12 +544,14 @@
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, _extensions_),
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, uninterpreted_option_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _has_bits_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, number_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, label_),
@@ -572,6 +579,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, options_),
   0,
@@ -581,6 +589,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, start_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, end_),
   0,
@@ -590,6 +599,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, value_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, options_),
@@ -605,6 +615,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, number_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, options_),
@@ -616,6 +627,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, method_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, options_),
@@ -627,6 +639,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, input_type_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, output_type_),
@@ -644,6 +657,7 @@
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileOptions, _extensions_),
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileOptions, java_package_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileOptions, java_outer_classname_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FileOptions, java_multiple_files_),
@@ -691,6 +705,7 @@
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MessageOptions, _extensions_),
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MessageOptions, message_set_wire_format_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MessageOptions, no_standard_descriptor_accessor_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MessageOptions, deprecated_),
@@ -706,6 +721,7 @@
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldOptions, _extensions_),
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldOptions, ctype_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldOptions, packed_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldOptions, jstype_),
@@ -725,12 +741,14 @@
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::OneofOptions, _extensions_),
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::OneofOptions, uninterpreted_option_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumOptions, _has_bits_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumOptions, _internal_metadata_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumOptions, _extensions_),
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumOptions, allow_alias_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumOptions, deprecated_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumOptions, uninterpreted_option_),
@@ -742,6 +760,7 @@
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumValueOptions, _extensions_),
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumValueOptions, deprecated_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumValueOptions, uninterpreted_option_),
   0,
@@ -751,6 +770,7 @@
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::ServiceOptions, _extensions_),
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::ServiceOptions, deprecated_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::ServiceOptions, uninterpreted_option_),
   0,
@@ -760,6 +780,7 @@
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MethodOptions, _extensions_),
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MethodOptions, deprecated_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MethodOptions, idempotency_level_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::MethodOptions, uninterpreted_option_),
@@ -771,6 +792,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, name_part_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, is_extension_),
   0,
@@ -780,6 +802,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::UninterpretedOption, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::UninterpretedOption, identifier_value_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::UninterpretedOption, positive_int_value_),
@@ -799,6 +822,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, path_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, span_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, leading_comments_),
@@ -814,12 +838,14 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::SourceCodeInfo, location_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _has_bits_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, path_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, source_file_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, begin_),
@@ -833,36 +859,37 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo, annotation_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::FileDescriptorSet)},
-  { 6, 23, sizeof(PROTOBUF_NAMESPACE_ID::FileDescriptorProto)},
-  { 35, 43, sizeof(PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange)},
-  { 46, 53, sizeof(PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange)},
-  { 55, 70, sizeof(PROTOBUF_NAMESPACE_ID::DescriptorProto)},
-  { 80, -1, sizeof(PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions)},
-  { 86, 102, sizeof(PROTOBUF_NAMESPACE_ID::FieldDescriptorProto)},
-  { 113, 120, sizeof(PROTOBUF_NAMESPACE_ID::OneofDescriptorProto)},
-  { 122, 129, sizeof(PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange)},
-  { 131, 141, sizeof(PROTOBUF_NAMESPACE_ID::EnumDescriptorProto)},
-  { 146, 154, sizeof(PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto)},
-  { 157, 165, sizeof(PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto)},
-  { 168, 179, sizeof(PROTOBUF_NAMESPACE_ID::MethodDescriptorProto)},
-  { 185, 211, sizeof(PROTOBUF_NAMESPACE_ID::FileOptions)},
-  { 232, 242, sizeof(PROTOBUF_NAMESPACE_ID::MessageOptions)},
-  { 247, 259, sizeof(PROTOBUF_NAMESPACE_ID::FieldOptions)},
-  { 266, -1, sizeof(PROTOBUF_NAMESPACE_ID::OneofOptions)},
-  { 272, 280, sizeof(PROTOBUF_NAMESPACE_ID::EnumOptions)},
-  { 283, 290, sizeof(PROTOBUF_NAMESPACE_ID::EnumValueOptions)},
-  { 292, 299, sizeof(PROTOBUF_NAMESPACE_ID::ServiceOptions)},
-  { 301, 309, sizeof(PROTOBUF_NAMESPACE_ID::MethodOptions)},
-  { 312, 319, sizeof(PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart)},
-  { 321, 333, sizeof(PROTOBUF_NAMESPACE_ID::UninterpretedOption)},
-  { 340, 350, sizeof(PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location)},
-  { 355, -1, sizeof(PROTOBUF_NAMESPACE_ID::SourceCodeInfo)},
-  { 361, 370, sizeof(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation)},
-  { 374, -1, sizeof(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::FileDescriptorSet)},
+  { 7, 25, -1, sizeof(PROTOBUF_NAMESPACE_ID::FileDescriptorProto)},
+  { 37, 46, -1, sizeof(PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange)},
+  { 49, 57, -1, sizeof(PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange)},
+  { 59, 75, -1, sizeof(PROTOBUF_NAMESPACE_ID::DescriptorProto)},
+  { 85, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions)},
+  { 92, 109, -1, sizeof(PROTOBUF_NAMESPACE_ID::FieldDescriptorProto)},
+  { 120, 128, -1, sizeof(PROTOBUF_NAMESPACE_ID::OneofDescriptorProto)},
+  { 130, 138, -1, sizeof(PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange)},
+  { 140, 151, -1, sizeof(PROTOBUF_NAMESPACE_ID::EnumDescriptorProto)},
+  { 156, 165, -1, sizeof(PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto)},
+  { 168, 177, -1, sizeof(PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto)},
+  { 180, 192, -1, sizeof(PROTOBUF_NAMESPACE_ID::MethodDescriptorProto)},
+  { 198, 225, -1, sizeof(PROTOBUF_NAMESPACE_ID::FileOptions)},
+  { 246, 257, -1, sizeof(PROTOBUF_NAMESPACE_ID::MessageOptions)},
+  { 262, 275, -1, sizeof(PROTOBUF_NAMESPACE_ID::FieldOptions)},
+  { 282, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::OneofOptions)},
+  { 289, 298, -1, sizeof(PROTOBUF_NAMESPACE_ID::EnumOptions)},
+  { 301, 309, -1, sizeof(PROTOBUF_NAMESPACE_ID::EnumValueOptions)},
+  { 311, 319, -1, sizeof(PROTOBUF_NAMESPACE_ID::ServiceOptions)},
+  { 321, 330, -1, sizeof(PROTOBUF_NAMESPACE_ID::MethodOptions)},
+  { 333, 341, -1, sizeof(PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart)},
+  { 343, 356, -1, sizeof(PROTOBUF_NAMESPACE_ID::UninterpretedOption)},
+  { 363, 374, -1, sizeof(PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location)},
+  { 379, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::SourceCodeInfo)},
+  { 386, 396, -1, sizeof(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation)},
+  { 400, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -1305,28 +1332,29 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1367,13 +1395,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FileDescriptorSet::_class_data_ = {
@@ -1382,8 +1404,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileDescriptorSet::GetClassData() const { return &_class_data_; }
 
-void FileDescriptorSet::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void FileDescriptorSet::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<FileDescriptorSet *>(to)->MergeFrom(
       static_cast<const FileDescriptorSet &>(from));
 }
@@ -1599,7 +1621,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string package = 2;
       case 2:
@@ -1610,7 +1633,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.package");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated string dependency = 3;
       case 3:
@@ -1626,7 +1650,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.DescriptorProto message_type = 4;
       case 4:
@@ -1638,7 +1663,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
       case 5:
@@ -1650,7 +1676,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.ServiceDescriptorProto service = 6;
       case 6:
@@ -1662,7 +1689,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.FieldDescriptorProto extension = 7;
       case 7:
@@ -1674,21 +1702,24 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<58>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.FileOptions options = 8;
       case 8:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 66)) {
           ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
       case 9:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 74)) {
           ptr = ctx->ParseMessage(_internal_mutable_source_code_info(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated int32 public_dependency = 10;
       case 10:
@@ -1703,7 +1734,8 @@
         } else if (static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 82) {
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_public_dependency(), ptr, ctx);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated int32 weak_dependency = 11;
       case 11:
@@ -1718,7 +1750,8 @@
         } else if (static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 90) {
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_weak_dependency(), ptr, ctx);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string syntax = 12;
       case 12:
@@ -1729,29 +1762,30 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.syntax");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1970,13 +2004,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FileDescriptorProto::_class_data_ = {
@@ -1985,8 +2013,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileDescriptorProto::GetClassData() const { return &_class_data_; }
 
-void FileDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void FileDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<FileDescriptorProto *>(to)->MergeFrom(
       static_cast<const FileDescriptorProto &>(from));
 }
@@ -2046,6 +2074,8 @@
 
 void FileDescriptorProto::InternalSwap(FileDescriptorProto* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   dependency_.InternalSwap(&other->dependency_);
@@ -2057,18 +2087,18 @@
   weak_dependency_.InternalSwap(&other->weak_dependency_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &package_, GetArenaForAllocation(),
-      &other->package_, other->GetArenaForAllocation()
+      &package_, lhs_arena,
+      &other->package_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &syntax_, GetArenaForAllocation(),
-      &other->syntax_, other->GetArenaForAllocation()
+      &syntax_, lhs_arena,
+      &other->syntax_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(FileDescriptorProto, source_code_info_)
@@ -2191,7 +2221,8 @@
           _Internal::set_has_start(&has_bits);
           start_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 end = 2;
       case 2:
@@ -2199,36 +2230,38 @@
           _Internal::set_has_end(&has_bits);
           end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.ExtensionRangeOptions options = 3;
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 26)) {
           ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -2286,26 +2319,16 @@
 
     // optional int32 start = 1;
     if (cached_has_bits & 0x00000002u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_start());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_start());
     }
 
     // optional int32 end = 2;
     if (cached_has_bits & 0x00000004u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_end());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_end());
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DescriptorProto_ExtensionRange::_class_data_ = {
@@ -2314,8 +2337,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto_ExtensionRange::GetClassData() const { return &_class_data_; }
 
-void DescriptorProto_ExtensionRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void DescriptorProto_ExtensionRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<DescriptorProto_ExtensionRange *>(to)->MergeFrom(
       static_cast<const DescriptorProto_ExtensionRange &>(from));
 }
@@ -2464,7 +2487,8 @@
           _Internal::set_has_start(&has_bits);
           start_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 end = 2;
       case 2:
@@ -2472,29 +2496,30 @@
           _Internal::set_has_end(&has_bits);
           end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -2537,26 +2562,16 @@
   if (cached_has_bits & 0x00000003u) {
     // optional int32 start = 1;
     if (cached_has_bits & 0x00000001u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_start());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_start());
     }
 
     // optional int32 end = 2;
     if (cached_has_bits & 0x00000002u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_end());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_end());
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DescriptorProto_ReservedRange::_class_data_ = {
@@ -2565,8 +2580,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto_ReservedRange::GetClassData() const { return &_class_data_; }
 
-void DescriptorProto_ReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void DescriptorProto_ReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<DescriptorProto_ReservedRange *>(to)->MergeFrom(
       static_cast<const DescriptorProto_ReservedRange &>(from));
 }
@@ -2752,7 +2767,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.DescriptorProto.name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.FieldDescriptorProto field = 2;
       case 2:
@@ -2764,7 +2780,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.DescriptorProto nested_type = 3;
       case 3:
@@ -2776,7 +2793,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
       case 4:
@@ -2788,7 +2806,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
       case 5:
@@ -2800,7 +2819,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.FieldDescriptorProto extension = 6;
       case 6:
@@ -2812,14 +2832,16 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.MessageOptions options = 7;
       case 7:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 58)) {
           ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
       case 8:
@@ -2831,7 +2853,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<66>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
       case 9:
@@ -2843,7 +2866,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<74>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated string reserved_name = 10;
       case 10:
@@ -2859,29 +2883,30 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<82>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -3066,13 +3091,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DescriptorProto::_class_data_ = {
@@ -3081,8 +3100,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto::GetClassData() const { return &_class_data_; }
 
-void DescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void DescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<DescriptorProto *>(to)->MergeFrom(
       static_cast<const DescriptorProto &>(from));
 }
@@ -3136,6 +3155,8 @@
 
 void DescriptorProto::InternalSwap(DescriptorProto* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   field_.InternalSwap(&other->field_);
@@ -3148,8 +3169,8 @@
   reserved_name_.InternalSwap(&other->reserved_name_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   swap(options_, other->options_);
 }
@@ -3236,34 +3257,34 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-      if ((8000u <= tag)) {
-        ptr = _extensions_.ParseField(tag, ptr,
-            internal_default_instance(), &_internal_metadata_, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -3283,7 +3304,7 @@
 
   // Extension range [1000, 536870912)
   target = _extensions_._InternalSerialize(
-      1000, 536870912, target, stream);
+  internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
@@ -3310,13 +3331,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ExtensionRangeOptions::_class_data_ = {
@@ -3325,8 +3340,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ExtensionRangeOptions::GetClassData() const { return &_class_data_; }
 
-void ExtensionRangeOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void ExtensionRangeOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<ExtensionRangeOptions *>(to)->MergeFrom(
       static_cast<const ExtensionRangeOptions &>(from));
 }
@@ -3565,7 +3580,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string extendee = 2;
       case 2:
@@ -3576,7 +3592,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.extendee");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 number = 3;
       case 3:
@@ -3584,7 +3601,8 @@
           _Internal::set_has_number(&has_bits);
           number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
       case 4:
@@ -3596,7 +3614,8 @@
           } else {
             ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(4, val, mutable_unknown_fields());
           }
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
       case 5:
@@ -3608,7 +3627,8 @@
           } else {
             ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(5, val, mutable_unknown_fields());
           }
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string type_name = 6;
       case 6:
@@ -3619,7 +3639,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.type_name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string default_value = 7;
       case 7:
@@ -3630,14 +3651,16 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.default_value");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.FieldOptions options = 8;
       case 8:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 66)) {
           ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 oneof_index = 9;
       case 9:
@@ -3645,7 +3668,8 @@
           _Internal::set_has_oneof_index(&has_bits);
           oneof_index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string json_name = 10;
       case 10:
@@ -3656,7 +3680,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.json_name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool proto3_optional = 17;
       case 17:
@@ -3664,29 +3689,30 @@
           _Internal::set_has_proto3_optional(&has_bits);
           proto3_optional_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -3849,16 +3875,12 @@
 
     // optional int32 number = 3;
     if (cached_has_bits & 0x00000040u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_number());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_number());
     }
 
     // optional int32 oneof_index = 9;
     if (cached_has_bits & 0x00000080u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_oneof_index());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
     }
 
   }
@@ -3881,13 +3903,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FieldDescriptorProto::_class_data_ = {
@@ -3896,8 +3912,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldDescriptorProto::GetClassData() const { return &_class_data_; }
 
-void FieldDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void FieldDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<FieldDescriptorProto *>(to)->MergeFrom(
       static_cast<const FieldDescriptorProto &>(from));
 }
@@ -3968,32 +3984,34 @@
 
 void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &extendee_, GetArenaForAllocation(),
-      &other->extendee_, other->GetArenaForAllocation()
+      &extendee_, lhs_arena,
+      &other->extendee_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &type_name_, GetArenaForAllocation(),
-      &other->type_name_, other->GetArenaForAllocation()
+      &type_name_, lhs_arena,
+      &other->type_name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &default_value_, GetArenaForAllocation(),
-      &other->default_value_, other->GetArenaForAllocation()
+      &default_value_, lhs_arena,
+      &other->default_value_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &json_name_, GetArenaForAllocation(),
-      &other->json_name_, other->GetArenaForAllocation()
+      &json_name_, lhs_arena,
+      &other->json_name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(FieldDescriptorProto, proto3_optional_)
@@ -4119,36 +4137,38 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.OneofDescriptorProto.name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.OneofOptions options = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) {
           ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -4210,13 +4230,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData OneofDescriptorProto::_class_data_ = {
@@ -4225,8 +4239,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*OneofDescriptorProto::GetClassData() const { return &_class_data_; }
 
-void OneofDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void OneofDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<OneofDescriptorProto *>(to)->MergeFrom(
       static_cast<const OneofDescriptorProto &>(from));
 }
@@ -4266,12 +4280,14 @@
 
 void OneofDescriptorProto::InternalSwap(OneofDescriptorProto* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   swap(options_, other->options_);
 }
@@ -4371,7 +4387,8 @@
           _Internal::set_has_start(&has_bits);
           start_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 end = 2;
       case 2:
@@ -4379,29 +4396,30 @@
           _Internal::set_has_end(&has_bits);
           end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -4444,26 +4462,16 @@
   if (cached_has_bits & 0x00000003u) {
     // optional int32 start = 1;
     if (cached_has_bits & 0x00000001u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_start());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_start());
     }
 
     // optional int32 end = 2;
     if (cached_has_bits & 0x00000002u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_end());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_end());
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumDescriptorProto_EnumReservedRange::_class_data_ = {
@@ -4472,8 +4480,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumDescriptorProto_EnumReservedRange::GetClassData() const { return &_class_data_; }
 
-void EnumDescriptorProto_EnumReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void EnumDescriptorProto_EnumReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<EnumDescriptorProto_EnumReservedRange *>(to)->MergeFrom(
       static_cast<const EnumDescriptorProto_EnumReservedRange &>(from));
 }
@@ -4644,7 +4652,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.EnumDescriptorProto.name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
       case 2:
@@ -4656,14 +4665,16 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.EnumOptions options = 3;
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 26)) {
           ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
       case 4:
@@ -4675,7 +4686,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated string reserved_name = 5;
       case 5:
@@ -4691,29 +4703,30 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -4823,13 +4836,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumDescriptorProto::_class_data_ = {
@@ -4838,8 +4845,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumDescriptorProto::GetClassData() const { return &_class_data_; }
 
-void EnumDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void EnumDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<EnumDescriptorProto *>(to)->MergeFrom(
       static_cast<const EnumDescriptorProto &>(from));
 }
@@ -4883,6 +4890,8 @@
 
 void EnumDescriptorProto::InternalSwap(EnumDescriptorProto* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   value_.InternalSwap(&other->value_);
@@ -4890,8 +4899,8 @@
   reserved_name_.InternalSwap(&other->reserved_name_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   swap(options_, other->options_);
 }
@@ -5018,7 +5027,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.EnumValueDescriptorProto.name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 number = 2;
       case 2:
@@ -5026,36 +5036,38 @@
           _Internal::set_has_number(&has_bits);
           number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.EnumValueOptions options = 3;
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 26)) {
           ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -5124,19 +5136,11 @@
 
     // optional int32 number = 2;
     if (cached_has_bits & 0x00000004u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_number());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_number());
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumValueDescriptorProto::_class_data_ = {
@@ -5145,8 +5149,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValueDescriptorProto::GetClassData() const { return &_class_data_; }
 
-void EnumValueDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void EnumValueDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<EnumValueDescriptorProto *>(to)->MergeFrom(
       static_cast<const EnumValueDescriptorProto &>(from));
 }
@@ -5190,12 +5194,14 @@
 
 void EnumValueDescriptorProto::InternalSwap(EnumValueDescriptorProto* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(EnumValueDescriptorProto, number_)
@@ -5322,7 +5328,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.ServiceDescriptorProto.name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.MethodDescriptorProto method = 2;
       case 2:
@@ -5334,36 +5341,38 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.ServiceOptions options = 3;
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 26)) {
           ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -5440,13 +5449,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ServiceDescriptorProto::_class_data_ = {
@@ -5455,8 +5458,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ServiceDescriptorProto::GetClassData() const { return &_class_data_; }
 
-void ServiceDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void ServiceDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<ServiceDescriptorProto *>(to)->MergeFrom(
       static_cast<const ServiceDescriptorProto &>(from));
 }
@@ -5498,13 +5501,15 @@
 
 void ServiceDescriptorProto::InternalSwap(ServiceDescriptorProto* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   method_.InternalSwap(&other->method_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   swap(options_, other->options_);
 }
@@ -5664,7 +5669,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.name");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string input_type = 2;
       case 2:
@@ -5675,7 +5681,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.input_type");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string output_type = 3;
       case 3:
@@ -5686,14 +5693,16 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.output_type");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.MethodOptions options = 4;
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 34)) {
           ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool client_streaming = 5 [default = false];
       case 5:
@@ -5701,7 +5710,8 @@
           _Internal::set_has_client_streaming(&has_bits);
           client_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool server_streaming = 6 [default = false];
       case 6:
@@ -5709,29 +5719,30 @@
           _Internal::set_has_server_streaming(&has_bits);
           server_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -5849,13 +5860,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MethodDescriptorProto::_class_data_ = {
@@ -5864,8 +5869,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MethodDescriptorProto::GetClassData() const { return &_class_data_; }
 
-void MethodDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void MethodDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<MethodDescriptorProto *>(to)->MergeFrom(
       static_cast<const MethodDescriptorProto &>(from));
 }
@@ -5918,22 +5923,24 @@
 
 void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &input_type_, GetArenaForAllocation(),
-      &other->input_type_, other->GetArenaForAllocation()
+      &input_type_, lhs_arena,
+      &other->input_type_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &output_type_, GetArenaForAllocation(),
-      &other->output_type_, other->GetArenaForAllocation()
+      &output_type_, lhs_arena,
+      &other->output_type_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(MethodDescriptorProto, server_streaming_)
@@ -6214,7 +6221,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.java_package");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string java_outer_classname = 8;
       case 8:
@@ -6225,7 +6233,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.java_outer_classname");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
       case 9:
@@ -6237,7 +6246,8 @@
           } else {
             ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(9, val, mutable_unknown_fields());
           }
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool java_multiple_files = 10 [default = false];
       case 10:
@@ -6245,7 +6255,8 @@
           _Internal::set_has_java_multiple_files(&has_bits);
           java_multiple_files_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string go_package = 11;
       case 11:
@@ -6256,7 +6267,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.go_package");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool cc_generic_services = 16 [default = false];
       case 16:
@@ -6264,7 +6276,8 @@
           _Internal::set_has_cc_generic_services(&has_bits);
           cc_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool java_generic_services = 17 [default = false];
       case 17:
@@ -6272,7 +6285,8 @@
           _Internal::set_has_java_generic_services(&has_bits);
           java_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool py_generic_services = 18 [default = false];
       case 18:
@@ -6280,7 +6294,8 @@
           _Internal::set_has_py_generic_services(&has_bits);
           py_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
       case 20:
@@ -6288,7 +6303,8 @@
           _Internal::set_has_java_generate_equals_and_hash(&has_bits);
           java_generate_equals_and_hash_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool deprecated = 23 [default = false];
       case 23:
@@ -6296,7 +6312,8 @@
           _Internal::set_has_deprecated(&has_bits);
           deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool java_string_check_utf8 = 27 [default = false];
       case 27:
@@ -6304,7 +6321,8 @@
           _Internal::set_has_java_string_check_utf8(&has_bits);
           java_string_check_utf8_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool cc_enable_arenas = 31 [default = true];
       case 31:
@@ -6312,7 +6330,8 @@
           _Internal::set_has_cc_enable_arenas(&has_bits);
           cc_enable_arenas_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string objc_class_prefix = 36;
       case 36:
@@ -6323,7 +6342,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.objc_class_prefix");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string csharp_namespace = 37;
       case 37:
@@ -6334,7 +6354,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.csharp_namespace");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string swift_prefix = 39;
       case 39:
@@ -6345,7 +6366,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.swift_prefix");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string php_class_prefix = 40;
       case 40:
@@ -6356,7 +6378,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.php_class_prefix");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string php_namespace = 41;
       case 41:
@@ -6367,7 +6390,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.php_namespace");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool php_generic_services = 42 [default = false];
       case 42:
@@ -6375,7 +6399,8 @@
           _Internal::set_has_php_generic_services(&has_bits);
           php_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string php_metadata_namespace = 44;
       case 44:
@@ -6386,7 +6411,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.php_metadata_namespace");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string ruby_package = 45;
       case 45:
@@ -6397,7 +6423,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.ruby_package");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
@@ -6409,35 +6436,35 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-      if ((8000u <= tag)) {
-        ptr = _extensions_.ParseField(tag, ptr,
-            internal_default_instance(), &_internal_metadata_, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -6619,7 +6646,7 @@
 
   // Extension range [1000, 536870912)
   target = _extensions_._InternalSerialize(
-      1000, 536870912, target, stream);
+  internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
@@ -6774,13 +6801,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FileOptions::_class_data_ = {
@@ -6789,8 +6810,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileOptions::GetClassData() const { return &_class_data_; }
 
-void FileOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void FileOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<FileOptions *>(to)->MergeFrom(
       static_cast<const FileOptions &>(from));
 }
@@ -6895,58 +6916,60 @@
 void FileOptions::InternalSwap(FileOptions* other) {
   using std::swap;
   _extensions_.InternalSwap(&other->_extensions_);
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   uninterpreted_option_.InternalSwap(&other->uninterpreted_option_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &java_package_, GetArenaForAllocation(),
-      &other->java_package_, other->GetArenaForAllocation()
+      &java_package_, lhs_arena,
+      &other->java_package_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &java_outer_classname_, GetArenaForAllocation(),
-      &other->java_outer_classname_, other->GetArenaForAllocation()
+      &java_outer_classname_, lhs_arena,
+      &other->java_outer_classname_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &go_package_, GetArenaForAllocation(),
-      &other->go_package_, other->GetArenaForAllocation()
+      &go_package_, lhs_arena,
+      &other->go_package_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &objc_class_prefix_, GetArenaForAllocation(),
-      &other->objc_class_prefix_, other->GetArenaForAllocation()
+      &objc_class_prefix_, lhs_arena,
+      &other->objc_class_prefix_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &csharp_namespace_, GetArenaForAllocation(),
-      &other->csharp_namespace_, other->GetArenaForAllocation()
+      &csharp_namespace_, lhs_arena,
+      &other->csharp_namespace_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &swift_prefix_, GetArenaForAllocation(),
-      &other->swift_prefix_, other->GetArenaForAllocation()
+      &swift_prefix_, lhs_arena,
+      &other->swift_prefix_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &php_class_prefix_, GetArenaForAllocation(),
-      &other->php_class_prefix_, other->GetArenaForAllocation()
+      &php_class_prefix_, lhs_arena,
+      &other->php_class_prefix_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &php_namespace_, GetArenaForAllocation(),
-      &other->php_namespace_, other->GetArenaForAllocation()
+      &php_namespace_, lhs_arena,
+      &other->php_namespace_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &php_metadata_namespace_, GetArenaForAllocation(),
-      &other->php_metadata_namespace_, other->GetArenaForAllocation()
+      &php_metadata_namespace_, lhs_arena,
+      &other->php_metadata_namespace_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &ruby_package_, GetArenaForAllocation(),
-      &other->ruby_package_, other->GetArenaForAllocation()
+      &ruby_package_, lhs_arena,
+      &other->ruby_package_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(FileOptions, deprecated_)
@@ -7062,7 +7085,8 @@
           _Internal::set_has_message_set_wire_format(&has_bits);
           message_set_wire_format_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool no_standard_descriptor_accessor = 2 [default = false];
       case 2:
@@ -7070,7 +7094,8 @@
           _Internal::set_has_no_standard_descriptor_accessor(&has_bits);
           no_standard_descriptor_accessor_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool deprecated = 3 [default = false];
       case 3:
@@ -7078,7 +7103,8 @@
           _Internal::set_has_deprecated(&has_bits);
           deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool map_entry = 7;
       case 7:
@@ -7086,7 +7112,8 @@
           _Internal::set_has_map_entry(&has_bits);
           map_entry_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
@@ -7098,35 +7125,35 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-      if ((8000u <= tag)) {
-        ptr = _extensions_.ParseField(tag, ptr,
-            internal_default_instance(), &_internal_metadata_, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -7171,7 +7198,7 @@
 
   // Extension range [1000, 536870912)
   target = _extensions_._InternalSerialize(
-      1000, 536870912, target, stream);
+  internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
@@ -7221,13 +7248,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MessageOptions::_class_data_ = {
@@ -7236,8 +7257,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MessageOptions::GetClassData() const { return &_class_data_; }
 
-void MessageOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void MessageOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<MessageOptions *>(to)->MergeFrom(
       static_cast<const MessageOptions &>(from));
 }
@@ -7417,7 +7438,8 @@
           } else {
             ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(1, val, mutable_unknown_fields());
           }
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool packed = 2;
       case 2:
@@ -7425,7 +7447,8 @@
           _Internal::set_has_packed(&has_bits);
           packed_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool deprecated = 3 [default = false];
       case 3:
@@ -7433,7 +7456,8 @@
           _Internal::set_has_deprecated(&has_bits);
           deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool lazy = 5 [default = false];
       case 5:
@@ -7441,7 +7465,8 @@
           _Internal::set_has_lazy(&has_bits);
           lazy_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
       case 6:
@@ -7453,7 +7478,8 @@
           } else {
             ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(6, val, mutable_unknown_fields());
           }
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool weak = 10 [default = false];
       case 10:
@@ -7461,7 +7487,8 @@
           _Internal::set_has_weak(&has_bits);
           weak_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
@@ -7473,35 +7500,35 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-      if ((8000u <= tag)) {
-        ptr = _extensions_.ParseField(tag, ptr,
-            internal_default_instance(), &_internal_metadata_, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -7560,7 +7587,7 @@
 
   // Extension range [1000, 536870912)
   target = _extensions_._InternalSerialize(
-      1000, 536870912, target, stream);
+  internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
@@ -7622,13 +7649,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FieldOptions::_class_data_ = {
@@ -7637,8 +7658,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldOptions::GetClassData() const { return &_class_data_; }
 
-void FieldOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void FieldOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<FieldOptions *>(to)->MergeFrom(
       static_cast<const FieldOptions &>(from));
 }
@@ -7789,34 +7810,34 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-      if ((8000u <= tag)) {
-        ptr = _extensions_.ParseField(tag, ptr,
-            internal_default_instance(), &_internal_metadata_, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -7836,7 +7857,7 @@
 
   // Extension range [1000, 536870912)
   target = _extensions_._InternalSerialize(
-      1000, 536870912, target, stream);
+  internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
@@ -7863,13 +7884,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData OneofOptions::_class_data_ = {
@@ -7878,8 +7893,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*OneofOptions::GetClassData() const { return &_class_data_; }
 
-void OneofOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void OneofOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<OneofOptions *>(to)->MergeFrom(
       static_cast<const OneofOptions &>(from));
 }
@@ -8017,7 +8032,8 @@
           _Internal::set_has_allow_alias(&has_bits);
           allow_alias_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bool deprecated = 3 [default = false];
       case 3:
@@ -8025,7 +8041,8 @@
           _Internal::set_has_deprecated(&has_bits);
           deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
@@ -8037,35 +8054,35 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-      if ((8000u <= tag)) {
-        ptr = _extensions_.ParseField(tag, ptr,
-            internal_default_instance(), &_internal_metadata_, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -8098,7 +8115,7 @@
 
   // Extension range [1000, 536870912)
   target = _extensions_._InternalSerialize(
-      1000, 536870912, target, stream);
+  internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
@@ -8138,13 +8155,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumOptions::_class_data_ = {
@@ -8153,8 +8164,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumOptions::GetClassData() const { return &_class_data_; }
 
-void EnumOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void EnumOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<EnumOptions *>(to)->MergeFrom(
       static_cast<const EnumOptions &>(from));
 }
@@ -8299,7 +8310,8 @@
           _Internal::set_has_deprecated(&has_bits);
           deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
@@ -8311,35 +8323,35 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-      if ((8000u <= tag)) {
-        ptr = _extensions_.ParseField(tag, ptr,
-            internal_default_instance(), &_internal_metadata_, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -8366,7 +8378,7 @@
 
   // Extension range [1000, 536870912)
   target = _extensions_._InternalSerialize(
-      1000, 536870912, target, stream);
+  internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
@@ -8399,13 +8411,7 @@
     total_size += 1 + 1;
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumValueOptions::_class_data_ = {
@@ -8414,8 +8420,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValueOptions::GetClassData() const { return &_class_data_; }
 
-void EnumValueOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void EnumValueOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<EnumValueOptions *>(to)->MergeFrom(
       static_cast<const EnumValueOptions &>(from));
 }
@@ -8548,7 +8554,8 @@
           _Internal::set_has_deprecated(&has_bits);
           deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
@@ -8560,35 +8567,35 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-      if ((8000u <= tag)) {
-        ptr = _extensions_.ParseField(tag, ptr,
-            internal_default_instance(), &_internal_metadata_, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -8615,7 +8622,7 @@
 
   // Extension range [1000, 536870912)
   target = _extensions_._InternalSerialize(
-      1000, 536870912, target, stream);
+  internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
@@ -8648,13 +8655,7 @@
     total_size += 2 + 1;
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ServiceOptions::_class_data_ = {
@@ -8663,8 +8664,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ServiceOptions::GetClassData() const { return &_class_data_; }
 
-void ServiceOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void ServiceOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<ServiceOptions *>(to)->MergeFrom(
       static_cast<const ServiceOptions &>(from));
 }
@@ -8810,7 +8811,8 @@
           _Internal::set_has_deprecated(&has_bits);
           deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
       case 34:
@@ -8822,7 +8824,8 @@
           } else {
             ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(34, val, mutable_unknown_fields());
           }
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
@@ -8834,35 +8837,35 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-      if ((8000u <= tag)) {
-        ptr = _extensions_.ParseField(tag, ptr,
-            internal_default_instance(), &_internal_metadata_, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -8896,7 +8899,7 @@
 
   // Extension range [1000, 536870912)
   target = _extensions_._InternalSerialize(
-      1000, 536870912, target, stream);
+  internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
@@ -8937,13 +8940,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MethodOptions::_class_data_ = {
@@ -8952,8 +8949,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MethodOptions::GetClassData() const { return &_class_data_; }
 
-void MethodOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void MethodOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<MethodOptions *>(to)->MergeFrom(
       static_cast<const MethodOptions &>(from));
 }
@@ -9112,7 +9109,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.UninterpretedOption.NamePart.name_part");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // required bool is_extension = 2;
       case 2:
@@ -9120,29 +9118,30 @@
           _Internal::set_has_is_extension(&has_bits);
           is_extension_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -9215,13 +9214,7 @@
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UninterpretedOption_NamePart::_class_data_ = {
@@ -9230,8 +9223,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UninterpretedOption_NamePart::GetClassData() const { return &_class_data_; }
 
-void UninterpretedOption_NamePart::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void UninterpretedOption_NamePart::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<UninterpretedOption_NamePart *>(to)->MergeFrom(
       static_cast<const UninterpretedOption_NamePart &>(from));
 }
@@ -9270,12 +9263,14 @@
 
 void UninterpretedOption_NamePart::InternalSwap(UninterpretedOption_NamePart* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_part_, GetArenaForAllocation(),
-      &other->name_part_, other->GetArenaForAllocation()
+      &name_part_, lhs_arena,
+      &other->name_part_, rhs_arena
   );
   swap(is_extension_, other->is_extension_);
 }
@@ -9426,7 +9421,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string identifier_value = 3;
       case 3:
@@ -9437,7 +9433,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.UninterpretedOption.identifier_value");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional uint64 positive_int_value = 4;
       case 4:
@@ -9445,7 +9442,8 @@
           _Internal::set_has_positive_int_value(&has_bits);
           positive_int_value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int64 negative_int_value = 5;
       case 5:
@@ -9453,7 +9451,8 @@
           _Internal::set_has_negative_int_value(&has_bits);
           negative_int_value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional double double_value = 6;
       case 6:
@@ -9461,7 +9460,8 @@
           _Internal::set_has_double_value(&has_bits);
           double_value_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<double>(ptr);
           ptr += sizeof(double);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional bytes string_value = 7;
       case 7:
@@ -9469,7 +9469,8 @@
           auto str = _internal_mutable_string_value();
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string aggregate_value = 8;
       case 8:
@@ -9480,29 +9481,30 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.UninterpretedOption.aggregate_value");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -9613,16 +9615,12 @@
 
     // optional uint64 positive_int_value = 4;
     if (cached_has_bits & 0x00000008u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64Size(
-          this->_internal_positive_int_value());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64SizePlusOne(this->_internal_positive_int_value());
     }
 
     // optional int64 negative_int_value = 5;
     if (cached_has_bits & 0x00000010u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64Size(
-          this->_internal_negative_int_value());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_negative_int_value());
     }
 
     // optional double double_value = 6;
@@ -9631,13 +9629,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UninterpretedOption::_class_data_ = {
@@ -9646,8 +9638,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UninterpretedOption::GetClassData() const { return &_class_data_; }
 
-void UninterpretedOption::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void UninterpretedOption::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<UninterpretedOption *>(to)->MergeFrom(
       static_cast<const UninterpretedOption &>(from));
 }
@@ -9699,23 +9691,25 @@
 
 void UninterpretedOption::InternalSwap(UninterpretedOption* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   name_.InternalSwap(&other->name_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &identifier_value_, GetArenaForAllocation(),
-      &other->identifier_value_, other->GetArenaForAllocation()
+      &identifier_value_, lhs_arena,
+      &other->identifier_value_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &string_value_, GetArenaForAllocation(),
-      &other->string_value_, other->GetArenaForAllocation()
+      &string_value_, lhs_arena,
+      &other->string_value_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &aggregate_value_, GetArenaForAllocation(),
-      &other->aggregate_value_, other->GetArenaForAllocation()
+      &aggregate_value_, lhs_arena,
+      &other->aggregate_value_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(UninterpretedOption, double_value_)
@@ -9841,7 +9835,8 @@
         } else if (static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8) {
           _internal_add_path(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated int32 span = 2 [packed = true];
       case 2:
@@ -9851,7 +9846,8 @@
         } else if (static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 16) {
           _internal_add_span(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string leading_comments = 3;
       case 3:
@@ -9862,7 +9858,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.leading_comments");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string trailing_comments = 4;
       case 4:
@@ -9873,7 +9870,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.trailing_comments");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated string leading_detached_comments = 6;
       case 6:
@@ -9889,29 +9887,30 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -10041,13 +10040,7 @@
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData SourceCodeInfo_Location::_class_data_ = {
@@ -10056,8 +10049,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceCodeInfo_Location::GetClassData() const { return &_class_data_; }
 
-void SourceCodeInfo_Location::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void SourceCodeInfo_Location::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<SourceCodeInfo_Location *>(to)->MergeFrom(
       static_cast<const SourceCodeInfo_Location &>(from));
 }
@@ -10097,6 +10090,8 @@
 
 void SourceCodeInfo_Location::InternalSwap(SourceCodeInfo_Location* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   path_.InternalSwap(&other->path_);
@@ -10104,13 +10099,13 @@
   leading_detached_comments_.InternalSwap(&other->leading_detached_comments_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &leading_comments_, GetArenaForAllocation(),
-      &other->leading_comments_, other->GetArenaForAllocation()
+      &leading_comments_, lhs_arena,
+      &other->leading_comments_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &trailing_comments_, GetArenaForAllocation(),
-      &other->trailing_comments_, other->GetArenaForAllocation()
+      &trailing_comments_, lhs_arena,
+      &other->trailing_comments_, rhs_arena
   );
 }
 
@@ -10193,28 +10188,29 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -10255,13 +10251,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData SourceCodeInfo::_class_data_ = {
@@ -10270,8 +10260,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceCodeInfo::GetClassData() const { return &_class_data_; }
 
-void SourceCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void SourceCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<SourceCodeInfo *>(to)->MergeFrom(
       static_cast<const SourceCodeInfo &>(from));
 }
@@ -10417,7 +10407,8 @@
         } else if (static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8) {
           _internal_add_path(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional string source_file = 2;
       case 2:
@@ -10428,7 +10419,8 @@
           ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
           #endif  // !NDEBUG
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 begin = 3;
       case 3:
@@ -10436,7 +10428,8 @@
           _Internal::set_has_begin(&has_bits);
           begin_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // optional int32 end = 4;
       case 4:
@@ -10444,29 +10437,30 @@
           _Internal::set_has_end(&has_bits);
           end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   _has_bits_.Or(has_bits);
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -10550,26 +10544,16 @@
 
     // optional int32 begin = 3;
     if (cached_has_bits & 0x00000002u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_begin());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_begin());
     }
 
     // optional int32 end = 4;
     if (cached_has_bits & 0x00000004u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-          this->_internal_end());
+      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_end());
     }
 
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData GeneratedCodeInfo_Annotation::_class_data_ = {
@@ -10578,8 +10562,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GeneratedCodeInfo_Annotation::GetClassData() const { return &_class_data_; }
 
-void GeneratedCodeInfo_Annotation::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void GeneratedCodeInfo_Annotation::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<GeneratedCodeInfo_Annotation *>(to)->MergeFrom(
       static_cast<const GeneratedCodeInfo_Annotation &>(from));
 }
@@ -10621,13 +10605,15 @@
 
 void GeneratedCodeInfo_Annotation::InternalSwap(GeneratedCodeInfo_Annotation* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   path_.InternalSwap(&other->path_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &source_file_, GetArenaForAllocation(),
-      &other->source_file_, other->GetArenaForAllocation()
+      &source_file_, lhs_arena,
+      &other->source_file_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(GeneratedCodeInfo_Annotation, end_)
@@ -10716,28 +10702,29 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -10778,13 +10765,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData GeneratedCodeInfo::_class_data_ = {
@@ -10793,8 +10774,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GeneratedCodeInfo::GetClassData() const { return &_class_data_; }
 
-void GeneratedCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void GeneratedCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<GeneratedCodeInfo *>(to)->MergeFrom(
       static_cast<const GeneratedCodeInfo &>(from));
 }
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index b72cdea..968b70c 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -413,7 +413,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const FileDescriptorSet& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -568,7 +568,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const FileDescriptorProto& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -958,7 +958,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const DescriptorProto_ExtensionRange& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -1144,7 +1144,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const DescriptorProto_ReservedRange& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -1310,7 +1310,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const DescriptorProto& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -1655,7 +1655,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const ExtensionRangeOptions& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -1713,7 +1713,196 @@
   const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
       uninterpreted_option() const;
 
-  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ExtensionRangeOptions)
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline PROTOBUF_MUST_USE_RESULT
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_extensions_);
+  }
+
   // @@protoc_insertion_point(class_scope:google.protobuf.ExtensionRangeOptions)
  private:
   class _Internal;
@@ -1813,7 +2002,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const FieldDescriptorProto& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -2238,7 +2427,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const OneofDescriptorProto& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -2414,7 +2603,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const EnumDescriptorProto_EnumReservedRange& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -2580,7 +2769,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const EnumDescriptorProto& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -2824,7 +3013,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const EnumValueDescriptorProto& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -3015,7 +3204,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const ServiceDescriptorProto& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -3211,7 +3400,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const MethodDescriptorProto& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -3457,7 +3646,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const FileOptions& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -3877,7 +4066,196 @@
   void _internal_set_cc_enable_arenas(bool value);
   public:
 
-  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions)
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline PROTOBUF_MUST_USE_RESULT
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_extensions_);
+  }
+
   // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions)
  private:
   class _Internal;
@@ -3998,7 +4376,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const MessageOptions& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -4112,7 +4490,196 @@
   void _internal_set_map_entry(bool value);
   public:
 
-  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions)
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline PROTOBUF_MUST_USE_RESULT
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_extensions_);
+  }
+
   // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions)
  private:
   class _Internal;
@@ -4217,7 +4784,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const FieldOptions& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -4423,7 +4990,196 @@
   void _internal_set_jstype(PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value);
   public:
 
-  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions)
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline PROTOBUF_MUST_USE_RESULT
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_extensions_);
+  }
+
   // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions)
  private:
   class _Internal;
@@ -4530,7 +5286,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const OneofOptions& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -4588,7 +5344,196 @@
   const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
       uninterpreted_option() const;
 
-  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(OneofOptions)
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline PROTOBUF_MUST_USE_RESULT
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_extensions_);
+  }
+
   // @@protoc_insertion_point(class_scope:google.protobuf.OneofOptions)
  private:
   class _Internal;
@@ -4688,7 +5633,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const EnumOptions& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -4774,7 +5719,196 @@
   void _internal_set_deprecated(bool value);
   public:
 
-  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions)
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline PROTOBUF_MUST_USE_RESULT
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_extensions_);
+  }
+
   // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions)
  private:
   class _Internal;
@@ -4877,7 +6011,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const EnumValueOptions& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -4949,7 +6083,196 @@
   void _internal_set_deprecated(bool value);
   public:
 
-  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions)
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline PROTOBUF_MUST_USE_RESULT
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_extensions_);
+  }
+
   // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions)
  private:
   class _Internal;
@@ -5051,7 +6374,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const ServiceOptions& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -5123,7 +6446,196 @@
   void _internal_set_deprecated(bool value);
   public:
 
-  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions)
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline PROTOBUF_MUST_USE_RESULT
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_extensions_);
+  }
+
   // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions)
  private:
   class _Internal;
@@ -5225,7 +6737,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const MethodOptions& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -5343,7 +6855,196 @@
   void _internal_set_idempotency_level(PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel value);
   public:
 
-  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions)
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline PROTOBUF_MUST_USE_RESULT
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_extensions_);
+  }
+
   // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions)
  private:
   class _Internal;
@@ -5446,7 +7147,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const UninterpretedOption_NamePart& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -5620,7 +7321,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const UninterpretedOption& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -5883,7 +7584,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const SourceCodeInfo_Location& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -6135,7 +7836,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const SourceCodeInfo& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -6292,7 +7993,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const GeneratedCodeInfo_Annotation& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -6503,7 +8204,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const GeneratedCodeInfo& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc
index 5f53cd1..b101dd2 100644
--- a/src/google/protobuf/descriptor_database.cc
+++ b/src/google/protobuf/descriptor_database.cc
@@ -587,10 +587,10 @@
 
   // Optimization:  The name should be the first field in the encoded message.
   //   Try to just read it directly.
-  io::CodedInputStream input(static_cast<const uint8*>(encoded_file.first),
+  io::CodedInputStream input(static_cast<const uint8_t*>(encoded_file.first),
                              encoded_file.second);
 
-  const uint32 kNameTag = internal::WireFormatLite::MakeTag(
+  const uint32_t kNameTag = internal::WireFormatLite::MakeTag(
       FileDescriptorProto::kNameFieldNumber,
       internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
 
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index a7e5db2..b98e7f7 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -56,6 +56,7 @@
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <gmock/gmock.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 #include <google/protobuf/stubs/logging.h>
@@ -723,6 +724,8 @@
     AddField(message4, "field_name6", 6, FieldDescriptorProto::LABEL_OPTIONAL,
              FieldDescriptorProto::TYPE_INT32)
         ->set_json_name("@type");
+    AddField(message4, "fieldname7", 7, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
 
     // Build the descriptors and get the pointers.
     foo_file_ = pool_.BuildFile(foo_file);
@@ -814,6 +817,46 @@
   EXPECT_TRUE(message2_->containing_type() == nullptr);
 }
 
+TEST_F(DescriptorTest, FieldNamesDedup) {
+  const auto collect_unique_names = [](const FieldDescriptor* field) {
+    std::set<std::string> names{field->name(), field->lowercase_name(),
+                                field->camelcase_name(), field->json_name()};
+    // Verify that we have the same number of string objects as we have string
+    // values. That is, duplicate names use the same std::string object.
+    // This is for memory efficiency.
+    EXPECT_EQ(names.size(), (std::set<const std::string*>{
+                                &field->name(), &field->lowercase_name(),
+                                &field->camelcase_name(), &field->json_name()}
+                                 .size()))
+        << testing::PrintToString(names);
+    return names;
+  };
+
+  using testing::ElementsAre;
+  // field_name1
+  EXPECT_THAT(collect_unique_names(message4_->field(0)),
+              ElementsAre("fieldName1", "field_name1"));
+  // fieldName2
+  EXPECT_THAT(collect_unique_names(message4_->field(1)),
+              ElementsAre("fieldName2", "fieldname2"));
+  // FieldName3
+  EXPECT_THAT(collect_unique_names(message4_->field(2)),
+              ElementsAre("FieldName3", "fieldName3", "fieldname3"));
+  // _field_name4
+  EXPECT_THAT(collect_unique_names(message4_->field(3)),
+              ElementsAre("FieldName4", "_field_name4", "fieldName4"));
+  // FIELD_NAME5
+  EXPECT_THAT(
+      collect_unique_names(message4_->field(4)),
+      ElementsAre("FIELDNAME5", "FIELD_NAME5", "fIELDNAME5", "field_name5"));
+  // field_name6, with json name @type
+  EXPECT_THAT(collect_unique_names(message4_->field(5)),
+              ElementsAre("@type", "fieldName6", "field_name6"));
+  // fieldname7
+  EXPECT_THAT(collect_unique_names(message4_->field(6)),
+              ElementsAre("fieldname7"));
+}
+
 TEST_F(DescriptorTest, FieldsByIndex) {
   ASSERT_EQ(4, message_->field_count());
   EXPECT_EQ(foo_, message_->field(0));
@@ -913,33 +956,36 @@
 
   DescriptorProto proto;
   message4_->CopyTo(&proto);
-  ASSERT_EQ(6, proto.field_size());
+  ASSERT_EQ(7, proto.field_size());
   EXPECT_FALSE(proto.field(0).has_json_name());
   EXPECT_FALSE(proto.field(1).has_json_name());
   EXPECT_FALSE(proto.field(2).has_json_name());
   EXPECT_FALSE(proto.field(3).has_json_name());
   EXPECT_FALSE(proto.field(4).has_json_name());
   EXPECT_EQ("@type", proto.field(5).json_name());
+  EXPECT_FALSE(proto.field(6).has_json_name());
 
   proto.Clear();
   CopyWithJsonName(message4_, &proto);
-  ASSERT_EQ(6, proto.field_size());
+  ASSERT_EQ(7, proto.field_size());
   EXPECT_EQ("fieldName1", proto.field(0).json_name());
   EXPECT_EQ("fieldName2", proto.field(1).json_name());
   EXPECT_EQ("FieldName3", proto.field(2).json_name());
   EXPECT_EQ("FieldName4", proto.field(3).json_name());
   EXPECT_EQ("FIELDNAME5", proto.field(4).json_name());
   EXPECT_EQ("@type", proto.field(5).json_name());
+  EXPECT_EQ("fieldname7", proto.field(6).json_name());
 
   // Test generated descriptor.
   const Descriptor* generated = protobuf_unittest::TestJsonName::descriptor();
-  ASSERT_EQ(6, generated->field_count());
+  ASSERT_EQ(7, generated->field_count());
   EXPECT_EQ("fieldName1", generated->field(0)->json_name());
   EXPECT_EQ("fieldName2", generated->field(1)->json_name());
   EXPECT_EQ("FieldName3", generated->field(2)->json_name());
   EXPECT_EQ("FieldName4", generated->field(3)->json_name());
   EXPECT_EQ("FIELDNAME5", generated->field(4)->json_name());
   EXPECT_EQ("@type", generated->field(5)->json_name());
+  EXPECT_EQ("fieldname7", generated->field(6)->json_name());
 }
 
 TEST_F(DescriptorTest, FieldFile) {
@@ -1858,6 +1904,7 @@
     //     repeated TestEnum foo_enum = 19;
     //   }
     //   message Bar {
+    //     optional int32 non_ext_int32 = 1;
     //     extend Foo {
     //       optional Qux foo_message = 30;
     //       repeated Qux foo_group = 39;  // (but internally set to TYPE_GROUP)
@@ -1883,6 +1930,8 @@
         ->set_type_name("Baz");
 
     DescriptorProto* bar = AddMessage(&foo_file, "Bar");
+    AddField(bar, "non_ext_int32", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
     AddNestedExtension(bar, "Foo", "foo_message", 30,
                        FieldDescriptorProto::LABEL_OPTIONAL,
                        FieldDescriptorProto::TYPE_MESSAGE)
@@ -1995,6 +2044,15 @@
   EXPECT_TRUE(foo_->FindExtensionByName("foo_message") == nullptr);
 }
 
+TEST_F(ExtensionDescriptorTest, FieldVsExtension) {
+  EXPECT_EQ(foo_->FindFieldByName("foo_message"), nullptr);
+  EXPECT_EQ(bar_->FindFieldByName("foo_message"), nullptr);
+  EXPECT_NE(bar_->FindFieldByName("non_ext_int32"), nullptr);
+  EXPECT_EQ(foo_->FindExtensionByName("foo_message"), nullptr);
+  EXPECT_NE(bar_->FindExtensionByName("foo_message"), nullptr);
+  EXPECT_EQ(bar_->FindExtensionByName("non_ext_int32"), nullptr);
+}
+
 TEST_F(ExtensionDescriptorTest, FindExtensionByPrintableName) {
   EXPECT_TRUE(pool_.FindExtensionByPrintableName(foo_, "no_such_extension") ==
               nullptr);
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index 2f02356..94c1f0a 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -41,11 +41,12 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Duration, seconds_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Duration, nanos_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::Duration)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Duration)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -150,35 +151,37 @@
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) {
           seconds_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // int32 nanos = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 16)) {
           nanos_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -218,25 +221,15 @@
 
   // int64 seconds = 1;
   if (this->_internal_seconds() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64Size(
-        this->_internal_seconds());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
   }
 
   // int32 nanos = 2;
   if (this->_internal_nanos() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-        this->_internal_nanos());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Duration::_class_data_ = {
@@ -245,8 +238,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Duration::GetClassData() const { return &_class_data_; }
 
-void Duration::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Duration::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Duration *>(to)->MergeFrom(
       static_cast<const Duration &>(from));
 }
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index 7a5caa0..b7bd056 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -142,7 +142,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Duration& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index 0bfb94a..a8b4a2c 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -55,8 +55,8 @@
 //
 // Note on memory allocation:  This module often calls "operator new()"
 // to allocate untyped memory, rather than calling something like
-// "new uint8[]".  This is because "operator new()" means "Give me some
-// space which I can use as I please." while "new uint8[]" means "Give
+// "new uint8_t[]".  This is because "operator new()" means "Give me some
+// space which I can use as I please." while "new uint8_t[]" means "Give
 // me an array of 8-bit integers.".  In practice, the later may return
 // a pointer that is not aligned correctly for general use.  I believe
 // Item 8 of "More Effective C++" discusses this in more detail, though
@@ -100,6 +100,14 @@
 // ===================================================================
 // Some helper tables and functions...
 
+class DynamicMessageReflectionHelper {
+ public:
+  static bool IsLazyField(const Reflection* reflection,
+                          const FieldDescriptor* field) {
+    return reflection->IsLazyField(field);
+  }
+};
+
 namespace {
 
 bool IsMapFieldInApi(const FieldDescriptor* field) { return field->is_map(); }
@@ -132,13 +140,13 @@
   if (field->label() == FD::LABEL_REPEATED) {
     switch (field->cpp_type()) {
       case FD::CPPTYPE_INT32:
-        return sizeof(RepeatedField<int32>);
+        return sizeof(RepeatedField<int32_t>);
       case FD::CPPTYPE_INT64:
-        return sizeof(RepeatedField<int64>);
+        return sizeof(RepeatedField<int64_t>);
       case FD::CPPTYPE_UINT32:
-        return sizeof(RepeatedField<uint32>);
+        return sizeof(RepeatedField<uint32_t>);
       case FD::CPPTYPE_UINT64:
-        return sizeof(RepeatedField<uint64>);
+        return sizeof(RepeatedField<uint64_t>);
       case FD::CPPTYPE_DOUBLE:
         return sizeof(RepeatedField<double>);
       case FD::CPPTYPE_FLOAT:
@@ -165,13 +173,13 @@
   } else {
     switch (field->cpp_type()) {
       case FD::CPPTYPE_INT32:
-        return sizeof(int32);
+        return sizeof(int32_t);
       case FD::CPPTYPE_INT64:
-        return sizeof(int64);
+        return sizeof(int64_t);
       case FD::CPPTYPE_UINT32:
-        return sizeof(uint32);
+        return sizeof(uint32_t);
       case FD::CPPTYPE_UINT64:
-        return sizeof(uint64);
+        return sizeof(uint64_t);
       case FD::CPPTYPE_DOUBLE:
         return sizeof(double);
       case FD::CPPTYPE_FLOAT:
@@ -200,8 +208,8 @@
 
 inline int DivideRoundingUp(int i, int j) { return (i + (j - 1)) / j; }
 
-static const int kSafeAlignment = sizeof(uint64);
-static const int kMaxOneofUnionSize = sizeof(uint64);
+static const int kSafeAlignment = sizeof(uint64_t);
+static const int kMaxOneofUnionSize = sizeof(uint64_t);
 
 inline int AlignTo(int offset, int alignment) {
   return DivideRoundingUp(offset, alignment) * alignment;
@@ -270,13 +278,26 @@
 
   bool is_prototype() const;
 
+  inline int OffsetValue(int v, FieldDescriptor::Type type) const {
+    if (type == FieldDescriptor::TYPE_MESSAGE) {
+      return v & ~0x1u;
+    }
+    return v;
+  }
+
   inline void* OffsetToPointer(int offset) {
-    return reinterpret_cast<uint8*>(this) + offset;
+    return reinterpret_cast<uint8_t*>(this) + offset;
   }
   inline const void* OffsetToPointer(int offset) const {
-    return reinterpret_cast<const uint8*>(this) + offset;
+    return reinterpret_cast<const uint8_t*>(this) + offset;
   }
 
+  void* MutableRaw(int i);
+  void* MutableExtensionsRaw();
+  void* MutableWeakFieldMapRaw();
+  void* MutableOneofCaseRaw(int i);
+  void* MutableOneofFieldRaw(const FieldDescriptor* f);
+
   const DynamicMessageFactory::TypeInfo* type_info_;
   mutable std::atomic<int> cached_byte_size_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
@@ -295,8 +316,8 @@
 
   // Warning:  The order in which the following pointers are defined is
   //   important (the prototype must be deleted *before* the offsets).
-  std::unique_ptr<uint32[]> offsets;
-  std::unique_ptr<uint32[]> has_bits_indices;
+  std::unique_ptr<uint32_t[]> offsets;
+  std::unique_ptr<uint32_t[]> has_bits_indices;
   std::unique_ptr<const Reflection> reflection;
   // Don't use a unique_ptr to hold the prototype: the destructor for
   // DynamicMessage needs to know whether it is the prototype, and does so by
@@ -325,7 +346,7 @@
                                bool lock_factory)
     : type_info_(type_info), cached_byte_size_(0) {
   // The prototype in type_info has to be set before creating the prototype
-  // instance on memory. e.g., message Foo { map<int32, Foo> a = 1; }. When
+  // instance on memory. e.g., message Foo { map<int32_t, Foo> a = 1; }. When
   // creating prototype for Foo, prototype of the map entry will also be
   // created, which needs the address of the prototype of Foo (the value in
   // map). To break the cyclic dependency, we have to assign the address of
@@ -334,6 +355,26 @@
   SharedCtor(lock_factory);
 }
 
+void* DynamicMessage::MutableRaw(int i) {
+  return OffsetToPointer(
+      OffsetValue(type_info_->offsets[i], type_info_->type->field(i)->type()));
+}
+void* DynamicMessage::MutableExtensionsRaw() {
+  return OffsetToPointer(type_info_->extensions_offset);
+}
+void* DynamicMessage::MutableWeakFieldMapRaw() {
+  return OffsetToPointer(type_info_->weak_field_map_offset);
+}
+void* DynamicMessage::MutableOneofCaseRaw(int i) {
+  return OffsetToPointer(type_info_->oneof_case_offset + sizeof(uint32_t) * i);
+}
+void* DynamicMessage::MutableOneofFieldRaw(const FieldDescriptor* f) {
+  return OffsetToPointer(
+      OffsetValue(type_info_->offsets[type_info_->type->field_count() +
+                                      f->containing_oneof()->index()],
+                  f->type()));
+}
+
 void DynamicMessage::SharedCtor(bool lock_factory) {
   // We need to call constructors for various fields manually and set
   // default values where appropriate.  We use placement new to call
@@ -349,17 +390,15 @@
   int oneof_count = 0;
   for (int i = 0; i < descriptor->oneof_decl_count(); ++i) {
     if (descriptor->oneof_decl(i)->is_synthetic()) continue;
-    new (OffsetToPointer(type_info_->oneof_case_offset +
-                         sizeof(uint32) * oneof_count++)) uint32(0);
+    new (MutableOneofCaseRaw(oneof_count++)) uint32_t{0};
   }
 
   if (type_info_->extensions_offset != -1) {
-    new (OffsetToPointer(type_info_->extensions_offset))
-        ExtensionSet(GetArenaForAllocation());
+    new (MutableExtensionsRaw()) ExtensionSet(GetArenaForAllocation());
   }
   for (int i = 0; i < descriptor->field_count(); i++) {
     const FieldDescriptor* field = descriptor->field(i);
-    void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
+    void* field_ptr = MutableRaw(i);
     if (InRealOneof(field)) {
       continue;
     }
@@ -373,10 +412,10 @@
     }                                                               \
     break;
 
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(BOOL, bool);
@@ -384,7 +423,7 @@
 
       case FieldDescriptor::CPPTYPE_ENUM:
         if (!field->is_repeated()) {
-          new (field_ptr) int(field->default_value_enum()->number());
+          new (field_ptr) int{field->default_value_enum()->number()};
         } else {
           new (field_ptr) RepeatedField<int>(GetArenaForAllocation());
         }
@@ -480,9 +519,7 @@
   _internal_metadata_.Delete<UnknownFieldSet>();
 
   if (type_info_->extensions_offset != -1) {
-    reinterpret_cast<ExtensionSet*>(
-        OffsetToPointer(type_info_->extensions_offset))
-        ->~ExtensionSet();
+    reinterpret_cast<ExtensionSet*>(MutableExtensionsRaw())->~ExtensionSet();
   }
 
   // We need to manually run the destructors for repeated fields and strings,
@@ -496,13 +533,9 @@
   for (int i = 0; i < descriptor->field_count(); i++) {
     const FieldDescriptor* field = descriptor->field(i);
     if (InRealOneof(field)) {
-      void* field_ptr =
-          OffsetToPointer(type_info_->oneof_case_offset +
-                          sizeof(uint32) * field->containing_oneof()->index());
-      if (*(reinterpret_cast<const int32*>(field_ptr)) == field->number()) {
-        field_ptr = OffsetToPointer(
-            type_info_->offsets[descriptor->field_count() +
-                                field->containing_oneof()->index()]);
+      void* field_ptr = MutableOneofCaseRaw(field->containing_oneof()->index());
+      if (*(reinterpret_cast<const int32_t*>(field_ptr)) == field->number()) {
+        field_ptr = MutableOneofFieldRaw(field);
         if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
           switch (field->options().ctype()) {
             default:
@@ -523,7 +556,7 @@
       }
       continue;
     }
-    void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
+    void* field_ptr = MutableRaw(i);
 
     if (field->is_repeated()) {
       switch (field->cpp_type()) {
@@ -533,10 +566,10 @@
         ->~RepeatedField<LOWERCASE>();                     \
     break
 
-        HANDLE_TYPE(INT32, int32);
-        HANDLE_TYPE(INT64, int64);
-        HANDLE_TYPE(UINT32, uint32);
-        HANDLE_TYPE(UINT64, uint64);
+        HANDLE_TYPE(INT32, int32_t);
+        HANDLE_TYPE(INT64, int64_t);
+        HANDLE_TYPE(UINT32, uint32_t);
+        HANDLE_TYPE(UINT64, uint64_t);
         HANDLE_TYPE(DOUBLE, double);
         HANDLE_TYPE(FLOAT, float);
         HANDLE_TYPE(BOOL, bool);
@@ -598,10 +631,10 @@
   // Cross-link default messages.
   for (int i = 0; i < descriptor->field_count(); i++) {
     const FieldDescriptor* field = descriptor->field(i);
-    void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
         !field->options().weak() && !InRealOneof(field) &&
         !field->is_repeated()) {
+      void* field_ptr = MutableRaw(i);
       // For fields with message types, we need to cross-link with the
       // prototype for the field's type.
       // For singular fields, the field is just a pointer which should
@@ -695,7 +728,7 @@
   }
 
   // Compute size and offsets.
-  uint32* offsets = new uint32[type->field_count() + real_oneof_count];
+  uint32_t* offsets = new uint32_t[type->field_count() + real_oneof_count];
   type_info->offsets.reset(offsets);
 
   // Decide all field offsets by packing in order.
@@ -713,10 +746,10 @@
         // At least one field in the message requires a hasbit, so allocate
         // hasbits.
         type_info->has_bits_offset = size;
-        uint32* has_bits_indices = new uint32[type->field_count()];
+        uint32_t* has_bits_indices = new uint32_t[type->field_count()];
         for (int i = 0; i < type->field_count(); i++) {
           // Initialize to -1, fields that need a hasbit will overwrite.
-          has_bits_indices[i] = static_cast<uint32>(-1);
+          has_bits_indices[i] = static_cast<uint32_t>(-1);
         }
         type_info->has_bits_indices.reset(has_bits_indices);
       }
@@ -725,15 +758,15 @@
   }
 
   if (max_hasbit > 0) {
-    int has_bits_array_size = DivideRoundingUp(max_hasbit, bitsizeof(uint32));
-    size += has_bits_array_size * sizeof(uint32);
+    int has_bits_array_size = DivideRoundingUp(max_hasbit, bitsizeof(uint32_t));
+    size += has_bits_array_size * sizeof(uint32_t);
     size = AlignOffset(size);
   }
 
   // The oneof_case, if any. It is an array of uint32s.
   if (real_oneof_count > 0) {
     type_info->oneof_case_offset = size;
-    size += real_oneof_count * sizeof(uint32);
+    size += real_oneof_count * sizeof(uint32_t);
     size = AlignOffset(size);
   }
 
diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h
index b85e00f..d0af57c 100644
--- a/src/google/protobuf/dynamic_message.h
+++ b/src/google/protobuf/dynamic_message.h
@@ -182,23 +182,23 @@
           return first < second;
         }
         case FieldDescriptor::CPPTYPE_INT32: {
-          int32 first = reflection->GetInt32(*a, field_);
-          int32 second = reflection->GetInt32(*b, field_);
+          int32_t first = reflection->GetInt32(*a, field_);
+          int32_t second = reflection->GetInt32(*b, field_);
           return first < second;
         }
         case FieldDescriptor::CPPTYPE_INT64: {
-          int64 first = reflection->GetInt64(*a, field_);
-          int64 second = reflection->GetInt64(*b, field_);
+          int64_t first = reflection->GetInt64(*a, field_);
+          int64_t second = reflection->GetInt64(*b, field_);
           return first < second;
         }
         case FieldDescriptor::CPPTYPE_UINT32: {
-          uint32 first = reflection->GetUInt32(*a, field_);
-          uint32 second = reflection->GetUInt32(*b, field_);
+          uint32_t first = reflection->GetUInt32(*a, field_);
+          uint32_t second = reflection->GetUInt32(*b, field_);
           return first < second;
         }
         case FieldDescriptor::CPPTYPE_UINT64: {
-          uint64 first = reflection->GetUInt64(*a, field_);
-          uint64 second = reflection->GetUInt64(*b, field_);
+          uint64_t first = reflection->GetUInt64(*a, field_);
+          uint64_t second = reflection->GetUInt64(*b, field_);
           return first < second;
         }
         case FieldDescriptor::CPPTYPE_STRING: {
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 96ee74a..126587b 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -39,9 +39,10 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::Empty)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Empty)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -78,144 +79,30 @@
 
 Empty::Empty(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                          bool is_message_owned)
-  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
-  SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
+  : ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase(arena, is_message_owned) {
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Empty)
 }
 Empty::Empty(const Empty& from)
-  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  : ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase() {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.Empty)
 }
 
-void Empty::SharedCtor() {
-}
 
-Empty::~Empty() {
-  // @@protoc_insertion_point(destructor:google.protobuf.Empty)
-  if (GetArenaForAllocation() != nullptr) return;
-  SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
-}
 
-inline void Empty::SharedDtor() {
-  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
-}
 
-void Empty::ArenaDtor(void* object) {
-  Empty* _this = reinterpret_cast< Empty* >(object);
-  (void)_this;
-}
-void Empty::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
-void Empty::SetCachedSize(int size) const {
-  _cached_size_.Set(size);
-}
-
-void Empty::Clear() {
-// @@protoc_insertion_point(message_clear_start:google.protobuf.Empty)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  // Prevent compiler warnings about cached_has_bits being unused
-  (void) cached_has_bits;
-
-  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
-}
-
-const char* Empty::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
-  while (!ctx->Done(&ptr)) {
-    ::PROTOBUF_NAMESPACE_ID::uint32 tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-  }  // while
-success:
-  return ptr;
-failure:
-  ptr = nullptr;
-  goto success;
-#undef CHK_
-}
-
-::PROTOBUF_NAMESPACE_ID::uint8* Empty::_InternalSerialize(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
-  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Empty)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
-  }
-  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Empty)
-  return target;
-}
-
-size_t Empty::ByteSizeLong() const {
-// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Empty)
-  size_t total_size = 0;
-
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  // Prevent compiler warnings about cached_has_bits being unused
-  (void) cached_has_bits;
-
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
-}
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Empty::_class_data_ = {
-    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck,
-    Empty::MergeImpl
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::CopyImpl,
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::MergeImpl,
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Empty::GetClassData() const { return &_class_data_; }
 
-void Empty::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
-  static_cast<Empty *>(to)->MergeFrom(
-      static_cast<const Empty &>(from));
-}
 
 
-void Empty::MergeFrom(const Empty& from) {
-// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Empty)
-  GOOGLE_DCHECK_NE(&from, this);
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
 
-  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-}
 
-void Empty::CopyFrom(const Empty& from) {
-// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Empty)
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
 
-bool Empty::IsInitialized() const {
-  return true;
-}
-
-void Empty::InternalSwap(Empty* other) {
-  using std::swap;
-  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
-}
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Empty::GetMetadata() const {
   return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index 64a3bde..84d914d 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -66,10 +66,9 @@
 // ===================================================================
 
 class PROTOBUF_EXPORT Empty final :
-    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Empty) */ {
+    public ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase /* @@protoc_insertion_point(class_definition:google.protobuf.Empty) */ {
  public:
   inline Empty() : Empty(nullptr) {}
-  ~Empty() override;
   explicit constexpr Empty(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
 
   Empty(const Empty& from);
@@ -137,27 +136,15 @@
   Empty* New(::PROTOBUF_NAMESPACE_ID::Arena* arena) const final {
     return CreateMaybeMessage<Empty>(arena);
   }
-  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
-  void CopyFrom(const Empty& from);
-  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
-  void MergeFrom(const Empty& from);
-  private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  using ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::CopyFrom;
+  inline void CopyFrom(const Empty& from) {
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::CopyImpl(this, from);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::MergeFrom;
+  void MergeFrom(const Empty& from) {
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::MergeImpl(this, from);
+  }
   public:
-  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
-  bool IsInitialized() const final;
-
-  size_t ByteSizeLong() const final;
-  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
-  ::PROTOBUF_NAMESPACE_ID::uint8* _InternalSerialize(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
-  int GetCachedSize() const final { return _cached_size_.Get(); }
-
-  private:
-  void SharedCtor();
-  void SharedDtor();
-  void SetCachedSize(int size) const final;
-  void InternalSwap(Empty* other);
   friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
   static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
     return "google.protobuf.Empty";
@@ -166,8 +153,6 @@
   explicit Empty(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
   private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index bad23a6..2d5ca21 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -35,8 +35,9 @@
 #include <google/protobuf/extension_set.h>
 
 #include <tuple>
-#include <unordered_map>
+#include <unordered_set>
 #include <utility>
+
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/extension_set_inl.h>
 #include <google/protobuf/parse_context.h>
@@ -84,39 +85,53 @@
 }
 
 // Registry stuff.
-struct ExtensionHasher {
-  std::size_t operator()(const std::pair<const MessageLite*, int>& p) const {
-    return std::hash<const MessageLite*>{}(p.first) ^
-           std::hash<int>{}(p.second);
+
+// Note that we cannot use hetererogeneous lookup for std containers since we
+// need to support C++11.
+struct ExtensionEq {
+  bool operator()(const ExtensionInfo& lhs, const ExtensionInfo& rhs) const {
+    return lhs.message == rhs.message && lhs.number == rhs.number;
   }
 };
 
-typedef std::unordered_map<std::pair<const MessageLite*, int>, ExtensionInfo,
-                           ExtensionHasher>
-    ExtensionRegistry;
+struct ExtensionHasher {
+  std::size_t operator()(const ExtensionInfo& info) const {
+    return std::hash<const MessageLite*>{}(info.message) ^
+           std::hash<int>{}(info.number);
+  }
+};
+
+using ExtensionRegistry =
+    std::unordered_set<ExtensionInfo, ExtensionHasher, ExtensionEq>;
 
 static const ExtensionRegistry* global_registry = nullptr;
 
 // This function is only called at startup, so there is no need for thread-
 // safety.
-void Register(const MessageLite* containing_type, int number,
-              ExtensionInfo info) {
+void Register(const ExtensionInfo& info) {
   static auto local_static_registry = OnShutdownDelete(new ExtensionRegistry);
   global_registry = local_static_registry;
-  if (!InsertIfNotPresent(local_static_registry,
-                               std::make_pair(containing_type, number), info)) {
+  if (!InsertIfNotPresent(local_static_registry, info)) {
     GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \""
-               << containing_type->GetTypeName() << "\", field number "
-               << number << ".";
+               << info.message->GetTypeName() << "\", field number "
+               << info.number << ".";
   }
 }
 
-const ExtensionInfo* FindRegisteredExtension(const MessageLite* containing_type,
+const ExtensionInfo* FindRegisteredExtension(const MessageLite* extendee,
                                              int number) {
-  return global_registry == nullptr
-             ? nullptr
-             : FindOrNull(*global_registry,
-                               std::make_pair(containing_type, number));
+  if (!global_registry) return nullptr;
+
+  ExtensionInfo info;
+  info.message = extendee;
+  info.number = number;
+
+  auto it = global_registry->find(info);
+  if (it == global_registry->end()) {
+    return nullptr;
+  } else {
+    return &*it;
+  }
 }
 
 }  // namespace
@@ -124,8 +139,7 @@
 ExtensionFinder::~ExtensionFinder() {}
 
 bool GeneratedExtensionFinder::Find(int number, ExtensionInfo* output) {
-  const ExtensionInfo* extension =
-      FindRegisteredExtension(containing_type_, number);
+  const ExtensionInfo* extension = FindRegisteredExtension(extendee_, number);
   if (extension == NULL) {
     return false;
   } else {
@@ -134,14 +148,14 @@
   }
 }
 
-void ExtensionSet::RegisterExtension(const MessageLite* containing_type,
-                                     int number, FieldType type,
-                                     bool is_repeated, bool is_packed) {
+void ExtensionSet::RegisterExtension(const MessageLite* extendee, int number,
+                                     FieldType type, bool is_repeated,
+                                     bool is_packed) {
   GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_ENUM);
   GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_MESSAGE);
   GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_GROUP);
-  ExtensionInfo info(type, is_repeated, is_packed);
-  Register(containing_type, number, info);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed);
+  Register(info);
 }
 
 static bool CallNoArgValidityFunc(const void* arg, int number) {
@@ -157,27 +171,27 @@
   return ((EnumValidityFunc*)arg)(number);
 }
 
-void ExtensionSet::RegisterEnumExtension(const MessageLite* containing_type,
+void ExtensionSet::RegisterEnumExtension(const MessageLite* extendee,
                                          int number, FieldType type,
                                          bool is_repeated, bool is_packed,
                                          EnumValidityFunc* is_valid) {
   GOOGLE_CHECK_EQ(type, WireFormatLite::TYPE_ENUM);
-  ExtensionInfo info(type, is_repeated, is_packed);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed);
   info.enum_validity_check.func = CallNoArgValidityFunc;
   // See comment in CallNoArgValidityFunc() about why we use a c-style cast.
   info.enum_validity_check.arg = (void*)is_valid;
-  Register(containing_type, number, info);
+  Register(info);
 }
 
-void ExtensionSet::RegisterMessageExtension(const MessageLite* containing_type,
+void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee,
                                             int number, FieldType type,
                                             bool is_repeated, bool is_packed,
                                             const MessageLite* prototype) {
   GOOGLE_CHECK(type == WireFormatLite::TYPE_MESSAGE ||
         type == WireFormatLite::TYPE_GROUP);
-  ExtensionInfo info(type, is_repeated, is_packed);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed);
   info.message_info = {prototype};
-  Register(containing_type, number, info);
+  Register(info);
 }
 
 // ===================================================================
@@ -204,7 +218,7 @@
 }
 
 void ExtensionSet::DeleteFlatMap(const ExtensionSet::KeyValue* flat,
-                                 uint16 flat_capacity) {
+                                 uint16_t flat_capacity) {
 #ifdef __cpp_sized_deallocation
   // Arena::CreateArray already requires a trivially destructible type, but
   // ensure this constraint is not violated in the future.
@@ -220,7 +234,7 @@
 }
 
 // Defined in extension_set_heavy.cc.
-// void ExtensionSet::AppendToList(const Descriptor* containing_type,
+// void ExtensionSet::AppendToList(const Descriptor* extendee,
 //                                 const DescriptorPool* pool,
 //                                 vector<const FieldDescriptor*>* output) const
 
@@ -293,6 +307,17 @@
     }                                                                         \
   }                                                                           \
                                                                               \
+  const LOWERCASE& ExtensionSet::GetRef##CAMELCASE(                           \
+      int number, const LOWERCASE& default_value) const {                     \
+    const Extension* extension = FindOrNull(number);                          \
+    if (extension == NULL || extension->is_cleared) {                         \
+      return default_value;                                                   \
+    } else {                                                                  \
+      GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE);                     \
+      return extension->LOWERCASE##_value;                                    \
+    }                                                                         \
+  }                                                                           \
+                                                                              \
   void ExtensionSet::Set##CAMELCASE(int number, FieldType type,               \
                                     LOWERCASE value,                          \
                                     const FieldDescriptor* descriptor) {      \
@@ -317,6 +342,14 @@
     return extension->repeated_##LOWERCASE##_value->Get(index);               \
   }                                                                           \
                                                                               \
+  const LOWERCASE& ExtensionSet::GetRefRepeated##CAMELCASE(int number,        \
+                                                           int index) const { \
+    const Extension* extension = FindOrNull(number);                          \
+    GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";      \
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                       \
+    return extension->repeated_##LOWERCASE##_value->Get(index);               \
+  }                                                                           \
+                                                                              \
   void ExtensionSet::SetRepeated##CAMELCASE(int number, int index,            \
                                             LOWERCASE value) {                \
     Extension* extension = FindOrNull(number);                                \
@@ -344,10 +377,10 @@
     extension->repeated_##LOWERCASE##_value->Add(value);                      \
   }
 
-PRIMITIVE_ACCESSORS(INT32, int32, Int32)
-PRIMITIVE_ACCESSORS(INT64, int64, Int64)
-PRIMITIVE_ACCESSORS(UINT32, uint32, UInt32)
-PRIMITIVE_ACCESSORS(UINT64, uint64, UInt64)
+PRIMITIVE_ACCESSORS(INT32, int32_t, Int32)
+PRIMITIVE_ACCESSORS(INT64, int64_t, Int64)
+PRIMITIVE_ACCESSORS(UINT32, uint32_t, UInt32)
+PRIMITIVE_ACCESSORS(UINT64, uint64_t, UInt64)
 PRIMITIVE_ACCESSORS(FLOAT, float, Float)
 PRIMITIVE_ACCESSORS(DOUBLE, double, Double)
 PRIMITIVE_ACCESSORS(BOOL, bool, Bool)
@@ -362,7 +395,7 @@
   }
   // We assume that all the RepeatedField<>* pointers have the same
   // size and alignment within the anonymous union in Extension.
-  return extension->repeated_int32_value;
+  return extension->repeated_int32_t_value;
 }
 
 void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type,
@@ -380,20 +413,20 @@
     switch (WireFormatLite::FieldTypeToCppType(
         static_cast<WireFormatLite::FieldType>(field_type))) {
       case WireFormatLite::CPPTYPE_INT32:
-        extension->repeated_int32_value =
-            Arena::CreateMessage<RepeatedField<int32>>(arena_);
+        extension->repeated_int32_t_value =
+            Arena::CreateMessage<RepeatedField<int32_t>>(arena_);
         break;
       case WireFormatLite::CPPTYPE_INT64:
-        extension->repeated_int64_value =
-            Arena::CreateMessage<RepeatedField<int64>>(arena_);
+        extension->repeated_int64_t_value =
+            Arena::CreateMessage<RepeatedField<int64_t>>(arena_);
         break;
       case WireFormatLite::CPPTYPE_UINT32:
-        extension->repeated_uint32_value =
-            Arena::CreateMessage<RepeatedField<uint32>>(arena_);
+        extension->repeated_uint32_t_value =
+            Arena::CreateMessage<RepeatedField<uint32_t>>(arena_);
         break;
       case WireFormatLite::CPPTYPE_UINT64:
-        extension->repeated_uint64_value =
-            Arena::CreateMessage<RepeatedField<uint64>>(arena_);
+        extension->repeated_uint64_t_value =
+            Arena::CreateMessage<RepeatedField<uint64_t>>(arena_);
         break;
       case WireFormatLite::CPPTYPE_DOUBLE:
         extension->repeated_double_value =
@@ -424,7 +457,7 @@
 
   // We assume that all the RepeatedField<>* pointers have the same
   // size and alignment within the anonymous union in Extension.
-  return extension->repeated_int32_value;
+  return extension->repeated_int32_t_value;
 }
 
 // Compatible version using old call signature. Does not create extensions when
@@ -434,7 +467,7 @@
   GOOGLE_CHECK(extension != NULL) << "Extension not found.";
   // We assume that all the RepeatedField<>* pointers have the same
   // size and alignment within the anonymous union in Extension.
-  return extension->repeated_int32_value;
+  return extension->repeated_int32_t_value;
 }
 
 // -------------------------------------------------------------------
@@ -451,6 +484,18 @@
   }
 }
 
+const int& ExtensionSet::GetRefEnum(int number,
+                                    const int& default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr || extension->is_cleared) {
+    // Not present.  Return the default value.
+    return default_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
+    return extension->enum_value;
+  }
+}
+
 void ExtensionSet::SetEnum(int number, FieldType type, int value,
                            const FieldDescriptor* descriptor) {
   Extension* extension;
@@ -467,14 +512,21 @@
 
 int ExtensionSet::GetRepeatedEnum(int number, int index) const {
   const Extension* extension = FindOrNull(number);
-  GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
+  return extension->repeated_enum_value->Get(index);
+}
+
+const int& ExtensionSet::GetRefRepeatedEnum(int number, int index) const {
+  const Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
   GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
   return extension->repeated_enum_value->Get(index);
 }
 
 void ExtensionSet::SetRepeatedEnum(int number, int index, int value) {
   Extension* extension = FindOrNull(number);
-  GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
   GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
   extension->repeated_enum_value->Set(index, value);
 }
@@ -616,10 +668,8 @@
     ClearExtension(number);
     return;
   }
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
   GOOGLE_DCHECK(message->GetOwningArena() == nullptr ||
          message->GetOwningArena() == arena_);
-#endif  // PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
   Arena* message_arena = message->GetOwningArena();
   Extension* extension;
   if (MaybeNewExtension(number, descriptor, &extension)) {
@@ -796,16 +846,16 @@
 
   switch (cpp_type(extension->type)) {
     case WireFormatLite::CPPTYPE_INT32:
-      extension->repeated_int32_value->RemoveLast();
+      extension->repeated_int32_t_value->RemoveLast();
       break;
     case WireFormatLite::CPPTYPE_INT64:
-      extension->repeated_int64_value->RemoveLast();
+      extension->repeated_int64_t_value->RemoveLast();
       break;
     case WireFormatLite::CPPTYPE_UINT32:
-      extension->repeated_uint32_value->RemoveLast();
+      extension->repeated_uint32_t_value->RemoveLast();
       break;
     case WireFormatLite::CPPTYPE_UINT64:
-      extension->repeated_uint64_value->RemoveLast();
+      extension->repeated_uint64_t_value->RemoveLast();
       break;
     case WireFormatLite::CPPTYPE_FLOAT:
       extension->repeated_float_value->RemoveLast();
@@ -836,6 +886,14 @@
   return extension->repeated_message_value->ReleaseLast();
 }
 
+MessageLite* ExtensionSet::UnsafeArenaReleaseLast(int number) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK(extension->is_repeated);
+  GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE);
+  return extension->repeated_message_value->UnsafeArenaReleaseLast();
+}
+
 void ExtensionSet::SwapElements(int number, int index1, int index2) {
   Extension* extension = FindOrNull(number);
   GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";
@@ -843,16 +901,16 @@
 
   switch (cpp_type(extension->type)) {
     case WireFormatLite::CPPTYPE_INT32:
-      extension->repeated_int32_value->SwapElements(index1, index2);
+      extension->repeated_int32_t_value->SwapElements(index1, index2);
       break;
     case WireFormatLite::CPPTYPE_INT64:
-      extension->repeated_int64_value->SwapElements(index1, index2);
+      extension->repeated_int64_t_value->SwapElements(index1, index2);
       break;
     case WireFormatLite::CPPTYPE_UINT32:
-      extension->repeated_uint32_value->SwapElements(index1, index2);
+      extension->repeated_uint32_t_value->SwapElements(index1, index2);
       break;
     case WireFormatLite::CPPTYPE_UINT64:
-      extension->repeated_uint64_value->SwapElements(index1, index2);
+      extension->repeated_uint64_t_value->SwapElements(index1, index2);
       break;
     case WireFormatLite::CPPTYPE_FLOAT:
       extension->repeated_float_value->SwapElements(index1, index2);
@@ -947,10 +1005,10 @@
         *other_extension.repeated_##LOWERCASE##_value);  \
     break;
 
-      HANDLE_TYPE(INT32, int32, RepeatedField<int32>);
-      HANDLE_TYPE(INT64, int64, RepeatedField<int64>);
-      HANDLE_TYPE(UINT32, uint32, RepeatedField<uint32>);
-      HANDLE_TYPE(UINT64, uint64, RepeatedField<uint64>);
+      HANDLE_TYPE(INT32, int32_t, RepeatedField<int32_t>);
+      HANDLE_TYPE(INT64, int64_t, RepeatedField<int64_t>);
+      HANDLE_TYPE(UINT32, uint32_t, RepeatedField<uint32_t>);
+      HANDLE_TYPE(UINT64, uint64_t, RepeatedField<uint64_t>);
       HANDLE_TYPE(FLOAT, float, RepeatedField<float>);
       HANDLE_TYPE(DOUBLE, double, RepeatedField<double>);
       HANDLE_TYPE(BOOL, bool, RepeatedField<bool>);
@@ -991,10 +1049,10 @@
                    other_extension.descriptor);       \
     break;
 
-        HANDLE_TYPE(INT32, int32, Int32);
-        HANDLE_TYPE(INT64, int64, Int64);
-        HANDLE_TYPE(UINT32, uint32, UInt32);
-        HANDLE_TYPE(UINT64, uint64, UInt64);
+        HANDLE_TYPE(INT32, int32_t, Int32);
+        HANDLE_TYPE(INT64, int64_t, Int64);
+        HANDLE_TYPE(UINT32, uint32_t, UInt32);
+        HANDLE_TYPE(UINT64, uint64_t, UInt64);
         HANDLE_TYPE(FLOAT, float, Float);
         HANDLE_TYPE(DOUBLE, double, Double);
         HANDLE_TYPE(BOOL, bool, Bool);
@@ -1158,7 +1216,7 @@
   return true;
 }
 
-bool ExtensionSet::FindExtensionInfoFromTag(uint32 tag,
+bool ExtensionSet::FindExtensionInfoFromTag(uint32_t tag,
                                             ExtensionFinder* extension_finder,
                                             int* field_number,
                                             ExtensionInfo* extension,
@@ -1172,7 +1230,7 @@
 
 bool ExtensionSet::FindExtensionInfoFromFieldNumber(
     int wire_type, int field_number, ExtensionFinder* extension_finder,
-    ExtensionInfo* extension, bool* was_packed_on_wire) {
+    ExtensionInfo* extension, bool* was_packed_on_wire) const {
   if (!extension_finder->Find(field_number, extension)) {
     return false;
   }
@@ -1192,7 +1250,7 @@
   return expected_wire_type == wire_type;
 }
 
-bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
+bool ExtensionSet::ParseField(uint32_t tag, io::CodedInputStream* input,
                               ExtensionFinder* extension_finder,
                               FieldSkipper* field_skipper) {
   int number;
@@ -1207,11 +1265,11 @@
   }
 }
 
-const char* ExtensionSet::ParseField(uint64 tag, const char* ptr,
-                                     const MessageLite* containing_type,
+const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr,
+                                     const MessageLite* extendee,
                                      internal::InternalMetadata* metadata,
                                      internal::ParseContext* ctx) {
-  GeneratedExtensionFinder finder(containing_type);
+  GeneratedExtensionFinder finder(extendee);
   int number = tag >> 3;
   bool was_packed_on_wire;
   ExtensionInfo extension;
@@ -1225,9 +1283,9 @@
 }
 
 const char* ExtensionSet::ParseMessageSetItem(
-    const char* ptr, const MessageLite* containing_type,
+    const char* ptr, const MessageLite* extendee,
     internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
-  return ParseMessageSetItemTmpl<MessageLite, std::string>(ptr, containing_type,
+  return ParseMessageSetItemTmpl<MessageLite, std::string>(ptr, extendee,
                                                            metadata, ctx);
 }
 
@@ -1239,7 +1297,7 @@
   // Explicitly not read extension.is_packed, instead check whether the field
   // was encoded in packed form on the wire.
   if (was_packed_on_wire) {
-    uint32 size;
+    uint32_t size;
     if (!input->ReadVarint32(&size)) return false;
     io::CodedInputStream::Limit limit = input->PushLimit(size);
 
@@ -1257,16 +1315,16 @@
     }                                                                       \
     break
 
-      HANDLE_TYPE(INT32, Int32, int32);
-      HANDLE_TYPE(INT64, Int64, int64);
-      HANDLE_TYPE(UINT32, UInt32, uint32);
-      HANDLE_TYPE(UINT64, UInt64, uint64);
-      HANDLE_TYPE(SINT32, Int32, int32);
-      HANDLE_TYPE(SINT64, Int64, int64);
-      HANDLE_TYPE(FIXED32, UInt32, uint32);
-      HANDLE_TYPE(FIXED64, UInt64, uint64);
-      HANDLE_TYPE(SFIXED32, Int32, int32);
-      HANDLE_TYPE(SFIXED64, Int64, int64);
+      HANDLE_TYPE(INT32, Int32, int32_t);
+      HANDLE_TYPE(INT64, Int64, int64_t);
+      HANDLE_TYPE(UINT32, UInt32, uint32_t);
+      HANDLE_TYPE(UINT64, UInt64, uint64_t);
+      HANDLE_TYPE(SINT32, Int32, int32_t);
+      HANDLE_TYPE(SINT64, Int64, int64_t);
+      HANDLE_TYPE(FIXED32, UInt32, uint32_t);
+      HANDLE_TYPE(FIXED64, UInt64, uint64_t);
+      HANDLE_TYPE(SFIXED32, Int32, int32_t);
+      HANDLE_TYPE(SFIXED64, Int64, int64_t);
       HANDLE_TYPE(FLOAT, Float, float);
       HANDLE_TYPE(DOUBLE, Double, double);
       HANDLE_TYPE(BOOL, Bool, bool);
@@ -1316,16 +1374,16 @@
     }                                                                       \
   } break
 
-      HANDLE_TYPE(INT32, Int32, int32);
-      HANDLE_TYPE(INT64, Int64, int64);
-      HANDLE_TYPE(UINT32, UInt32, uint32);
-      HANDLE_TYPE(UINT64, UInt64, uint64);
-      HANDLE_TYPE(SINT32, Int32, int32);
-      HANDLE_TYPE(SINT64, Int64, int64);
-      HANDLE_TYPE(FIXED32, UInt32, uint32);
-      HANDLE_TYPE(FIXED64, UInt64, uint64);
-      HANDLE_TYPE(SFIXED32, Int32, int32);
-      HANDLE_TYPE(SFIXED64, Int64, int64);
+      HANDLE_TYPE(INT32, Int32, int32_t);
+      HANDLE_TYPE(INT64, Int64, int64_t);
+      HANDLE_TYPE(UINT32, UInt32, uint32_t);
+      HANDLE_TYPE(UINT64, UInt64, uint64_t);
+      HANDLE_TYPE(SINT32, Int32, int32_t);
+      HANDLE_TYPE(SINT64, Int64, int64_t);
+      HANDLE_TYPE(FIXED32, UInt32, uint32_t);
+      HANDLE_TYPE(FIXED64, UInt64, uint64_t);
+      HANDLE_TYPE(SFIXED32, Int32, int32_t);
+      HANDLE_TYPE(SFIXED64, Int64, int64_t);
       HANDLE_TYPE(FLOAT, Float, float);
       HANDLE_TYPE(DOUBLE, Double, double);
       HANDLE_TYPE(BOOL, Bool, bool);
@@ -1404,18 +1462,18 @@
   return true;
 }
 
-bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
-                              const MessageLite* containing_type) {
+bool ExtensionSet::ParseField(uint32_t tag, io::CodedInputStream* input,
+                              const MessageLite* extendee) {
   FieldSkipper skipper;
-  GeneratedExtensionFinder finder(containing_type);
+  GeneratedExtensionFinder finder(extendee);
   return ParseField(tag, input, &finder, &skipper);
 }
 
-bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
-                              const MessageLite* containing_type,
+bool ExtensionSet::ParseField(uint32_t tag, io::CodedInputStream* input,
+                              const MessageLite* extendee,
                               io::CodedOutputStream* unknown_fields) {
   CodedOutputStreamFieldSkipper skipper(unknown_fields);
-  GeneratedExtensionFinder finder(containing_type);
+  GeneratedExtensionFinder finder(extendee);
   return ParseField(tag, input, &finder, &skipper);
 }
 
@@ -1423,7 +1481,7 @@
                                        ExtensionFinder* extension_finder,
                                        FieldSkipper* field_skipper) {
   while (true) {
-    const uint32 tag = input->ReadTag();
+    const uint32_t tag = input->ReadTag();
     switch (tag) {
       case 0:
         return true;
@@ -1451,7 +1509,7 @@
           extension_finder, field_skipper);
     }
 
-    bool SkipField(uint32 tag, io::CodedInputStream* input) {
+    bool SkipField(uint32_t tag, io::CodedInputStream* input) {
       return field_skipper->SkipField(input, tag);
     }
 
@@ -1465,24 +1523,24 @@
 }
 
 bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
-                                   const MessageLite* containing_type,
+                                   const MessageLite* extendee,
                                    std::string* unknown_fields) {
   io::StringOutputStream zcis(unknown_fields);
   io::CodedOutputStream output(&zcis);
   CodedOutputStreamFieldSkipper skipper(&output);
-  GeneratedExtensionFinder finder(containing_type);
+  GeneratedExtensionFinder finder(extendee);
   return ParseMessageSetLite(input, &finder, &skipper);
 }
 
-uint8* ExtensionSet::_InternalSerializeImpl(
-    int start_field_number, int end_field_number, uint8* target,
-    io::EpsCopyOutputStream* stream) const {
+uint8_t* ExtensionSet::_InternalSerializeImpl(
+    const MessageLite* extendee, int start_field_number, int end_field_number,
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
   if (PROTOBUF_PREDICT_FALSE(is_large())) {
     const auto& end = map_.large->end();
     for (auto it = map_.large->lower_bound(start_field_number);
          it != end && it->first < end_field_number; ++it) {
       target = it->second.InternalSerializeFieldWithCachedSizesToArray(
-          it->first, target, stream);
+          extendee, this, it->first, target, stream);
     }
     return target;
   }
@@ -1491,16 +1549,19 @@
            flat_begin(), end, start_field_number, KeyValue::FirstComparator());
        it != end && it->first < end_field_number; ++it) {
     target = it->second.InternalSerializeFieldWithCachedSizesToArray(
-        it->first, target, stream);
+        extendee, this, it->first, target, stream);
   }
   return target;
 }
 
-uint8* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
-    uint8* target, io::EpsCopyOutputStream* stream) const {
-  ForEach([&target, stream](int number, const Extension& ext) {
+uint8_t* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
+    const MessageLite* extendee, uint8_t* target,
+    io::EpsCopyOutputStream* stream) const {
+  const ExtensionSet* extension_set = this;
+  ForEach([&target, extendee, stream, extension_set](int number,
+                                                     const Extension& ext) {
     target = ext.InternalSerializeMessageSetItemWithCachedSizesToArray(
-        number, target, stream);
+        extendee, extension_set, number, target, stream);
   });
   return target;
 }
@@ -1536,10 +1597,10 @@
     repeated_##LOWERCASE##_value->Clear();  \
     break
 
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(BOOL, bool);
@@ -1587,12 +1648,12 @@
     }                                                                \
     break
 
-        HANDLE_TYPE(INT32, Int32, int32);
-        HANDLE_TYPE(INT64, Int64, int64);
-        HANDLE_TYPE(UINT32, UInt32, uint32);
-        HANDLE_TYPE(UINT64, UInt64, uint64);
-        HANDLE_TYPE(SINT32, SInt32, int32);
-        HANDLE_TYPE(SINT64, SInt64, int64);
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
         HANDLE_TYPE(ENUM, Enum, enum);
 #undef HANDLE_TYPE
 
@@ -1602,10 +1663,10 @@
     result += WireFormatLite::k##CAMELCASE##Size *               \
               FromIntSize(repeated_##LOWERCASE##_value->size()); \
     break
-        HANDLE_TYPE(FIXED32, Fixed32, uint32);
-        HANDLE_TYPE(FIXED64, Fixed64, uint64);
-        HANDLE_TYPE(SFIXED32, SFixed32, int32);
-        HANDLE_TYPE(SFIXED64, SFixed64, int64);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
         HANDLE_TYPE(FLOAT, Float, float);
         HANDLE_TYPE(DOUBLE, Double, double);
         HANDLE_TYPE(BOOL, Bool, bool);
@@ -1638,12 +1699,12 @@
     }                                                                       \
     break
 
-        HANDLE_TYPE(INT32, Int32, int32);
-        HANDLE_TYPE(INT64, Int64, int64);
-        HANDLE_TYPE(UINT32, UInt32, uint32);
-        HANDLE_TYPE(UINT64, UInt64, uint64);
-        HANDLE_TYPE(SINT32, SInt32, int32);
-        HANDLE_TYPE(SINT64, SInt64, int64);
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
         HANDLE_TYPE(STRING, String, string);
         HANDLE_TYPE(BYTES, Bytes, string);
         HANDLE_TYPE(ENUM, Enum, enum);
@@ -1657,10 +1718,10 @@
     result += (tag_size + WireFormatLite::k##CAMELCASE##Size) *  \
               FromIntSize(repeated_##LOWERCASE##_value->size()); \
     break
-        HANDLE_TYPE(FIXED32, Fixed32, uint32);
-        HANDLE_TYPE(FIXED64, Fixed64, uint64);
-        HANDLE_TYPE(SFIXED32, SFixed32, int32);
-        HANDLE_TYPE(SFIXED64, SFixed64, int64);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
         HANDLE_TYPE(FLOAT, Float, float);
         HANDLE_TYPE(DOUBLE, Double, double);
         HANDLE_TYPE(BOOL, Bool, bool);
@@ -1675,12 +1736,12 @@
     result += WireFormatLite::CAMELCASE##Size(LOWERCASE); \
     break
 
-      HANDLE_TYPE(INT32, Int32, int32_value);
-      HANDLE_TYPE(INT64, Int64, int64_value);
-      HANDLE_TYPE(UINT32, UInt32, uint32_value);
-      HANDLE_TYPE(UINT64, UInt64, uint64_value);
-      HANDLE_TYPE(SINT32, SInt32, int32_value);
-      HANDLE_TYPE(SINT64, SInt64, int64_value);
+      HANDLE_TYPE(INT32, Int32, int32_t_value);
+      HANDLE_TYPE(INT64, Int64, int64_t_value);
+      HANDLE_TYPE(UINT32, UInt32, uint32_t_value);
+      HANDLE_TYPE(UINT64, UInt64, uint64_t_value);
+      HANDLE_TYPE(SINT32, SInt32, int32_t_value);
+      HANDLE_TYPE(SINT64, SInt64, int64_t_value);
       HANDLE_TYPE(STRING, String, *string_value);
       HANDLE_TYPE(BYTES, Bytes, *string_value);
       HANDLE_TYPE(ENUM, Enum, enum_value);
@@ -1722,10 +1783,10 @@
   case WireFormatLite::CPPTYPE_##UPPERCASE: \
     return repeated_##LOWERCASE##_value->size()
 
-    HANDLE_TYPE(INT32, int32);
-    HANDLE_TYPE(INT64, int64);
-    HANDLE_TYPE(UINT32, uint32);
-    HANDLE_TYPE(UINT64, uint64);
+    HANDLE_TYPE(INT32, int32_t);
+    HANDLE_TYPE(INT64, int64_t);
+    HANDLE_TYPE(UINT32, uint32_t);
+    HANDLE_TYPE(UINT64, uint64_t);
     HANDLE_TYPE(FLOAT, float);
     HANDLE_TYPE(DOUBLE, double);
     HANDLE_TYPE(BOOL, bool);
@@ -1749,10 +1810,10 @@
     delete repeated_##LOWERCASE##_value;    \
     break
 
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(BOOL, bool);
@@ -1807,16 +1868,15 @@
 void ExtensionSet::LazyMessageExtension::UnusedKeyMethod() {}
 
 const ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) const {
-  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+  if (flat_size_ == 0) {
+    return nullptr;
+  } else if (PROTOBUF_PREDICT_TRUE(!is_large())) {
+    auto it = std::lower_bound(flat_begin(), flat_end() - 1, key,
+                               KeyValue::FirstComparator());
+    return it->first == key ? &it->second : nullptr;
+  } else {
     return FindOrNullInLargeMap(key);
   }
-  const KeyValue* end = flat_end();
-  const KeyValue* it =
-      std::lower_bound(flat_begin(), end, key, KeyValue::FirstComparator());
-  if (it != end && it->first == key) {
-    return &it->second;
-  }
-  return NULL;
 }
 
 const ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(
@@ -1830,25 +1890,14 @@
 }
 
 ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) {
-  if (PROTOBUF_PREDICT_FALSE(is_large())) {
-    return FindOrNullInLargeMap(key);
-  }
-  KeyValue* end = flat_end();
-  KeyValue* it =
-      std::lower_bound(flat_begin(), end, key, KeyValue::FirstComparator());
-  if (it != end && it->first == key) {
-    return &it->second;
-  }
-  return NULL;
+  const auto* const_this = this;
+  return const_cast<ExtensionSet::Extension*>(const_this->FindOrNull(key));
 }
 
 ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(int key) {
-  assert(is_large());
-  LargeMap::iterator it = map_.large->find(key);
-  if (it != map_.large->end()) {
-    return &it->second;
-  }
-  return NULL;
+  const auto* const_this = this;
+  return const_cast<ExtensionSet::Extension*>(
+      const_this->FindOrNullInLargeMap(key));
 }
 
 std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(int key) {
@@ -1895,6 +1944,8 @@
     for (const KeyValue* it = begin; it != end; ++it) {
       hint = new_map.large->insert(hint, {it->first, it->second});
     }
+    flat_size_ = static_cast<uint16_t>(-1);
+    GOOGLE_DCHECK(is_large());
   } else {
     new_map.flat = Arena::CreateArray<KeyValue>(arena_, new_flat_capacity);
     std::copy(begin, end, new_map.flat);
@@ -1908,7 +1959,7 @@
 }
 
 // static
-constexpr uint16 ExtensionSet::kMaximumFlatCapacity;
+constexpr uint16_t ExtensionSet::kMaximumFlatCapacity;
 
 void ExtensionSet::Erase(int key) {
   if (PROTOBUF_PREDICT_FALSE(is_large())) {
@@ -1938,8 +1989,9 @@
   return instance;
 }
 
-uint8* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
-    int number, uint8* target, io::EpsCopyOutputStream* stream) const {
+uint8_t* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
+    const MessageLite* extendee, const ExtensionSet* extension_set, int number,
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
   if (is_repeated) {
     if (is_packed) {
       if (cached_size == 0) return target;
@@ -1959,16 +2011,16 @@
     }                                                                \
     break
 
-        HANDLE_TYPE(INT32, Int32, int32);
-        HANDLE_TYPE(INT64, Int64, int64);
-        HANDLE_TYPE(UINT32, UInt32, uint32);
-        HANDLE_TYPE(UINT64, UInt64, uint64);
-        HANDLE_TYPE(SINT32, SInt32, int32);
-        HANDLE_TYPE(SINT64, SInt64, int64);
-        HANDLE_TYPE(FIXED32, Fixed32, uint32);
-        HANDLE_TYPE(FIXED64, Fixed64, uint64);
-        HANDLE_TYPE(SFIXED32, SFixed32, int32);
-        HANDLE_TYPE(SFIXED64, SFixed64, int64);
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
         HANDLE_TYPE(FLOAT, Float, float);
         HANDLE_TYPE(DOUBLE, Double, double);
         HANDLE_TYPE(BOOL, Bool, bool);
@@ -1993,16 +2045,16 @@
     }                                                                \
     break
 
-        HANDLE_TYPE(INT32, Int32, int32);
-        HANDLE_TYPE(INT64, Int64, int64);
-        HANDLE_TYPE(UINT32, UInt32, uint32);
-        HANDLE_TYPE(UINT64, UInt64, uint64);
-        HANDLE_TYPE(SINT32, SInt32, int32);
-        HANDLE_TYPE(SINT64, SInt64, int64);
-        HANDLE_TYPE(FIXED32, Fixed32, uint32);
-        HANDLE_TYPE(FIXED64, Fixed64, uint64);
-        HANDLE_TYPE(SFIXED32, SFixed32, int32);
-        HANDLE_TYPE(SFIXED64, SFixed64, int64);
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
         HANDLE_TYPE(FLOAT, Float, float);
         HANDLE_TYPE(DOUBLE, Double, double);
         HANDLE_TYPE(BOOL, Bool, bool);
@@ -2041,16 +2093,16 @@
     target = WireFormatLite::Write##CAMELCASE##ToArray(number, VALUE, target); \
     break
 
-      HANDLE_TYPE(INT32, Int32, int32_value);
-      HANDLE_TYPE(INT64, Int64, int64_value);
-      HANDLE_TYPE(UINT32, UInt32, uint32_value);
-      HANDLE_TYPE(UINT64, UInt64, uint64_value);
-      HANDLE_TYPE(SINT32, SInt32, int32_value);
-      HANDLE_TYPE(SINT64, SInt64, int64_value);
-      HANDLE_TYPE(FIXED32, Fixed32, uint32_value);
-      HANDLE_TYPE(FIXED64, Fixed64, uint64_value);
-      HANDLE_TYPE(SFIXED32, SFixed32, int32_value);
-      HANDLE_TYPE(SFIXED64, SFixed64, int64_value);
+      HANDLE_TYPE(INT32, Int32, int32_t_value);
+      HANDLE_TYPE(INT64, Int64, int64_t_value);
+      HANDLE_TYPE(UINT32, UInt32, uint32_t_value);
+      HANDLE_TYPE(UINT64, UInt64, uint64_t_value);
+      HANDLE_TYPE(SINT32, SInt32, int32_t_value);
+      HANDLE_TYPE(SINT64, SInt64, int64_t_value);
+      HANDLE_TYPE(FIXED32, Fixed32, uint32_t_value);
+      HANDLE_TYPE(FIXED64, Fixed64, uint64_t_value);
+      HANDLE_TYPE(SFIXED32, SFixed32, int32_t_value);
+      HANDLE_TYPE(SFIXED64, SFixed64, int64_t_value);
       HANDLE_TYPE(FLOAT, Float, float_value);
       HANDLE_TYPE(DOUBLE, Double, double_value);
       HANDLE_TYPE(BOOL, Bool, bool_value);
@@ -2071,8 +2123,10 @@
         break;
       case WireFormatLite::TYPE_MESSAGE:
         if (is_lazy) {
-          target =
-              lazymessage_value->WriteMessageToArray(number, target, stream);
+          const auto* prototype =
+              extension_set->GetPrototypeForLazyMessage(extendee, number);
+          target = lazymessage_value->WriteMessageToArray(prototype, number,
+                                                          target, stream);
         } else {
           target = stream->EnsureSpace(target);
           target = WireFormatLite::InternalWriteMessage(number, *message_value,
@@ -2084,13 +2138,28 @@
   return target;
 }
 
-uint8*
+const MessageLite* ExtensionSet::GetPrototypeForLazyMessage(
+    const MessageLite* extendee, int number) const {
+  GeneratedExtensionFinder finder(extendee);
+  bool was_packed_on_wire = false;
+  ExtensionInfo extension_info;
+  if (!FindExtensionInfoFromFieldNumber(
+          WireFormatLite::WireType::WIRETYPE_LENGTH_DELIMITED, number, &finder,
+          &extension_info, &was_packed_on_wire)) {
+    return nullptr;
+  }
+  return extension_info.message_info.prototype;
+}
+
+uint8_t*
 ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray(
-    int number, uint8* target, io::EpsCopyOutputStream* stream) const {
+    const MessageLite* extendee, const ExtensionSet* extension_set, int number,
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
   if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
     // Not a valid MessageSet extension, but serialize it the normal way.
     GOOGLE_LOG(WARNING) << "Invalid message set extension.";
-    return InternalSerializeFieldWithCachedSizesToArray(number, target, stream);
+    return InternalSerializeFieldWithCachedSizesToArray(extendee, extension_set,
+                                                        number, target, stream);
   }
 
   if (is_cleared) return target;
@@ -2104,8 +2173,10 @@
       WireFormatLite::kMessageSetTypeIdNumber, number, target);
   // Write message.
   if (is_lazy) {
+    const auto* prototype =
+        extension_set->GetPrototypeForLazyMessage(extendee, number);
     target = lazymessage_value->WriteMessageToArray(
-        WireFormatLite::kMessageSetMessageNumber, target, stream);
+        prototype, WireFormatLite::kMessageSetMessageNumber, target, stream);
   } else {
     target = WireFormatLite::InternalWriteMessage(
         WireFormatLite::kMessageSetMessageNumber, *message_value, target,
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index e3d1669..9389273 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -85,7 +85,7 @@
 // #include wire_format_lite.h.  Also, ensures that we use only one byte to
 // store these values, which is important to keep the layout of
 // ExtensionSet::Extension small.
-typedef uint8 FieldType;
+typedef uint8_t FieldType;
 
 // A function which, given an integer value, returns true if the number
 // matches one of the defined values for the corresponding enum type.  This
@@ -99,12 +99,18 @@
 // Information about a registered extension.
 struct ExtensionInfo {
   inline ExtensionInfo() {}
-  inline ExtensionInfo(FieldType type_param, bool isrepeated, bool ispacked)
-      : type(type_param),
+  inline ExtensionInfo(const MessageLite* extendee, int param_number,
+                       FieldType type_param, bool isrepeated, bool ispacked)
+      : message(extendee),
+        number(param_number),
+        type(type_param),
         is_repeated(isrepeated),
         is_packed(ispacked),
         descriptor(NULL) {}
 
+  const MessageLite* message;
+  int number;
+
   FieldType type;
   bool is_repeated;
   bool is_packed;
@@ -143,15 +149,15 @@
 // files which have been compiled into the binary.
 class PROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder {
  public:
-  GeneratedExtensionFinder(const MessageLite* containing_type)
-      : containing_type_(containing_type) {}
+  explicit GeneratedExtensionFinder(const MessageLite* extendee)
+      : extendee_(extendee) {}
   ~GeneratedExtensionFinder() override {}
 
   // Returns true and fills in *output if found, otherwise returns false.
   bool Find(int number, ExtensionInfo* output) override;
 
  private:
-  const MessageLite* containing_type_;
+  const MessageLite* extendee_;
 };
 
 // A FieldSkipper used for parsing MessageSet.
@@ -182,24 +188,22 @@
   // to look up extensions for parsed field numbers.  Note that dynamic parsing
   // does not use ParseField(); only protocol-compiler-generated parsing
   // methods do.
-  static void RegisterExtension(const MessageLite* containing_type, int number,
+  static void RegisterExtension(const MessageLite* extendee, int number,
                                 FieldType type, bool is_repeated,
                                 bool is_packed);
-  static void RegisterEnumExtension(const MessageLite* containing_type,
-                                    int number, FieldType type,
-                                    bool is_repeated, bool is_packed,
-                                    EnumValidityFunc* is_valid);
-  static void RegisterMessageExtension(const MessageLite* containing_type,
-                                       int number, FieldType type,
-                                       bool is_repeated, bool is_packed,
+  static void RegisterEnumExtension(const MessageLite* extendee, int number,
+                                    FieldType type, bool is_repeated,
+                                    bool is_packed, EnumValidityFunc* is_valid);
+  static void RegisterMessageExtension(const MessageLite* extendee, int number,
+                                       FieldType type, bool is_repeated,
+                                       bool is_packed,
                                        const MessageLite* prototype);
 
   // =================================================================
 
   // Add all fields which are currently present to the given vector.  This
   // is useful to implement Reflection::ListFields().
-  void AppendToList(const Descriptor* containing_type,
-                    const DescriptorPool* pool,
+  void AppendToList(const Descriptor* extendee, const DescriptorPool* pool,
                     std::vector<const FieldDescriptor*>* output) const;
 
   // =================================================================
@@ -240,10 +244,10 @@
 
   // singular fields -------------------------------------------------
 
-  int32 GetInt32(int number, int32 default_value) const;
-  int64 GetInt64(int number, int64 default_value) const;
-  uint32 GetUInt32(int number, uint32 default_value) const;
-  uint64 GetUInt64(int number, uint64 default_value) const;
+  int32_t GetInt32(int number, int32_t default_value) const;
+  int64_t GetInt64(int number, int64_t default_value) const;
+  uint32_t GetUInt32(int number, uint32_t default_value) const;
+  uint64_t GetUInt64(int number, uint64_t default_value) const;
   float GetFloat(int number, float default_value) const;
   double GetDouble(int number, double default_value) const;
   bool GetBool(int number, bool default_value) const;
@@ -259,10 +263,10 @@
   // the extension lives in the same pool as the descriptor for the containing
   // type.
 #define desc const FieldDescriptor* descriptor  // avoid line wrapping
-  void SetInt32(int number, FieldType type, int32 value, desc);
-  void SetInt64(int number, FieldType type, int64 value, desc);
-  void SetUInt32(int number, FieldType type, uint32 value, desc);
-  void SetUInt64(int number, FieldType type, uint64 value, desc);
+  void SetInt32(int number, FieldType type, int32_t value, desc);
+  void SetInt64(int number, FieldType type, int64_t value, desc);
+  void SetUInt32(int number, FieldType type, uint32_t value, desc);
+  void SetUInt64(int number, FieldType type, uint64_t value, desc);
   void SetFloat(int number, FieldType type, float value, desc);
   void SetDouble(int number, FieldType type, double value, desc);
   void SetBool(int number, FieldType type, bool value, desc);
@@ -312,10 +316,10 @@
   // (E.g.: borg/clients/internal/proto1/proto2_reflection.cc.)
   void* MutableRawRepeatedField(int number);
 
-  int32 GetRepeatedInt32(int number, int index) const;
-  int64 GetRepeatedInt64(int number, int index) const;
-  uint32 GetRepeatedUInt32(int number, int index) const;
-  uint64 GetRepeatedUInt64(int number, int index) const;
+  int32_t GetRepeatedInt32(int number, int index) const;
+  int64_t GetRepeatedInt64(int number, int index) const;
+  uint32_t GetRepeatedUInt32(int number, int index) const;
+  uint64_t GetRepeatedUInt64(int number, int index) const;
   float GetRepeatedFloat(int number, int index) const;
   double GetRepeatedDouble(int number, int index) const;
   bool GetRepeatedBool(int number, int index) const;
@@ -323,10 +327,10 @@
   const std::string& GetRepeatedString(int number, int index) const;
   const MessageLite& GetRepeatedMessage(int number, int index) const;
 
-  void SetRepeatedInt32(int number, int index, int32 value);
-  void SetRepeatedInt64(int number, int index, int64 value);
-  void SetRepeatedUInt32(int number, int index, uint32 value);
-  void SetRepeatedUInt64(int number, int index, uint64 value);
+  void SetRepeatedInt32(int number, int index, int32_t value);
+  void SetRepeatedInt64(int number, int index, int64_t value);
+  void SetRepeatedUInt32(int number, int index, uint32_t value);
+  void SetRepeatedUInt64(int number, int index, uint64_t value);
   void SetRepeatedFloat(int number, int index, float value);
   void SetRepeatedDouble(int number, int index, double value);
   void SetRepeatedBool(int number, int index, bool value);
@@ -336,10 +340,10 @@
   MessageLite* MutableRepeatedMessage(int number, int index);
 
 #define desc const FieldDescriptor* descriptor  // avoid line wrapping
-  void AddInt32(int number, FieldType type, bool packed, int32 value, desc);
-  void AddInt64(int number, FieldType type, bool packed, int64 value, desc);
-  void AddUInt32(int number, FieldType type, bool packed, uint32 value, desc);
-  void AddUInt64(int number, FieldType type, bool packed, uint64 value, desc);
+  void AddInt32(int number, FieldType type, bool packed, int32_t value, desc);
+  void AddInt64(int number, FieldType type, bool packed, int64_t value, desc);
+  void AddUInt32(int number, FieldType type, bool packed, uint32_t value, desc);
+  void AddUInt64(int number, FieldType type, bool packed, uint64_t value, desc);
   void AddFloat(int number, FieldType type, bool packed, float value, desc);
   void AddDouble(int number, FieldType type, bool packed, double value, desc);
   void AddBool(int number, FieldType type, bool packed, bool value, desc);
@@ -352,10 +356,13 @@
                           MessageFactory* factory);
   void AddAllocatedMessage(const FieldDescriptor* descriptor,
                            MessageLite* new_entry);
+  void UnsafeArenaAddAllocatedMessage(const FieldDescriptor* descriptor,
+                                      MessageLite* new_entry);
 #undef desc
 
   void RemoveLast(int number);
   PROTOBUF_MUST_USE_RESULT MessageLite* ReleaseLast(int number);
+  MessageLite* UnsafeArenaReleaseLast(int number);
   void SwapElements(int number, int index1, int index2);
 
   // -----------------------------------------------------------------
@@ -377,49 +384,47 @@
 
   // Parses a single extension from the input. The input should start out
   // positioned immediately after the tag.
-  bool ParseField(uint32 tag, io::CodedInputStream* input,
+  bool ParseField(uint32_t tag, io::CodedInputStream* input,
                   ExtensionFinder* extension_finder,
                   FieldSkipper* field_skipper);
 
   // Specific versions for lite or full messages (constructs the appropriate
-  // FieldSkipper automatically).  |containing_type| is the default
+  // FieldSkipper automatically).  |extendee| is the default
   // instance for the containing message; it is used only to look up the
   // extension by number.  See RegisterExtension(), above.  Unlike the other
   // methods of ExtensionSet, this only works for generated message types --
   // it looks up extensions registered using RegisterExtension().
-  bool ParseField(uint32 tag, io::CodedInputStream* input,
-                  const MessageLite* containing_type);
-  bool ParseField(uint32 tag, io::CodedInputStream* input,
-                  const Message* containing_type,
-                  UnknownFieldSet* unknown_fields);
-  bool ParseField(uint32 tag, io::CodedInputStream* input,
-                  const MessageLite* containing_type,
+  bool ParseField(uint32_t tag, io::CodedInputStream* input,
+                  const MessageLite* extendee);
+  bool ParseField(uint32_t tag, io::CodedInputStream* input,
+                  const Message* extendee, UnknownFieldSet* unknown_fields);
+  bool ParseField(uint32_t tag, io::CodedInputStream* input,
+                  const MessageLite* extendee,
                   io::CodedOutputStream* unknown_fields);
 
   // Lite parser
-  const char* ParseField(uint64 tag, const char* ptr,
-                         const MessageLite* containing_type,
+  const char* ParseField(uint64_t tag, const char* ptr,
+                         const MessageLite* extendee,
                          internal::InternalMetadata* metadata,
                          internal::ParseContext* ctx);
   // Full parser
-  const char* ParseField(uint64 tag, const char* ptr,
-                         const Message* containing_type,
+  const char* ParseField(uint64_t tag, const char* ptr, const Message* extendee,
                          internal::InternalMetadata* metadata,
                          internal::ParseContext* ctx);
   template <typename Msg>
-  const char* ParseMessageSet(const char* ptr, const Msg* containing_type,
+  const char* ParseMessageSet(const char* ptr, const Msg* extendee,
                               InternalMetadata* metadata,
                               internal::ParseContext* ctx) {
     struct MessageSetItem {
       const char* _InternalParse(const char* ptr, ParseContext* ctx) {
-        return me->ParseMessageSetItem(ptr, containing_type, metadata, ctx);
+        return me->ParseMessageSetItem(ptr, extendee, metadata, ctx);
       }
       ExtensionSet* me;
-      const Msg* containing_type;
+      const Msg* extendee;
       InternalMetadata* metadata;
-    } item{this, containing_type, metadata};
+    } item{this, extendee, metadata};
     while (!ctx->Done(&ptr)) {
-      uint32 tag;
+      uint32_t tag;
       ptr = ReadTag(ptr, &tag);
       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       if (tag == WireFormatLite::kMessageSetItemStartTag) {
@@ -430,7 +435,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = ParseField(tag, ptr, containing_type, metadata, ctx);
+        ptr = ParseField(tag, ptr, extendee, metadata, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       }
     }
@@ -448,21 +453,21 @@
 
   // Specific versions for lite or full messages (constructs the appropriate
   // FieldSkipper automatically).
-  bool ParseMessageSet(io::CodedInputStream* input,
-                       const MessageLite* containing_type,
+  bool ParseMessageSet(io::CodedInputStream* input, const MessageLite* extendee,
                        std::string* unknown_fields);
-  bool ParseMessageSet(io::CodedInputStream* input,
-                       const Message* containing_type,
+  bool ParseMessageSet(io::CodedInputStream* input, const Message* extendee,
                        UnknownFieldSet* unknown_fields);
 
   // Write all extension fields with field numbers in the range
   //   [start_field_number, end_field_number)
   // to the output stream, using the cached sizes computed when ByteSize() was
   // last called.  Note that the range bounds are inclusive-exclusive.
-  void SerializeWithCachedSizes(int start_field_number, int end_field_number,
+  void SerializeWithCachedSizes(const MessageLite* extendee,
+                                int start_field_number, int end_field_number,
                                 io::CodedOutputStream* output) const {
-    output->SetCur(_InternalSerialize(start_field_number, end_field_number,
-                                      output->Cur(), output->EpsCopy()));
+    output->SetCur(_InternalSerialize(extendee, start_field_number,
+                                      end_field_number, output->Cur(),
+                                      output->EpsCopy()));
   }
 
   // Same as SerializeWithCachedSizes, but without any bounds checking.
@@ -470,32 +475,37 @@
   // serialized extensions.
   //
   // Returns a pointer past the last written byte.
-  uint8* _InternalSerialize(int start_field_number, int end_field_number,
-                            uint8* target,
-                            io::EpsCopyOutputStream* stream) const {
+
+  uint8_t* _InternalSerialize(const MessageLite* extendee,
+                              int start_field_number, int end_field_number,
+                              uint8_t* target,
+                              io::EpsCopyOutputStream* stream) const {
     if (flat_size_ == 0) {
       assert(!is_large());
       return target;
     }
-    return _InternalSerializeImpl(start_field_number, end_field_number, target,
-                                  stream);
+    return _InternalSerializeImpl(extendee, start_field_number,
+                                  end_field_number, target, stream);
   }
 
   // Like above but serializes in MessageSet format.
-  void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const {
+  void SerializeMessageSetWithCachedSizes(const MessageLite* extendee,
+                                          io::CodedOutputStream* output) const {
     output->SetCur(InternalSerializeMessageSetWithCachedSizesToArray(
-        output->Cur(), output->EpsCopy()));
+        extendee, output->Cur(), output->EpsCopy()));
   }
-  uint8* InternalSerializeMessageSetWithCachedSizesToArray(
-      uint8* target, io::EpsCopyOutputStream* stream) const;
+  uint8_t* InternalSerializeMessageSetWithCachedSizesToArray(
+      const MessageLite* extendee, uint8_t* target,
+      io::EpsCopyOutputStream* stream) const;
 
   // For backward-compatibility, versions of two of the above methods that
   // serialize deterministically iff SetDefaultSerializationDeterministic()
   // has been called.
-  uint8* SerializeWithCachedSizesToArray(int start_field_number,
-                                         int end_field_number,
-                                         uint8* target) const;
-  uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const;
+  uint8_t* SerializeWithCachedSizesToArray(int start_field_number,
+                                           int end_field_number,
+                                           uint8_t* target) const;
+  uint8_t* SerializeMessageSetWithCachedSizesToArray(
+      const MessageLite* extendee, uint8_t* target) const;
 
   // Returns the total serialized size of all the extensions.
   size_t ByteSize() const;
@@ -520,10 +530,40 @@
   int SpaceUsedExcludingSelf() const;
 
  private:
+  template <typename Type>
+  friend class PrimitiveTypeTraits;
+
+  template <typename Type>
+  friend class RepeatedPrimitiveTypeTraits;
+
+  template <typename Type, bool IsValid(int)>
+  friend class EnumTypeTraits;
+
+  template <typename Type, bool IsValid(int)>
+  friend class RepeatedEnumTypeTraits;
+
+  const int32_t& GetRefInt32(int number, const int32_t& default_value) const;
+  const int64_t& GetRefInt64(int number, const int64_t& default_value) const;
+  const uint32_t& GetRefUInt32(int number, const uint32_t& default_value) const;
+  const uint64_t& GetRefUInt64(int number, const uint64_t& default_value) const;
+  const float& GetRefFloat(int number, const float& default_value) const;
+  const double& GetRefDouble(int number, const double& default_value) const;
+  const bool& GetRefBool(int number, const bool& default_value) const;
+  const int& GetRefEnum(int number, const int& default_value) const;
+  const int32_t& GetRefRepeatedInt32(int number, int index) const;
+  const int64_t& GetRefRepeatedInt64(int number, int index) const;
+  const uint32_t& GetRefRepeatedUInt32(int number, int index) const;
+  const uint64_t& GetRefRepeatedUInt64(int number, int index) const;
+  const float& GetRefRepeatedFloat(int number, int index) const;
+  const double& GetRefRepeatedDouble(int number, int index) const;
+  const bool& GetRefRepeatedBool(int number, int index) const;
+  const int& GetRefRepeatedEnum(int number, int index) const;
+
   // Implementation of _InternalSerialize for non-empty map_.
-  uint8* _InternalSerializeImpl(int start_field_number, int end_field_number,
-                                uint8* target,
-                                io::EpsCopyOutputStream* stream) const;
+  uint8_t* _InternalSerializeImpl(const MessageLite* extendee,
+                                  int start_field_number, int end_field_number,
+                                  uint8_t* target,
+                                  io::EpsCopyOutputStream* stream) const;
   // Interface of a lazily parsed singular message extension.
   class PROTOBUF_EXPORT LazyMessageExtension {
    public:
@@ -554,8 +594,9 @@
     virtual bool ReadMessage(const MessageLite& prototype,
                              io::CodedInputStream* input) = 0;
     virtual const char* _InternalParse(const char* ptr, ParseContext* ctx) = 0;
-    virtual uint8* WriteMessageToArray(
-        int number, uint8* target, io::EpsCopyOutputStream* stream) const = 0;
+    virtual uint8_t* WriteMessageToArray(
+        const MessageLite* prototype, int number, uint8_t* target,
+        io::EpsCopyOutputStream* stream) const = 0;
 
    private:
     virtual void UnusedKeyMethod();  // Dummy key method to avoid weak vtable.
@@ -566,10 +607,10 @@
     // The order of these fields packs Extension into 24 bytes when using 8
     // byte alignment. Consider this when adding or removing fields here.
     union {
-      int32 int32_value;
-      int64 int64_value;
-      uint32 uint32_value;
-      uint64 uint64_value;
+      int32_t int32_t_value;
+      int64_t int64_t_value;
+      uint32_t uint32_t_value;
+      uint64_t uint64_t_value;
       float float_value;
       double double_value;
       bool bool_value;
@@ -578,10 +619,10 @@
       MessageLite* message_value;
       LazyMessageExtension* lazymessage_value;
 
-      RepeatedField<int32>* repeated_int32_value;
-      RepeatedField<int64>* repeated_int64_value;
-      RepeatedField<uint32>* repeated_uint32_value;
-      RepeatedField<uint64>* repeated_uint64_value;
+      RepeatedField<int32_t>* repeated_int32_t_value;
+      RepeatedField<int64_t>* repeated_int64_t_value;
+      RepeatedField<uint32_t>* repeated_uint32_t_value;
+      RepeatedField<uint64_t>* repeated_uint64_t_value;
       RepeatedField<float>* repeated_float_value;
       RepeatedField<double>* repeated_double_value;
       RepeatedField<bool>* repeated_bool_value;
@@ -622,10 +663,12 @@
     const FieldDescriptor* descriptor;
 
     // Some helper methods for operations on a single Extension.
-    uint8* InternalSerializeFieldWithCachedSizesToArray(
-        int number, uint8* target, io::EpsCopyOutputStream* stream) const;
-    uint8* InternalSerializeMessageSetItemWithCachedSizesToArray(
-        int number, uint8* target, io::EpsCopyOutputStream* stream) const;
+    uint8_t* InternalSerializeFieldWithCachedSizesToArray(
+        const MessageLite* extendee, const ExtensionSet* extension_set,
+        int number, uint8_t* target, io::EpsCopyOutputStream* stream) const;
+    uint8_t* InternalSerializeMessageSetItemWithCachedSizesToArray(
+        const MessageLite* extendee, const ExtensionSet* extension_set,
+        int number, uint8_t* target, io::EpsCopyOutputStream* stream) const;
     size_t ByteSize(int number) const;
     size_t MessageSetItemByteSize(int number) const;
     void Clear();
@@ -678,8 +721,8 @@
   // Grows the flat_capacity_.
   // If flat_capacity_ > kMaximumFlatCapacity, converts to LargeMap.
   void GrowCapacity(size_t minimum_new_capacity);
-  static constexpr uint16 kMaximumFlatCapacity = 256;
-  bool is_large() const { return flat_capacity_ > kMaximumFlatCapacity; }
+  static constexpr uint16_t kMaximumFlatCapacity = 256;
+  bool is_large() const { return static_cast<int16_t>(flat_size_) < 0; }
 
   // Removes a key from the ExtensionSet.
   void Erase(int key);
@@ -723,7 +766,7 @@
   // Note to support packed repeated field compatibility, it also fills whether
   // the tag on wire is packed, which can be different from
   // extension->is_packed (whether packed=true is specified).
-  bool FindExtensionInfoFromTag(uint32 tag, ExtensionFinder* extension_finder,
+  bool FindExtensionInfoFromTag(uint32_t tag, ExtensionFinder* extension_finder,
                                 int* field_number, ExtensionInfo* extension,
                                 bool* was_packed_on_wire);
 
@@ -734,7 +777,12 @@
   bool FindExtensionInfoFromFieldNumber(int wire_type, int field_number,
                                         ExtensionFinder* extension_finder,
                                         ExtensionInfo* extension,
-                                        bool* was_packed_on_wire);
+                                        bool* was_packed_on_wire) const;
+
+  // Find the prototype for a LazyMessage from the extension registry. Returns
+  // null if the extension is not found.
+  const MessageLite* GetPrototypeForLazyMessage(const MessageLite* extendee,
+                                                int number) const;
 
   // Parses a single extension from the input. The input should start out
   // positioned immediately after the wire tag. This method is called in
@@ -772,36 +820,33 @@
                            ExtensionFinder* extension_finder,
                            MessageSetFieldSkipper* field_skipper);
 
-  bool FindExtension(int wire_type, uint32 field,
-                     const MessageLite* containing_type,
+  bool FindExtension(int wire_type, uint32_t field, const MessageLite* extendee,
                      const internal::ParseContext* /*ctx*/,
                      ExtensionInfo* extension, bool* was_packed_on_wire) {
-    GeneratedExtensionFinder finder(containing_type);
+    GeneratedExtensionFinder finder(extendee);
     return FindExtensionInfoFromFieldNumber(wire_type, field, &finder,
                                             extension, was_packed_on_wire);
   }
-  inline bool FindExtension(int wire_type, uint32 field,
-                            const Message* containing_type,
+  inline bool FindExtension(int wire_type, uint32_t field,
+                            const Message* extendee,
                             const internal::ParseContext* ctx,
                             ExtensionInfo* extension, bool* was_packed_on_wire);
   // Used for MessageSet only
-  const char* ParseFieldMaybeLazily(uint64 tag, const char* ptr,
-                                    const MessageLite* containing_type,
+  const char* ParseFieldMaybeLazily(uint64_t tag, const char* ptr,
+                                    const MessageLite* extendee,
                                     internal::InternalMetadata* metadata,
                                     internal::ParseContext* ctx) {
     // Lite MessageSet doesn't implement lazy.
-    return ParseField(tag, ptr, containing_type, metadata, ctx);
+    return ParseField(tag, ptr, extendee, metadata, ctx);
   }
-  const char* ParseFieldMaybeLazily(uint64 tag, const char* ptr,
-                                    const Message* containing_type,
+  const char* ParseFieldMaybeLazily(uint64_t tag, const char* ptr,
+                                    const Message* extendee,
                                     internal::InternalMetadata* metadata,
                                     internal::ParseContext* ctx);
-  const char* ParseMessageSetItem(const char* ptr,
-                                  const MessageLite* containing_type,
+  const char* ParseMessageSetItem(const char* ptr, const MessageLite* extendee,
                                   internal::InternalMetadata* metadata,
                                   internal::ParseContext* ctx);
-  const char* ParseMessageSetItem(const char* ptr,
-                                  const Message* containing_type,
+  const char* ParseMessageSetItem(const char* ptr, const Message* extendee,
                                   internal::InternalMetadata* metadata,
                                   internal::ParseContext* ctx);
 
@@ -813,8 +858,7 @@
                                           const char* ptr,
                                           internal::ParseContext* ctx);
   template <typename Msg, typename T>
-  const char* ParseMessageSetItemTmpl(const char* ptr,
-                                      const Msg* containing_type,
+  const char* ParseMessageSetItemTmpl(const char* ptr, const Msg* extendee,
                                       internal::InternalMetadata* metadata,
                                       internal::ParseContext* ctx);
 
@@ -850,8 +894,8 @@
   // Manual memory-management:
   // map_.flat is an allocated array of flat_capacity_ elements.
   // [map_.flat, map_.flat + flat_size_) is the currently-in-use prefix.
-  uint16 flat_capacity_;
-  uint16 flat_size_;
+  uint16_t flat_capacity_;
+  uint16_t flat_size_;  // negative int16_t(flat_size_) indicates is_large()
   union AllocatedData {
     KeyValue* flat;
 
@@ -860,7 +904,7 @@
     LargeMap* large;
   } map_;
 
-  static void DeleteFlatMap(const KeyValue* flat, uint16 flat_capacity);
+  static void DeleteFlatMap(const KeyValue* flat, uint16_t flat_capacity);
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
 };
@@ -937,7 +981,7 @@
 // For example, if "foo" is an extension of type "optional int32", then if you
 // try to write code like:
 //   my_message.MutableExtension(foo)
-// you will get a compile error because PrimitiveTypeTraits<int32> does not
+// you will get a compile error because PrimitiveTypeTraits<int32_t> does not
 // have a "Mutable()" method.
 
 // -------------------------------------------------------------------
@@ -955,6 +999,9 @@
 
   static inline ConstType Get(int number, const ExtensionSet& set,
                               ConstType default_value);
+
+  static inline const ConstType* GetPtr(int number, const ExtensionSet& set,
+                                        const ConstType& default_value);
   static inline void Set(int number, FieldType field_type, ConstType value,
                          ExtensionSet* set);
   template <typename ExtendeeT>
@@ -974,6 +1021,10 @@
   typedef RepeatedField<Type> RepeatedFieldType;
 
   static inline Type Get(int number, const ExtensionSet& set, int index);
+  static inline const Type* GetPtr(int number, const ExtensionSet& set,
+                                   int index);
+  static inline const RepeatedField<ConstType>* GetRepeatedPtr(
+      int number, const ExtensionSet& set);
   static inline void Set(int number, int index, Type value, ExtensionSet* set);
   static inline void Add(int number, FieldType field_type, bool is_packed,
                          Type value, ExtensionSet* set);
@@ -998,10 +1049,10 @@
   template <typename Type>
   friend class RepeatedPrimitiveTypeTraits;
   static const RepeatedPrimitiveDefaults* default_instance();
-  RepeatedField<int32> default_repeated_field_int32_;
-  RepeatedField<int64> default_repeated_field_int64_;
-  RepeatedField<uint32> default_repeated_field_uint32_;
-  RepeatedField<uint64> default_repeated_field_uint64_;
+  RepeatedField<int32_t> default_repeated_field_int32_t_;
+  RepeatedField<int64_t> default_repeated_field_int64_t_;
+  RepeatedField<uint32_t> default_repeated_field_uint32_t_;
+  RepeatedField<uint64_t> default_repeated_field_uint64_t_;
   RepeatedField<double> default_repeated_field_double_;
   RepeatedField<float> default_repeated_field_float_;
   RepeatedField<bool> default_repeated_field_bool_;
@@ -1014,6 +1065,11 @@
     return set.Get##METHOD(number, default_value);                             \
   }                                                                            \
   template <>                                                                  \
+  inline const TYPE* PrimitiveTypeTraits<TYPE>::GetPtr(                        \
+      int number, const ExtensionSet& set, const TYPE& default_value) {        \
+    return &set.GetRef##METHOD(number, default_value);                         \
+  }                                                                            \
+  template <>                                                                  \
   inline void PrimitiveTypeTraits<TYPE>::Set(int number, FieldType field_type, \
                                              TYPE value, ExtensionSet* set) {  \
     set->Set##METHOD(number, field_type, value, NULL);                         \
@@ -1025,6 +1081,11 @@
     return set.GetRepeated##METHOD(number, index);                             \
   }                                                                            \
   template <>                                                                  \
+  inline const TYPE* RepeatedPrimitiveTypeTraits<TYPE>::GetPtr(                \
+      int number, const ExtensionSet& set, int index) {                        \
+    return &set.GetRefRepeated##METHOD(number, index);                         \
+  }                                                                            \
+  template <>                                                                  \
   inline void RepeatedPrimitiveTypeTraits<TYPE>::Set(                          \
       int number, int index, TYPE value, ExtensionSet* set) {                  \
     set->SetRepeated##METHOD(number, index, value);                            \
@@ -1049,6 +1110,12 @@
         set.GetRawRepeatedField(number, GetDefaultRepeatedField()));           \
   }                                                                            \
   template <>                                                                  \
+  inline const RepeatedField<TYPE>*                                            \
+  RepeatedPrimitiveTypeTraits<TYPE>::GetRepeatedPtr(int number,                \
+                                                    const ExtensionSet& set) { \
+    return &GetRepeated(number, set);                                          \
+  }                                                                            \
+  template <>                                                                  \
   inline RepeatedField<TYPE>*                                                  \
   RepeatedPrimitiveTypeTraits<TYPE>::MutableRepeated(                          \
       int number, FieldType field_type, bool is_packed, ExtensionSet* set) {   \
@@ -1056,10 +1123,10 @@
         set->MutableRawRepeatedField(number, field_type, is_packed, NULL));    \
   }
 
-PROTOBUF_DEFINE_PRIMITIVE_TYPE(int32, Int32)
-PROTOBUF_DEFINE_PRIMITIVE_TYPE(int64, Int64)
-PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32, UInt32)
-PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64, UInt64)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(int32_t, Int32)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(int64_t, Int64)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32_t, UInt32)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64_t, UInt64)
 PROTOBUF_DEFINE_PRIMITIVE_TYPE(float, Float)
 PROTOBUF_DEFINE_PRIMITIVE_TYPE(double, Double)
 PROTOBUF_DEFINE_PRIMITIVE_TYPE(bool, Bool)
@@ -1080,6 +1147,10 @@
                                        ConstType default_value) {
     return set.GetString(number, default_value);
   }
+  static inline const std::string* GetPtr(int number, const ExtensionSet& set,
+                                          ConstType default_value) {
+    return &Get(number, set, default_value);
+  }
   static inline void Set(int number, FieldType field_type,
                          const std::string& value, ExtensionSet* set) {
     set->SetString(number, field_type, value, NULL);
@@ -1107,6 +1178,14 @@
                                        int index) {
     return set.GetRepeatedString(number, index);
   }
+  static inline const std::string* GetPtr(int number, const ExtensionSet& set,
+                                          int index) {
+    return &Get(number, set, index);
+  }
+  static inline const RepeatedPtrField<std::string>* GetRepeatedPtr(
+      int number, const ExtensionSet& set) {
+    return &GetRepeated(number, set);
+  }
   static inline void Set(int number, int index, const std::string& value,
                          ExtensionSet* set) {
     set->SetRepeatedString(number, index, value);
@@ -1163,6 +1242,11 @@
                               ConstType default_value) {
     return static_cast<Type>(set.GetEnum(number, default_value));
   }
+  static inline const ConstType* GetPtr(int number, const ExtensionSet& set,
+                                        const ConstType& default_value) {
+    return reinterpret_cast<const Type*>(
+        &set.GetRefEnum(number, default_value));
+  }
   static inline void Set(int number, FieldType field_type, ConstType value,
                          ExtensionSet* set) {
     GOOGLE_DCHECK(IsValid(value));
@@ -1187,6 +1271,11 @@
   static inline ConstType Get(int number, const ExtensionSet& set, int index) {
     return static_cast<Type>(set.GetRepeatedEnum(number, index));
   }
+  static inline const ConstType* GetPtr(int number, const ExtensionSet& set,
+                                        int index) {
+    return reinterpret_cast<const Type*>(
+        &set.GetRefRepeatedEnum(number, index));
+  }
   static inline void Set(int number, int index, ConstType value,
                          ExtensionSet* set) {
     GOOGLE_DCHECK(IsValid(value));
@@ -1206,7 +1295,10 @@
     return *reinterpret_cast<const RepeatedField<Type>*>(
         set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
   }
-
+  static inline const RepeatedField<Type>* GetRepeatedPtr(
+      int number, const ExtensionSet& set) {
+    return &GetRepeated(number, set);
+  }
   static inline RepeatedField<Type>* MutableRepeated(int number,
                                                      FieldType field_type,
                                                      bool is_packed,
@@ -1220,10 +1312,10 @@
     // RepeatedField<int>. We need to be able to instantiate global static
     // objects to return as default (empty) repeated fields on non-existent
     // extensions. We would not be able to know a-priori all of the enum types
-    // (values of |Type|) to instantiate all of these, so we just re-use int32's
-    // default repeated field object.
+    // (values of |Type|) to instantiate all of these, so we just re-use
+    // int32_t's default repeated field object.
     return reinterpret_cast<const RepeatedField<Type>*>(
-        RepeatedPrimitiveTypeTraits<int32>::GetDefaultRepeatedField());
+        RepeatedPrimitiveTypeTraits<int32_t>::GetDefaultRepeatedField());
   }
   template <typename ExtendeeT>
   static void Register(int number, FieldType type, bool is_packed) {
@@ -1249,6 +1341,11 @@
                               ConstType default_value) {
     return static_cast<const Type&>(set.GetMessage(number, default_value));
   }
+  static inline std::nullptr_t GetPtr(int number, const ExtensionSet& set,
+                                      ConstType default_value) {
+    // Cannot be implemented because of forward declared messages?
+    return nullptr;
+  }
   static inline MutableType Mutable(int number, FieldType field_type,
                                     ExtensionSet* set) {
     return static_cast<Type*>(set->MutableMessage(
@@ -1282,7 +1379,7 @@
   }
 };
 
-// forward declaration
+// forward declaration.
 class RepeatedMessageGenericTypeTraits;
 
 template <typename Type>
@@ -1297,6 +1394,16 @@
   static inline ConstType Get(int number, const ExtensionSet& set, int index) {
     return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
   }
+  static inline std::nullptr_t GetPtr(int number, const ExtensionSet& set,
+                                      int index) {
+    // Cannot be implemented because of forward declared messages?
+    return nullptr;
+  }
+  static inline std::nullptr_t GetRepeatedPtr(int number,
+                                              const ExtensionSet& set) {
+    // Cannot be implemented because of forward declared messages?
+    return nullptr;
+  }
   static inline MutableType Mutable(int number, int index, ExtensionSet* set) {
     return static_cast<Type*>(set->MutableRepeatedMessage(number, index));
   }
@@ -1347,7 +1454,7 @@
 //     optional int32 bar = 1234;
 //   }
 // then "bar" will be defined in C++ as:
-//   ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32>, 5, false> bar(1234);
+//   ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32_t>, 5, false> bar(1234);
 //
 // Note that we could, in theory, supply the field number as a template
 // parameter, and thus make an instance of ExtensionIdentifier have no
@@ -1378,6 +1485,10 @@
     TypeTraits::template Register<ExtendeeType>(number, field_type, is_packed);
   }
 
+  typename TypeTraits::ConstType const& default_value_ref() const {
+    return default_value_;
+  }
+
  private:
   const int number_;
   typename TypeTraits::ConstType default_value_;
@@ -1386,190 +1497,6 @@
 // -------------------------------------------------------------------
 // Generated accessors
 
-// This macro should be expanded in the context of a generated type which
-// has extensions.
-//
-// We use "_proto_TypeTraits" as a type name below because "TypeTraits"
-// causes problems if the class has a nested message or enum type with that
-// name and "_TypeTraits" is technically reserved for the C++ library since
-// it starts with an underscore followed by a capital letter.
-//
-// For similar reason, we use "_field_type" and "_is_packed" as parameter names
-// below, so that "field_type" and "is_packed" can be used as field names.
-#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME)                       \
-  /* Has, Size, Clear */                                                      \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline bool HasExtension(                                                   \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
-    return _extensions_.Has(id.number());                                     \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline void ClearExtension(                                                 \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) {       \
-    _extensions_.ClearExtension(id.number());                                 \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline int ExtensionSize(                                                   \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
-    return _extensions_.ExtensionSize(id.number());                           \
-  }                                                                           \
-                                                                              \
-  /* Singular accessors */                                                    \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(        \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
-    return _proto_TypeTraits::Get(id.number(), _extensions_,                  \
-                                  id.default_value());                        \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(  \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) {       \
-    return _proto_TypeTraits::Mutable(id.number(), _field_type,               \
-                                      &_extensions_);                         \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline void SetExtension(                                                   \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id,         \
-      typename _proto_TypeTraits::Singular::ConstType value) {                \
-    _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_);   \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline void SetAllocatedExtension(                                          \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id,         \
-      typename _proto_TypeTraits::Singular::MutableType value) {              \
-    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,          \
-                                    &_extensions_);                           \
-  }                                                                           \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline void UnsafeArenaSetAllocatedExtension(                               \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id,         \
-      typename _proto_TypeTraits::Singular::MutableType value) {              \
-    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,      \
-                                               value, &_extensions_);         \
-  }                                                                           \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline PROTOBUF_MUST_USE_RESULT                                             \
-      typename _proto_TypeTraits::Singular::MutableType                       \
-      ReleaseExtension(                                                       \
-          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<       \
-              CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) {   \
-    return _proto_TypeTraits::Release(id.number(), _field_type,               \
-                                      &_extensions_);                         \
-  }                                                                           \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline typename _proto_TypeTraits::Singular::MutableType                    \
-  UnsafeArenaReleaseExtension(                                                \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) {       \
-    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,    \
-                                                 &_extensions_);              \
-  }                                                                           \
-                                                                              \
-  /* Repeated accessors */                                                    \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(        \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id,         \
-      int index) const {                                                      \
-    return _proto_TypeTraits::Get(id.number(), _extensions_, index);          \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(  \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id,         \
-      int index) {                                                            \
-    return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_);     \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline void SetExtension(                                                   \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id,         \
-      int index, typename _proto_TypeTraits::Repeated::ConstType value) {     \
-    _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);         \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(      \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) {       \
-    return _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_);   \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline void AddExtension(                                                   \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id,         \
-      typename _proto_TypeTraits::Repeated::ConstType value) {                \
-    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,       \
-                           &_extensions_);                                    \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&       \
-  GetRepeatedExtension(                                                       \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
-    return _proto_TypeTraits::GetRepeated(id.number(), _extensions_);         \
-  }                                                                           \
-                                                                              \
-  template <typename _proto_TypeTraits,                                       \
-            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,         \
-            bool _is_packed>                                                  \
-  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*             \
-  MutableRepeatedExtension(                                                   \
-      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<           \
-          CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) {       \
-    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,       \
-                                              _is_packed, &_extensions_);     \
-  }
-
 }  // namespace internal
 
 // Call this function to ensure that this extensions's reflection is linked into
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 76ac076..375be1e 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -35,8 +35,6 @@
 // Contains methods defined in extension_set.h which cannot be part of the
 // lite library because they use descriptors or reflection.
 
-#include <google/protobuf/extension_set.h>
-
 #include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/extension_set_inl.h>
@@ -44,7 +42,9 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/extension_set.h>
 #include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format.h>
@@ -62,16 +62,16 @@
  public:
   explicit MessageSetFieldSkipper(UnknownFieldSet* unknown_fields)
       : UnknownFieldSetFieldSkipper(unknown_fields) {}
-  virtual ~MessageSetFieldSkipper() {}
+  ~MessageSetFieldSkipper() override {}
 
   virtual bool SkipMessageSetField(io::CodedInputStream* input,
                                    int field_number);
 };
 bool MessageSetFieldSkipper::SkipMessageSetField(io::CodedInputStream* input,
                                                  int field_number) {
-  uint32 length;
+  uint32_t length;
   if (!input->ReadVarint32(&length)) return false;
-  if (unknown_fields_ == NULL) {
+  if (unknown_fields_ == nullptr) {
     return input->Skip(length);
   } else {
     return input->ReadString(unknown_fields_->AddLengthDelimited(field_number),
@@ -116,7 +116,7 @@
       //   initialized, so they might not even be constructed until
       //   AppendToList() is called.
 
-      if (ext.descriptor == NULL) {
+      if (ext.descriptor == nullptr) {
         output->push_back(pool->FindExtensionByNumber(containing_type, number));
       } else {
         output->push_back(ext.descriptor);
@@ -150,7 +150,7 @@
                                             const Descriptor* message_type,
                                             MessageFactory* factory) const {
   const Extension* extension = FindOrNull(number);
-  if (extension == NULL || extension->is_cleared) {
+  if (extension == nullptr || extension->is_cleared) {
     // Not present.  Return the default value.
     return *factory->GetPrototype(message_type);
   } else {
@@ -193,20 +193,20 @@
 MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
                                           MessageFactory* factory) {
   Extension* extension = FindOrNull(descriptor->number());
-  if (extension == NULL) {
+  if (extension == nullptr) {
     // Not present.  Return NULL.
-    return NULL;
+    return nullptr;
   } else {
     GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
-    MessageLite* ret = NULL;
+    MessageLite* ret = nullptr;
     if (extension->is_lazy) {
       ret = extension->lazymessage_value->ReleaseMessage(
           *factory->GetPrototype(descriptor->message_type()));
-      if (arena_ == NULL) {
+      if (arena_ == nullptr) {
         delete extension->lazymessage_value;
       }
     } else {
-      if (arena_ != NULL) {
+      if (arena_ != nullptr) {
         ret = extension->message_value->New();
         ret->CheckTypeAndMergeFrom(*extension->message_value);
       } else {
@@ -221,16 +221,16 @@
 MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
     const FieldDescriptor* descriptor, MessageFactory* factory) {
   Extension* extension = FindOrNull(descriptor->number());
-  if (extension == NULL) {
+  if (extension == nullptr) {
     // Not present.  Return NULL.
-    return NULL;
+    return nullptr;
   } else {
     GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
-    MessageLite* ret = NULL;
+    MessageLite* ret = nullptr;
     if (extension->is_lazy) {
       ret = extension->lazymessage_value->UnsafeArenaReleaseMessage(
           *factory->GetPrototype(descriptor->message_type()));
-      if (arena_ == NULL) {
+      if (arena_ == nullptr) {
         delete extension->lazymessage_value;
       }
     } else {
@@ -266,11 +266,11 @@
       reinterpret_cast<internal::RepeatedPtrFieldBase*>(
           extension->repeated_message_value)
           ->AddFromCleared<GenericTypeHandler<MessageLite> >();
-  if (result == NULL) {
+  if (result == nullptr) {
     const MessageLite* prototype;
-    if (extension->repeated_message_value->size() == 0) {
+    if (extension->repeated_message_value->empty()) {
       prototype = factory->GetPrototype(descriptor->message_type());
-      GOOGLE_CHECK(prototype != NULL);
+      GOOGLE_CHECK(prototype != nullptr);
     } else {
       prototype = &extension->repeated_message_value->Get(0);
     }
@@ -287,15 +287,22 @@
   extension->repeated_message_value->AddAllocated(new_entry);
 }
 
+void ExtensionSet::UnsafeArenaAddAllocatedMessage(
+    const FieldDescriptor* descriptor, MessageLite* new_entry) {
+  Extension* extension = MaybeNewRepeatedExtension(descriptor);
+
+  extension->repeated_message_value->UnsafeArenaAddAllocated(new_entry);
+}
+
 static bool ValidateEnumUsingDescriptor(const void* arg, int number) {
   return reinterpret_cast<const EnumDescriptor*>(arg)->FindValueByNumber(
-             number) != NULL;
+             number) != nullptr;
 }
 
 bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
   const FieldDescriptor* extension =
       pool_->FindExtensionByNumber(containing_type_, number);
-  if (extension == NULL) {
+  if (extension == nullptr) {
     return false;
   } else {
     output->type = extension->type();
@@ -318,7 +325,7 @@
 }
 
 
-bool ExtensionSet::FindExtension(int wire_type, uint32 field,
+bool ExtensionSet::FindExtension(int wire_type, uint32_t field,
                                  const Message* containing_type,
                                  const internal::ParseContext* ctx,
                                  ExtensionInfo* extension,
@@ -340,7 +347,7 @@
   return true;
 }
 
-const char* ExtensionSet::ParseField(uint64 tag, const char* ptr,
+const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr,
                                      const Message* containing_type,
                                      internal::InternalMetadata* metadata,
                                      internal::ParseContext* ctx) {
@@ -357,7 +364,7 @@
 }
 
 const char* ExtensionSet::ParseFieldMaybeLazily(
-    uint64 tag, const char* ptr, const Message* containing_type,
+    uint64_t tag, const char* ptr, const Message* containing_type,
     internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
   return ParseField(tag, ptr, containing_type, metadata, ctx);
 }
@@ -369,11 +376,11 @@
                                                            metadata, ctx);
 }
 
-bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
+bool ExtensionSet::ParseField(uint32_t tag, io::CodedInputStream* input,
                               const Message* containing_type,
                               UnknownFieldSet* unknown_fields) {
   UnknownFieldSetFieldSkipper skipper(unknown_fields);
-  if (input->GetExtensionPool() == NULL) {
+  if (input->GetExtensionPool() == nullptr) {
     GeneratedExtensionFinder finder(containing_type);
     return ParseField(tag, input, &finder, &skipper);
   } else {
@@ -388,7 +395,7 @@
                                    const Message* containing_type,
                                    UnknownFieldSet* unknown_fields) {
   MessageSetFieldSkipper skipper(unknown_fields);
-  if (input->GetExtensionPool() == NULL) {
+  if (input->GetExtensionPool() == nullptr) {
     GeneratedExtensionFinder finder(containing_type);
     return ParseMessageSet(input, &finder, &skipper);
   } else {
@@ -426,10 +433,10 @@
                   repeated_##LOWERCASE##_value->SpaceUsedExcludingSelfLong(); \
     break
 
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(BOOL, bool);
@@ -469,12 +476,13 @@
   return total_size;
 }
 
-uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
-    uint8* target) const {
+uint8_t* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
+    const MessageLite* extendee, uint8_t* target) const {
   io::EpsCopyOutputStream stream(
       target, MessageSetByteSize(),
       io::CodedOutputStream::IsDefaultSerializationDeterministic());
-  return InternalSerializeMessageSetWithCachedSizesToArray(target, &stream);
+  return InternalSerializeMessageSetWithCachedSizesToArray(extendee, target,
+                                                           &stream);
 }
 
 bool ExtensionSet::ParseFieldMaybeLazily(
@@ -490,7 +498,7 @@
                                    ExtensionFinder* extension_finder,
                                    MessageSetFieldSkipper* field_skipper) {
   while (true) {
-    const uint32 tag = input->ReadTag();
+    const uint32_t tag = input->ReadTag();
     switch (tag) {
       case 0:
         return true;
@@ -518,7 +526,7 @@
           extension_finder, field_skipper);
     }
 
-    bool SkipField(uint32 tag, io::CodedInputStream* input) {
+    bool SkipField(uint32_t tag, io::CodedInputStream* input) {
       return field_skipper->SkipField(input, tag);
     }
 
diff --git a/src/google/protobuf/extension_set_inl.h b/src/google/protobuf/extension_set_inl.h
index 074784b..291990f 100644
--- a/src/google/protobuf/extension_set_inl.h
+++ b/src/google/protobuf/extension_set_inl.h
@@ -83,7 +83,7 @@
     switch (extension.type) {
 #define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE)                        \
   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    uint64 value;                                                           \
+    uint64_t value;                                                         \
     ptr = VarintParse(ptr, &value);                                         \
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
     if (extension.is_repeated) {                                            \
@@ -103,7 +103,7 @@
 #undef HANDLE_VARINT_TYPE
 #define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE)                 \
   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    uint64 val;                                                             \
+    uint64_t val;                                                           \
     ptr = VarintParse(ptr, &val);                                           \
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
     auto value = WireFormatLite::ZigZagDecode##SIZE(val);                   \
@@ -132,16 +132,16 @@
     }                                                                       \
   } break
 
-      HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32);
-      HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64);
-      HANDLE_FIXED_TYPE(SFIXED32, Int32, int32);
-      HANDLE_FIXED_TYPE(SFIXED64, Int64, int64);
+      HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32_t);
+      HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64_t);
+      HANDLE_FIXED_TYPE(SFIXED32, Int32, int32_t);
+      HANDLE_FIXED_TYPE(SFIXED64, Int64, int64_t);
       HANDLE_FIXED_TYPE(FLOAT, Float, float);
       HANDLE_FIXED_TYPE(DOUBLE, Double, double);
 #undef HANDLE_FIXED_TYPE
 
       case WireFormatLite::TYPE_ENUM: {
-        uint64 val;
+        uint64_t val;
         ptr = VarintParse(ptr, &val);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         int value = val;
@@ -181,7 +181,7 @@
                 : MutableMessage(number, WireFormatLite::TYPE_GROUP,
                                  *extension.message_info.prototype,
                                  extension.descriptor);
-        uint32 tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
+        uint32_t tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
         return ctx->ParseGroup(value, ptr, tag);
       }
 
@@ -203,22 +203,22 @@
 
 template <typename Msg, typename T>
 const char* ExtensionSet::ParseMessageSetItemTmpl(
-    const char* ptr, const Msg* containing_type,
-    internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
+    const char* ptr, const Msg* extendee, internal::InternalMetadata* metadata,
+    internal::ParseContext* ctx) {
   std::string payload;
-  uint32 type_id = 0;
+  uint32_t type_id = 0;
   bool payload_read = false;
   while (!ctx->Done(&ptr)) {
-    uint32 tag = static_cast<uint8>(*ptr++);
+    uint32_t tag = static_cast<uint8_t>(*ptr++);
     if (tag == WireFormatLite::kMessageSetTypeIdTag) {
-      uint64 tmp;
+      uint64_t tmp;
       ptr = ParseBigVarint(ptr, &tmp);
       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       type_id = tmp;
       if (payload_read) {
         ExtensionInfo extension;
         bool was_packed_on_wire;
-        if (!FindExtension(2, type_id, containing_type, ctx, &extension,
+        if (!FindExtension(2, type_id, extendee, ctx, &extension,
                            &was_packed_on_wire)) {
           WriteLengthDelimited(type_id, payload,
                                metadata->mutable_unknown_fields<T>());
@@ -245,12 +245,12 @@
       }
     } else if (tag == WireFormatLite::kMessageSetMessageTag) {
       if (type_id != 0) {
-        ptr = ParseFieldMaybeLazily(static_cast<uint64>(type_id) * 8 + 2, ptr,
-                                    containing_type, metadata, ctx);
+        ptr = ParseFieldMaybeLazily(static_cast<uint64_t>(type_id) * 8 + 2, ptr,
+                                    extendee, metadata, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         type_id = 0;
       } else {
-        int32 size = ReadSize(&ptr);
+        int32_t size = ReadSize(&ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ptr = ctx->ReadString(ptr, size, &payload);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
@@ -262,7 +262,7 @@
         ctx->SetLastTag(tag);
         return ptr;
       }
-      ptr = ParseField(tag, ptr, containing_type, metadata, ctx);
+      ptr = ParseField(tag, ptr, extendee, metadata, ctx);
       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     }
   }
diff --git a/src/google/protobuf/field_access_listener.cc b/src/google/protobuf/field_access_listener.cc
index 56e175a..52913ce 100644
--- a/src/google/protobuf/field_access_listener.cc
+++ b/src/google/protobuf/field_access_listener.cc
@@ -29,24 +29,3 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <google/protobuf/field_access_listener.h>
-
-#include <google/protobuf/stubs/once.h>
-
-namespace google {
-namespace protobuf {
-
-internal::once_flag FieldAccessListener::register_once_ = {};
-FieldAccessListener* FieldAccessListener::field_listener_ = nullptr;
-
-FieldAccessListener* FieldAccessListener::GetListener() {
-  return field_listener_;
-}
-
-void FieldAccessListener::RegisterListener(FieldAccessListener* listener) {
-  // TODO(danilak): Add a GOOGLE_DCHECK for message_injector_ to be nullptr and update
-  // tests.
-  internal::call_once(register_once_, [&] { field_listener_ = listener; });
-}
-
-}  // namespace protobuf
-}  // namespace google
diff --git a/src/google/protobuf/field_access_listener.h b/src/google/protobuf/field_access_listener.h
index 660ad73..47422e6 100644
--- a/src/google/protobuf/field_access_listener.h
+++ b/src/google/protobuf/field_access_listener.h
@@ -32,215 +32,141 @@
 #define GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
 
 #include <cstddef>
-#include <functional>
-#include <string>
-#include <type_traits>
-#include <utility>
-#include <vector>
 
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/arenastring.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/map.h>
-#include <google/protobuf/stubs/once.h>
-#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/message_lite.h>
 
 
 namespace google {
 namespace protobuf {
-namespace internal {
-template <typename T>
-struct ResolvedType {
-  using type = T;
+
+// A default/no-op implementation of message hooks.
+//
+// See go/statically-dispatched-message-hooks for details.
+template <typename Proto>
+struct NoOpAccessListener {
+  // Number of fields are provided at compile time for the trackers to be able
+  // to have stack allocated bitmaps for the fields. This is useful for
+  // performance critical trackers. This is also to avoid cyclic dependencies
+  // if the number of fields is needed.
+  static constexpr int kFields = Proto::_kInternalFieldNumber;
+  // Default constructor is called during the static global initialization of
+  // the program.
+  // We provide a pointer to extract the name of the proto not to get cyclic
+  // dependencies on GetDescriptor() and OnGetMetadata() calls. If you want
+  // to differentiate the protos during the runtime before the start of the
+  // program, use this functor to get its name. We either way need it for
+  // LITE_RUNTIME protos as they don't have descriptors at all.
+  explicit NoOpAccessListener(StringPiece (*name_extractor)()) {}
+  // called repeatedly during serialization/deserialization/ByteSize of
+  // Reflection as:
+  //   AccessListener<MessageT>::OnSerialize(this);
+  static void OnSerialize(const MessageLite* msg) {}
+  static void OnDeserialize(const MessageLite* msg) {}
+  static void OnByteSize(const MessageLite* msg) {}
+  static void OnMergeFrom(const MessageLite* to, const MessageLite* from) {}
+
+  // NOTE: This function can be called pre-main. Make sure it does not make
+  // the state of the listener invalid.
+  static void OnGetMetadata() {}
+
+  // called from accessors as:
+  //   AccessListener<MessageT>::On$operation(this, &field_storage_);
+  // If you need to override this with type, in your hook implementation
+  // introduce
+  // template <int kFieldNum, typename T>
+  // static void On$operation(const MessageLite* msg,
+  //                          const T* field) {}
+  // And overloads for std::nullptr_t for incomplete types such as Messages,
+  // Maps. Extract them using reflection if you need. Consequently, second
+  // argument can be null pointer.
+  // For an example, see proto_hooks/testing/memory_test_field_listener.h
+  // And argument template deduction will deduce the type itself without
+  // changing the generated code.
+
+  // add_<field>(f)
+  template <int kFieldNum>
+  static void OnAdd(const MessageLite* msg, const void* field) {}
+
+  // add_<field>()
+  template <int kFieldNum>
+  static void OnAddMutable(const MessageLite* msg, const void* field) {}
+
+  // <field>() and <repeated_field>(i)
+  template <int kFieldNum>
+  static void OnGet(const MessageLite* msg, const void* field) {}
+
+  // clear_<field>()
+  template <int kFieldNum>
+  static void OnClear(const MessageLite* msg, const void* field) {}
+
+  // has_<field>()
+  template <int kFieldNum>
+  static void OnHas(const MessageLite* msg, const void* field) {}
+
+  // <repeated_field>()
+  template <int kFieldNum>
+  static void OnList(const MessageLite* msg, const void* field) {}
+
+  // mutable_<field>()
+  template <int kFieldNum>
+  static void OnMutable(const MessageLite* msg, const void* field) {}
+
+  // mutable_<repeated_field>()
+  template <int kFieldNum>
+  static void OnMutableList(const MessageLite* msg, const void* field) {}
+
+  // release_<field>()
+  template <int kFieldNum>
+  static void OnRelease(const MessageLite* msg, const void* field) {}
+
+  // set_<field>() and set_<repeated_field>(i)
+  template <int kFieldNum>
+  static void OnSet(const MessageLite* msg, const void* field) {}
+
+  // <repeated_field>_size()
+  template <int kFieldNum>
+  static void OnSize(const MessageLite* msg, const void* field) {}
+
+  static void OnHasExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  // TODO(b/190614678): Support clear in the proto compiler.
+  static void OnClearExtension(const MessageLite* msg, int extension_tag,
+                               const void* field) {}
+  static void OnExtensionSize(const MessageLite* msg, int extension_tag,
+                              const void* field) {}
+  static void OnGetExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  static void OnMutableExtension(const MessageLite* msg, int extension_tag,
+                                 const void* field) {}
+  static void OnSetExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  static void OnReleaseExtension(const MessageLite* msg, int extension_tag,
+                                 const void* field) {}
+  static void OnAddExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  static void OnAddMutableExtension(const MessageLite* msg, int extension_tag,
+                                    const void* field) {}
+  static void OnListExtension(const MessageLite* msg, int extension_tag,
+                              const void* field) {}
+  static void OnMutableListExtension(const MessageLite* msg, int extension_tag,
+                                     const void* field) {}
 };
-}  // namespace internal
-// Tracks the events of field accesses for all protos
-// that are built with --inject_field_listener_events. This is a global
-// interface which you must implement yourself and register with
-// RegisterListener() function. All events consist of Descriptors,
-// FieldAccessTypes and the underlying storage for tracking the memory which is
-// accessed where possible and makes sense. Users are responsible for the
-// implementations to be thread safe.
-class FieldAccessListener {
- public:
-  FieldAccessListener() = default;
-  virtual ~FieldAccessListener() = default;
-
-  // The memory annotations of the proto fields that are touched by the
-  // accessors. They are returned as if the operation completes.
-  struct DataAnnotation {
-    DataAnnotation() = default;
-    DataAnnotation(const void* other_address, size_t other_size)
-        : address(other_address), size(other_size) {}
-    const void* address = nullptr;
-    size_t size = 0;
-  };
-  using AddressInfo = std::vector<DataAnnotation>;
-  using AddressInfoExtractor = std::function<AddressInfo()>;
-
-  enum class FieldAccessType {
-    kAdd,          // add_<field>(f)
-    kAddMutable,   // add_<field>()
-    kGet,          // <field>() and <repeated_field>(i)
-    kClear,        // clear_<field>()
-    kHas,          // has_<field>()
-    kList,         // <repeated_field>()
-    kMutable,      // mutable_<field>()
-    kMutableList,  // mutable_<repeated_field>()
-    kRelease,      // release_<field>()
-    kSet,          // set_<field>() and set_<repeated_field>(i)
-    kSize,         // <repeated_field>_size()
-  };
-
-  static FieldAccessListener* GetListener();
-
-  // Registers the field listener, can be called only once, |listener| must
-  // outlive all proto accesses (in most cases, the lifetime of the program).
-  static void RegisterListener(FieldAccessListener* listener);
-
-  // All field accessors noted in FieldAccessType have this call.
-  // |extractor| extracts the address info from the field
-  virtual void OnFieldAccess(const AddressInfoExtractor& extractor,
-                             const FieldDescriptor* descriptor,
-                             FieldAccessType access_type) = 0;
-
-  // Side effect calls.
-  virtual void OnDeserializationAccess(const Message* message) = 0;
-  virtual void OnSerializationAccess(const Message* message) = 0;
-  virtual void OnReflectionAccess(const Descriptor* descriptor) = 0;
-  virtual void OnByteSizeAccess(const Message* message) = 0;
-  // We can probably add more if we need to, like {Merge,Copy}{From}Access.
-
-  // Extracts all the addresses from the underlying fields.
-  template <typename T>
-  AddressInfo ExtractFieldInfo(const T* field_value);
-
-
- private:
-  template <typename T>
-  AddressInfo ExtractFieldInfoSpecific(const T* field_value,
-                                       internal::ResolvedType<T>);
-
-  AddressInfo ExtractFieldInfoSpecific(const Message* field_value,
-                                       internal::ResolvedType<Message>);
-
-  AddressInfo ExtractFieldInfoSpecific(const std::string* field_value,
-                                       internal::ResolvedType<std::string>);
-
-  AddressInfo ExtractFieldInfoSpecific(
-      const internal::ArenaStringPtr* field_value,
-      internal::ResolvedType<internal::ArenaStringPtr>);
-
-  template <typename T>
-  AddressInfo ExtractFieldInfoSpecific(
-      const RepeatedField<T>* field_value,
-      internal::ResolvedType<RepeatedField<T>>);
-
-  template <typename T>
-  AddressInfo ExtractFieldInfoSpecific(
-      const RepeatedPtrField<T>* field_value,
-      internal::ResolvedType<RepeatedPtrField<T>>);
-
-  template <typename K, typename V>
-  AddressInfo ExtractFieldInfoSpecific(const Map<K, V>* field_value,
-                                       internal::ResolvedType<Map<K, V>>);
-
-  static internal::once_flag register_once_;
-  static FieldAccessListener* field_listener_;
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldAccessListener);
-};
-
-template <typename T>
-inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfo(
-    const T* field_value) {
-  return ExtractFieldInfoSpecific(field_value, internal::ResolvedType<T>());
-}
-
-
-template <typename T>
-inline FieldAccessListener::AddressInfo
-FieldAccessListener::ExtractFieldInfoSpecific(const T* field_value,
-                                              internal::ResolvedType<T>) {
-  static_assert(std::is_trivial<T>::value,
-                "This overload should be chosen only for trivial types");
-  return FieldAccessListener::AddressInfo{FieldAccessListener::DataAnnotation(
-      static_cast<const void*>(field_value), sizeof(*field_value))};
-}
-
-inline FieldAccessListener::AddressInfo
-FieldAccessListener::ExtractFieldInfoSpecific(
-    const std::string* field_value, internal::ResolvedType<std::string>) {
-  return FieldAccessListener::AddressInfo{FieldAccessListener::DataAnnotation(
-      static_cast<const void*>(field_value->c_str()), field_value->length())};
-}
-
-inline FieldAccessListener::AddressInfo
-FieldAccessListener::ExtractFieldInfoSpecific(
-    const internal::ArenaStringPtr* field_value,
-    internal::ResolvedType<internal::ArenaStringPtr>) {
-  return FieldAccessListener::ExtractFieldInfoSpecific(
-      field_value->GetPointer(), internal::ResolvedType<std::string>());
-}
-
-template <typename T>
-inline FieldAccessListener::AddressInfo
-FieldAccessListener::ExtractFieldInfoSpecific(
-    const RepeatedField<T>* field_value,
-    internal::ResolvedType<RepeatedField<T>>) {
-  // TODO(jianzhouzh): This can cause data races. Synchronize this if needed.
-  FieldAccessListener::AddressInfo address_info;
-  address_info.reserve(field_value->size());
-  for (int i = 0, ie = field_value->size(); i < ie; ++i) {
-    auto sub = ExtractFieldInfoSpecific(&field_value->Get(i),
-                                        internal::ResolvedType<T>());
-    address_info.insert(address_info.end(), sub.begin(), sub.end());
-  }
-  return address_info;
-}
-
-template <typename T>
-inline FieldAccessListener::AddressInfo
-FieldAccessListener::ExtractFieldInfoSpecific(
-    const RepeatedPtrField<T>* field_value,
-    internal::ResolvedType<RepeatedPtrField<T>>) {
-  FieldAccessListener::AddressInfo address_info;
-  // TODO(jianzhouzh): This can cause data races. Synchronize this if needed.
-  address_info.reserve(field_value->size());
-  for (int i = 0, ie = field_value->size(); i < ie; ++i) {
-    auto sub = ExtractFieldInfoSpecific(&field_value->Get(i),
-                                        internal::ResolvedType<T>());
-    address_info.insert(address_info.end(), sub.begin(), sub.end());
-  }
-  return address_info;
-}
-
-template <typename K, typename V>
-inline FieldAccessListener::AddressInfo
-FieldAccessListener::ExtractFieldInfoSpecific(
-    const Map<K, V>* field_value, internal::ResolvedType<Map<K, V>>) {
-  // TODO(jianzhouzh): This can cause data races. Synchronize this if needed.
-  FieldAccessListener::AddressInfo address_info;
-  address_info.reserve(field_value->size());
-  for (auto it = field_value->begin(); it != field_value->end(); ++it) {
-    auto sub_first =
-        ExtractFieldInfoSpecific(&it->first, internal::ResolvedType<K>());
-    auto sub_second =
-        ExtractFieldInfoSpecific(&it->second, internal::ResolvedType<V>());
-    address_info.insert(address_info.end(), sub_first.begin(), sub_first.end());
-    address_info.insert(address_info.end(), sub_second.begin(),
-                        sub_second.end());
-  }
-  return address_info;
-}
-
-inline FieldAccessListener::AddressInfo
-FieldAccessListener::ExtractFieldInfoSpecific(const Message* field_value,
-                                              internal::ResolvedType<Message>) {
-  // TODO(jianzhouzh): implement and adjust all annotations in the compiler.
-  return {};
-}
 
 }  // namespace protobuf
 }  // namespace google
 
+#ifndef REPLACE_PROTO_LISTENER_IMPL
+namespace google {
+namespace protobuf {
+template <class T>
+using AccessListener = NoOpAccessListener<T>;
+}  // namespace protobuf
+}  // namespace google
+#else
+// You can put your implementations of hooks/listeners here.
+// All hooks are subject to approval by protobuf-team@.
+
+#endif  // !REPLACE_PROTO_LISTENER_IMPL
+
 #endif  // GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index d073936..988dd34 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -40,10 +40,11 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FieldMask, paths_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::FieldMask)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::FieldMask)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -148,28 +149,29 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -213,13 +215,7 @@
       paths_.Get(i));
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FieldMask::_class_data_ = {
@@ -228,8 +224,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldMask::GetClassData() const { return &_class_data_; }
 
-void FieldMask::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void FieldMask::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<FieldMask *>(to)->MergeFrom(
       static_cast<const FieldMask &>(from));
 }
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index 2c690fa..a46011a 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -142,7 +142,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const FieldMask& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index f50352f..a77d04f 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -43,6 +43,7 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/inlined_string_field.h>
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/map_field_inl.h>
 #include <google/protobuf/stubs/mutex.h>
@@ -61,6 +62,7 @@
 using google::protobuf::internal::ExtensionSet;
 using google::protobuf::internal::GenericTypeHandler;
 using google::protobuf::internal::GetEmptyString;
+using google::protobuf::internal::InlinedStringField;
 using google::protobuf::internal::InternalMetadata;
 using google::protobuf::internal::LazyField;
 using google::protobuf::internal::MapFieldBase;
@@ -256,6 +258,10 @@
           schema_.IsEagerlyVerifiedLazyField(field));
 }
 
+bool Reflection::IsInlined(const FieldDescriptor* field) const {
+  return schema_.IsFieldInlined(field);
+}
+
 size_t Reflection::SpaceUsedLong(const Message& message) const {
   // object_size_ already includes the in-memory representation of each field
   // in the message, so we only need to account for additional memory used by
@@ -277,10 +283,10 @@
                       .SpaceUsedExcludingSelfLong();                \
     break
 
-        HANDLE_TYPE(INT32, int32);
-        HANDLE_TYPE(INT64, int64);
-        HANDLE_TYPE(UINT32, uint32);
-        HANDLE_TYPE(UINT64, uint64);
+        HANDLE_TYPE(INT32, int32_t);
+        HANDLE_TYPE(INT64, int64_t);
+        HANDLE_TYPE(UINT32, uint32_t);
+        HANDLE_TYPE(UINT64, uint64_t);
         HANDLE_TYPE(DOUBLE, double);
         HANDLE_TYPE(FLOAT, float);
         HANDLE_TYPE(BOOL, bool);
@@ -332,6 +338,13 @@
           switch (field->options().ctype()) {
             default:  // TODO(kenton):  Support other string reps.
             case FieldOptions::STRING: {
+              if (IsInlined(field)) {
+                const std::string* ptr =
+                    &GetField<InlinedStringField>(message, field).GetNoArena();
+                total_size += StringSpaceUsedExcludingSelfLong(*ptr);
+                break;
+              }
+
               const std::string* ptr =
                   GetField<ArenaStringPtr>(message, field).GetPointer();
 
@@ -370,6 +383,71 @@
   return total_size;
 }
 
+namespace {
+
+template <bool unsafe_shallow_swap>
+struct OneofFieldMover {
+  template <typename FromType, typename ToType>
+  void operator()(const FieldDescriptor* field, FromType* from, ToType* to) {
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32:
+        to->SetInt32(from->GetInt32());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        to->SetInt64(from->GetInt64());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        to->SetUint32(from->GetUint32());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        to->SetUint64(from->GetUint64());
+        break;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        to->SetFloat(from->GetFloat());
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        to->SetDouble(from->GetDouble());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        to->SetBool(from->GetBool());
+        break;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        to->SetEnum(from->GetEnum());
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (!unsafe_shallow_swap) {
+          to->SetMessage(from->GetMessage());
+        } else {
+          to->UnsafeSetMessage(from->UnsafeGetMessage());
+        }
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        if (!unsafe_shallow_swap) {
+          to->SetString(from->GetString());
+          break;
+        }
+        switch (field->options().ctype()) {
+          default:
+          case FieldOptions::STRING: {
+            to->SetArenaStringPtr(from->GetArenaStringPtr());
+            break;
+          }
+        }
+        break;
+      default:
+        GOOGLE_LOG(FATAL) << "unimplemented type: " << field->cpp_type();
+    }
+    if (unsafe_shallow_swap) {
+      // Not clearing oneof case after move may cause unwanted "ClearOneof"
+      // where the residual message or string value is deleted and causes
+      // use-after-free (only for unsafe swap).
+      from->ClearOneofCase();
+    }
+  }
+};
+
+}  // namespace
+
 namespace internal {
 
 class SwapFieldHelper {
@@ -380,6 +458,14 @@
                                       const FieldDescriptor* field);
 
   template <bool unsafe_shallow_swap>
+  static void SwapInlinedStrings(const Reflection* r, Message* lhs,
+                                 Message* rhs, const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapNonInlinedStrings(const Reflection* r, Message* lhs,
+                                    Message* rhs, const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
   static void SwapStringField(const Reflection* r, Message* lhs, Message* rhs,
                               const FieldDescriptor* field);
 
@@ -421,21 +507,61 @@
 }
 
 template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapInlinedStrings(const Reflection* r, Message* lhs,
+                                         Message* rhs,
+                                         const FieldDescriptor* field) {
+  // Inlined string field.
+  Arena* lhs_arena = lhs->GetArenaForAllocation();
+  Arena* rhs_arena = rhs->GetArenaForAllocation();
+  auto* lhs_string = r->MutableRaw<InlinedStringField>(lhs, field);
+  auto* rhs_string = r->MutableRaw<InlinedStringField>(rhs, field);
+  const uint32 index = r->schema_.InlinedStringIndex(field);
+  uint32* lhs_state = &r->MutableInlinedStringDonatedArray(lhs)[index / 32];
+  uint32* rhs_state = &r->MutableInlinedStringDonatedArray(rhs)[index / 32];
+  const uint32 mask = ~(static_cast<uint32>(1) << (index % 32));
+  if (unsafe_shallow_swap || lhs_arena == rhs_arena) {
+    lhs_string->Swap(rhs_string, /*default_value=*/nullptr, lhs_arena,
+                     r->IsInlinedStringDonated(*lhs, field),
+                     r->IsInlinedStringDonated(*rhs, field),
+                     /*donating_states=*/lhs_state, rhs_state, mask);
+  } else {
+    const std::string temp = lhs_string->Get();
+    lhs_string->Set(nullptr, rhs_string->Get(), lhs_arena,
+                    r->IsInlinedStringDonated(*lhs, field), lhs_state, mask);
+    rhs_string->Set(nullptr, temp, rhs_arena,
+                    r->IsInlinedStringDonated(*rhs, field), rhs_state, mask);
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapNonInlinedStrings(const Reflection* r, Message* lhs,
+                                            Message* rhs,
+                                            const FieldDescriptor* field) {
+  ArenaStringPtr* lhs_string = r->MutableRaw<ArenaStringPtr>(lhs, field);
+  ArenaStringPtr* rhs_string = r->MutableRaw<ArenaStringPtr>(rhs, field);
+  if (unsafe_shallow_swap) {
+    ArenaStringPtr::UnsafeShallowSwap(lhs_string, rhs_string);
+  } else {
+    SwapFieldHelper::SwapArenaStringPtr(
+        r->DefaultRaw<ArenaStringPtr>(field).GetPointer(),  //
+        lhs_string, lhs->GetArenaForAllocation(),           //
+        rhs_string, rhs->GetArenaForAllocation());
+  }
+}
+
+template <bool unsafe_shallow_swap>
 void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs,
                                       Message* rhs,
                                       const FieldDescriptor* field) {
   switch (field->options().ctype()) {
     default:
     case FieldOptions::STRING: {
-      ArenaStringPtr* lhs_string = r->MutableRaw<ArenaStringPtr>(lhs, field);
-      ArenaStringPtr* rhs_string = r->MutableRaw<ArenaStringPtr>(rhs, field);
-      if (unsafe_shallow_swap) {
-        ArenaStringPtr::UnsafeShallowSwap(lhs_string, rhs_string);
+      if (r->IsInlined(field)) {
+        SwapFieldHelper::SwapInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs,
+                                                                 field);
       } else {
-        SwapFieldHelper::SwapArenaStringPtr(
-            r->DefaultRaw<ArenaStringPtr>(field).GetPointer(),  //
-            lhs_string, lhs->GetArenaForAllocation(),           //
-            rhs_string, rhs->GetArenaForAllocation());
+        SwapFieldHelper::SwapNonInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs,
+                                                                    field);
       }
       break;
     }
@@ -550,10 +676,10 @@
         ->Swap(MutableRaw<RepeatedField<TYPE> >(message2, field)); \
     break;
 
-      SWAP_ARRAYS(INT32, int32);
-      SWAP_ARRAYS(INT64, int64);
-      SWAP_ARRAYS(UINT32, uint32);
-      SWAP_ARRAYS(UINT64, uint64);
+      SWAP_ARRAYS(INT32, int32_t);
+      SWAP_ARRAYS(INT64, int64_t);
+      SWAP_ARRAYS(UINT32, uint32_t);
+      SWAP_ARRAYS(UINT64, uint64_t);
       SWAP_ARRAYS(FLOAT, float);
       SWAP_ARRAYS(DOUBLE, double);
       SWAP_ARRAYS(BOOL, bool);
@@ -580,10 +706,10 @@
               *MutableRaw<TYPE>(message2, field)); \
     break;
 
-      SWAP_VALUES(INT32, int32);
-      SWAP_VALUES(INT64, int64);
-      SWAP_VALUES(UINT32, uint32);
-      SWAP_VALUES(UINT64, uint64);
+      SWAP_VALUES(INT32, int32_t);
+      SWAP_VALUES(INT64, int64_t);
+      SWAP_VALUES(UINT32, uint32_t);
+      SWAP_VALUES(UINT64, uint64_t);
       SWAP_VALUES(FLOAT, float);
       SWAP_VALUES(DOUBLE, double);
       SWAP_VALUES(BOOL, bool);
@@ -607,9 +733,6 @@
 
 void Reflection::UnsafeShallowSwapField(Message* message1, Message* message2,
                                         const FieldDescriptor* field) const {
-  GOOGLE_DCHECK_EQ(message1->GetArenaForAllocation(),
-            message2->GetArenaForAllocation());
-
   if (!field->is_repeated()) {
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       internal::SwapFieldHelper::SwapMessageField<true>(this, message1,
@@ -630,10 +753,10 @@
         ->InternalSwap(MutableRaw<RepeatedField<TYPE>>(message2, field)); \
     break;
 
-    SHALLOW_SWAP_ARRAYS(INT32, int32);
-    SHALLOW_SWAP_ARRAYS(INT64, int64);
-    SHALLOW_SWAP_ARRAYS(UINT32, uint32);
-    SHALLOW_SWAP_ARRAYS(UINT64, uint64);
+    SHALLOW_SWAP_ARRAYS(INT32, int32_t);
+    SHALLOW_SWAP_ARRAYS(INT64, int64_t);
+    SHALLOW_SWAP_ARRAYS(UINT32, uint32_t);
+    SHALLOW_SWAP_ARRAYS(UINT64, uint64_t);
     SHALLOW_SWAP_ARRAYS(FLOAT, float);
     SHALLOW_SWAP_ARRAYS(DOUBLE, double);
     SHALLOW_SWAP_ARRAYS(BOOL, bool);
@@ -654,158 +777,130 @@
   }
 }
 
-void Reflection::SwapOneofField(Message* message1, Message* message2,
+// Swaps oneof field between lhs and rhs. If unsafe_shallow_swap is true, it
+// directly swaps oneof values; otherwise, it may involve copy/delete. Note that
+// two messages may have different oneof cases. So, it has to be done in three
+// steps (i.e. lhs -> temp, rhs -> lhs, temp -> rhs).
+template <bool unsafe_shallow_swap>
+void Reflection::SwapOneofField(Message* lhs, Message* rhs,
                                 const OneofDescriptor* oneof_descriptor) const {
+  // Wraps a local variable to temporarily store oneof value.
+  struct LocalVarWrapper {
+#define LOCAL_VAR_ACCESSOR(type, var, name)               \
+  type Get##name() const { return oneof_val.type_##var; } \
+  void Set##name(type v) { oneof_val.type_##var = v; }
+
+    LOCAL_VAR_ACCESSOR(int32_t, int32, Int32);
+    LOCAL_VAR_ACCESSOR(int64_t, int64, Int64);
+    LOCAL_VAR_ACCESSOR(uint32_t, uint32, Uint32);
+    LOCAL_VAR_ACCESSOR(uint64_t, uint64, Uint64);
+    LOCAL_VAR_ACCESSOR(float, float, Float);
+    LOCAL_VAR_ACCESSOR(double, double, Double);
+    LOCAL_VAR_ACCESSOR(bool, bool, Bool);
+    LOCAL_VAR_ACCESSOR(int, enum, Enum);
+    LOCAL_VAR_ACCESSOR(Message*, message, Message);
+    LOCAL_VAR_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
+    const std::string& GetString() const { return string_val; }
+    void SetString(const std::string& v) { string_val = v; }
+    Message* UnsafeGetMessage() const { return GetMessage(); }
+    void UnsafeSetMessage(Message* v) { SetMessage(v); }
+    void ClearOneofCase() {}
+
+    union {
+      int32_t type_int32;
+      int64_t type_int64;
+      uint32_t type_uint32;
+      uint64_t type_uint64;
+      float type_float;
+      double type_double;
+      bool type_bool;
+      int type_enum;
+      Message* type_message;
+      internal::ArenaStringPtr type_arena_string_ptr;
+    } oneof_val;
+
+    // std::string cannot be in union.
+    std::string string_val;
+  };
+
+  // Wraps a message pointer to read and write a field.
+  struct MessageWrapper {
+#define MESSAGE_FIELD_ACCESSOR(type, var, name)         \
+  type Get##name() const {                              \
+    return reflection->GetField<type>(*message, field); \
+  }                                                     \
+  void Set##name(type v) { reflection->SetField<type>(message, field, v); }
+
+    MESSAGE_FIELD_ACCESSOR(int32_t, int32, Int32);
+    MESSAGE_FIELD_ACCESSOR(int64_t, int64, Int64);
+    MESSAGE_FIELD_ACCESSOR(uint32_t, uint32, Uint32);
+    MESSAGE_FIELD_ACCESSOR(uint64_t, uint64, Uint64);
+    MESSAGE_FIELD_ACCESSOR(float, float, Float);
+    MESSAGE_FIELD_ACCESSOR(double, double, Double);
+    MESSAGE_FIELD_ACCESSOR(bool, bool, Bool);
+    MESSAGE_FIELD_ACCESSOR(int, enum, Enum);
+    MESSAGE_FIELD_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
+    std::string GetString() const {
+      return reflection->GetString(*message, field);
+    }
+    void SetString(const std::string& v) {
+      reflection->SetString(message, field, v);
+    }
+    Message* GetMessage() const {
+      return reflection->ReleaseMessage(message, field);
+    }
+    void SetMessage(Message* v) {
+      reflection->SetAllocatedMessage(message, v, field);
+    }
+    Message* UnsafeGetMessage() const {
+      return reflection->UnsafeArenaReleaseMessage(message, field);
+    }
+    void UnsafeSetMessage(Message* v) {
+      reflection->UnsafeArenaSetAllocatedMessage(message, v, field);
+    }
+    void ClearOneofCase() {
+      *reflection->MutableOneofCase(message, field->containing_oneof()) = 0;
+    }
+
+    const Reflection* reflection;
+    Message* message;
+    const FieldDescriptor* field;
+  };
+
   GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
-  uint32 oneof_case1 = GetOneofCase(*message1, oneof_descriptor);
-  uint32 oneof_case2 = GetOneofCase(*message2, oneof_descriptor);
+  uint32 oneof_case_lhs = GetOneofCase(*lhs, oneof_descriptor);
+  uint32 oneof_case_rhs = GetOneofCase(*rhs, oneof_descriptor);
 
-  int32 temp_int32 = 0;
-  int64 temp_int64 = 0;
-  uint32 temp_uint32 = 0;
-  uint64 temp_uint64 = 0;
-  float temp_float = 0;
-  double temp_double = 0;
-  bool temp_bool = false;
-  int temp_int = 0;
-  Message* temp_message = nullptr;
-  std::string temp_string;
-
-  // Stores message1's oneof field to a temp variable.
-  const FieldDescriptor* field1 = nullptr;
-  if (oneof_case1 > 0) {
-    field1 = descriptor_->FindFieldByNumber(oneof_case1);
-    // oneof_descriptor->field(oneof_case1);
-    switch (field1->cpp_type()) {
-#define GET_TEMP_VALUE(CPPTYPE, TYPE)                \
-  case FieldDescriptor::CPPTYPE_##CPPTYPE:           \
-    temp_##TYPE = GetField<TYPE>(*message1, field1); \
-    break;
-
-      GET_TEMP_VALUE(INT32, int32);
-      GET_TEMP_VALUE(INT64, int64);
-      GET_TEMP_VALUE(UINT32, uint32);
-      GET_TEMP_VALUE(UINT64, uint64);
-      GET_TEMP_VALUE(FLOAT, float);
-      GET_TEMP_VALUE(DOUBLE, double);
-      GET_TEMP_VALUE(BOOL, bool);
-      GET_TEMP_VALUE(ENUM, int);
-#undef GET_TEMP_VALUE
-      case FieldDescriptor::CPPTYPE_MESSAGE:
-        temp_message = ReleaseMessage(message1, field1);
-        break;
-
-      case FieldDescriptor::CPPTYPE_STRING:
-        temp_string = GetString(*message1, field1);
-        break;
-
-      default:
-        GOOGLE_LOG(FATAL) << "Unimplemented type: " << field1->cpp_type();
-    }
+  LocalVarWrapper temp;
+  MessageWrapper lhs_wrapper, rhs_wrapper;
+  const FieldDescriptor* field_lhs = nullptr;
+  OneofFieldMover<unsafe_shallow_swap> mover;
+  // lhs --> temp
+  if (oneof_case_lhs > 0) {
+    field_lhs = descriptor_->FindFieldByNumber(oneof_case_lhs);
+    lhs_wrapper = {this, lhs, field_lhs};
+    mover(field_lhs, &lhs_wrapper, &temp);
+  }
+  // rhs --> lhs
+  if (oneof_case_rhs > 0) {
+    const FieldDescriptor* f = descriptor_->FindFieldByNumber(oneof_case_rhs);
+    lhs_wrapper = {this, lhs, f};
+    rhs_wrapper = {this, rhs, f};
+    mover(f, &rhs_wrapper, &lhs_wrapper);
+  } else if (!unsafe_shallow_swap) {
+    ClearOneof(lhs, oneof_descriptor);
+  }
+  // temp --> rhs
+  if (oneof_case_lhs > 0) {
+    rhs_wrapper = {this, rhs, field_lhs};
+    mover(field_lhs, &temp, &rhs_wrapper);
+  } else if (!unsafe_shallow_swap) {
+    ClearOneof(rhs, oneof_descriptor);
   }
 
-  // Sets message1's oneof field from the message2's oneof field.
-  if (oneof_case2 > 0) {
-    const FieldDescriptor* field2 = descriptor_->FindFieldByNumber(oneof_case2);
-    switch (field2->cpp_type()) {
-#define SET_ONEOF_VALUE1(CPPTYPE, TYPE)                                  \
-  case FieldDescriptor::CPPTYPE_##CPPTYPE:                               \
-    SetField<TYPE>(message1, field2, GetField<TYPE>(*message2, field2)); \
-    break;
-
-      SET_ONEOF_VALUE1(INT32, int32);
-      SET_ONEOF_VALUE1(INT64, int64);
-      SET_ONEOF_VALUE1(UINT32, uint32);
-      SET_ONEOF_VALUE1(UINT64, uint64);
-      SET_ONEOF_VALUE1(FLOAT, float);
-      SET_ONEOF_VALUE1(DOUBLE, double);
-      SET_ONEOF_VALUE1(BOOL, bool);
-      SET_ONEOF_VALUE1(ENUM, int);
-#undef SET_ONEOF_VALUE1
-      case FieldDescriptor::CPPTYPE_MESSAGE:
-        SetAllocatedMessage(message1, ReleaseMessage(message2, field2), field2);
-        break;
-
-      case FieldDescriptor::CPPTYPE_STRING:
-        SetString(message1, field2, GetString(*message2, field2));
-        break;
-
-      default:
-        GOOGLE_LOG(FATAL) << "Unimplemented type: " << field2->cpp_type();
-    }
-  } else {
-    ClearOneof(message1, oneof_descriptor);
-  }
-
-  // Sets message2's oneof field from the temp variable.
-  if (oneof_case1 > 0) {
-    switch (field1->cpp_type()) {
-#define SET_ONEOF_VALUE2(CPPTYPE, TYPE)            \
-  case FieldDescriptor::CPPTYPE_##CPPTYPE:         \
-    SetField<TYPE>(message2, field1, temp_##TYPE); \
-    break;
-
-      SET_ONEOF_VALUE2(INT32, int32);
-      SET_ONEOF_VALUE2(INT64, int64);
-      SET_ONEOF_VALUE2(UINT32, uint32);
-      SET_ONEOF_VALUE2(UINT64, uint64);
-      SET_ONEOF_VALUE2(FLOAT, float);
-      SET_ONEOF_VALUE2(DOUBLE, double);
-      SET_ONEOF_VALUE2(BOOL, bool);
-      SET_ONEOF_VALUE2(ENUM, int);
-#undef SET_ONEOF_VALUE2
-      case FieldDescriptor::CPPTYPE_MESSAGE:
-        SetAllocatedMessage(message2, temp_message, field1);
-        break;
-
-      case FieldDescriptor::CPPTYPE_STRING:
-        SetString(message2, field1, temp_string);
-        break;
-
-      default:
-        GOOGLE_LOG(FATAL) << "Unimplemented type: " << field1->cpp_type();
-    }
-  } else {
-    ClearOneof(message2, oneof_descriptor);
-  }
-}
-
-void Reflection::UnsafeShallowSwapOneofField(
-    Message* message1, Message* message2,
-    const OneofDescriptor* oneof_descriptor) const {
-  GOOGLE_DCHECK_EQ(message1->GetArenaForAllocation(),
-            message2->GetArenaForAllocation());
-
-  uint32 oneof_case1 = GetOneofCase(*message1, oneof_descriptor);
-  const FieldDescriptor* field1 =
-      oneof_case1 > 0 ? descriptor_->FindFieldByNumber(oneof_case1) : nullptr;
-  uint32 oneof_case2 = GetOneofCase(*message2, oneof_descriptor);
-  const FieldDescriptor* field2 =
-      oneof_case2 > 0 ? descriptor_->FindFieldByNumber(oneof_case2) : nullptr;
-
-  if ((field1 != nullptr &&
-       field1->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) ||
-      (field2 != nullptr &&
-       field2->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)) {
-    // Fallback to SwapOneofField for non-message fields.
-    SwapOneofField(message1, message2, oneof_descriptor);
-    return;
-  }
-
-  Message* temp_message =
-      oneof_case1 > 0 ? UnsafeArenaReleaseMessage(message1, field1) : nullptr;
-
-  if (oneof_case2 > 0) {
-    UnsafeArenaSetAllocatedMessage(
-        message1, UnsafeArenaReleaseMessage(message2, field2), field2);
-  } else {
-    ClearOneof(message1, oneof_descriptor);
-  }
-
-  if (oneof_case1 > 0) {
-    UnsafeArenaSetAllocatedMessage(message2, temp_message, field1);
-  } else {
-    ClearOneof(message2, oneof_descriptor);
+  if (unsafe_shallow_swap) {
+    *MutableOneofCase(lhs, oneof_descriptor) = oneof_case_rhs;
+    *MutableOneofCase(rhs, oneof_descriptor) = oneof_case_lhs;
   }
 }
 
@@ -858,6 +953,9 @@
     return;
   }
 
+  GOOGLE_DCHECK_EQ(message1->GetOwningArena(), message2->GetOwningArena());
+
+  // TODO(seongkim): use UnsafeArenaSwap() after some flight miles.
   for (int i = 0; i <= last_non_weak_field_index_; i++) {
     const FieldDescriptor* field = descriptor_->field(i);
     if (schema_.InRealOneof(field)) continue;
@@ -868,15 +966,15 @@
   for (int i = 0; i < oneof_decl_count; i++) {
     const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
     if (!oneof->is_synthetic()) {
-      SwapOneofField(message1, message2, oneof);
+      SwapOneofField<false>(message1, message2, oneof);
     }
   }
 
   // Swapping bits need to happen after swapping fields, because the latter may
   // depend on the has bit information.
   if (schema_.HasHasbits()) {
-    uint32* has_bits1 = MutableHasBits(message1);
-    uint32* has_bits2 = MutableHasBits(message2);
+    uint32_t* has_bits1 = MutableHasBits(message1);
+    uint32_t* has_bits2 = MutableHasBits(message2);
 
     int fields_with_has_bits = 0;
     for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -927,6 +1025,9 @@
 
   std::set<int> swapped_oneof;
 
+  GOOGLE_DCHECK(!unsafe_shallow_swap || message1->GetArenaForAllocation() ==
+                                     message2->GetArenaForAllocation());
+
   for (const auto* field : fields) {
     CheckInvalidAccess(schema_, field);
     if (field->is_extension()) {
@@ -945,12 +1046,8 @@
           continue;
         }
         swapped_oneof.insert(oneof_index);
-        if (unsafe_shallow_swap) {
-          UnsafeShallowSwapOneofField(message1, message2,
-                                      field->containing_oneof());
-        } else {
-          SwapOneofField(message1, message2, field->containing_oneof());
-        }
+        SwapOneofField<unsafe_shallow_swap>(message1, message2,
+                                            field->containing_oneof());
       } else {
         // Swap field.
         if (unsafe_shallow_swap) {
@@ -981,6 +1078,13 @@
   SwapFieldsImpl<true>(message1, message2, fields);
 }
 
+void Reflection::UnsafeArenaSwapFields(
+    Message* lhs, Message* rhs,
+    const std::vector<const FieldDescriptor*>& fields) const {
+  GOOGLE_DCHECK_EQ(lhs->GetArenaForAllocation(), rhs->GetArenaForAllocation());
+  UnsafeShallowSwapFields(lhs, rhs, fields);
+}
+
 // -------------------------------------------------------------------
 
 bool Reflection::HasField(const Message& message,
@@ -1000,6 +1104,52 @@
   }
 }
 
+void Reflection::UnsafeArenaSwap(Message* lhs, Message* rhs) const {
+  if (lhs == rhs) return;
+
+  MutableInternalMetadata(lhs)->InternalSwap(MutableInternalMetadata(rhs));
+
+  for (int i = 0; i <= last_non_weak_field_index_; i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (schema_.InRealOneof(field)) continue;
+    if (schema_.IsFieldStripped(field)) continue;
+    UnsafeShallowSwapField(lhs, rhs, field);
+  }
+  const int oneof_decl_count = descriptor_->oneof_decl_count();
+  for (int i = 0; i < oneof_decl_count; i++) {
+    const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+    if (!oneof->is_synthetic()) {
+      SwapOneofField<true>(lhs, rhs, oneof);
+    }
+  }
+
+  // Swapping bits need to happen after swapping fields, because the latter may
+  // depend on the has bit information.
+  if (schema_.HasHasbits()) {
+    uint32* lhs_has_bits = MutableHasBits(lhs);
+    uint32* rhs_has_bits = MutableHasBits(rhs);
+
+    int fields_with_has_bits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = descriptor_->field(i);
+      if (field->is_repeated() || schema_.InRealOneof(field)) {
+        continue;
+      }
+      fields_with_has_bits++;
+    }
+
+    int has_bits_size = (fields_with_has_bits + 31) / 32;
+
+    for (int i = 0; i < has_bits_size; i++) {
+      std::swap(lhs_has_bits[i], rhs_has_bits[i]);
+    }
+  }
+
+  if (schema_.HasExtensionSet()) {
+    MutableExtensionSet(lhs)->InternalSwap(MutableExtensionSet(rhs));
+  }
+}
+
 int Reflection::FieldSize(const Message& message,
                           const FieldDescriptor* field) const {
   USAGE_CHECK_MESSAGE_TYPE(FieldSize);
@@ -1014,10 +1164,10 @@
   case FieldDescriptor::CPPTYPE_##UPPERCASE: \
     return GetRaw<RepeatedField<LOWERCASE> >(message, field).size()
 
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(BOOL, bool);
@@ -1068,10 +1218,10 @@
     *MutableRaw<TYPE>(message, field) = field->default_value_##TYPE(); \
     break;
 
-        CLEAR_TYPE(INT32, int32);
-        CLEAR_TYPE(INT64, int64);
-        CLEAR_TYPE(UINT32, uint32);
-        CLEAR_TYPE(UINT64, uint64);
+        CLEAR_TYPE(INT32, int32_t);
+        CLEAR_TYPE(INT64, int64_t);
+        CLEAR_TYPE(UINT32, uint32_t);
+        CLEAR_TYPE(UINT64, uint64_t);
         CLEAR_TYPE(FLOAT, float);
         CLEAR_TYPE(DOUBLE, double);
         CLEAR_TYPE(BOOL, bool);
@@ -1086,6 +1236,12 @@
           switch (field->options().ctype()) {
             default:  // TODO(kenton):  Support other string reps.
             case FieldOptions::STRING: {
+              if (IsInlined(field)) {
+                // Currently, string with default value can't be inlined. So we
+                // don't have to handle default value here.
+                MutableRaw<InlinedStringField>(message, field)->ClearToEmpty();
+                break;
+              }
               const std::string* default_ptr =
                   DefaultRaw<ArenaStringPtr>(field).GetPointer();
               MutableRaw<ArenaStringPtr>(message, field)
@@ -1098,7 +1254,7 @@
         }
 
         case FieldDescriptor::CPPTYPE_MESSAGE:
-          if (schema_.HasBitIndex(field) == static_cast<uint32>(-1)) {
+          if (schema_.HasBitIndex(field) == static_cast<uint32_t>(-1)) {
             // Proto3 does not have has-bits and we need to set a message field
             // to nullptr in order to indicate its un-presence.
             if (message->GetArenaForAllocation() == nullptr) {
@@ -1118,10 +1274,10 @@
     MutableRaw<RepeatedField<LOWERCASE> >(message, field)->Clear(); \
     break
 
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(BOOL, bool);
@@ -1168,10 +1324,10 @@
     MutableRaw<RepeatedField<LOWERCASE> >(message, field)->RemoveLast(); \
     break
 
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(BOOL, bool);
@@ -1228,6 +1384,26 @@
 #endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
 }
 
+Message* Reflection::UnsafeArenaReleaseLast(
+    Message* message, const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(UnsafeArenaReleaseLast, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->UnsafeArenaReleaseLast(field->number()));
+  } else {
+    if (IsMapFieldInApi(field)) {
+      return MutableRaw<MapFieldBase>(message, field)
+          ->MutableRepeatedField()
+          ->UnsafeArenaReleaseLast<GenericTypeHandler<Message>>();
+    } else {
+      return MutableRaw<RepeatedPtrFieldBase>(message, field)
+          ->UnsafeArenaReleaseLast<GenericTypeHandler<Message>>();
+    }
+  }
+}
+
 void Reflection::SwapElements(Message* message, const FieldDescriptor* field,
                               int index1, int index2) const {
   USAGE_CHECK_MESSAGE_TYPE(Swap);
@@ -1244,10 +1420,10 @@
         ->SwapElements(index1, index2);                   \
     break
 
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(BOOL, bool);
@@ -1278,10 +1454,10 @@
   }
 };
 
-bool IsIndexInHasBitSet(const uint32* has_bit_set, uint32 has_bit_index) {
+bool IsIndexInHasBitSet(const uint32_t* has_bit_set, uint32_t has_bit_index) {
   GOOGLE_DCHECK_NE(has_bit_index, ~0u);
   return ((has_bit_set[has_bit_index / 32] >> (has_bit_index % 32)) &
-          static_cast<uint32>(1)) != 0;
+          static_cast<uint32_t>(1)) != 0;
 }
 
 bool CreateUnknownEnumValues(const FileDescriptor* file) {
@@ -1310,9 +1486,9 @@
   // encapsulation because this function takes a noticeable about of CPU
   // fleetwide and properly allowing this optimization through public interfaces
   // seems more trouble than it is worth.
-  const uint32* const has_bits =
+  const uint32_t* const has_bits =
       schema_.HasHasbits() ? GetHasBits(message) : nullptr;
-  const uint32* const has_bits_indices = schema_.has_bit_indices_;
+  const uint32_t* const has_bits_indices = schema_.has_bit_indices_;
   output->reserve(descriptor_->field_count());
   const int last_non_weak_field_index = last_non_weak_field_index_;
   for (int i = 0; i <= last_non_weak_field_index; i++) {
@@ -1327,14 +1503,15 @@
     } else {
       const OneofDescriptor* containing_oneof = field->containing_oneof();
       if (schema_.InRealOneof(field)) {
-        const uint32* const oneof_case_array = GetConstPointerAtOffset<uint32>(
-            &message, schema_.oneof_case_offset_);
+        const uint32_t* const oneof_case_array =
+            GetConstPointerAtOffset<uint32_t>(&message,
+                                              schema_.oneof_case_offset_);
         // Equivalent to: HasOneofField(message, field)
-        if (static_cast<int64>(oneof_case_array[containing_oneof->index()]) ==
+        if (static_cast<int64_t>(oneof_case_array[containing_oneof->index()]) ==
             field->number()) {
           output->push_back(field);
         }
-      } else if (has_bits && has_bits_indices[i] != static_cast<uint32>(-1)) {
+      } else if (has_bits && has_bits_indices[i] != static_cast<uint32_t>(-1)) {
         CheckInvalidAccess(schema_, field);
         // Equivalent to: HasBit(message, field)
         if (IsIndexInHasBitSet(has_bits, has_bits_indices[i])) {
@@ -1427,10 +1604,10 @@
     }                                                                          \
   }
 
-DEFINE_PRIMITIVE_ACCESSORS(Int32, int32, int32, INT32)
-DEFINE_PRIMITIVE_ACCESSORS(Int64, int64, int64, INT64)
-DEFINE_PRIMITIVE_ACCESSORS(UInt32, uint32, uint32, UINT32)
-DEFINE_PRIMITIVE_ACCESSORS(UInt64, uint64, uint64, UINT64)
+DEFINE_PRIMITIVE_ACCESSORS(Int32, int32_t, int32_t, INT32)
+DEFINE_PRIMITIVE_ACCESSORS(Int64, int64_t, int64_t, INT64)
+DEFINE_PRIMITIVE_ACCESSORS(UInt32, uint32_t, uint32_t, UINT32)
+DEFINE_PRIMITIVE_ACCESSORS(UInt64, uint64_t, uint64_t, UINT64)
 DEFINE_PRIMITIVE_ACCESSORS(Float, float, float, FLOAT)
 DEFINE_PRIMITIVE_ACCESSORS(Double, double, double, DOUBLE)
 DEFINE_PRIMITIVE_ACCESSORS(Bool, bool, bool, BOOL)
@@ -1451,6 +1628,10 @@
     switch (field->options().ctype()) {
       default:  // TODO(kenton):  Support other string reps.
       case FieldOptions::STRING: {
+        if (IsInlined(field)) {
+          return GetField<InlinedStringField>(message, field).GetNoArena();
+        }
+
         if (auto* value =
                 GetField<ArenaStringPtr>(message, field).GetPointer()) {
           return *value;
@@ -1475,6 +1656,10 @@
     switch (field->options().ctype()) {
       default:  // TODO(kenton):  Support other string reps.
       case FieldOptions::STRING: {
+        if (IsInlined(field)) {
+          return GetField<InlinedStringField>(message, field).GetNoArena();
+        }
+
         if (auto* value =
                 GetField<ArenaStringPtr>(message, field).GetPointer()) {
           return *value;
@@ -1496,6 +1681,17 @@
     switch (field->options().ctype()) {
       default:  // TODO(kenton):  Support other string reps.
       case FieldOptions::STRING: {
+        if (IsInlined(field)) {
+          const uint32_t index = schema_.InlinedStringIndex(field);
+          uint32_t* states =
+              &MutableInlinedStringDonatedArray(message)[index / 32];
+          uint32_t mask = ~(static_cast<uint32_t>(1) << (index % 32));
+          MutableField<InlinedStringField>(message, field)
+              ->Set(nullptr, value, message->GetArenaForAllocation(),
+                    IsInlinedStringDonated(*message, field), states, mask);
+          break;
+        }
+
         // Oneof string fields are never set as a default instance.
         // We just need to pass some arbitrary default string to make it work.
         // This allows us to not have the real default accessible from
@@ -1599,7 +1795,7 @@
                              const FieldDescriptor* field) const {
   USAGE_CHECK_ALL(GetEnumValue, SINGULAR, ENUM);
 
-  int32 value;
+  int32_t value;
   if (field->is_extension()) {
     value = GetExtensionSet(message).GetEnum(
         field->number(), field->default_value_enum()->number());
@@ -1838,6 +2034,7 @@
   USAGE_CHECK_ALL(SetAllocatedMessage, SINGULAR, MESSAGE);
   CheckInvalidAccess(schema_, field);
 
+
   if (field->is_extension()) {
     MutableExtensionSet(message)->UnsafeArenaSetAllocatedMessage(
         field->number(), field->type(), field, sub_message);
@@ -1868,10 +2065,8 @@
 
 void Reflection::SetAllocatedMessage(Message* message, Message* sub_message,
                                      const FieldDescriptor* field) const {
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
-  GOOGLE_DCHECK(sub_message->GetOwningArena() == nullptr ||
+  GOOGLE_DCHECK(sub_message == nullptr || sub_message->GetOwningArena() == nullptr ||
          sub_message->GetOwningArena() == message->GetArenaForAllocation());
-#endif  // PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
   CheckInvalidAccess(schema_, field);
 
   // If message and sub-message are in different memory ownership domains
@@ -2051,6 +2246,27 @@
   }
 }
 
+void Reflection::UnsafeArenaAddAllocatedMessage(Message* message,
+                                                const FieldDescriptor* field,
+                                                Message* new_entry) const {
+  USAGE_CHECK_ALL(UnsafeArenaAddAllocatedMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->UnsafeArenaAddAllocatedMessage(field,
+                                                                 new_entry);
+  } else {
+    RepeatedPtrFieldBase* repeated = nullptr;
+    if (IsMapFieldInApi(field)) {
+      repeated =
+          MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+    } else {
+      repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+    }
+    repeated->UnsafeArenaAddAllocated<GenericTypeHandler<Message>>(new_entry);
+  }
+}
+
 void* Reflection::MutableRawRepeatedField(Message* message,
                                           const FieldDescriptor* field,
                                           FieldDescriptor::CppType cpptype,
@@ -2115,7 +2331,7 @@
     const FieldDescriptor* field = oneof_descriptor->field(0);
     return HasField(message, field) ? field : nullptr;
   }
-  uint32 field_number = GetOneofCase(message, oneof_descriptor);
+  uint32_t field_number = GetOneofCase(message, oneof_descriptor);
   if (field_number == 0) {
     return nullptr;
   }
@@ -2218,40 +2434,25 @@
 }
 
 template <typename Type>
-const Type& Reflection::GetRaw(const Message& message,
-                               const FieldDescriptor* field) const {
-  GOOGLE_DCHECK(!schema_.InRealOneof(field) || HasOneofField(message, field))
-      << "Field = " << field->full_name();
-  return GetConstRefAtOffset<Type>(message, schema_.GetFieldOffset(field));
-}
-
-template <typename Type>
 Type* Reflection::MutableRaw(Message* message,
                              const FieldDescriptor* field) const {
   return GetPointerAtOffset<Type>(message, schema_.GetFieldOffset(field));
 }
 
-const uint32* Reflection::GetHasBits(const Message& message) const {
+const uint32_t* Reflection::GetHasBits(const Message& message) const {
   GOOGLE_DCHECK(schema_.HasHasbits());
-  return &GetConstRefAtOffset<uint32>(message, schema_.HasBitsOffset());
+  return &GetConstRefAtOffset<uint32_t>(message, schema_.HasBitsOffset());
 }
 
-uint32* Reflection::MutableHasBits(Message* message) const {
+uint32_t* Reflection::MutableHasBits(Message* message) const {
   GOOGLE_DCHECK(schema_.HasHasbits());
-  return GetPointerAtOffset<uint32>(message, schema_.HasBitsOffset());
+  return GetPointerAtOffset<uint32_t>(message, schema_.HasBitsOffset());
 }
 
-uint32 Reflection::GetOneofCase(const Message& message,
-                                const OneofDescriptor* oneof_descriptor) const {
-  GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
-  return GetConstRefAtOffset<uint32>(
-      message, schema_.GetOneofCaseOffset(oneof_descriptor));
-}
-
-uint32* Reflection::MutableOneofCase(
+uint32_t* Reflection::MutableOneofCase(
     Message* message, const OneofDescriptor* oneof_descriptor) const {
   GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
-  return GetPointerAtOffset<uint32>(
+  return GetPointerAtOffset<uint32_t>(
       message, schema_.GetOneofCaseOffset(oneof_descriptor));
 }
 
@@ -2276,11 +2477,31 @@
                                               schema_.GetMetadataOffset());
 }
 
+const uint32_t* Reflection::GetInlinedStringDonatedArray(
+    const Message& message) const {
+  GOOGLE_DCHECK(schema_.HasInlinedString());
+  return &GetConstRefAtOffset<uint32_t>(message,
+                                        schema_.InlinedStringDonatedOffset());
+}
+
+uint32_t* Reflection::MutableInlinedStringDonatedArray(Message* message) const {
+  GOOGLE_DCHECK(schema_.HasHasbits());
+  return GetPointerAtOffset<uint32_t>(message,
+                                      schema_.InlinedStringDonatedOffset());
+}
+
+// Simple accessors for manipulating _inlined_string_donated_;
+bool Reflection::IsInlinedStringDonated(const Message& message,
+                                        const FieldDescriptor* field) const {
+  return IsIndexInHasBitSet(GetInlinedStringDonatedArray(message),
+                            schema_.InlinedStringIndex(field));
+}
+
 // Simple accessors for manipulating has_bits_.
 bool Reflection::HasBit(const Message& message,
                         const FieldDescriptor* field) const {
   GOOGLE_DCHECK(!field->options().weak());
-  if (schema_.HasBitIndex(field) != static_cast<uint32>(-1)) {
+  if (schema_.HasBitIndex(field) != static_cast<uint32_t>(-1)) {
     return IsIndexInHasBitSet(GetHasBits(message), schema_.HasBitIndex(field));
   }
 
@@ -2307,6 +2528,12 @@
       case FieldDescriptor::CPPTYPE_STRING:
         switch (field->options().ctype()) {
           default: {
+            if (IsInlined(field)) {
+              return !GetField<InlinedStringField>(message, field)
+                          .GetNoArena()
+                          .empty();
+            }
+
             return GetField<ArenaStringPtr>(message, field).Get().size() > 0;
           }
         }
@@ -2314,13 +2541,13 @@
       case FieldDescriptor::CPPTYPE_BOOL:
         return GetRaw<bool>(message, field) != false;
       case FieldDescriptor::CPPTYPE_INT32:
-        return GetRaw<int32>(message, field) != 0;
+        return GetRaw<int32_t>(message, field) != 0;
       case FieldDescriptor::CPPTYPE_INT64:
-        return GetRaw<int64>(message, field) != 0;
+        return GetRaw<int64_t>(message, field) != 0;
       case FieldDescriptor::CPPTYPE_UINT32:
-        return GetRaw<uint32>(message, field) != 0;
+        return GetRaw<uint32_t>(message, field) != 0;
       case FieldDescriptor::CPPTYPE_UINT64:
-        return GetRaw<uint64>(message, field) != 0;
+        return GetRaw<uint64_t>(message, field) != 0;
       case FieldDescriptor::CPPTYPE_FLOAT:
         return GetRaw<float>(message, field) != 0.0;
       case FieldDescriptor::CPPTYPE_DOUBLE:
@@ -2338,19 +2565,19 @@
 
 void Reflection::SetBit(Message* message, const FieldDescriptor* field) const {
   GOOGLE_DCHECK(!field->options().weak());
-  const uint32 index = schema_.HasBitIndex(field);
-  if (index == static_cast<uint32>(-1)) return;
+  const uint32_t index = schema_.HasBitIndex(field);
+  if (index == static_cast<uint32_t>(-1)) return;
   MutableHasBits(message)[index / 32] |=
-      (static_cast<uint32>(1) << (index % 32));
+      (static_cast<uint32_t>(1) << (index % 32));
 }
 
 void Reflection::ClearBit(Message* message,
                           const FieldDescriptor* field) const {
   GOOGLE_DCHECK(!field->options().weak());
-  const uint32 index = schema_.HasBitIndex(field);
-  if (index == static_cast<uint32>(-1)) return;
+  const uint32_t index = schema_.HasBitIndex(field);
+  if (index == static_cast<uint32_t>(-1)) return;
   MutableHasBits(message)[index / 32] &=
-      ~(static_cast<uint32>(1) << (index % 32));
+      ~(static_cast<uint32_t>(1) << (index % 32));
 }
 
 void Reflection::SwapBit(Message* message1, Message* message2,
@@ -2380,12 +2607,6 @@
   return (GetOneofCase(message, oneof_descriptor) > 0);
 }
 
-bool Reflection::HasOneofField(const Message& message,
-                               const FieldDescriptor* field) const {
-  return (GetOneofCase(message, field->containing_oneof()) ==
-          static_cast<uint32>(field->number()));
-}
-
 void Reflection::SetOneofCase(Message* message,
                               const FieldDescriptor* field) const {
   *MutableOneofCase(message, field->containing_oneof()) = field->number();
@@ -2407,7 +2628,7 @@
   // TODO(jieluo): Consider to cache the unused object instead of deleting
   // it. It will be much faster if an application switches a lot from
   // a few oneof fields.  Time/space tradeoff
-  uint32 oneof_case = GetOneofCase(*message, oneof_descriptor);
+  uint32_t oneof_case = GetOneofCase(*message, oneof_descriptor);
   if (oneof_case > 0) {
     const FieldDescriptor* field = descriptor_->FindFieldByNumber(oneof_case);
     if (message->GetArenaForAllocation() == nullptr) {
@@ -2455,10 +2676,10 @@
         MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, NULL));  \
   }
 
-HANDLE_TYPE(int32, FieldDescriptor::CPPTYPE_INT32, -1);
-HANDLE_TYPE(int64, FieldDescriptor::CPPTYPE_INT64, -1);
-HANDLE_TYPE(uint32, FieldDescriptor::CPPTYPE_UINT32, -1);
-HANDLE_TYPE(uint64, FieldDescriptor::CPPTYPE_UINT64, -1);
+HANDLE_TYPE(int32_t, FieldDescriptor::CPPTYPE_INT32, -1);
+HANDLE_TYPE(int64_t, FieldDescriptor::CPPTYPE_INT64, -1);
+HANDLE_TYPE(uint32_t, FieldDescriptor::CPPTYPE_UINT32, -1);
+HANDLE_TYPE(uint64_t, FieldDescriptor::CPPTYPE_UINT64, -1);
 HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1);
 HANDLE_TYPE(double, FieldDescriptor::CPPTYPE_DOUBLE, -1);
 HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1);
@@ -2560,7 +2781,7 @@
          cpp_type == FieldDescriptor::CPPTYPE_INT32))
       << "The type parameter T in RepeatedFieldRef<T> API doesn't match "
       << "the actual field type (for enums T should be the generated enum "
-      << "type or int32).";
+      << "type or int32_t).";
   if (message_type != nullptr) {
     GOOGLE_CHECK_EQ(message_type, field->message_type());
   }
@@ -2590,13 +2811,13 @@
 
 // Helper function to transform migration schema into reflection schema.
 ReflectionSchema MigrationToReflectionSchema(
-    const Message* const* default_instance, const uint32* offsets,
+    const Message* const* default_instance, const uint32_t* offsets,
     MigrationSchema migration_schema) {
   ReflectionSchema result;
   result.default_instance_ = *default_instance;
-  // First 6 offsets are offsets to the special fields. The following offsets
+  // First 7 offsets are offsets to the special fields. The following offsets
   // are the proto fields.
-  result.offsets_ = offsets + migration_schema.offsets_index + 5;
+  result.offsets_ = offsets + migration_schema.offsets_index + 6;
   result.has_bit_indices_ = offsets + migration_schema.has_bit_indices_index;
   result.has_bits_offset_ = offsets[migration_schema.offsets_index + 0];
   result.metadata_offset_ = offsets[migration_schema.offsets_index + 1];
@@ -2604,6 +2825,10 @@
   result.oneof_case_offset_ = offsets[migration_schema.offsets_index + 3];
   result.object_size_ = migration_schema.object_size;
   result.weak_field_map_offset_ = offsets[migration_schema.offsets_index + 4];
+  result.inlined_string_donated_offset_ =
+      offsets[migration_schema.offsets_index + 5];
+  result.inlined_string_indices_ =
+      offsets + migration_schema.inlined_string_indices_index;
   return result;
 }
 
@@ -2616,7 +2841,7 @@
                           const EnumDescriptor** file_level_enum_descriptors,
                           const MigrationSchema* schemas,
                           const Message* const* default_instance_data,
-                          const uint32* offsets)
+                          const uint32_t* offsets)
       : factory_(factory),
         file_level_metadata_(file_level_metadata),
         file_level_enum_descriptors_(file_level_enum_descriptors),
@@ -2657,7 +2882,7 @@
   const EnumDescriptor** file_level_enum_descriptors_;
   const MigrationSchema* schemas_;
   const Message* const* default_instance_data_;
-  const uint32* offsets_;
+  const uint32_t* offsets_;
 };
 
 namespace {
@@ -2818,8 +3043,8 @@
   RegisterAllTypesInternal(table->file_level_metadata, table->num_messages);
 }
 
-void UnknownFieldSetSerializer(const uint8* base, uint32 offset, uint32 tag,
-                               uint32 has_offset,
+void UnknownFieldSetSerializer(const uint8_t* base, uint32_t offset,
+                               uint32_t tag, uint32_t has_offset,
                                io::CodedOutputStream* output) {
   const void* ptr = base + offset;
   const InternalMetadata* metadata = static_cast<const InternalMetadata*>(ptr);
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
index 1771b474..6a570ff 100644
--- a/src/google/protobuf/generated_message_reflection.h
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -107,7 +107,7 @@
 //                  message, or -1 if the message type has no extension
 //                  ranges.
 //   oneof_case_offset:  Offset in the message of an array of uint32s of
-//                  size descriptor->oneof_decl_count().  Each uint32
+//                  size descriptor->oneof_decl_count().  Each uint32_t
 //                  indicates what field is set for each oneof.
 //   object_size:   The size of a message object of this type, as measured
 //                  by sizeof().
@@ -119,7 +119,7 @@
 struct ReflectionSchema {
  public:
   // Size of a google::protobuf::Message object of this type.
-  uint32 GetObjectSize() const { return static_cast<uint32>(object_size_); }
+  uint32_t GetObjectSize() const { return static_cast<uint32_t>(object_size_); }
 
   bool InRealOneof(const FieldDescriptor* field) const {
     return field->containing_oneof() &&
@@ -128,13 +128,13 @@
 
   // Offset of a non-oneof field.  Getting a field offset is slightly more
   // efficient when we know statically that it is not a oneof field.
-  uint32 GetFieldOffsetNonOneof(const FieldDescriptor* field) const {
+  uint32_t GetFieldOffsetNonOneof(const FieldDescriptor* field) const {
     GOOGLE_DCHECK(!InRealOneof(field));
     return OffsetValue(offsets_[field->index()], field->type());
   }
 
   // Offset of any field.
-  uint32 GetFieldOffset(const FieldDescriptor* field) const {
+  uint32_t GetFieldOffset(const FieldDescriptor* field) const {
     if (InRealOneof(field)) {
       size_t offset =
           static_cast<size_t>(field->containing_type()->field_count() +
@@ -145,42 +145,62 @@
     }
   }
 
-  uint32 GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const {
-    return static_cast<uint32>(oneof_case_offset_) +
-           static_cast<uint32>(static_cast<size_t>(oneof_descriptor->index()) *
-                               sizeof(uint32));
+  bool IsFieldInlined(const FieldDescriptor* field) const {
+    return Inlined(offsets_[field->index()], field->type());
+  }
+
+  uint32_t GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const {
+    return static_cast<uint32_t>(oneof_case_offset_) +
+           static_cast<uint32_t>(
+               static_cast<size_t>(oneof_descriptor->index()) *
+               sizeof(uint32_t));
   }
 
   bool HasHasbits() const { return has_bits_offset_ != -1; }
 
   // Bit index within the bit array of hasbits.  Bit order is low-to-high.
-  uint32 HasBitIndex(const FieldDescriptor* field) const {
-    if (has_bits_offset_ == -1) return static_cast<uint32>(-1);
+  uint32_t HasBitIndex(const FieldDescriptor* field) const {
+    if (has_bits_offset_ == -1) return static_cast<uint32_t>(-1);
     GOOGLE_DCHECK(HasHasbits());
     return has_bit_indices_[field->index()];
   }
 
   // Byte offset of the hasbits array.
-  uint32 HasBitsOffset() const {
+  uint32_t HasBitsOffset() const {
     GOOGLE_DCHECK(HasHasbits());
-    return static_cast<uint32>(has_bits_offset_);
+    return static_cast<uint32_t>(has_bits_offset_);
+  }
+
+  bool HasInlinedString() const { return inlined_string_donated_offset_ != -1; }
+
+  // Bit index within the bit array of _inlined_string_donated_.  Bit order is
+  // low-to-high.
+  uint32_t InlinedStringIndex(const FieldDescriptor* field) const {
+    GOOGLE_DCHECK(HasInlinedString());
+    return inlined_string_indices_[field->index()];
+  }
+
+  // Byte offset of the _inlined_string_donated_ array.
+  uint32_t InlinedStringDonatedOffset() const {
+    GOOGLE_DCHECK(HasInlinedString());
+    return static_cast<uint32_t>(inlined_string_donated_offset_);
   }
 
   // The offset of the InternalMetadataWithArena member.
   // For Lite this will actually be an InternalMetadataWithArenaLite.
   // The schema doesn't contain enough information to distinguish between
   // these two cases.
-  uint32 GetMetadataOffset() const {
-    return static_cast<uint32>(metadata_offset_);
+  uint32_t GetMetadataOffset() const {
+    return static_cast<uint32_t>(metadata_offset_);
   }
 
   // Whether this message has an ExtensionSet.
   bool HasExtensionSet() const { return extensions_offset_ != -1; }
 
   // The offset of the ExtensionSet in this message.
-  uint32 GetExtensionSetOffset() const {
+  uint32_t GetExtensionSetOffset() const {
     GOOGLE_DCHECK(HasExtensionSet());
-    return static_cast<uint32>(extensions_offset_);
+    return static_cast<uint32_t>(extensions_offset_);
   }
 
   // The off set of WeakFieldMap when the message contains weak fields.
@@ -194,7 +214,7 @@
   // Returns a pointer to the default value for this field.  The size and type
   // of the underlying data depends on the field's type.
   const void* GetFieldDefault(const FieldDescriptor* field) const {
-    return reinterpret_cast<const uint8*>(default_instance_) +
+    return reinterpret_cast<const uint8_t*>(default_instance_) +
            OffsetValue(offsets_[field->index()], field->type());
   }
 
@@ -232,23 +252,37 @@
   //   ReflectionSchema schema = {a, b, c, d, e, ...};
   // private:
   const Message* default_instance_;
-  const uint32* offsets_;
-  const uint32* has_bit_indices_;
+  const uint32_t* offsets_;
+  const uint32_t* has_bit_indices_;
   int has_bits_offset_;
   int metadata_offset_;
   int extensions_offset_;
   int oneof_case_offset_;
   int object_size_;
   int weak_field_map_offset_;
+  const uint32_t* inlined_string_indices_;
+  int inlined_string_donated_offset_;
 
   // We tag offset values to provide additional data about fields (such as
-  // "unused" or "lazy").
-  static uint32 OffsetValue(uint32 v, FieldDescriptor::Type type) {
-    if (type == FieldDescriptor::TYPE_MESSAGE) {
+  // "unused" or "lazy" or "inlined").
+  static uint32_t OffsetValue(uint32_t v, FieldDescriptor::Type type) {
+    if (type == FieldDescriptor::TYPE_MESSAGE ||
+        type == FieldDescriptor::TYPE_STRING ||
+        type == FieldDescriptor::TYPE_BYTES) {
       return v & 0x7FFFFFFEu;
     }
     return v & 0x7FFFFFFFu;
   }
+
+  static bool Inlined(uint32_t v, FieldDescriptor::Type type) {
+    if (type == FieldDescriptor::TYPE_STRING ||
+        type == FieldDescriptor::TYPE_BYTES) {
+      return (v & 1u) != 0u;
+    } else {
+      // Non string/byte fields are not inlined.
+      return false;
+    }
+  }
 };
 
 // Structs that the code generator emits directly to describe a message.
@@ -258,8 +292,9 @@
 // EXPERIMENTAL: these are changing rapidly, and may completely disappear
 // or merge with ReflectionSchema.
 struct MigrationSchema {
-  int32 offsets_index;
-  int32 has_bit_indices_index;
+  int32_t offsets_index;
+  int32_t has_bit_indices_index;
+  int32_t inlined_string_indices_index;
   int object_size;
 };
 
@@ -278,7 +313,7 @@
   int num_messages;
   const MigrationSchema* schemas;
   const Message* const* default_instances;
-  const uint32* offsets;
+  const uint32_t* offsets;
   // update the following descriptor arrays.
   Metadata* file_level_metadata;
   const EnumDescriptor** file_level_enum_descriptors;
@@ -309,8 +344,9 @@
                                            const Metadata& metadata);
 
 // These cannot be in lite so we put them in the reflection.
-PROTOBUF_EXPORT void UnknownFieldSetSerializer(const uint8* base, uint32 offset,
-                                               uint32 tag, uint32 has_offset,
+PROTOBUF_EXPORT void UnknownFieldSetSerializer(const uint8_t* base,
+                                               uint32_t offset, uint32_t tag,
+                                               uint32_t has_offset,
                                                io::CodedOutputStream* output);
 
 struct PROTOBUF_EXPORT AddDescriptorsRunner {
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index 0b6ed8e..a0c4ea5 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -166,147 +166,185 @@
             &reflection->GetMessage(message, F("optional_import_message")));
 }
 
-TEST(GeneratedMessageReflectionTest, Swap) {
-  unittest::TestAllTypes message1;
-  unittest::TestAllTypes message2;
+class GeneratedMessageReflectionSwapTest : public testing::TestWithParam<bool> {
+ protected:
+  void Swap(const Reflection* reflection, Message* lhs, Message* rhs) {
+    if (GetParam()) {
+      reflection->UnsafeArenaSwap(lhs, rhs);
+    } else {
+      reflection->Swap(lhs, rhs);
+    }
+  }
+  void SwapFields(const Reflection* reflection, Message* lhs, Message* rhs,
+                  const std::vector<const FieldDescriptor*>& fields) {
+    if (GetParam()) {
+      reflection->UnsafeArenaSwapFields(lhs, rhs, fields);
+    } else {
+      reflection->SwapFields(lhs, rhs, fields);
+    }
+  }
+};
 
-  TestUtil::SetAllFields(&message1);
+// unsafe_shallow_swap: true -> UnsafeArena* API.
+INSTANTIATE_TEST_SUITE_P(ReflectionSwap, GeneratedMessageReflectionSwapTest,
+                         testing::Bool());
 
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
+TEST_P(GeneratedMessageReflectionSwapTest, LhsSet) {
+  unittest::TestAllTypes lhs;
+  unittest::TestAllTypes rhs;
 
-  TestUtil::ExpectClear(message1);
-  TestUtil::ExpectAllFieldsSet(message2);
+  TestUtil::SetAllFields(&lhs);
+
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+
+  TestUtil::ExpectClear(lhs);
+  TestUtil::ExpectAllFieldsSet(rhs);
 }
 
-TEST(GeneratedMessageReflectionTest, SwapWithBothSet) {
-  unittest::TestAllTypes message1;
-  unittest::TestAllTypes message2;
+TEST_P(GeneratedMessageReflectionSwapTest, BothSet) {
+  unittest::TestAllTypes lhs;
+  unittest::TestAllTypes rhs;
 
-  TestUtil::SetAllFields(&message1);
-  TestUtil::SetAllFields(&message2);
-  TestUtil::ModifyRepeatedFields(&message2);
+  TestUtil::SetAllFields(&lhs);
+  TestUtil::SetAllFields(&rhs);
+  TestUtil::ModifyRepeatedFields(&rhs);
 
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
+  const Reflection* reflection = lhs.GetReflection();
+  Swap(reflection, &lhs, &rhs);
 
-  TestUtil::ExpectRepeatedFieldsModified(message1);
-  TestUtil::ExpectAllFieldsSet(message2);
+  TestUtil::ExpectRepeatedFieldsModified(lhs);
+  TestUtil::ExpectAllFieldsSet(rhs);
 
-  message1.set_optional_int32(532819);
+  lhs.set_optional_int32(532819);
 
-  reflection->Swap(&message1, &message2);
+  Swap(reflection, &lhs, &rhs);
 
-  EXPECT_EQ(532819, message2.optional_int32());
+  EXPECT_EQ(532819, rhs.optional_int32());
 }
 
-TEST(GeneratedMessageReflectionTest, SwapWithLhsCleared) {
-  unittest::TestAllTypes message1;
-  unittest::TestAllTypes message2;
+TEST_P(GeneratedMessageReflectionSwapTest, LhsCleared) {
+  unittest::TestAllTypes lhs;
+  unittest::TestAllTypes rhs;
 
-  TestUtil::SetAllFields(&message1);
+  TestUtil::SetAllFields(&lhs);
 
   // For proto2 message, for message field, Clear only reset hasbits, but
   // doesn't delete the underlying field.
-  message1.Clear();
+  lhs.Clear();
 
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
+  Swap(lhs.GetReflection(), &lhs, &rhs);
 
-  TestUtil::ExpectClear(message2);
+  TestUtil::ExpectClear(rhs);
 }
 
-TEST(GeneratedMessageReflectionTest, SwapWithRhsCleared) {
-  unittest::TestAllTypes message1;
-  unittest::TestAllTypes message2;
+TEST_P(GeneratedMessageReflectionSwapTest, RhsCleared) {
+  unittest::TestAllTypes lhs;
+  unittest::TestAllTypes rhs;
 
-  TestUtil::SetAllFields(&message2);
+  TestUtil::SetAllFields(&rhs);
 
   // For proto2 message, for message field, Clear only reset hasbits, but
   // doesn't delete the underlying field.
-  message2.Clear();
+  rhs.Clear();
 
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
+  Swap(lhs.GetReflection(), &lhs, &rhs);
 
-  TestUtil::ExpectClear(message1);
+  TestUtil::ExpectClear(lhs);
 }
 
-TEST(GeneratedMessageReflectionTest, SwapExtensions) {
-  unittest::TestAllExtensions message1;
-  unittest::TestAllExtensions message2;
+TEST_P(GeneratedMessageReflectionSwapTest, Extensions) {
+  unittest::TestAllExtensions lhs;
+  unittest::TestAllExtensions rhs;
 
-  TestUtil::SetAllExtensions(&message1);
+  TestUtil::SetAllExtensions(&lhs);
 
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
+  Swap(lhs.GetReflection(), &lhs, &rhs);
 
-  TestUtil::ExpectExtensionsClear(message1);
-  TestUtil::ExpectAllExtensionsSet(message2);
+  TestUtil::ExpectExtensionsClear(lhs);
+  TestUtil::ExpectAllExtensionsSet(rhs);
 }
 
-TEST(GeneratedMessageReflectionTest, SwapUnknown) {
-  unittest::TestEmptyMessage message1, message2;
+TEST_P(GeneratedMessageReflectionSwapTest, Unknown) {
+  unittest::TestEmptyMessage lhs, rhs;
 
-  message1.mutable_unknown_fields()->AddVarint(1234, 1);
+  lhs.mutable_unknown_fields()->AddVarint(1234, 1);
 
-  EXPECT_EQ(1, message1.unknown_fields().field_count());
-  EXPECT_EQ(0, message2.unknown_fields().field_count());
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
-  EXPECT_EQ(0, message1.unknown_fields().field_count());
-  EXPECT_EQ(1, message2.unknown_fields().field_count());
+  EXPECT_EQ(1, lhs.unknown_fields().field_count());
+  EXPECT_EQ(0, rhs.unknown_fields().field_count());
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+  EXPECT_EQ(0, lhs.unknown_fields().field_count());
+  EXPECT_EQ(1, rhs.unknown_fields().field_count());
 }
 
-TEST(GeneratedMessageReflectionTest, SwapFields) {
-  unittest::TestAllTypes message1, message2;
-  message1.set_optional_double(12.3);
-  message1.mutable_repeated_int32()->Add(10);
-  message1.mutable_repeated_int32()->Add(20);
+TEST_P(GeneratedMessageReflectionSwapTest, Oneof) {
+  unittest::TestOneof2 lhs, rhs;
+  TestUtil::SetOneof1(&lhs);
 
-  message2.set_optional_string("hello");
-  message2.mutable_repeated_int64()->Add(30);
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+
+  TestUtil::ExpectOneofClear(lhs);
+  TestUtil::ExpectOneofSet1(rhs);
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, OneofBothSet) {
+  unittest::TestOneof2 lhs, rhs;
+  TestUtil::SetOneof1(&lhs);
+  TestUtil::SetOneof2(&rhs);
+
+  Swap(lhs.GetReflection(), &lhs, &rhs);
+
+  TestUtil::ExpectOneofSet2(lhs);
+  TestUtil::ExpectOneofSet1(rhs);
+}
+
+TEST_P(GeneratedMessageReflectionSwapTest, SwapFields) {
+  unittest::TestAllTypes lhs, rhs;
+  lhs.set_optional_double(12.3);
+  lhs.mutable_repeated_int32()->Add(10);
+  lhs.mutable_repeated_int32()->Add(20);
+
+  rhs.set_optional_string("hello");
+  rhs.mutable_repeated_int64()->Add(30);
 
   std::vector<const FieldDescriptor*> fields;
-  const Descriptor* descriptor = message1.GetDescriptor();
+  const Descriptor* descriptor = lhs.GetDescriptor();
   fields.push_back(descriptor->FindFieldByName("optional_double"));
   fields.push_back(descriptor->FindFieldByName("repeated_int32"));
   fields.push_back(descriptor->FindFieldByName("optional_string"));
   fields.push_back(descriptor->FindFieldByName("optional_uint64"));
 
-  const Reflection* reflection = message1.GetReflection();
-  reflection->SwapFields(&message1, &message2, fields);
+  SwapFields(lhs.GetReflection(), &lhs, &rhs, fields);
 
-  EXPECT_FALSE(message1.has_optional_double());
-  EXPECT_EQ(0, message1.repeated_int32_size());
-  EXPECT_TRUE(message1.has_optional_string());
-  EXPECT_EQ("hello", message1.optional_string());
-  EXPECT_EQ(0, message1.repeated_int64_size());
-  EXPECT_FALSE(message1.has_optional_uint64());
+  EXPECT_FALSE(lhs.has_optional_double());
+  EXPECT_EQ(0, lhs.repeated_int32_size());
+  EXPECT_TRUE(lhs.has_optional_string());
+  EXPECT_EQ("hello", lhs.optional_string());
+  EXPECT_EQ(0, lhs.repeated_int64_size());
+  EXPECT_FALSE(lhs.has_optional_uint64());
 
-  EXPECT_TRUE(message2.has_optional_double());
-  EXPECT_EQ(12.3, message2.optional_double());
-  EXPECT_EQ(2, message2.repeated_int32_size());
-  EXPECT_EQ(10, message2.repeated_int32(0));
-  EXPECT_EQ(20, message2.repeated_int32(1));
-  EXPECT_FALSE(message2.has_optional_string());
-  EXPECT_EQ(1, message2.repeated_int64_size());
-  EXPECT_FALSE(message2.has_optional_uint64());
+  EXPECT_TRUE(rhs.has_optional_double());
+  EXPECT_EQ(12.3, rhs.optional_double());
+  EXPECT_EQ(2, rhs.repeated_int32_size());
+  EXPECT_EQ(10, rhs.repeated_int32(0));
+  EXPECT_EQ(20, rhs.repeated_int32(1));
+  EXPECT_FALSE(rhs.has_optional_string());
+  EXPECT_EQ(1, rhs.repeated_int64_size());
+  EXPECT_FALSE(rhs.has_optional_uint64());
 }
 
-TEST(GeneratedMessageReflectionTest, SwapFieldsAll) {
-  unittest::TestAllTypes message1;
-  unittest::TestAllTypes message2;
+TEST_P(GeneratedMessageReflectionSwapTest, SwapFieldsAll) {
+  unittest::TestAllTypes lhs;
+  unittest::TestAllTypes rhs;
 
-  TestUtil::SetAllFields(&message2);
+  TestUtil::SetAllFields(&rhs);
 
   std::vector<const FieldDescriptor*> fields;
-  const Reflection* reflection = message1.GetReflection();
-  reflection->ListFields(message2, &fields);
-  reflection->SwapFields(&message1, &message2, fields);
+  const Reflection* reflection = lhs.GetReflection();
+  reflection->ListFields(rhs, &fields);
+  SwapFields(reflection, &lhs, &rhs, fields);
 
-  TestUtil::ExpectAllFieldsSet(message1);
-  TestUtil::ExpectClear(message2);
+  TestUtil::ExpectAllFieldsSet(lhs);
+  TestUtil::ExpectClear(rhs);
 }
 
 TEST(GeneratedMessageReflectionTest, SwapFieldsAllOnDifferentArena) {
@@ -476,29 +514,6 @@
                 unittest::repeated_foreign_message_extension));
 }
 
-TEST(GeneratedMessageReflectionTest, SwapOneof) {
-  unittest::TestOneof2 message1, message2;
-  TestUtil::SetOneof1(&message1);
-
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
-
-  TestUtil::ExpectOneofClear(message1);
-  TestUtil::ExpectOneofSet1(message2);
-}
-
-TEST(GeneratedMessageReflectionTest, SwapOneofBothSet) {
-  unittest::TestOneof2 message1, message2;
-  TestUtil::SetOneof1(&message1);
-  TestUtil::SetOneof2(&message2);
-
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
-
-  TestUtil::ExpectOneofSet2(message1);
-  TestUtil::ExpectOneofSet1(message2);
-}
-
 TEST(GeneratedMessageReflectionTest, SwapFieldsOneof) {
   unittest::TestOneof2 message1, message2;
   TestUtil::SetOneof1(&message1);
diff --git a/src/google/protobuf/generated_message_table_driven.cc b/src/google/protobuf/generated_message_table_driven.cc
index 56f1a6a..71ee647 100644
--- a/src/google/protobuf/generated_message_table_driven.cc
+++ b/src/google/protobuf/generated_message_table_driven.cc
@@ -45,7 +45,7 @@
 
 namespace {
 
-UnknownFieldSet* MutableUnknownFields(MessageLite* msg, int64 arena_offset) {
+UnknownFieldSet* MutableUnknownFields(MessageLite* msg, int64_t arena_offset) {
   return Raw<InternalMetadata>(msg, arena_offset)
       ->mutable_unknown_fields<UnknownFieldSet>();
 }
diff --git a/src/google/protobuf/generated_message_table_driven.h b/src/google/protobuf/generated_message_table_driven.h
index def4a1f..178a0c1 100644
--- a/src/google/protobuf/generated_message_table_driven.h
+++ b/src/google/protobuf/generated_message_table_driven.h
@@ -73,19 +73,21 @@
   TYPE_STRING_STRING_PIECE = 20,
   TYPE_BYTES_CORD = 21,
   TYPE_BYTES_STRING_PIECE = 22,
-  TYPE_MAP = 23,
+  TYPE_STRING_INLINED = 23,
+  TYPE_BYTES_INLINED = 24,
+  TYPE_MAP = 25,
 };
 
 static_assert(TYPE_MAP < kRepeatedMask, "Invalid enum");
 
 struct PROTOBUF_EXPORT FieldMetadata {
-  uint32 offset;  // offset of this field in the struct
-  uint32 tag;     // field * 8 + wire_type
+  uint32_t offset;  // offset of this field in the struct
+  uint32_t tag;     // field * 8 + wire_type
   // byte offset * 8 + bit_offset;
   // if the high bit is set then this is the byte offset of the oneof_case
   // for this field.
-  uint32 has_offset;
-  uint32 type;      // the type of this field.
+  uint32_t has_offset;
+  uint32_t type;    // the type of this field.
   const void* ptr;  // auxiliary data
 
   // From the serializer point of view each fundamental type can occur in
@@ -104,7 +106,8 @@
   enum {
     kCordType = 19,
     kStringPieceType = 20,
-    kNumTypes = 20,
+    kInlinedType = 21,
+    kNumTypes = 21,
     kSpecial = kNumTypes * kNumTypeClasses,
   };
 
@@ -119,10 +122,10 @@
 // Additional data, needed for some types, is stored in
 // AuxiliaryParseTableField.
 struct ParseTableField {
-  uint32 offset;
+  uint32_t offset;
   // The presence_index ordinarily represents a has_bit index, but for fields
   // inside a oneof it represents the index in _oneof_case_.
-  uint32 presence_index;
+  uint32_t presence_index;
   unsigned char normal_wiretype;
   unsigned char packed_wiretype;
 
@@ -184,10 +187,10 @@
   // TODO(ckennelly): Do something with this padding.
 
   // TODO(ckennelly): Vet these for sign extension.
-  int64 has_bits_offset;
-  int64 oneof_case_offset;
-  int64 extension_offset;
-  int64 arena_offset;
+  int64_t has_bits_offset;
+  int64_t oneof_case_offset;
+  int64_t extension_offset;
+  int64_t arena_offset;
 
   // ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
   // the tables from being constructed as a constexpr.  We use void to avoid
@@ -243,9 +246,9 @@
   const FieldMetadata* field_table;
 };
 
-PROTOBUF_EXPORT void SerializeInternal(const uint8* base,
+PROTOBUF_EXPORT void SerializeInternal(const uint8_t* base,
                                        const FieldMetadata* table,
-                                       int32 num_fields,
+                                       int32_t num_fields,
                                        io::CodedOutputStream* output);
 
 inline void TableSerialize(const MessageLite& msg,
@@ -253,24 +256,25 @@
                            io::CodedOutputStream* output) {
   const FieldMetadata* field_table = table->field_table;
   int num_fields = table->num_fields - 1;
-  const uint8* base = reinterpret_cast<const uint8*>(&msg);
+  const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
   // TODO(gerbens) This skips the first test if we could use the fast
   // array serialization path, we should make this
   // int cached_size =
-  //    *reinterpret_cast<const int32*>(base + field_table->offset);
+  //    *reinterpret_cast<const int32_t*>(base + field_table->offset);
   // SerializeWithCachedSize(msg, field_table + 1, num_fields, cached_size, ...)
   // But we keep conformance with the old way for now.
   SerializeInternal(base, field_table + 1, num_fields, output);
 }
 
-PROTOBUF_EXPORT uint8* SerializeInternalToArray(const uint8* base, const FieldMetadata* table,
-                                int32 num_fields, bool is_deterministic,
-                                uint8* buffer);
+PROTOBUF_EXPORT uint8_t* SerializeInternalToArray(const uint8_t* base,
+                                  const FieldMetadata* table,
+                                  int32_t num_fields, bool is_deterministic,
+                                  uint8_t* buffer);
 
-inline uint8* TableSerializeToArray(const MessageLite& msg,
-                                    const SerializationTable* table,
-                                    bool is_deterministic, uint8* buffer) {
-  const uint8* base = reinterpret_cast<const uint8*>(&msg);
+inline uint8_t* TableSerializeToArray(const MessageLite& msg,
+                                      const SerializationTable* table,
+                                      bool is_deterministic, uint8_t* buffer) {
+  const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
   const FieldMetadata* field_table = table->field_table + 1;
   int num_fields = table->num_fields - 1;
   return SerializeInternalToArray(base, field_table, num_fields,
@@ -302,8 +306,8 @@
 };
 
 template <typename MapFieldType, const SerializationTable* table>
-void MapFieldSerializer(const uint8* base, uint32 offset, uint32 tag,
-                        uint32 has_offset, io::CodedOutputStream* output) {
+void MapFieldSerializer(const uint8_t* base, uint32_t offset, uint32_t tag,
+                        uint32_t has_offset, io::CodedOutputStream* output) {
   typedef MapEntryHelper<typename MapFieldType::EntryTypeTrait> Entry;
   typedef typename MapFieldType::MapType::const_iterator Iter;
 
@@ -318,7 +322,7 @@
       Entry map_entry(*it);
       output->WriteVarint32(tag);
       output->WriteVarint32(map_entry._cached_size_);
-      SerializeInternal(reinterpret_cast<const uint8*>(&map_entry),
+      SerializeInternal(reinterpret_cast<const uint8_t*>(&map_entry),
                         t->field_table, t->num_fields, output);
     }
   } else {
@@ -331,7 +335,7 @@
     for (int i = 0; i < v.size(); i++) {
       output->WriteVarint32(tag);
       output->WriteVarint32(v[i]._cached_size_);
-      SerializeInternal(reinterpret_cast<const uint8*>(&v[i]), t->field_table,
+      SerializeInternal(reinterpret_cast<const uint8_t*>(&v[i]), t->field_table,
                         t->num_fields, output);
     }
   }
diff --git a/src/google/protobuf/generated_message_table_driven_lite.cc b/src/google/protobuf/generated_message_table_driven_lite.cc
index 02e6dac..42c3475 100644
--- a/src/google/protobuf/generated_message_table_driven_lite.cc
+++ b/src/google/protobuf/generated_message_table_driven_lite.cc
@@ -43,7 +43,7 @@
 
 namespace {
 
-std::string* MutableUnknownFields(MessageLite* msg, int64 arena_offset) {
+std::string* MutableUnknownFields(MessageLite* msg, int64_t arena_offset) {
   return Raw<InternalMetadata>(msg, arena_offset)
       ->mutable_unknown_fields<std::string>();
 }
diff --git a/src/google/protobuf/generated_message_table_driven_lite.h b/src/google/protobuf/generated_message_table_driven_lite.h
index 32cc16e..032dd0e 100644
--- a/src/google/protobuf/generated_message_table_driven_lite.h
+++ b/src/google/protobuf/generated_message_table_driven_lite.h
@@ -35,6 +35,7 @@
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/inlined_string_field.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <type_traits>
@@ -49,6 +50,7 @@
 
 enum StringType {
   StringType_STRING = 0,
+  StringType_INLINED = 3
 };
 
 // Logically a superset of StringType, consisting of all field types that
@@ -57,7 +59,8 @@
   ProcessingType_STRING = 0,
   ProcessingType_CORD = 1,
   ProcessingType_STRING_PIECE = 2,
-  ProcessingType_MESSAGE = 3,
+  ProcessingType_INLINED = 3,
+  ProcessingType_MESSAGE = 4,
 };
 
 enum Cardinality {
@@ -67,17 +70,18 @@
 };
 
 template <typename Type>
-inline Type* Raw(MessageLite* msg, int64 offset) {
-  return reinterpret_cast<Type*>(reinterpret_cast<uint8*>(msg) + offset);
+inline Type* Raw(MessageLite* msg, int64_t offset) {
+  return reinterpret_cast<Type*>(reinterpret_cast<uint8_t*>(msg) + offset);
 }
 
 template <typename Type>
-inline const Type* Raw(const MessageLite* msg, int64 offset) {
-  return reinterpret_cast<const Type*>(reinterpret_cast<const uint8*>(msg) +
+inline const Type* Raw(const MessageLite* msg, int64_t offset) {
+  return reinterpret_cast<const Type*>(reinterpret_cast<const uint8_t*>(msg) +
                                        offset);
 }
 
-inline ExtensionSet* GetExtensionSet(MessageLite* msg, int64 extension_offset) {
+inline ExtensionSet* GetExtensionSet(MessageLite* msg,
+                                     int64_t extension_offset) {
   if (extension_offset == -1) {
     return NULL;
   }
@@ -86,15 +90,17 @@
 }
 
 template <typename Type>
-inline Type* AddField(MessageLite* msg, int64 offset) {
-  static_assert(std::is_trivial<Type>::value, "Do not assign");
+inline Type* AddField(MessageLite* msg, int64_t offset) {
+  static_assert(std::is_trivial<Type>::value ||
+                    std::is_same<Type, InlinedStringField>::value,
+                "Do not assign");
 
   RepeatedField<Type>* repeated = Raw<RepeatedField<Type>>(msg, offset);
   return repeated->Add();
 }
 
 template <>
-inline std::string* AddField<std::string>(MessageLite* msg, int64 offset) {
+inline std::string* AddField<std::string>(MessageLite* msg, int64_t offset) {
   RepeatedPtrField<std::string>* repeated =
       Raw<RepeatedPtrField<std::string>>(msg, offset);
   return repeated->Add();
@@ -102,35 +108,35 @@
 
 
 template <typename Type>
-inline void AddField(MessageLite* msg, int64 offset, Type value) {
+inline void AddField(MessageLite* msg, int64_t offset, Type value) {
   static_assert(std::is_trivial<Type>::value, "Do not assign");
   *AddField<Type>(msg, offset) = value;
 }
 
-inline void SetBit(uint32* has_bits, uint32 has_bit_index) {
+inline void SetBit(uint32_t* has_bits, uint32_t has_bit_index) {
   GOOGLE_DCHECK(has_bits != nullptr);
 
-  uint32 mask = static_cast<uint32>(1u) << (has_bit_index % 32);
+  uint32_t mask = static_cast<uint32_t>(1u) << (has_bit_index % 32);
   has_bits[has_bit_index / 32u] |= mask;
 }
 
 template <typename Type>
-inline Type* MutableField(MessageLite* msg, uint32* has_bits,
-                          uint32 has_bit_index, int64 offset) {
+inline Type* MutableField(MessageLite* msg, uint32_t* has_bits,
+                          uint32_t has_bit_index, int64_t offset) {
   SetBit(has_bits, has_bit_index);
   return Raw<Type>(msg, offset);
 }
 
 template <typename Type>
-inline void SetField(MessageLite* msg, uint32* has_bits, uint32 has_bit_index,
-                     int64 offset, Type value) {
+inline void SetField(MessageLite* msg, uint32_t* has_bits,
+                     uint32_t has_bit_index, int64_t offset, Type value) {
   static_assert(std::is_trivial<Type>::value, "Do not assign");
   *MutableField<Type>(msg, has_bits, has_bit_index, offset) = value;
 }
 
 template <typename Type>
-inline void SetOneofField(MessageLite* msg, uint32* oneof_case,
-                          uint32 oneof_case_index, int64 offset,
+inline void SetOneofField(MessageLite* msg, uint32_t* oneof_case,
+                          uint32_t oneof_case_index, int64_t offset,
                           int field_number, Type value) {
   oneof_case[oneof_case_index] = field_number;
   *Raw<Type>(msg, offset) = value;
@@ -153,6 +159,11 @@
           ->Destroy(ArenaStringPtr::EmptyDefault{}, arena);
       break;
 
+    case TYPE_STRING_INLINED:
+    case TYPE_BYTES_INLINED:
+      Raw<InlinedStringField>(msg, field.offset)->DestroyNoArena(NULL);
+      break;
+
     default:
       // No cleanup needed.
       break;
@@ -167,9 +178,10 @@
 // _oneof_case_ array.
 template <ProcessingType field_type>
 inline void ResetOneofField(const ParseTable& table, int field_number,
-                            Arena* arena, MessageLite* msg, uint32* oneof_case,
-                            int64 offset, const void* default_ptr) {
-  if (static_cast<int64>(*oneof_case) == field_number) {
+                            Arena* arena, MessageLite* msg,
+                            uint32_t* oneof_case, int64_t offset,
+                            const void* default_ptr) {
+  if (static_cast<int64_t>(*oneof_case) == field_number) {
     // The oneof is already set to the right type, so there is no need to clear
     // it.
     return;
@@ -185,6 +197,10 @@
       Raw<ArenaStringPtr>(msg, offset)
           ->UnsafeSetDefault(static_cast<const std::string*>(default_ptr));
       break;
+    case ProcessingType_INLINED:
+      new (Raw<InlinedStringField>(msg, offset))
+          InlinedStringField(*static_cast<const std::string*>(default_ptr));
+      break;
     case ProcessingType_MESSAGE:
       MessageLite** submessage = Raw<MessageLite*>(msg, offset);
       const MessageLite* prototype =
@@ -197,8 +213,8 @@
 template <typename UnknownFieldHandler, Cardinality cardinality,
           bool is_string_type, StringType ctype>
 static inline bool HandleString(io::CodedInputStream* input, MessageLite* msg,
-                                Arena* arena, uint32* has_bits,
-                                uint32 has_bit_index, int64 offset,
+                                Arena* arena, uint32_t* has_bits,
+                                uint32_t has_bit_index, int64_t offset,
                                 const void* default_ptr,
                                 const char* field_name) {
   StringPiece utf8_string_data;
@@ -209,6 +225,30 @@
 #endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
 
   switch (ctype) {
+    case StringType_INLINED: {
+      std::string* value = nullptr;
+      switch (cardinality) {
+        case Cardinality_SINGULAR: {
+          // TODO(ckennelly): Is this optimal?
+          InlinedStringField* s = MutableField<InlinedStringField>(
+              msg, has_bits, has_bit_index, offset);
+          value = s->UnsafeMutablePointer();
+        } break;
+        case Cardinality_REPEATED: {
+          value = AddField<std::string>(msg, offset);
+        } break;
+        case Cardinality_ONEOF: {
+          InlinedStringField* s = Raw<InlinedStringField>(msg, offset);
+          value = s->UnsafeMutablePointer();
+        } break;
+      }
+      GOOGLE_DCHECK(value != nullptr);
+      if (PROTOBUF_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
+        return false;
+      }
+      utf8_string_data = *value;
+      break;
+    }
     case StringType_STRING: {
       switch (cardinality) {
         case Cardinality_SINGULAR: {
@@ -260,8 +300,8 @@
 
 template <typename UnknownFieldHandler, Cardinality cardinality>
 inline bool HandleEnum(const ParseTable& table, io::CodedInputStream* input,
-                       MessageLite* msg, uint32* presence,
-                       uint32 presence_index, int64 offset, uint32 tag,
+                       MessageLite* msg, uint32_t* presence,
+                       uint32_t presence_index, int64_t offset, uint32_t tag,
                        int field_number) {
   int value;
   if (PROTOBUF_PREDICT_FALSE(
@@ -326,7 +366,7 @@
   }
 };
 
-template <typename UnknownFieldHandler, uint32 kMaxTag>
+template <typename UnknownFieldHandler, uint32_t kMaxTag>
 bool MergePartialFromCodedStreamInlined(MessageLite* msg,
                                         const ParseTable& table,
                                         io::CodedInputStream* input) {
@@ -335,11 +375,11 @@
   //
   // TODO(ckennelly):  Make this a compile-time parameter with templates.
   GOOGLE_DCHECK_GE(table.has_bits_offset, 0);
-  uint32* has_bits = Raw<uint32>(msg, table.has_bits_offset);
+  uint32_t* has_bits = Raw<uint32_t>(msg, table.has_bits_offset);
   GOOGLE_DCHECK(has_bits != NULL);
 
   while (true) {
-    uint32 tag = input->ReadTagWithCutoffNoLastTag(kMaxTag).first;
+    uint32_t tag = input->ReadTagWithCutoffNoLastTag(kMaxTag).first;
     const WireFormatLite::WireType wire_type =
         WireFormatLite::GetTagWireType(tag);
     const int field_number = WireFormatLite::GetTagFieldNumber(tag);
@@ -367,8 +407,8 @@
     const ParseTableField* data = table.fields + field_number;
 
     // TODO(ckennelly): Avoid sign extension
-    const int64 presence_index = data->presence_index;
-    const int64 offset = data->offset;
+    const int64_t presence_index = data->presence_index;
+    const int64_t offset = data->offset;
     const unsigned char processing_type = data->processing_type;
 
     if (data->normal_wiretype == static_cast<unsigned char>(wire_type)) {
@@ -394,7 +434,7 @@
     break;                                                                     \
   }                                                                            \
   case (WireFormatLite::TYPE_##TYPE) | kOneofMask: {                           \
-    uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);            \
+    uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);        \
     CPPTYPE value;                                                             \
     if (PROTOBUF_PREDICT_FALSE(                                                \
             (!WireFormatLite::ReadPrimitive<                                   \
@@ -408,17 +448,17 @@
     break;                                                                     \
   }
 
-        HANDLE_TYPE(INT32, int32)
-        HANDLE_TYPE(INT64, int64)
-        HANDLE_TYPE(SINT32, int32)
-        HANDLE_TYPE(SINT64, int64)
-        HANDLE_TYPE(UINT32, uint32)
-        HANDLE_TYPE(UINT64, uint64)
+        HANDLE_TYPE(INT32, int32_t)
+        HANDLE_TYPE(INT64, int64_t)
+        HANDLE_TYPE(SINT32, int32_t)
+        HANDLE_TYPE(SINT64, int64_t)
+        HANDLE_TYPE(UINT32, uint32_t)
+        HANDLE_TYPE(UINT64, uint64_t)
 
-        HANDLE_TYPE(FIXED32, uint32)
-        HANDLE_TYPE(FIXED64, uint64)
-        HANDLE_TYPE(SFIXED32, int32)
-        HANDLE_TYPE(SFIXED64, int64)
+        HANDLE_TYPE(FIXED32, uint32_t)
+        HANDLE_TYPE(FIXED64, uint64_t)
+        HANDLE_TYPE(SFIXED32, int32_t)
+        HANDLE_TYPE(SFIXED64, int64_t)
 
         HANDLE_TYPE(FLOAT, float)
         HANDLE_TYPE(DOUBLE, double)
@@ -442,13 +482,30 @@
           }
           break;
         }
+        case TYPE_BYTES_INLINED:
+#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+        case TYPE_STRING_INLINED:
+#endif  // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+        {
+          Arena* const arena = msg->GetArena();
+          const void* default_ptr = table.aux[field_number].strings.default_ptr;
+
+          if (PROTOBUF_PREDICT_FALSE(
+                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+                                 false, StringType_INLINED>(
+                      input, msg, arena, has_bits, presence_index, offset,
+                      default_ptr, nullptr)))) {
+            return false;
+          }
+          break;
+        }
         case WireFormatLite::TYPE_BYTES | kOneofMask:
 #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         case WireFormatLite::TYPE_STRING | kOneofMask:
 #endif  // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         {
           Arena* const arena = msg->GetArena();
-          uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
+          uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);
           const void* default_ptr = table.aux[field_number].strings.default_ptr;
 
           ResetOneofField<ProcessingType_STRING>(
@@ -465,8 +522,10 @@
           break;
         }
         case (WireFormatLite::TYPE_BYTES) | kRepeatedMask:
+        case TYPE_BYTES_INLINED | kRepeatedMask:
 #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         case (WireFormatLite::TYPE_STRING) | kRepeatedMask:
+        case TYPE_STRING_INLINED | kRepeatedMask:
 #endif  // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         {
           Arena* const arena = msg->GetArena();
@@ -496,6 +555,7 @@
           }
           break;
         }
+        case TYPE_STRING_INLINED | kRepeatedMask:
         case (WireFormatLite::TYPE_STRING) | kRepeatedMask: {
           Arena* const arena = msg->GetArena();
           const void* default_ptr = table.aux[field_number].strings.default_ptr;
@@ -512,7 +572,7 @@
         }
         case (WireFormatLite::TYPE_STRING) | kOneofMask: {
           Arena* const arena = msg->GetArena();
-          uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
+          uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);
           const void* default_ptr = table.aux[field_number].strings.default_ptr;
           const char* field_name = table.aux[field_number].strings.field_name;
 
@@ -549,7 +609,7 @@
           break;
         }
         case WireFormatLite::TYPE_ENUM | kOneofMask: {
-          uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
+          uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);
           if (PROTOBUF_PREDICT_FALSE(
                   (!HandleEnum<UnknownFieldHandler, Cardinality_ONEOF>(
                       table, input, msg, oneof_case, presence_index, offset,
@@ -639,7 +699,7 @@
         }
         case WireFormatLite::TYPE_MESSAGE | kOneofMask: {
           Arena* const arena = msg->GetArena();
-          uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
+          uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);
           MessageLite** submsg_holder = Raw<MessageLite*>(msg, offset);
           ResetOneofField<ProcessingType_MESSAGE>(
               table, field_number, arena, msg, oneof_case + presence_index,
@@ -653,6 +713,22 @@
 
           break;
         }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+        case TYPE_STRING_INLINED: {
+          Arena* const arena = msg->GetArena();
+          const void* default_ptr = table.aux[field_number].strings.default_ptr;
+          const char* field_name = table.aux[field_number].strings.field_name;
+
+          if (PROTOBUF_PREDICT_FALSE(
+                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+                                 true, StringType_INLINED>(
+                      input, msg, arena, has_bits, presence_index, offset,
+                      default_ptr, field_name)))) {
+            return false;
+          }
+          break;
+        }
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         case TYPE_MAP: {
           if (PROTOBUF_PREDICT_FALSE(!(*table.aux[field_number].maps.parse_map)(
                   input, Raw<void>(msg, offset)))) {
@@ -675,6 +751,8 @@
       GOOGLE_DCHECK_NE(processing_type, kRepeatedMask);
       GOOGLE_DCHECK_EQ(0, processing_type & kOneofMask);
 
+      GOOGLE_DCHECK_NE(TYPE_BYTES_INLINED | kRepeatedMask, processing_type);
+      GOOGLE_DCHECK_NE(TYPE_STRING_INLINED | kRepeatedMask, processing_type);
 
       // Mask out kRepeatedMask bit, allowing the jump table to be smaller.
       switch (static_cast<WireFormatLite::FieldType>(processing_type ^
@@ -690,17 +768,17 @@
     break;                                                                     \
   }
 
-        HANDLE_PACKED_TYPE(INT32, int32, Int32)
-        HANDLE_PACKED_TYPE(INT64, int64, Int64)
-        HANDLE_PACKED_TYPE(SINT32, int32, Int32)
-        HANDLE_PACKED_TYPE(SINT64, int64, Int64)
-        HANDLE_PACKED_TYPE(UINT32, uint32, UInt32)
-        HANDLE_PACKED_TYPE(UINT64, uint64, UInt64)
+        HANDLE_PACKED_TYPE(INT32, int32_t, Int32)
+        HANDLE_PACKED_TYPE(INT64, int64_t, Int64)
+        HANDLE_PACKED_TYPE(SINT32, int32_t, Int32)
+        HANDLE_PACKED_TYPE(SINT64, int64_t, Int64)
+        HANDLE_PACKED_TYPE(UINT32, uint32_t, UInt32)
+        HANDLE_PACKED_TYPE(UINT64, uint64_t, UInt64)
 
-        HANDLE_PACKED_TYPE(FIXED32, uint32, UInt32)
-        HANDLE_PACKED_TYPE(FIXED64, uint64, UInt64)
-        HANDLE_PACKED_TYPE(SFIXED32, int32, Int32)
-        HANDLE_PACKED_TYPE(SFIXED64, int64, Int64)
+        HANDLE_PACKED_TYPE(FIXED32, uint32_t, UInt32)
+        HANDLE_PACKED_TYPE(FIXED64, uint64_t, UInt64)
+        HANDLE_PACKED_TYPE(SFIXED32, int32_t, Int32)
+        HANDLE_PACKED_TYPE(SFIXED64, int64_t, Int64)
 
         HANDLE_PACKED_TYPE(FLOAT, float, Float)
         HANDLE_PACKED_TYPE(DOUBLE, double, Double)
@@ -712,7 +790,7 @@
           // InternalMetadata) when all inputs in the repeated series
           // are valid, we implement our own parser rather than call
           // WireFormat::ReadPackedEnumPreserveUnknowns.
-          uint32 length;
+          uint32_t length;
           if (PROTOBUF_PREDICT_FALSE(!input->ReadVarint32(&length))) {
             return false;
           }
@@ -785,8 +863,8 @@
         msg, table, input);
   } else {
     return MergePartialFromCodedStreamInlined<
-        UnknownFieldHandler, std::numeric_limits<uint32>::max()>(msg, table,
-                                                                 input);
+        UnknownFieldHandler, std::numeric_limits<uint32_t>::max()>(msg, table,
+                                                                   input);
   }
 }
 
diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h
index 9d2bc40d..d294caa 100644
--- a/src/google/protobuf/generated_message_tctable_decl.h
+++ b/src/google/protobuf/generated_message_tctable_decl.h
@@ -41,6 +41,9 @@
 #include <google/protobuf/parse_context.h>
 #include <google/protobuf/message_lite.h>
 
+// Must come last:
+#include <google/protobuf/port_def.inc>
+
 namespace google {
 namespace protobuf {
 namespace internal {
@@ -52,7 +55,10 @@
       : data(static_cast<uint64_t>(offset) << 48 |
              static_cast<uint64_t>(hasbit_idx) << 16 | coded_tag) {}
 
-  uint16_t coded_tag() const { return static_cast<uint16_t>(data); }
+  template <typename TagType = uint16_t>
+  TagType coded_tag() const {
+    return static_cast<TagType>(data);
+  }
   uint8_t hasbit_idx() const { return static_cast<uint8_t>(data >> 16); }
   uint16_t offset() const { return static_cast<uint16_t>(data >> 48); }
 
@@ -62,19 +68,21 @@
 struct TailCallParseTableBase;
 
 // TailCallParseFunc is the function pointer type used in the tailcall table.
-typedef const char* (*TailCallParseFunc)(MessageLite* msg, const char* ptr,
-                                         ParseContext* ctx,
-                                         const TailCallParseTableBase* table,
-                                         uint64_t hasbits, TcFieldData data);
+typedef const char* (*TailCallParseFunc)(PROTOBUF_TC_PARAM_DECL);
+
+#if defined(_MSC_VER) && !defined(_WIN64)
+#pragma warning(push)
+// TailCallParseTableBase is intentionally overaligned on 32 bit targets.
+#pragma warning(disable : 4324)
+#endif
 
 // Base class for message-level table with info for the tail-call parser.
-struct TailCallParseTableBase {
+struct alignas(uint64_t) TailCallParseTableBase {
   // Common attributes for message layout:
   uint16_t has_bits_offset;
   uint16_t extension_offset;
   uint32_t extension_range_low;
   uint32_t extension_range_high;
-  uint32_t has_bits_required_mask;
   const MessageLite* default_instance;
 
   // Handler for fields which are not handled by table dispatch.
@@ -93,6 +101,10 @@
   }
 };
 
+#if defined(_MSC_VER) && !defined(_WIN64)
+#pragma warning(pop)
+#endif
+
 static_assert(sizeof(TailCallParseTableBase::FieldEntry) <= 16,
               "Field entry is too big.");
 
@@ -120,4 +132,6 @@
 }  // namespace protobuf
 }  // namespace google
 
+#include <google/protobuf/port_undef.inc>
+
 #endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h
index 07879bd..aec2eed 100644
--- a/src/google/protobuf/generated_message_tctable_impl.h
+++ b/src/google/protobuf/generated_message_tctable_impl.h
@@ -53,20 +53,46 @@
 
 namespace internal {
 
-// PROTOBUF_TC_PARAM_DECL are the parameters for tailcall functions.
+// PROTOBUF_TC_PARAM_DECL are the parameters for tailcall functions, it is
+// defined in port_def.inc.
 //
 // Note that this is performance sensitive: changing the parameters will change
 // the registers used by the ABI calling convention, which subsequently affects
 // register selection logic inside the function.
-#define PROTOBUF_TC_PARAM_DECL                                 \
-  ::google::protobuf::MessageLite *msg, const char *ptr,                 \
-      ::google::protobuf::internal::ParseContext *ctx,                   \
-      const ::google::protobuf::internal::TailCallParseTableBase *table, \
-      uint64_t hasbits, ::google::protobuf::internal::TcFieldData data
 
 // PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
 #define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, table, hasbits, data
 
+// PROTOBUF_TC_PARSE_* decide which function is used to parse message-typed
+// fields. The guard macros are defined in port_def.inc.
+#if PROTOBUF_TC_STATIC_PARSE_SINGULAR1
+#define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) MESSAGE::Tct_ParseS1
+#else
+#define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) \
+  ::google::protobuf::internal::TcParserBase::SingularParseMessage<MESSAGE, uint8_t>
+#endif  // PROTOBUF_TC_STATIC_PARSE_SINGULAR1
+
+#if PROTOBUF_TC_STATIC_PARSE_SINGULAR2
+#define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) MESSAGE::Tct_ParseS2
+#else
+#define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) \
+  ::google::protobuf::internal::TcParserBase::SingularParseMessage<MESSAGE, uint16_t>
+#endif  // PROTOBUF_TC_STATIC_PARSE_SINGULAR2
+
+#if PROTOBUF_TC_STATIC_PARSE_REPEATED1
+#define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) MESSAGE::Tct_ParseR1
+#else
+#define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) \
+  ::google::protobuf::internal::TcParserBase::RepeatedParseMessage<MESSAGE, uint8_t>
+#endif  // PROTOBUF_TC_STATIC_PARSE_REPEATED1
+
+#if PROTOBUF_TC_STATIC_PARSE_REPEATED2
+#define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) MESSAGE::Tct_ParseR2
+#else
+#define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) \
+  ::google::protobuf::internal::TcParserBase::RepeatedParseMessage<MESSAGE, uint16_t>
+#endif  // PROTOBUF_TC_STATIC_PARSE_REPEATED2
+
 class TcParserBase {
  public:
   static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL);
@@ -75,7 +101,7 @@
   template <typename FieldType, typename TagType>
   PROTOBUF_NOINLINE static const char* SingularParseMessage(
       PROTOBUF_TC_PARAM_DECL) {
-    if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+    if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
       return table->fallback(PROTOBUF_TC_PARAM_PASS);
     }
     ptr += sizeof(TagType);
@@ -96,7 +122,7 @@
   template <typename FieldType, typename TagType>
   PROTOBUF_NOINLINE static const char* RepeatedParseMessage(
       PROTOBUF_TC_PARAM_DECL) {
-    if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+    if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
       return table->fallback(PROTOBUF_TC_PARAM_PASS);
     }
     ptr += sizeof(TagType);
@@ -123,7 +149,6 @@
   template <typename TagType, Utf8Type utf8>
   static const char* RepeatedString(PROTOBUF_TC_PARAM_DECL);
 
- protected:
   template <typename T>
   static T& RefAt(void* x, size_t offset) {
     T* target = reinterpret_cast<T*>(static_cast<char*>(x) + offset);
@@ -141,6 +166,7 @@
     }
   }
 
+ protected:
   static inline PROTOBUF_ALWAYS_INLINE const char* Return(
       PROTOBUF_TC_PARAM_DECL) {
     SyncHasbits(msg, hasbits, table);
diff --git a/src/google/protobuf/generated_message_tctable_impl.inc b/src/google/protobuf/generated_message_tctable_impl.inc
index e6e5dd5..f1eaff9 100644
--- a/src/google/protobuf/generated_message_tctable_impl.inc
+++ b/src/google/protobuf/generated_message_tctable_impl.inc
@@ -30,226 +30,124 @@
 
 // clang-format off
 #ifdef PROTOBUF_TCT_SOURCE
-template const char* TcParser<1>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<1>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<2>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<3>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<4>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParser<5>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::PackedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
+#define PROTOBUF_TCT_EXTERN
 #else
-extern template const char* TcParser<1>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<1>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<2>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<3>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<4>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParser<5>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::PackedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-extern template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
+#define PROTOBUF_TCT_EXTERN extern
 #endif
+PROTOBUF_TCT_EXTERN template const char *TcParser<1>::ParseLoop(PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, PROTOBUF_NAMESPACE_ID::internal::ParseContext*, PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
+PROTOBUF_TCT_EXTERN template const char *TcParser<2>::ParseLoop(PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, PROTOBUF_NAMESPACE_ID::internal::ParseContext*, PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
+PROTOBUF_TCT_EXTERN template const char *TcParser<3>::ParseLoop(PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, PROTOBUF_NAMESPACE_ID::internal::ParseContext*, PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
+PROTOBUF_TCT_EXTERN template const char *TcParser<4>::ParseLoop(PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, PROTOBUF_NAMESPACE_ID::internal::ParseContext*, PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
+PROTOBUF_TCT_EXTERN template const char *TcParser<5>::ParseLoop(PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, PROTOBUF_NAMESPACE_ID::internal::ParseContext*, PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
+PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
+#undef PROTOBUF_TCT_EXTERN
 // clang-format on
diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc
index f8a09f4..fedb07b 100644
--- a/src/google/protobuf/generated_message_tctable_lite.cc
+++ b/src/google/protobuf/generated_message_tctable_lite.cc
@@ -53,7 +53,7 @@
 
 // Offset returns the address `offset` bytes after `base`.
 inline void* Offset(void* base, uint32_t offset) {
-  return static_cast<uint8*>(base) + offset;
+  return static_cast<uint8_t*>(base) + offset;
 }
 
 // InvertPacked changes tag bits from the given wire type to length
@@ -73,7 +73,7 @@
 template <uint32_t kPowerOf2>
 template <typename LayoutType, typename TagType>
 const char* TcParser<kPowerOf2>::SingularFixed(PROTOBUF_TC_PARAM_DECL) {
-  if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     return table->fallback(PROTOBUF_TC_PARAM_PASS);
   }
   ptr += sizeof(TagType);  // Consume tag
@@ -86,13 +86,13 @@
 
 template <typename LayoutType, typename TagType>
 const char* TcParserBase::RepeatedFixed(PROTOBUF_TC_PARAM_DECL) {
-  if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     // Check if the field can be parsed as packed repeated:
     constexpr WireFormatLite::WireType fallback_wt =
         sizeof(LayoutType) == 4 ? WireFormatLite::WIRETYPE_FIXED32
                                 : WireFormatLite::WIRETYPE_FIXED64;
     InvertPacked<fallback_wt>(data);
-    if (static_cast<TagType>(data.coded_tag()) == 0) {
+    if (data.coded_tag<TagType>() == 0) {
       return PackedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
     } else {
       return table->fallback(PROTOBUF_TC_PARAM_PASS);
@@ -117,13 +117,13 @@
 
 template <typename LayoutType, typename TagType>
 const char* TcParserBase::PackedFixed(PROTOBUF_TC_PARAM_DECL) {
-  if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     // Try parsing as non-packed repeated:
     constexpr WireFormatLite::WireType fallback_wt =
         sizeof(LayoutType) == 4 ? WireFormatLite::WIRETYPE_FIXED32
                                 : WireFormatLite::WIRETYPE_FIXED64;
     InvertPacked<fallback_wt>(data);
-    if (static_cast<TagType>(data.coded_tag()) == 0) {
+    if (data.coded_tag<TagType>() == 0) {
       return RepeatedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
     } else {
       return table->fallback(PROTOBUF_TC_PARAM_PASS);
@@ -273,13 +273,31 @@
   }
 }
 
+template <typename FieldType, TcParserBase::VarintDecode =
+                                  TcParserBase::VarintDecode::kNoConversion>
+FieldType ZigZagDecodeHelper(uint64_t value) {
+  return static_cast<FieldType>(value);
+}
+
+template <>
+int32_t ZigZagDecodeHelper<int32_t, TcParserBase::VarintDecode::kZigZag>(
+    uint64_t value) {
+  return WireFormatLite::ZigZagDecode32(value);
+}
+
+template <>
+int64_t ZigZagDecodeHelper<int64_t, TcParserBase::VarintDecode::kZigZag>(
+    uint64_t value) {
+  return WireFormatLite::ZigZagDecode64(value);
+}
+
 }  // namespace
 
 template <uint32_t kPowerOf2>
 template <typename FieldType, typename TagType,
           TcParserBase::VarintDecode zigzag>
 const char* TcParser<kPowerOf2>::SingularVarint(PROTOBUF_TC_PARAM_DECL) {
-  if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     return table->fallback(PROTOBUF_TC_PARAM_PASS);
   }
   ptr += sizeof(TagType);  // Consume tag
@@ -289,8 +307,8 @@
   if (ptr == nullptr) {
     return Error(PROTOBUF_TC_PARAM_PASS);
   }
-  RefAt<FieldType>(msg, data.offset()) = static_cast<FieldType>(
-      zigzag ? google::protobuf::internal::WireFormatLite::ZigZagDecode64(tmp) : tmp);
+  RefAt<FieldType>(msg, data.offset()) =
+      ZigZagDecodeHelper<FieldType, zigzag>(tmp);
   PROTOBUF_MUSTTAIL return TailCall(PROTOBUF_TC_PARAM_PASS);
 }
 
@@ -298,10 +316,10 @@
           TcParserBase::VarintDecode zigzag>
 PROTOBUF_NOINLINE const char* TcParserBase::RepeatedVarint(
     PROTOBUF_TC_PARAM_DECL) {
-  if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     // Try parsing as non-packed repeated:
     InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
-    if (static_cast<TagType>(data.coded_tag()) == 0) {
+    if (data.coded_tag<TagType>() == 0) {
       return PackedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
     } else {
       return table->fallback(PROTOBUF_TC_PARAM_PASS);
@@ -316,8 +334,7 @@
     if (ptr == nullptr) {
       return Error(PROTOBUF_TC_PARAM_PASS);
     }
-    field.Add(zigzag ? google::protobuf::internal::WireFormatLite::ZigZagDecode64(tmp)
-                     : tmp);
+    field.Add(ZigZagDecodeHelper<FieldType, zigzag>(tmp));
     if (!ctx->DataAvailable(ptr)) {
       break;
     }
@@ -329,9 +346,9 @@
           TcParserBase::VarintDecode zigzag>
 PROTOBUF_NOINLINE const char* TcParserBase::PackedVarint(
     PROTOBUF_TC_PARAM_DECL) {
-  if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
-    if (static_cast<TagType>(data.coded_tag()) == 0) {
+    if (data.coded_tag<TagType>() == 0) {
       return RepeatedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
     } else {
       return table->fallback(PROTOBUF_TC_PARAM_PASS);
@@ -380,7 +397,7 @@
 
 template <typename TagType, TcParserBase::Utf8Type utf8>
 const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL) {
-  if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     return table->fallback(PROTOBUF_TC_PARAM_PASS);
   }
   ptr += sizeof(TagType);
@@ -411,7 +428,7 @@
 
 template <typename TagType, TcParserBase::Utf8Type utf8>
 const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL) {
-  if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     return table->fallback(PROTOBUF_TC_PARAM_PASS);
   }
   auto expected_tag = UnalignedLoad<TagType>(ptr);
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index 605fa98..cbe771e 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -119,93 +119,93 @@
   static void Serialize(const void* ptr, io::CodedOutputStream* output) {
     WireFormatLite::WriteBoolNoTag(Get<bool>(ptr), output);
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     return WireFormatLite::WriteBoolNoTagToArray(Get<Type>(ptr), buffer);
   }
 };
 
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {
-  typedef int32 Type;
+  typedef int32_t Type;
   static void Serialize(const void* ptr, io::CodedOutputStream* output) {
-    WireFormatLite::WriteInt32NoTag(Get<int32>(ptr), output);
+    WireFormatLite::WriteInt32NoTag(Get<int32_t>(ptr), output);
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     return WireFormatLite::WriteInt32NoTagToArray(Get<Type>(ptr), buffer);
   }
 };
 
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT32> {
-  typedef int32 Type;
+  typedef int32_t Type;
   static void Serialize(const void* ptr, io::CodedOutputStream* output) {
-    WireFormatLite::WriteSInt32NoTag(Get<int32>(ptr), output);
+    WireFormatLite::WriteSInt32NoTag(Get<int32_t>(ptr), output);
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     return WireFormatLite::WriteSInt32NoTagToArray(Get<Type>(ptr), buffer);
   }
 };
 
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT32> {
-  typedef uint32 Type;
+  typedef uint32_t Type;
   static void Serialize(const void* ptr, io::CodedOutputStream* output) {
-    WireFormatLite::WriteUInt32NoTag(Get<uint32>(ptr), output);
+    WireFormatLite::WriteUInt32NoTag(Get<uint32_t>(ptr), output);
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     return WireFormatLite::WriteUInt32NoTagToArray(Get<Type>(ptr), buffer);
   }
 };
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT64> {
-  typedef int64 Type;
+  typedef int64_t Type;
   static void Serialize(const void* ptr, io::CodedOutputStream* output) {
-    WireFormatLite::WriteInt64NoTag(Get<int64>(ptr), output);
+    WireFormatLite::WriteInt64NoTag(Get<int64_t>(ptr), output);
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     return WireFormatLite::WriteInt64NoTagToArray(Get<Type>(ptr), buffer);
   }
 };
 
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT64> {
-  typedef int64 Type;
+  typedef int64_t Type;
   static void Serialize(const void* ptr, io::CodedOutputStream* output) {
-    WireFormatLite::WriteSInt64NoTag(Get<int64>(ptr), output);
+    WireFormatLite::WriteSInt64NoTag(Get<int64_t>(ptr), output);
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     return WireFormatLite::WriteSInt64NoTagToArray(Get<Type>(ptr), buffer);
   }
 };
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT64> {
-  typedef uint64 Type;
+  typedef uint64_t Type;
   static void Serialize(const void* ptr, io::CodedOutputStream* output) {
-    WireFormatLite::WriteUInt64NoTag(Get<uint64>(ptr), output);
+    WireFormatLite::WriteUInt64NoTag(Get<uint64_t>(ptr), output);
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     return WireFormatLite::WriteUInt64NoTagToArray(Get<Type>(ptr), buffer);
   }
 };
 
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
-  typedef uint32 Type;
+  typedef uint32_t Type;
   static void Serialize(const void* ptr, io::CodedOutputStream* output) {
-    WireFormatLite::WriteFixed32NoTag(Get<uint32>(ptr), output);
+    WireFormatLite::WriteFixed32NoTag(Get<uint32_t>(ptr), output);
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     return WireFormatLite::WriteFixed32NoTagToArray(Get<Type>(ptr), buffer);
   }
 };
 
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
-  typedef uint64 Type;
+  typedef uint64_t Type;
   static void Serialize(const void* ptr, io::CodedOutputStream* output) {
-    WireFormatLite::WriteFixed64NoTag(Get<uint64>(ptr), output);
+    WireFormatLite::WriteFixed64NoTag(Get<uint64_t>(ptr), output);
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     return WireFormatLite::WriteFixed64NoTagToArray(Get<Type>(ptr), buffer);
   }
 };
@@ -217,12 +217,12 @@
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED32>
     : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
-  typedef int32 Type;
+  typedef int32_t Type;
 };
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED64>
     : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
-  typedef int64 Type;
+  typedef int64_t Type;
 };
 template <>
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_FLOAT>
@@ -243,7 +243,7 @@
     output->WriteVarint32(value.size());
     output->WriteRawMaybeAliased(value.data(), value.size());
   }
-  static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
     const Type& value = *static_cast<const Type*>(ptr);
     return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer);
   }
@@ -254,6 +254,10 @@
     : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
 
 
+template <>
+struct PrimitiveTypeHelper<FieldMetadata::kInlinedType>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
+
 // We want to serialize to both CodedOutputStream and directly into byte arrays
 // without duplicating the code. In fact we might want extra output channels in
 // the future.
@@ -266,12 +270,12 @@
 }
 
 template <typename O>
-void WriteTagTo(uint32 tag, O* output) {
+void WriteTagTo(uint32_t tag, O* output) {
   SerializeTo<WireFormatLite::TYPE_UINT32>(&tag, output);
 }
 
 template <typename O>
-void WriteLengthTo(uint32 length, O* output) {
+void WriteLengthTo(uint32_t length, O* output) {
   SerializeTo<WireFormatLite::TYPE_UINT32>(&length, output);
 }
 
@@ -285,7 +289,7 @@
 
 // Specialization for writing into a plain array
 struct ArrayOutput {
-  uint8* ptr;
+  uint8_t* ptr;
   bool is_deterministic;
 };
 
@@ -312,17 +316,17 @@
 // Helper to branch to fast path if possible
 void SerializeMessageDispatch(const MessageLite& msg,
                               const FieldMetadata* field_table, int num_fields,
-                              int32 cached_size,
+                              int32_t cached_size,
                               io::CodedOutputStream* output) {
-  const uint8* base = reinterpret_cast<const uint8*>(&msg);
+  const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
   SerializeInternal(base, field_table, num_fields, output);
 }
 
 // Helper to branch to fast path if possible
 void SerializeMessageDispatch(const MessageLite& msg,
                               const FieldMetadata* field_table, int num_fields,
-                              int32 cached_size, ArrayOutput* output) {
-  const uint8* base = reinterpret_cast<const uint8*>(&msg);
+                              int32_t cached_size, ArrayOutput* output) {
+  const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
   output->ptr = SerializeInternalToArray(base, field_table, num_fields,
                                          output->is_deterministic, output->ptr);
 }
@@ -341,8 +345,9 @@
     return;
   }
   const FieldMetadata* field_table = table->field_table;
-  const uint8* base = reinterpret_cast<const uint8*>(msg);
-  int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
+  const uint8_t* base = reinterpret_cast<const uint8_t*>(msg);
+  int cached_size =
+      *reinterpret_cast<const int32_t*>(base + field_table->offset);
   WriteLengthTo(cached_size, output);
   int num_fields = table->num_fields - 1;
   SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
@@ -361,8 +366,9 @@
     return;
   }
   const FieldMetadata* field_table = table->field_table;
-  const uint8* base = reinterpret_cast<const uint8*>(msg);
-  int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
+  const uint8_t* base = reinterpret_cast<const uint8_t*>(msg);
+  int cached_size =
+      *reinterpret_cast<const int32_t*>(base + field_table->offset);
   int num_fields = table->num_fields - 1;
   SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
                            output);
@@ -412,6 +418,15 @@
   }
 };
 
+template <>
+struct SingularFieldHelper<FieldMetadata::kInlinedType> {
+  template <typename O>
+  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
+    WriteTagTo(md.tag, output);
+    SerializeTo<FieldMetadata::kInlinedType>(&Get<std::string>(field), output);
+  }
+};
+
 template <int type>
 struct RepeatedFieldHelper {
   template <typename O>
@@ -484,6 +499,10 @@
 };
 
 
+template <>
+struct RepeatedFieldHelper<FieldMetadata::kInlinedType>
+    : RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
+
 template <int type>
 struct PackedFieldHelper {
   template <typename O>
@@ -493,7 +512,7 @@
     if (array.empty()) return;
     WriteTagTo(md.tag, output);
     int cached_size =
-        Get<int>(static_cast<const uint8*>(field) + sizeof(RepeatedField<T>));
+        Get<int>(static_cast<const uint8_t*>(field) + sizeof(RepeatedField<T>));
     WriteLengthTo(cached_size, output);
     for (int i = 0; i < array.size(); i++) {
       SerializeTo<type>(&array[i], output);
@@ -519,6 +538,9 @@
 template <>
 struct PackedFieldHelper<WireFormatLite::TYPE_MESSAGE>
     : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
+template <>
+struct PackedFieldHelper<FieldMetadata::kInlinedType>
+    : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
 
 template <int type>
 struct OneOfFieldHelper {
@@ -529,6 +551,15 @@
 };
 
 
+template <>
+struct OneOfFieldHelper<FieldMetadata::kInlinedType> {
+  template <typename O>
+  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
+    SingularFieldHelper<FieldMetadata::kInlinedType>::Serialize(
+        Get<const std::string*>(field), md, output);
+  }
+};
+
 void SerializeNotImplemented(int field) {
   GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
 }
@@ -569,6 +600,11 @@
 }
 
 
+template <>
+bool IsNull<FieldMetadata::kInlinedType>(const void* ptr) {
+  return static_cast<const std::string*>(ptr)->empty();
+}
+
 #define SERIALIZERS_FOR_TYPE(type)                                            \
   case SERIALIZE_TABLE_OP(type, FieldMetadata::kPresence):                    \
     if (!IsPresent(base, field_metadata.has_offset)) continue;                \
@@ -590,13 +626,13 @@
     OneOfFieldHelper<type>::Serialize(ptr, field_metadata, output);           \
     break
 
-void SerializeInternal(const uint8* base,
+void SerializeInternal(const uint8_t* base,
                        const FieldMetadata* field_metadata_table,
-                       int32 num_fields, io::CodedOutputStream* output) {
+                       int32_t num_fields, io::CodedOutputStream* output) {
   SpecialSerializer func = nullptr;
   for (int i = 0; i < num_fields; i++) {
     const FieldMetadata& field_metadata = field_metadata_table[i];
-    const uint8* ptr = base + field_metadata.offset;
+    const uint8_t* ptr = base + field_metadata.offset;
     switch (field_metadata.type) {
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
@@ -616,6 +652,7 @@
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
+      SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
 
       // Special cases
       case FieldMetadata::kSpecial:
@@ -631,16 +668,16 @@
   }
 }
 
-uint8* SerializeInternalToArray(const uint8* base,
-                                const FieldMetadata* field_metadata_table,
-                                int32 num_fields, bool is_deterministic,
-                                uint8* buffer) {
+uint8_t* SerializeInternalToArray(const uint8_t* base,
+                                  const FieldMetadata* field_metadata_table,
+                                  int32_t num_fields, bool is_deterministic,
+                                  uint8_t* buffer) {
   ArrayOutput array_output = {buffer, is_deterministic};
   ArrayOutput* output = &array_output;
   SpecialSerializer func = nullptr;
   for (int i = 0; i < num_fields; i++) {
     const FieldMetadata& field_metadata = field_metadata_table[i];
-    const uint8* ptr = base + field_metadata.offset;
+    const uint8_t* ptr = base + field_metadata.offset;
     switch (field_metadata.type) {
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
@@ -660,6 +697,7 @@
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
       SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
+      SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
       // Special cases
       case FieldMetadata::kSpecial: {
         io::ArrayOutputStream array_stream(array_output.ptr, INT_MAX);
@@ -680,14 +718,15 @@
 }
 #undef SERIALIZERS_FOR_TYPE
 
-void ExtensionSerializer(const uint8* ptr, uint32 offset, uint32 tag,
-                         uint32 has_offset, io::CodedOutputStream* output) {
+void ExtensionSerializer(const MessageLite* extendee, const uint8_t* ptr,
+                         uint32_t offset, uint32_t tag, uint32_t has_offset,
+                         io::CodedOutputStream* output) {
   reinterpret_cast<const ExtensionSet*>(ptr + offset)
-      ->SerializeWithCachedSizes(tag, has_offset, output);
+      ->SerializeWithCachedSizes(extendee, tag, has_offset, output);
 }
 
-void UnknownFieldSerializerLite(const uint8* ptr, uint32 offset, uint32 tag,
-                                uint32 has_offset,
+void UnknownFieldSerializerLite(const uint8_t* ptr, uint32_t offset,
+                                uint32_t tag, uint32_t has_offset,
                                 io::CodedOutputStream* output) {
   output->WriteString(
       reinterpret_cast<const InternalMetadata*>(ptr + offset)
@@ -721,9 +760,7 @@
   GOOGLE_DCHECK(Arena::InternalHelper<MessageLite>::GetOwningArena(submessage) ==
          submessage_arena);
   GOOGLE_DCHECK(message_arena != submessage_arena);
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
   GOOGLE_DCHECK_EQ(submessage_arena, nullptr);
-#endif  // PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
   if (message_arena != NULL && submessage_arena == NULL) {
     message_arena->Own(submessage);
     return submessage;
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 94c6c29..336234c 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -132,27 +132,28 @@
   return true;
 }
 
-inline bool IsPresent(const void* base, uint32 hasbit) {
-  const uint32* has_bits_array = static_cast<const uint32*>(base);
+inline bool IsPresent(const void* base, uint32_t hasbit) {
+  const uint32_t* has_bits_array = static_cast<const uint32_t*>(base);
   return (has_bits_array[hasbit / 32] & (1u << (hasbit & 31))) != 0;
 }
 
-inline bool IsOneofPresent(const void* base, uint32 offset, uint32 tag) {
-  const uint32* oneof =
-      reinterpret_cast<const uint32*>(static_cast<const uint8*>(base) + offset);
+inline bool IsOneofPresent(const void* base, uint32_t offset, uint32_t tag) {
+  const uint32_t* oneof = reinterpret_cast<const uint32_t*>(
+      static_cast<const uint8_t*>(base) + offset);
   return *oneof == tag >> 3;
 }
 
-typedef void (*SpecialSerializer)(const uint8* base, uint32 offset, uint32 tag,
-                                  uint32 has_offset,
+typedef void (*SpecialSerializer)(const uint8_t* base, uint32_t offset,
+                                  uint32_t tag, uint32_t has_offset,
                                   io::CodedOutputStream* output);
 
-PROTOBUF_EXPORT void ExtensionSerializer(const uint8* base, uint32 offset,
-                                         uint32 tag, uint32 has_offset,
+PROTOBUF_EXPORT void ExtensionSerializer(const MessageLite* extendee,
+                                         const uint8_t* ptr, uint32_t offset,
+                                         uint32_t tag, uint32_t has_offset,
                                          io::CodedOutputStream* output);
-PROTOBUF_EXPORT void UnknownFieldSerializerLite(const uint8* base,
-                                                uint32 offset, uint32 tag,
-                                                uint32 has_offset,
+PROTOBUF_EXPORT void UnknownFieldSerializerLite(const uint8_t* base,
+                                                uint32_t offset, uint32_t tag,
+                                                uint32_t has_offset,
                                                 io::CodedOutputStream* output);
 
 PROTOBUF_EXPORT MessageLite* DuplicateIfNonNullInternal(MessageLite* message);
diff --git a/src/google/protobuf/has_bits.h b/src/google/protobuf/has_bits.h
index 66d3cd4..acbca68 100644
--- a/src/google/protobuf/has_bits.h
+++ b/src/google/protobuf/has_bits.h
@@ -53,11 +53,11 @@
     memset(has_bits_, 0, sizeof(has_bits_));
   }
 
-  PROTOBUF_NDEBUG_INLINE uint32& operator[](int index) {
+  PROTOBUF_NDEBUG_INLINE uint32_t& operator[](int index) {
     return has_bits_[index];
   }
 
-  PROTOBUF_NDEBUG_INLINE const uint32& operator[](int index) const {
+  PROTOBUF_NDEBUG_INLINE const uint32_t& operator[](int index) const {
     return has_bits_[index];
   }
 
@@ -76,7 +76,7 @@
   bool empty() const;
 
  private:
-  uint32 has_bits_[doublewords];
+  uint32_t has_bits_[doublewords];
 };
 
 template <>
diff --git a/src/google/protobuf/implicit_weak_message.h b/src/google/protobuf/implicit_weak_message.h
index bfa6a81..561e472 100644
--- a/src/google/protobuf/implicit_weak_message.h
+++ b/src/google/protobuf/implicit_weak_message.h
@@ -80,8 +80,8 @@
 
   size_t ByteSizeLong() const override { return data_.size(); }
 
-  uint8* _InternalSerialize(uint8* target,
-                            io::EpsCopyOutputStream* stream) const final {
+  uint8_t* _InternalSerialize(uint8_t* target,
+                              io::EpsCopyOutputStream* stream) const final {
     return stream->WriteRaw(data_.data(), static_cast<int>(data_.size()),
                             target);
   }
diff --git a/src/google/protobuf/inlined_string_field.cc b/src/google/protobuf/inlined_string_field.cc
new file mode 100644
index 0000000..0d16869
--- /dev/null
+++ b/src/google/protobuf/inlined_string_field.cc
@@ -0,0 +1,110 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/inlined_string_field.h>
+
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message_lite.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+
+std::string* InlinedStringField::Mutable(const LazyString& /*default_value*/,
+                                         Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask) {
+  if (arena == nullptr || !donated) {
+    return UnsafeMutablePointer();
+  }
+  return MutableSlow(arena, donated, donating_states, mask);
+}
+
+std::string* InlinedStringField::Mutable(ArenaStringPtr::EmptyDefault,
+                                         Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask) {
+  if (arena == nullptr || !donated) {
+    return UnsafeMutablePointer();
+  }
+  return MutableSlow(arena, donated, donating_states, mask);
+}
+
+std::string* InlinedStringField::MutableSlow(::google::protobuf::Arena* arena,
+                                             bool donated,
+                                             uint32_t* donating_states,
+                                             uint32_t mask) {
+  return UnsafeMutablePointer();
+}
+
+void InlinedStringField::SetAllocated(const std::string* default_value,
+                                      std::string* value, Arena* arena,
+                                      bool donated, uint32_t* donating_states,
+                                      uint32_t mask) {
+  SetAllocatedNoArena(default_value, value);
+}
+
+void InlinedStringField::Set(const std::string* default_value,
+                             std::string&& value, Arena* arena, bool donated,
+                             uint32_t* donating_states, uint32_t mask) {
+  SetNoArena(default_value, std::move(value));
+}
+
+std::string* InlinedStringField::Release(const std::string* default_value,
+                                         Arena* arena, bool donated) {
+  if (arena == nullptr && !donated) {
+    return ReleaseNonDefaultNoArena(default_value);
+  }
+  return ReleaseNonDefault(default_value, arena);
+}
+
+std::string* InlinedStringField::ReleaseNonDefault(
+    const std::string* default_value, Arena* arena) {
+  return ReleaseNonDefaultNoArena(default_value);
+}
+
+void InlinedStringField::ClearToDefault(const LazyString& default_value,
+                                        Arena* arena, bool donated) {
+  (void)arena;
+  get_mutable()->assign(default_value.get());
+}
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/inlined_string_field.h b/src/google/protobuf/inlined_string_field.h
new file mode 100644
index 0000000..9f45511
--- /dev/null
+++ b/src/google/protobuf/inlined_string_field.h
@@ -0,0 +1,379 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
+#define GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
+
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Arena;
+
+namespace internal {
+
+// InlinedStringField wraps a std::string instance and exposes an API similar to
+// ArenaStringPtr's wrapping of a std::string* instance.
+//
+// default_value parameters are taken for consistency with ArenaStringPtr, but
+// are not used for most methods. With inlining, these should be removed from
+// the generated binary.
+//
+// InlinedStringField has a donating mechanism that allows string buffer
+// allocated on arena. A string is donated means both the string container and
+// the data buffer are on arena. The donating mechanism here is similar to the
+// one in ArenaStringPtr with some differences:
+//
+// When an InlinedStringField is constructed, the donating state is true. This
+// is because the string container is directly stored in the message on the
+// arena:
+//
+//   Construction: donated=true
+//   Arena:
+//   +-----------------------+
+//   |Message foo:           |
+//   | +-------------------+ |
+//   | |InlinedStringField:| |
+//   | | +-----+           | |
+//   | | | | | |           | |
+//   | | +-----+           | |
+//   | +-------------------+ |
+//   +-----------------------+
+//
+// When lvalue Set is called, the donating state is still true. String data will
+// be allocated on the arena:
+//
+//   Lvalue Set: donated=true
+//   Arena:
+//   +-----------------------+
+//   |Message foo:           |
+//   | +-------------------+ |
+//   | |InlinedStringField:| |
+//   | | +-----+           | |
+//   | | | | | |           | |
+//   | | +|----+           | |
+//   | +--|----------------+ |
+//   |    V                  |
+//   |  +----------------+   |
+//   |  |'f','o','o',... |   |
+//   |  +----------------+   |
+//   +-----------------------+
+//
+// Some operations will undonate a donated string, including: Mutable,
+// SetAllocated, Rvalue Set, and Swap with a non-donated string.
+//
+// For more details of the donating states transitions, go/pd-inlined-string.
+class PROTOBUF_EXPORT InlinedStringField {
+ public:
+  InlinedStringField() { Init(); }
+  inline void Init() { new (get_mutable()) std::string(); }
+  // Add the dummy parameter just to make InlinedStringField(nullptr)
+  // unambiguous.
+  constexpr InlinedStringField(
+      const ExplicitlyConstructed<std::string>* /*default_value*/,
+      bool /*dummy*/)
+      : value_{} {}
+  explicit InlinedStringField(const std::string& default_value);
+  explicit InlinedStringField(Arena* arena);
+  ~InlinedStringField() { Destruct(); }
+
+  // Lvalue Set. To save space, we pack the donating states of multiple
+  // InlinedStringFields into an uint32_t `donating_states`. The `mask`
+  // indicates the position of the bit for this InlinedStringField. `donated` is
+  // whether this field is donated.
+  //
+  // The caller should guarantee that:
+  //
+  //   `donated == ((donating_states & ~mask) != 0)`
+  //
+  // This method never changes the `donating_states`.
+  void Set(const std::string* default_value, ConstStringParam value,
+           Arena* arena, bool donated, uint32_t* /*donating_states*/,
+           uint32_t /*mask*/) {
+    (void)arena;
+    (void)donated;
+    SetNoArena(default_value, value);
+  }
+
+  // Rvalue Set. If this field is donated, this method will undonate this field
+  // by mutating the `donating_states` according to `mask`.
+  void Set(const std::string* default_value, std::string&& value, Arena* arena,
+           bool donated, uint32_t* donating_states, uint32_t mask);
+
+  template <typename FirstParam>
+  void Set(FirstParam p1, const char* str, ::google::protobuf::Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask) {
+    Set(p1, ConstStringParam(str), arena, donated, donating_states, mask);
+  }
+
+  template <typename FirstParam>
+  void Set(FirstParam p1, const char* str, size_t size, ::google::protobuf::Arena* arena,
+           bool donated, uint32_t* donating_states, uint32_t mask) {
+    ConstStringParam sp{str, size};  // for string_view and `const string &`
+    Set(p1, sp, arena, donated, donating_states, mask);
+  }
+
+  template <typename FirstParam, typename RefWrappedType>
+  void Set(FirstParam p1,
+           std::reference_wrapper<RefWrappedType> const_string_ref,
+           ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+           uint32_t mask) {
+    Set(p1, const_string_ref.get(), arena, donated, donating_states, mask);
+  }
+
+  template <typename FirstParam, typename SecondParam>
+  void SetBytes(FirstParam p1, SecondParam&& p2, ::google::protobuf::Arena* arena,
+                bool donated, uint32_t* donating_states, uint32_t mask) {
+    Set(p1, static_cast<SecondParam&&>(p2), arena, donated, donating_states,
+        mask);
+  }
+
+  template <typename FirstParam>
+  void SetBytes(FirstParam p1, const void* str, size_t size,
+                ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+                uint32_t mask) {
+    // Must work whether ConstStringParam is string_view or `const string &`
+    ConstStringParam sp{static_cast<const char*>(str), size};
+    Set(p1, sp, arena, donated, donating_states, mask);
+  }
+
+  PROTOBUF_NDEBUG_INLINE void SetNoArena(const std::string* default_value,
+                                         StringPiece value);
+  PROTOBUF_NDEBUG_INLINE void SetNoArena(const std::string* default_value,
+                                         std::string&& value);
+
+  // Basic accessors.
+  PROTOBUF_NDEBUG_INLINE const std::string& Get() const { return GetNoArena(); }
+  PROTOBUF_NDEBUG_INLINE const std::string& GetNoArena() const;
+
+  // Mutable returns a std::string* instance that is heap-allocated. If this
+  // field is donated, this method undonates this field by mutating the
+  // `donating_states` according to `mask`, and copies the content of the
+  // original string to the returning string.
+  std::string* Mutable(const LazyString& default_value, Arena* arena,
+                       bool donated, uint32_t* donating_states, uint32_t mask);
+  std::string* Mutable(ArenaStringPtr::EmptyDefault, Arena* arena, bool donated,
+                       uint32_t* donating_states, uint32_t mask);
+
+  // Release returns a std::string* instance that is heap-allocated and is not
+  // Own()'d by any arena. If the field is not set, this returns NULL. The
+  // caller retains ownership. Clears this field back to NULL state. Used to
+  // implement release_<field>() methods on generated classes.
+  PROTOBUF_MUST_USE_RESULT std::string* Release(
+      const std::string* default_value, Arena* arena, bool donated);
+  PROTOBUF_MUST_USE_RESULT std::string* ReleaseNonDefault(
+      const std::string* default_value, Arena* arena);
+  std::string* ReleaseNonDefaultNoArena(const std::string* default_value);
+
+  // Takes a std::string that is heap-allocated, and takes ownership. The
+  // std::string's destructor is registered with the arena. Used to implement
+  // set_allocated_<field> in generated classes.
+  //
+  // If this field is donated, this method undonates this field by mutating the
+  // `donating_states` according to `mask`.
+  void SetAllocated(const std::string* default_value, std::string* value,
+                    Arena* arena, bool donated, uint32_t* donating_states,
+                    uint32_t mask);
+
+  void SetAllocatedNoArena(const std::string* default_value,
+                           std::string* value);
+
+  // When one of `this` and `from` is donated and the other is not donated, this
+  // method will undonate the donated one and swap the two heap-allocated
+  // strings.
+  PROTOBUF_NDEBUG_INLINE void Swap(InlinedStringField* from,
+                                   const std::string* default_value,
+                                   Arena* arena, bool donated,
+                                   bool from_donated, uint32_t* donating_states,
+                                   uint32_t* from_donating_states,
+                                   uint32_t mask);
+
+  // Frees storage (if not on an arena).
+  PROTOBUF_NDEBUG_INLINE void Destroy(const std::string* default_value,
+                                      Arena* arena) {
+    if (arena == nullptr) {
+      DestroyNoArena(default_value);
+    }
+  }
+  PROTOBUF_NDEBUG_INLINE void DestroyNoArena(const std::string* default_value);
+
+  // Clears content, but keeps allocated std::string, to avoid the overhead of
+  // heap operations. After this returns, the content (as seen by the user) will
+  // always be the empty std::string.
+  PROTOBUF_NDEBUG_INLINE void ClearToEmpty() { ClearNonDefaultToEmpty(); }
+  PROTOBUF_NDEBUG_INLINE void ClearNonDefaultToEmpty() {
+    get_mutable()->clear();
+  }
+
+  // Clears content, but keeps allocated std::string if arena != NULL, to avoid
+  // the overhead of heap operations. After this returns, the content (as seen
+  // by the user) will always be equal to |default_value|.
+  void ClearToDefault(const LazyString& default_value, Arena* arena,
+                      bool donated);
+
+  // Returns a mutable pointer, but doesn't initialize the string to the
+  // default value.
+  PROTOBUF_NDEBUG_INLINE std::string* MutableNoArenaNoDefault(
+      const std::string* /*default_value*/);
+
+  // Generated code / reflection only! Returns a mutable pointer to the string.
+  PROTOBUF_NDEBUG_INLINE std::string* UnsafeMutablePointer();
+
+  // InlinedStringField doesn't have things like the `default_value` pointer in
+  // ArenaStringPtr.
+  bool IsDefault(const std::string* /*default_value*/) const { return false; }
+
+ private:
+  void Destruct() { get_mutable()->~basic_string(); }
+
+  PROTOBUF_NDEBUG_INLINE std::string* get_mutable();
+  PROTOBUF_NDEBUG_INLINE const std::string* get_const() const;
+
+  alignas(std::string) char value_[sizeof(std::string)];
+
+  std::string* MutableSlow(::google::protobuf::Arena* arena, bool donated,
+                           uint32_t* donating_states, uint32_t mask);
+
+
+  // When constructed in an Arena, we want our destructor to be skipped.
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+};
+
+inline std::string* InlinedStringField::get_mutable() {
+  return reinterpret_cast<std::string*>(&value_);
+}
+
+inline const std::string* InlinedStringField::get_const() const {
+  return reinterpret_cast<const std::string*>(&value_);
+}
+
+inline InlinedStringField::InlinedStringField(
+    const std::string& default_value) {
+  new (get_mutable()) std::string(default_value);
+}
+
+inline InlinedStringField::InlinedStringField(Arena* /*arena*/) { Init(); }
+
+inline const std::string& InlinedStringField::GetNoArena() const {
+  return *get_const();
+}
+
+inline void InlinedStringField::SetAllocatedNoArena(
+    const std::string* /*default_value*/, std::string* value) {
+  if (value == nullptr) {
+    // Currently, inlined string field can't have non empty default.
+    get_mutable()->clear();
+  } else {
+    get_mutable()->assign(std::move(*value));
+    delete value;
+  }
+}
+
+inline void InlinedStringField::DestroyNoArena(const std::string*) {
+  // This is invoked from the generated message's ArenaDtor, which is used to
+  // clean up objects not allocated on the Arena.
+  this->~InlinedStringField();
+}
+
+inline std::string* InlinedStringField::ReleaseNonDefaultNoArena(
+    const std::string* /*default_value*/) {
+  // Currently, inlined string field can't have non empty default.
+  auto* released = new std::string();
+  get_mutable()->swap(*released);
+  return released;
+}
+
+inline void InlinedStringField::SetNoArena(const std::string* /*default_value*/,
+                                           StringPiece value) {
+  get_mutable()->assign(value.data(), value.length());
+}
+
+inline void InlinedStringField::SetNoArena(const std::string* /*default_value*/,
+                                           std::string&& value) {
+  get_mutable()->assign(std::move(value));
+}
+
+inline void InlinedStringField::Swap(
+    InlinedStringField* from, const std::string* /*default_value*/,
+    Arena* arena, bool donated, bool from_donated, uint32_t* donating_states,
+    uint32_t* from_donating_states, uint32_t mask) {
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  // If one is donated and the other is not, undonate the donated one.
+  if (donated && !from_donated) {
+    MutableSlow(arena, donated, donating_states, mask);
+  } else if (!donated && from_donated) {
+    from->MutableSlow(arena, from_donated, from_donating_states, mask);
+  }
+  // Then, swap the two undonated strings.
+#else
+  (void)arena;
+  (void)donated;
+  (void)from_donated;
+  (void)donating_states;
+  (void)from_donating_states;
+  (void)mask;
+#endif
+  get_mutable()->swap(*from->get_mutable());
+}
+
+inline std::string* InlinedStringField::MutableNoArenaNoDefault(
+    const std::string*) {
+  return get_mutable();
+}
+
+inline std::string* InlinedStringField::UnsafeMutablePointer() {
+  return get_mutable();
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
diff --git a/src/google/protobuf/inlined_string_field_unittest.cc b/src/google/protobuf/inlined_string_field_unittest.cc
new file mode 100644
index 0000000..52affbd
--- /dev/null
+++ b/src/google/protobuf/inlined_string_field_unittest.cc
@@ -0,0 +1,286 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/inlined_string_field.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/arenastring.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+namespace google {
+namespace protobuf {
+
+using internal::ArenaStringPtr;
+using internal::InlinedStringField;
+
+static std::string WrapString(const char* value) { return value; }
+
+namespace {
+
+const uint32 kMask = ~0x00000001u;
+const uint32 kMask1 = ~0x00000004u;
+const uint32 kMask2 = ~0x00000020u;
+
+TEST(InlinedStringFieldTest, SetOnHeap) {
+  InlinedStringField field;
+  uint32 donating_states = 0;
+  const std::string kDefaultValue = "default";
+  field.Set(&kDefaultValue, WrapString("Test short"), nullptr, false,
+            &donating_states, kMask);
+  EXPECT_EQ(std::string("Test short"), field.Get());
+  field.Set(&kDefaultValue, WrapString("Test long long long long value"),
+            nullptr, false, &donating_states, kMask);
+  EXPECT_EQ(std::string("Test long long long long value"), field.Get());
+}
+
+TEST(InlinedStringFieldTest, SetRvalueOnHeap) {
+  InlinedStringField field;
+  uint32 donating_states = 0;
+  std::string string_moved = "Moved long long long long string 1";
+  field.Set(nullptr, std::move(string_moved), nullptr, false, &donating_states,
+            kMask);
+  EXPECT_EQ("Moved long long long long string 1", field.Get());
+  EXPECT_EQ(donating_states & ~kMask1, 0);
+}
+
+TEST(InlinedStringFieldTest, UnsafeMutablePointerThenRelease) {
+  InlinedStringField field;
+  const std::string kDefaultValue = "default";
+  std::string* mut = field.UnsafeMutablePointer();
+  // The address of inlined string doesn't change behind the scene.
+  EXPECT_EQ(mut, field.UnsafeMutablePointer());
+  EXPECT_EQ(mut, &field.Get());
+  EXPECT_EQ(std::string(""), *mut);
+  *mut = "Test long long long long value";  // ensure string allocates
+  EXPECT_EQ(std::string("Test long long long long value"), field.Get());
+
+  std::string* released = field.ReleaseNonDefaultNoArena(&kDefaultValue);
+  EXPECT_EQ("Test long long long long value", *released);
+  // Default value is ignored.
+  EXPECT_EQ("", field.Get());
+  delete released;
+}
+
+// When donating mechanism is enabled:
+// - Initially, the string is donated.
+// - After lvalue Set: the string is still donated.
+// - After Mutable: the string is undonated. The data buffer of the string is a
+// new buffer on the heap.
+TEST(InlinedStringFieldTest, ArenaSetThenMutable) {
+  Arena arena;
+  auto* field_arena = Arena::CreateMessage<InlinedStringField>(&arena);
+  uint32 donating_states = ~0u;
+  const std::string kDefaultValue = "default";
+  field_arena->Set(&kDefaultValue, WrapString("Test short"), &arena,
+                   /*donated=*/true, &donating_states, kMask1);
+  EXPECT_EQ(std::string("Test short"), field_arena->Get());
+  field_arena->Set(&kDefaultValue, "Test long long long long value", &arena,
+                   /*donated=*/(donating_states & ~kMask1) != 0,
+                   &donating_states, kMask1);
+  EXPECT_EQ(std::string("Test long long long long value"), field_arena->Get());
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  EXPECT_NE(donating_states & ~kMask1, 0);  // donate.
+#endif
+
+  const std::string* old_string = &field_arena->Get();
+  const char* old_data = old_string->data();
+  (void)old_data;
+  std::string* mut = field_arena->Mutable(
+      ArenaStringPtr::EmptyDefault{}, &arena,
+      /*donated=*/(donating_states & ~kMask1) != 0, &donating_states, kMask1);
+  EXPECT_EQ(old_string, mut);
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  EXPECT_EQ(donating_states & ~kMask1, 0);
+  EXPECT_NE(old_data, mut->data());  // The data buffer of the mutated string is
+                                     // a new buffer on the heap.
+#endif
+  *mut = "Test an even longer long long long long value";
+  EXPECT_EQ(std::string("Test an even longer long long long long value"),
+            field_arena->Get());
+  EXPECT_EQ(&field_arena->Get(), mut);
+}
+
+// Release doesn't change the donating state.
+// When donating mechanism is enabled:
+// - Initially, the string is donated.
+// - Then lvalue Set: the string is still donated.
+// - Then Release: the string is cleared, and still donated.
+// - Then Mutable: the string is undonated.
+// - Then Release: the string is still undonated.
+TEST(InlinedStringFieldTest, ArenaRelease) {
+  Arena arena;
+  auto* field_arena = Arena::CreateMessage<InlinedStringField>(&arena);
+  uint32 donating_states = ~0u;
+  const std::string kDefaultValue = "default";
+  field_arena->Set(&kDefaultValue, WrapString("Test short"), &arena,
+                   /*donated=*/true, &donating_states, kMask1);
+  std::string* released = field_arena->Release(
+      &kDefaultValue, &arena, /*donated=*/(donating_states & ~kMask1) != 0);
+  EXPECT_EQ("Test short", *released);
+  EXPECT_EQ("", field_arena->Get());
+  EXPECT_NE(released, &field_arena->Get());
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  EXPECT_NE(donating_states & ~kMask1, 0);  // still donated.
+#endif
+  delete released;
+
+  std::string* mut = field_arena->Mutable(
+      ArenaStringPtr::EmptyDefault{}, &arena,
+      /*donated=*/(donating_states & ~kMask1) != 0u, &donating_states, kMask1);
+  *mut = "Test long long long long value";
+  std::string* released2 =
+      field_arena->Release(&kDefaultValue, &arena,
+                           /*donated=*/(donating_states & ~kMask1) != 0);
+  EXPECT_EQ("Test long long long long value", *released2);
+  EXPECT_EQ("", field_arena->Get());
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  EXPECT_EQ(donating_states & ~kMask1, 0);  // undonated.
+#endif
+  delete released2;
+}
+
+// Rvalue Set always undoantes a donated string.
+TEST(InlinedStringFieldTest, SetRvalueArena) {
+  Arena arena;
+  auto* field1_arena = Arena::CreateMessage<InlinedStringField>(&arena);
+  auto* field2_arena = Arena::CreateMessage<InlinedStringField>(&arena);
+  uint32 donating_states = ~0u;
+  const std::string kDefaultValue = "default";
+
+  std::string string_moved = "Moved long long long long string 1";
+  field1_arena->Set(nullptr, std::move(string_moved), &arena, true,
+                    &donating_states, kMask1);
+  EXPECT_EQ("Moved long long long long string 1", field1_arena->Get());
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  EXPECT_EQ(donating_states & ~kMask1, 0);  // Undonate.
+#endif
+
+  field2_arena->Set(nullptr, std::string("string 2 on heap"), &arena, true,
+                    &donating_states, kMask);
+  EXPECT_EQ("string 2 on heap", field2_arena->Get());
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  EXPECT_EQ(donating_states & ~kMask, 0);  // Undonated.
+#endif
+}
+
+// Tests SetAllocated for non-arena string fields and arena string fields.
+TEST(InlinedStringFieldTest, SetAllocated) {
+  InlinedStringField field;
+  Arena arena;
+  auto* field1_arena = Arena::CreateMessage<InlinedStringField>(&arena);
+  auto* field2_arena = Arena::CreateMessage<InlinedStringField>(&arena);
+  uint32 donating_states = ~0u;
+  const std::string kDefaultValue = "default";
+
+  // The string in field is on heap.
+  field.Set(&kDefaultValue, WrapString("String on heap"), nullptr, false,
+            &donating_states, kMask);
+  auto* allocated = new std::string("Allocated string on heap");
+  field.SetAllocatedNoArena(&kDefaultValue, allocated);
+  EXPECT_EQ("Allocated string on heap", field.Get());
+
+  // The string in field1_arena is on arena (aka. donated).
+  field1_arena->Set(&kDefaultValue, WrapString("String 1 on arena"), &arena,
+                    true, &donating_states, kMask1);
+  *field1_arena->Mutable(ArenaStringPtr::EmptyDefault{}, &arena,
+                         (donating_states & ~kMask1) != 0, &donating_states,
+                         kMask1) = "Mutated string 1 is now on heap long long";
+  // After Mutable, the string is undonated.
+  allocated = new std::string("Allocated string on heap long long long");
+  field1_arena->SetAllocated(&kDefaultValue, allocated, &arena,
+                             (donating_states & ~kMask1) != 0, &donating_states,
+                             kMask1);
+  EXPECT_EQ("Allocated string on heap long long long", field1_arena->Get());
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  EXPECT_EQ(donating_states & ~kMask1, 0);  // Still undonated.
+#endif
+
+  // The string in field2_arena is on arena (aka. donated).
+  field2_arena->Set(&kDefaultValue, WrapString("String 2 on arena long long"),
+                    &arena, true, &donating_states,
+                    kMask2);  // Still donated.
+  allocated = new std::string("Allocated string on heap long long long 2");
+  field2_arena->SetAllocated(&kDefaultValue, allocated, &arena, true,
+                             &donating_states, kMask2);
+  EXPECT_EQ("Allocated string on heap long long long 2", field2_arena->Get());
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  EXPECT_EQ(donating_states & ~kMask2, 0);  // Undonated.
+#endif
+}
+
+// Tests Swap for non-arena string fields and arena string fields.
+TEST(InlinedStringFieldTest, Swap) {
+  // Swap should only be called when the from and to are on the same arena.
+  InlinedStringField field1;
+  InlinedStringField field2;
+  uint32 donating_states = 0;
+  Arena arena;
+  auto* field1_arena = Arena::CreateMessage<InlinedStringField>(&arena);
+  auto* field2_arena = Arena::CreateMessage<InlinedStringField>(&arena);
+  uint32 donating_states_1 = ~0u;
+  uint32 donating_states_2 = ~0u;
+  const std::string kDefaultValue = "default";
+
+  const std::string& string1_heap = "String 1 on heap";
+  const std::string& string2_heap = "String 2 on heap long long long long";
+  const std::string& string1_arena = "String 1 on arena";
+  const std::string& string2_arena = "String 2 on arena long long long long";
+  field1.SetNoArena(&kDefaultValue, string1_heap);
+  field2.SetNoArena(&kDefaultValue, string2_heap);
+  field1_arena->Set(&kDefaultValue, string1_arena, &arena, true,
+                    &donating_states_1, kMask1);
+  field2_arena->Set(&kDefaultValue, string2_arena, &arena, true,
+                    &donating_states_2, kMask1);
+
+  field1.Swap(&field2, &kDefaultValue, nullptr, false, false, &donating_states,
+              &donating_states_2, kMask);
+  field1_arena->Swap(field2_arena, &kDefaultValue, &arena, true, true,
+                     &donating_states_1, &donating_states_2, kMask1);
+  EXPECT_EQ(field1.Get(), string2_heap);
+  EXPECT_EQ(field2.Get(), string1_heap);
+  EXPECT_EQ(field1_arena->Get(), string2_arena);
+  EXPECT_EQ(field2_arena->Get(), string1_arena);
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index a318da4..1b80068 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -151,7 +151,7 @@
 }
 
 CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
-  uint32 length;
+  uint32_t length;
   return PushLimit(ReadVarint32(&length) ? length : 0);
 }
 
@@ -243,7 +243,7 @@
   while ((current_buffer_size = BufferSize()) < size) {
     // Reading past end of buffer.  Copy what we have, then refresh.
     memcpy(buffer, buffer_, current_buffer_size);
-    buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
+    buffer = reinterpret_cast<uint8_t*>(buffer) + current_buffer_size;
     size -= current_buffer_size;
     Advance(current_buffer_size);
     if (!Refresh()) return false;
@@ -308,11 +308,11 @@
 }
 
 
-bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
-  uint8 bytes[sizeof(*value)];
+bool CodedInputStream::ReadLittleEndian32Fallback(uint32_t* value) {
+  uint8_t bytes[sizeof(*value)];
 
-  const uint8* ptr;
-  if (BufferSize() >= static_cast<int64>(sizeof(*value))) {
+  const uint8_t* ptr;
+  if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) {
     // Fast path:  Enough bytes in the buffer to read directly.
     ptr = buffer_;
     Advance(sizeof(*value));
@@ -325,11 +325,11 @@
   return true;
 }
 
-bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
-  uint8 bytes[sizeof(*value)];
+bool CodedInputStream::ReadLittleEndian64Fallback(uint64_t* value) {
+  uint8_t bytes[sizeof(*value)];
 
-  const uint8* ptr;
-  if (BufferSize() >= static_cast<int64>(sizeof(*value))) {
+  const uint8_t* ptr;
+  if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) {
     // Fast path:  Enough bytes in the buffer to read directly.
     ptr = buffer_;
     Advance(sizeof(*value));
@@ -348,11 +348,11 @@
 // compile time, compiler can generate optimal code. For example, instead of
 // subtracting 0x80 at each iteration, it subtracts properly shifted mask once.
 template <size_t N>
-const uint8* DecodeVarint64KnownSize(const uint8* buffer, uint64* value) {
+const uint8_t* DecodeVarint64KnownSize(const uint8_t* buffer, uint64_t* value) {
   GOOGLE_DCHECK_GT(N, 0);
-  uint64 result = static_cast<uint64>(buffer[N - 1]) << (7 * (N - 1));
+  uint64_t result = static_cast<uint64_t>(buffer[N - 1]) << (7 * (N - 1));
   for (size_t i = 0, offset = 0; i < N - 1; i++, offset += 7) {
-    result += static_cast<uint64>(buffer[i] - 0x80) << offset;
+    result += static_cast<uint64_t>(buffer[i] - 0x80) << offset;
   }
   *value = result;
   return buffer + N;
@@ -363,18 +363,18 @@
 // part is buffer + (number of bytes read).  This function is always inlined,
 // so returning a pair is costless.
 PROTOBUF_ALWAYS_INLINE
-::std::pair<bool, const uint8*> ReadVarint32FromArray(uint32 first_byte,
-                                                      const uint8* buffer,
-                                                      uint32* value);
-inline ::std::pair<bool, const uint8*> ReadVarint32FromArray(
-    uint32 first_byte, const uint8* buffer, uint32* value) {
+::std::pair<bool, const uint8_t*> ReadVarint32FromArray(uint32_t first_byte,
+                                                      const uint8_t* buffer,
+                                                      uint32_t* value);
+inline ::std::pair<bool, const uint8_t*> ReadVarint32FromArray(
+    uint32_t first_byte, const uint8_t* buffer, uint32_t* value) {
   // Fast path:  We have enough bytes left in the buffer to guarantee that
   // this read won't cross the end, so we can skip the checks.
   GOOGLE_DCHECK_EQ(*buffer, first_byte);
   GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte;
-  const uint8* ptr = buffer;
-  uint32 b;
-  uint32 result = first_byte - 0x80;
+  const uint8_t* ptr = buffer;
+  uint32_t b;
+  uint32_t result = first_byte - 0x80;
   ++ptr;  // We just processed the first byte.  Move on to the second.
   b = *(ptr++);
   result += b << 7;
@@ -409,14 +409,14 @@
   return std::make_pair(true, ptr);
 }
 
-PROTOBUF_ALWAYS_INLINE::std::pair<bool, const uint8*> ReadVarint64FromArray(
-    const uint8* buffer, uint64* value);
-inline ::std::pair<bool, const uint8*> ReadVarint64FromArray(
-    const uint8* buffer, uint64* value) {
+PROTOBUF_ALWAYS_INLINE::std::pair<bool, const uint8_t*> ReadVarint64FromArray(
+    const uint8_t* buffer, uint64_t* value);
+inline ::std::pair<bool, const uint8_t*> ReadVarint64FromArray(
+    const uint8_t* buffer, uint64_t* value) {
   // Assumes varint64 is at least 2 bytes.
   GOOGLE_DCHECK_GE(buffer[0], 128);
 
-  const uint8* next;
+  const uint8_t* next;
   if (buffer[1] < 128) {
     next = DecodeVarint64KnownSize<2>(buffer, value);
   } else if (buffer[2] < 128) {
@@ -446,23 +446,23 @@
 
 }  // namespace
 
-bool CodedInputStream::ReadVarint32Slow(uint32* value) {
+bool CodedInputStream::ReadVarint32Slow(uint32_t* value) {
   // Directly invoke ReadVarint64Fallback, since we already tried to optimize
   // for one-byte varints.
-  std::pair<uint64, bool> p = ReadVarint64Fallback();
-  *value = static_cast<uint32>(p.first);
+  std::pair<uint64_t, bool> p = ReadVarint64Fallback();
+  *value = static_cast<uint32_t>(p.first);
   return p.second;
 }
 
-int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) {
+int64_t CodedInputStream::ReadVarint32Fallback(uint32_t first_byte_or_zero) {
   if (BufferSize() >= kMaxVarintBytes ||
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
       (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
     GOOGLE_DCHECK_NE(first_byte_or_zero, 0)
         << "Caller should provide us with *buffer_ when buffer is non-empty";
-    uint32 temp;
-    ::std::pair<bool, const uint8*> p =
+    uint32_t temp;
+    ::std::pair<bool, const uint8_t*> p =
         ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp);
     if (!p.first) return -1;
     buffer_ = p.second;
@@ -471,16 +471,16 @@
     // Really slow case: we will incur the cost of an extra function call here,
     // but moving this out of line reduces the size of this function, which
     // improves the common case. In micro benchmarks, this is worth about 10-15%
-    uint32 temp;
-    return ReadVarint32Slow(&temp) ? static_cast<int64>(temp) : -1;
+    uint32_t temp;
+    return ReadVarint32Slow(&temp) ? static_cast<int64_t>(temp) : -1;
   }
 }
 
 int CodedInputStream::ReadVarintSizeAsIntSlow() {
   // Directly invoke ReadVarint64Fallback, since we already tried to optimize
   // for one-byte varints.
-  std::pair<uint64, bool> p = ReadVarint64Fallback();
-  if (!p.second || p.first > static_cast<uint64>(INT_MAX)) return -1;
+  std::pair<uint64_t, bool> p = ReadVarint64Fallback();
+  if (!p.second || p.first > static_cast<uint64_t>(INT_MAX)) return -1;
   return p.first;
 }
 
@@ -489,9 +489,9 @@
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
       (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
-    uint64 temp;
-    ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
-    if (!p.first || temp > static_cast<uint64>(INT_MAX)) return -1;
+    uint64_t temp;
+    ::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer_, &temp);
+    if (!p.first || temp > static_cast<uint64_t>(INT_MAX)) return -1;
     buffer_ = p.second;
     return temp;
   } else {
@@ -502,7 +502,7 @@
   }
 }
 
-uint32 CodedInputStream::ReadTagSlow() {
+uint32_t CodedInputStream::ReadTagSlow() {
   if (buffer_ == buffer_end_) {
     // Call refresh.
     if (!Refresh()) {
@@ -523,12 +523,12 @@
 
   // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
   // again, since we have now refreshed the buffer.
-  uint64 result = 0;
+  uint64_t result = 0;
   if (!ReadVarint64(&result)) return 0;
-  return static_cast<uint32>(result);
+  return static_cast<uint32_t>(result);
 }
 
-uint32 CodedInputStream::ReadTagFallback(uint32 first_byte_or_zero) {
+uint32_t CodedInputStream::ReadTagFallback(uint32_t first_byte_or_zero) {
   const int buf_size = BufferSize();
   if (buf_size >= kMaxVarintBytes ||
       // Optimization:  We're also safe if the buffer is non-empty and it ends
@@ -539,8 +539,8 @@
       ++buffer_;
       return 0;
     }
-    uint32 tag;
-    ::std::pair<bool, const uint8*> p =
+    uint32_t tag;
+    ::std::pair<bool, const uint8_t*> p =
         ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag);
     if (!p.first) {
       return 0;
@@ -565,13 +565,13 @@
   }
 }
 
-bool CodedInputStream::ReadVarint64Slow(uint64* value) {
+bool CodedInputStream::ReadVarint64Slow(uint64_t* value) {
   // Slow path:  This read might cross the end of the buffer, so we
   // need to check and refresh the buffer if and when it does.
 
-  uint64 result = 0;
+  uint64_t result = 0;
   int count = 0;
-  uint32 b;
+  uint32_t b;
 
   do {
     if (count == kMaxVarintBytes) {
@@ -585,7 +585,7 @@
       }
     }
     b = *buffer_;
-    result |= static_cast<uint64>(b & 0x7F) << (7 * count);
+    result |= static_cast<uint64_t>(b & 0x7F) << (7 * count);
     Advance(1);
     ++count;
   } while (b & 0x80);
@@ -594,20 +594,20 @@
   return true;
 }
 
-std::pair<uint64, bool> CodedInputStream::ReadVarint64Fallback() {
+std::pair<uint64_t, bool> CodedInputStream::ReadVarint64Fallback() {
   if (BufferSize() >= kMaxVarintBytes ||
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
       (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
-    uint64 temp;
-    ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
+    uint64_t temp;
+    ::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer_, &temp);
     if (!p.first) {
       return std::make_pair(0, false);
     }
     buffer_ = p.second;
     return std::make_pair(temp, true);
   } else {
-    uint64 temp;
+    uint64_t temp;
     bool success = ReadVarint64Slow(&temp);
     return std::make_pair(temp, success);
   }
@@ -633,7 +633,7 @@
   const void* void_buffer;
   int buffer_size;
   if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
-    buffer_ = reinterpret_cast<const uint8*>(void_buffer);
+    buffer_ = reinterpret_cast<const uint8_t*>(void_buffer);
     buffer_end_ = buffer_ + buffer_size;
     GOOGLE_CHECK_GE(buffer_size, 0);
 
@@ -670,7 +670,7 @@
   aliasing_enabled_ = enabled && stream_->AllowsAliasing();
 }
 
-int64 EpsCopyOutputStream::ByteCount(uint8* ptr) const {
+int64_t EpsCopyOutputStream::ByteCount(uint8_t* ptr) const {
   // Calculate the current offset relative to the end of the stream buffer.
   int delta = (end_ - ptr) + (buffer_end_ ? 0 : kSlopBytes);
   return stream_->ByteCount() - delta;
@@ -679,7 +679,7 @@
 // Flushes what's written out to the underlying ZeroCopyOutputStream buffers.
 // Returns the size remaining in the buffer and sets buffer_end_ to the start
 // of the remaining buffer, ie. [buffer_end_, buffer_end_ + return value)
-int EpsCopyOutputStream::Flush(uint8* ptr) {
+int EpsCopyOutputStream::Flush(uint8_t* ptr) {
   while (buffer_end_ && ptr > end_) {
     int overrun = ptr - end_;
     GOOGLE_DCHECK(!had_error_);
@@ -701,7 +701,7 @@
   return s;
 }
 
-uint8* EpsCopyOutputStream::Trim(uint8* ptr) {
+uint8_t* EpsCopyOutputStream::Trim(uint8_t* ptr) {
   if (had_error_) return ptr;
   int s = Flush(ptr);
   if (s) stream_->BackUp(s);
@@ -711,14 +711,14 @@
 }
 
 
-uint8* EpsCopyOutputStream::FlushAndResetBuffer(uint8* ptr) {
+uint8_t* EpsCopyOutputStream::FlushAndResetBuffer(uint8_t* ptr) {
   if (had_error_) return buffer_;
   int s = Flush(ptr);
   if (had_error_) return buffer_;
   return SetInitialBuffer(buffer_end_, s);
 }
 
-bool EpsCopyOutputStream::Skip(int count, uint8** pp) {
+bool EpsCopyOutputStream::Skip(int count, uint8_t** pp) {
   if (count < 0) return false;
   if (had_error_) {
     *pp = buffer_;
@@ -737,12 +737,12 @@
       return false;
     }
   }
-  *pp = SetInitialBuffer(static_cast<uint8*>(data) + count, size - count);
+  *pp = SetInitialBuffer(static_cast<uint8_t*>(data) + count, size - count);
   return true;
 }
 
 bool EpsCopyOutputStream::GetDirectBufferPointer(void** data, int* size,
-                                                 uint8** pp) {
+                                                 uint8_t** pp) {
   if (had_error_) {
     *pp = buffer_;
     return false;
@@ -763,8 +763,8 @@
   return true;
 }
 
-uint8* EpsCopyOutputStream::GetDirectBufferForNBytesAndAdvance(int size,
-                                                               uint8** pp) {
+uint8_t* EpsCopyOutputStream::GetDirectBufferForNBytesAndAdvance(int size,
+                                                               uint8_t** pp) {
   if (had_error_) {
     *pp = buffer_;
     return nullptr;
@@ -784,13 +784,13 @@
   }
 }
 
-uint8* EpsCopyOutputStream::Next() {
+uint8_t* EpsCopyOutputStream::Next() {
   GOOGLE_DCHECK(!had_error_);  // NOLINT
   if (PROTOBUF_PREDICT_FALSE(stream_ == nullptr)) return Error();
   if (buffer_end_) {
     // We're in the patch buffer and need to fill up the previous buffer.
     std::memcpy(buffer_end_, buffer_, end_ - buffer_);
-    uint8* ptr;
+    uint8_t* ptr;
     int size;
     do {
       void* data;
@@ -799,7 +799,7 @@
         // able to write.
         return Error();
       }
-      ptr = static_cast<uint8*>(data);
+      ptr = static_cast<uint8_t*>(data);
     } while (size == 0);
     if (PROTOBUF_PREDICT_TRUE(size > kSlopBytes)) {
       std::memcpy(ptr, end_, kSlopBytes);
@@ -822,7 +822,7 @@
   }
 }
 
-uint8* EpsCopyOutputStream::EnsureSpaceFallback(uint8* ptr) {
+uint8_t* EpsCopyOutputStream::EnsureSpaceFallback(uint8_t* ptr) {
   do {
     if (PROTOBUF_PREDICT_FALSE(had_error_)) return buffer_;
     int overrun = ptr - end_;
@@ -834,13 +834,13 @@
   return ptr;
 }
 
-uint8* EpsCopyOutputStream::WriteRawFallback(const void* data, int size,
-                                             uint8* ptr) {
+uint8_t* EpsCopyOutputStream::WriteRawFallback(const void* data, int size,
+                                             uint8_t* ptr) {
   int s = GetSize(ptr);
   while (s < size) {
     std::memcpy(ptr, data, s);
     size -= s;
-    data = static_cast<const uint8*>(data) + s;
+    data = static_cast<const uint8_t*>(data) + s;
     ptr = EnsureSpaceFallback(ptr + s);
     s = GetSize(ptr);
   }
@@ -848,8 +848,8 @@
   return ptr + size;
 }
 
-uint8* EpsCopyOutputStream::WriteAliasedRaw(const void* data, int size,
-                                            uint8* ptr) {
+uint8_t* EpsCopyOutputStream::WriteAliasedRaw(const void* data, int size,
+                                            uint8_t* ptr) {
   if (size < GetSize(ptr)
   ) {
     return WriteRaw(data, size, ptr);
@@ -861,13 +861,13 @@
 }
 
 #ifndef PROTOBUF_LITTLE_ENDIAN
-uint8* EpsCopyOutputStream::WriteRawLittleEndian32(const void* data, int size,
-                                                   uint8* ptr) {
-  auto p = static_cast<const uint8*>(data);
+uint8_t* EpsCopyOutputStream::WriteRawLittleEndian32(const void* data, int size,
+                                                   uint8_t* ptr) {
+  auto p = static_cast<const uint8_t*>(data);
   auto end = p + size;
   while (end - p >= kSlopBytes) {
     ptr = EnsureSpace(ptr);
-    uint32 buffer[4];
+    uint32_t buffer[4];
     static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
     std::memcpy(buffer, p, kSlopBytes);
     p += kSlopBytes;
@@ -876,7 +876,7 @@
   }
   while (p < end) {
     ptr = EnsureSpace(ptr);
-    uint32 buffer;
+    uint32_t buffer;
     std::memcpy(&buffer, p, 4);
     p += 4;
     ptr = CodedOutputStream::WriteLittleEndian32ToArray(buffer, ptr);
@@ -884,13 +884,13 @@
   return ptr;
 }
 
-uint8* EpsCopyOutputStream::WriteRawLittleEndian64(const void* data, int size,
-                                                   uint8* ptr) {
-  auto p = static_cast<const uint8*>(data);
+uint8_t* EpsCopyOutputStream::WriteRawLittleEndian64(const void* data, int size,
+                                                   uint8_t* ptr) {
+  auto p = static_cast<const uint8_t*>(data);
   auto end = p + size;
   while (end - p >= kSlopBytes) {
     ptr = EnsureSpace(ptr);
-    uint64 buffer[2];
+    uint64_t buffer[2];
     static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
     std::memcpy(buffer, p, kSlopBytes);
     p += kSlopBytes;
@@ -899,7 +899,7 @@
   }
   while (p < end) {
     ptr = EnsureSpace(ptr);
-    uint64 buffer;
+    uint64_t buffer;
     std::memcpy(&buffer, p, 8);
     p += 8;
     ptr = CodedOutputStream::WriteLittleEndian64ToArray(buffer, ptr);
@@ -909,19 +909,19 @@
 #endif
 
 
-uint8* EpsCopyOutputStream::WriteStringMaybeAliasedOutline(uint32 num,
+uint8_t* EpsCopyOutputStream::WriteStringMaybeAliasedOutline(uint32_t num,
                                                            const std::string& s,
-                                                           uint8* ptr) {
+                                                           uint8_t* ptr) {
   ptr = EnsureSpace(ptr);
-  uint32 size = s.size();
+  uint32_t size = s.size();
   ptr = WriteLengthDelim(num, size, ptr);
   return WriteRawMaybeAliased(s.data(), size, ptr);
 }
 
-uint8* EpsCopyOutputStream::WriteStringOutline(uint32 num, const std::string& s,
-                                               uint8* ptr) {
+uint8_t* EpsCopyOutputStream::WriteStringOutline(uint32_t num, const std::string& s,
+                                               uint8_t* ptr) {
   ptr = EnsureSpace(ptr);
-  uint32 size = s.size();
+  uint32_t size = s.size();
   ptr = WriteLengthDelim(num, size, ptr);
   return WriteRaw(s.data(), size, ptr);
 }
@@ -944,28 +944,28 @@
 CodedOutputStream::~CodedOutputStream() { Trim(); }
 
 
-uint8* CodedOutputStream::WriteStringWithSizeToArray(const std::string& str,
-                                                     uint8* target) {
+uint8_t* CodedOutputStream::WriteStringWithSizeToArray(const std::string& str,
+                                                     uint8_t* target) {
   GOOGLE_DCHECK_LE(str.size(), kuint32max);
   target = WriteVarint32ToArray(str.size(), target);
   return WriteStringToArray(str, target);
 }
 
-uint8* CodedOutputStream::WriteVarint32ToArrayOutOfLineHelper(uint32 value,
-                                                              uint8* target) {
+uint8_t* CodedOutputStream::WriteVarint32ToArrayOutOfLineHelper(uint32_t value,
+                                                              uint8_t* target) {
   GOOGLE_DCHECK_GE(value, 0x80);
-  target[0] |= static_cast<uint8>(0x80);
+  target[0] |= static_cast<uint8_t>(0x80);
   value >>= 7;
-  target[1] = static_cast<uint8>(value);
+  target[1] = static_cast<uint8_t>(value);
   if (value < 0x80) {
     return target + 2;
   }
   target += 2;
   do {
     // Turn on continuation bit in the byte we just wrote.
-    target[-1] |= static_cast<uint8>(0x80);
+    target[-1] |= static_cast<uint8_t>(0x80);
     value >>= 7;
-    *target = static_cast<uint8>(value);
+    *target = static_cast<uint8_t>(value);
     ++target;
   } while (value >= 0x80);
   return target;
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index 30dc91a..40896e7 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -75,7 +75,7 @@
 //     return;
 //   }
 //
-//   uint32 size;
+//   uint32_t size;
 //   coded_input->ReadVarint32(&size);
 //
 //   char* text = new char[size + 1];
@@ -194,7 +194,7 @@
   // Create a CodedInputStream that reads from the given flat array.  This is
   // faster than using an ArrayInputStream.  PushLimit(size) is implied by
   // this constructor.
-  explicit CodedInputStream(const uint8* buffer, int size);
+  explicit CodedInputStream(const uint8_t* buffer, int size);
 
   // Destroy the CodedInputStream and position the underlying
   // ZeroCopyInputStream at the first unread byte.  If an error occurred while
@@ -233,25 +233,25 @@
 
 
   // Read a 32-bit little-endian integer.
-  bool ReadLittleEndian32(uint32* value);
+  bool ReadLittleEndian32(uint32_t* value);
   // Read a 64-bit little-endian integer.
-  bool ReadLittleEndian64(uint64* value);
+  bool ReadLittleEndian64(uint64_t* value);
 
   // These methods read from an externally provided buffer. The caller is
   // responsible for ensuring that the buffer has sufficient space.
   // Read a 32-bit little-endian integer.
-  static const uint8* ReadLittleEndian32FromArray(const uint8* buffer,
-                                                  uint32* value);
+  static const uint8_t* ReadLittleEndian32FromArray(const uint8_t* buffer,
+                                                  uint32_t* value);
   // Read a 64-bit little-endian integer.
-  static const uint8* ReadLittleEndian64FromArray(const uint8* buffer,
-                                                  uint64* value);
+  static const uint8_t* ReadLittleEndian64FromArray(const uint8_t* buffer,
+                                                  uint64_t* value);
 
   // Read an unsigned integer with Varint encoding, truncating to 32 bits.
   // Reading a 32-bit value is equivalent to reading a 64-bit one and casting
-  // it to uint32, but may be more efficient.
-  bool ReadVarint32(uint32* value);
+  // it to uint32_t, but may be more efficient.
+  bool ReadVarint32(uint32_t* value);
   // Read an unsigned integer with Varint encoding.
-  bool ReadVarint64(uint64* value);
+  bool ReadVarint64(uint64_t* value);
 
   // Reads a varint off the wire into an "int". This should be used for reading
   // sizes off the wire (sizes of strings, submessages, bytes fields, etc).
@@ -272,11 +272,11 @@
   // Always inline because this is only called in one place per parse loop
   // but it is called for every iteration of said loop, so it should be fast.
   // GCC doesn't want to inline this by default.
-  PROTOBUF_ALWAYS_INLINE uint32 ReadTag() {
+  PROTOBUF_ALWAYS_INLINE uint32_t ReadTag() {
     return last_tag_ = ReadTagNoLastTag();
   }
 
-  PROTOBUF_ALWAYS_INLINE uint32 ReadTagNoLastTag();
+  PROTOBUF_ALWAYS_INLINE uint32_t ReadTagNoLastTag();
 
   // This usually a faster alternative to ReadTag() when cutoff is a manifest
   // constant.  It does particularly well for cutoff >= 127.  The first part
@@ -287,14 +287,14 @@
   // because that can arise in several ways, and for best performance we want
   // to avoid an extra "is tag == 0?" check here.)
   PROTOBUF_ALWAYS_INLINE
-  std::pair<uint32, bool> ReadTagWithCutoff(uint32 cutoff) {
-    std::pair<uint32, bool> result = ReadTagWithCutoffNoLastTag(cutoff);
+  std::pair<uint32_t, bool> ReadTagWithCutoff(uint32_t cutoff) {
+    std::pair<uint32_t, bool> result = ReadTagWithCutoffNoLastTag(cutoff);
     last_tag_ = result.first;
     return result;
   }
 
   PROTOBUF_ALWAYS_INLINE
-  std::pair<uint32, bool> ReadTagWithCutoffNoLastTag(uint32 cutoff);
+  std::pair<uint32_t, bool> ReadTagWithCutoffNoLastTag(uint32_t cutoff);
 
   // Usually returns true if calling ReadVarint32() now would produce the given
   // value.  Will always return false if ReadVarint32() would not return the
@@ -303,7 +303,7 @@
   // parameter.
   // Always inline because this collapses to a small number of instructions
   // when given a constant parameter, but GCC doesn't want to inline by default.
-  PROTOBUF_ALWAYS_INLINE bool ExpectTag(uint32 expected);
+  PROTOBUF_ALWAYS_INLINE bool ExpectTag(uint32_t expected);
 
   // Like above, except this reads from the specified buffer. The caller is
   // responsible for ensuring that the buffer is large enough to read a varint
@@ -313,7 +313,8 @@
   // Returns a pointer beyond the expected tag if it was found, or NULL if it
   // was not.
   PROTOBUF_ALWAYS_INLINE
-  static const uint8* ExpectTagFromArray(const uint8* buffer, uint32 expected);
+  static const uint8_t* ExpectTagFromArray(const uint8_t* buffer,
+                                         uint32_t expected);
 
   // Usually returns true if no more bytes can be read.  Always returns false
   // if more bytes can be read.  If ExpectAtEnd() returns true, a subsequent
@@ -332,8 +333,8 @@
   // of the enclosing message.  The enclosing message would like to check that
   // tag to make sure it had the right number, so it calls LastTagWas() on
   // return from the embedded parser to check.
-  bool LastTagWas(uint32 expected);
-  void SetLastTag(uint32 tag) { last_tag_ = tag; }
+  bool LastTagWas(uint32_t expected);
+  void SetLastTag(uint32_t tag) { last_tag_ = tag; }
 
   // When parsing message (but NOT a group), this method must be called
   // immediately after MergeFromCodedStream() returns (if it returns true)
@@ -536,8 +537,8 @@
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream);
 
-  const uint8* buffer_;
-  const uint8* buffer_end_;  // pointer to the end of the buffer.
+  const uint8_t* buffer_;
+  const uint8_t* buffer_end_;  // pointer to the end of the buffer.
   ZeroCopyInputStream* input_;
   int total_bytes_read_;  // total bytes read from input_, including
                           // the current buffer
@@ -547,7 +548,7 @@
   int overflow_bytes_;
 
   // LastTagWas() stuff.
-  uint32 last_tag_;  // result of last ReadTag() or ReadTagWithCutoff().
+  uint32_t last_tag_;  // result of last ReadTag() or ReadTagWithCutoff().
 
   // This is set true by ReadTag{Fallback/Slow}() if it is called when exactly
   // at EOF, or by ExpectAtEnd() when it returns true.  This happens when we
@@ -615,22 +616,22 @@
   // message crosses multiple buffers.  Note: ReadVarint32Fallback() and
   // ReadVarint64Fallback() are called frequently and generally not inlined, so
   // they have been optimized to avoid "out" parameters.  The former returns -1
-  // if it fails and the uint32 it read otherwise.  The latter has a bool
+  // if it fails and the uint32_t it read otherwise.  The latter has a bool
   // indicating success or failure as part of its return type.
-  int64 ReadVarint32Fallback(uint32 first_byte_or_zero);
+  int64_t ReadVarint32Fallback(uint32_t first_byte_or_zero);
   int ReadVarintSizeAsIntFallback();
-  std::pair<uint64, bool> ReadVarint64Fallback();
-  bool ReadVarint32Slow(uint32* value);
-  bool ReadVarint64Slow(uint64* value);
+  std::pair<uint64_t, bool> ReadVarint64Fallback();
+  bool ReadVarint32Slow(uint32_t* value);
+  bool ReadVarint64Slow(uint64_t* value);
   int ReadVarintSizeAsIntSlow();
-  bool ReadLittleEndian32Fallback(uint32* value);
-  bool ReadLittleEndian64Fallback(uint64* value);
+  bool ReadLittleEndian32Fallback(uint32_t* value);
+  bool ReadLittleEndian64Fallback(uint64_t* value);
 
   // Fallback/slow methods for reading tags. These do not update last_tag_,
   // but will set legitimate_message_end_ if we are at the end of the input
   // stream.
-  uint32 ReadTagFallback(uint32 first_byte_or_zero);
-  uint32 ReadTagSlow();
+  uint32_t ReadTagFallback(uint32_t first_byte_or_zero);
+  uint32_t ReadTagSlow();
   bool ReadStringFallback(std::string* buffer, int size);
 
   // Return the size of the buffer.
@@ -656,7 +657,7 @@
 
   // Initialize from a stream.
   EpsCopyOutputStream(ZeroCopyOutputStream* stream, bool deterministic,
-                      uint8** pp)
+                      uint8_t** pp)
       : end_(buffer_),
         stream_(stream),
         is_serialization_deterministic_(deterministic) {
@@ -667,33 +668,33 @@
   // pointed to the end of the array. When using this the total size is already
   // known, so no need to maintain the slop region.
   EpsCopyOutputStream(void* data, int size, bool deterministic)
-      : end_(static_cast<uint8*>(data) + size),
+      : end_(static_cast<uint8_t*>(data) + size),
         buffer_end_(nullptr),
         stream_(nullptr),
         is_serialization_deterministic_(deterministic) {}
 
   // Initialize from stream but with the first buffer already given (eager).
   EpsCopyOutputStream(void* data, int size, ZeroCopyOutputStream* stream,
-                      bool deterministic, uint8** pp)
+                      bool deterministic, uint8_t** pp)
       : stream_(stream), is_serialization_deterministic_(deterministic) {
     *pp = SetInitialBuffer(data, size);
   }
 
   // Flush everything that's written into the underlying ZeroCopyOutputStream
   // and trims the underlying stream to the location of ptr.
-  uint8* Trim(uint8* ptr);
+  uint8_t* Trim(uint8_t* ptr);
 
   // After this it's guaranteed you can safely write kSlopBytes to ptr. This
   // will never fail! The underlying stream can produce an error. Use HadError
   // to check for errors.
-  PROTOBUF_MUST_USE_RESULT uint8* EnsureSpace(uint8* ptr) {
+  PROTOBUF_MUST_USE_RESULT uint8_t* EnsureSpace(uint8_t* ptr) {
     if (PROTOBUF_PREDICT_FALSE(ptr >= end_)) {
       return EnsureSpaceFallback(ptr);
     }
     return ptr;
   }
 
-  uint8* WriteRaw(const void* data, int size, uint8* ptr) {
+  uint8_t* WriteRaw(const void* data, int size, uint8_t* ptr) {
     if (PROTOBUF_PREDICT_FALSE(end_ - ptr < size)) {
       return WriteRawFallback(data, size, ptr);
     }
@@ -704,7 +705,7 @@
   // aliasing the buffer (ie. not copying the data). The caller is responsible
   // to make sure the buffer is alive for the duration of the
   // ZeroCopyOutputStream.
-  uint8* WriteRawMaybeAliased(const void* data, int size, uint8* ptr) {
+  uint8_t* WriteRawMaybeAliased(const void* data, int size, uint8_t* ptr) {
     if (aliasing_enabled_) {
       return WriteAliasedRaw(data, size, ptr);
     } else {
@@ -713,78 +714,78 @@
   }
 
 
-  uint8* WriteStringMaybeAliased(uint32 num, const std::string& s, uint8* ptr) {
+  uint8_t* WriteStringMaybeAliased(uint32_t num, const std::string& s, uint8_t* ptr) {
     std::ptrdiff_t size = s.size();
     if (PROTOBUF_PREDICT_FALSE(
             size >= 128 || end_ - ptr + 16 - TagSize(num << 3) - 1 < size)) {
       return WriteStringMaybeAliasedOutline(num, s, ptr);
     }
     ptr = UnsafeVarint((num << 3) | 2, ptr);
-    *ptr++ = static_cast<uint8>(size);
+    *ptr++ = static_cast<uint8_t>(size);
     std::memcpy(ptr, s.data(), size);
     return ptr + size;
   }
-  uint8* WriteBytesMaybeAliased(uint32 num, const std::string& s, uint8* ptr) {
+  uint8_t* WriteBytesMaybeAliased(uint32_t num, const std::string& s, uint8_t* ptr) {
     return WriteStringMaybeAliased(num, s, ptr);
   }
 
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteString(uint32 num, const T& s,
-                                            uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteString(uint32_t num, const T& s,
+                                            uint8_t* ptr) {
     std::ptrdiff_t size = s.size();
     if (PROTOBUF_PREDICT_FALSE(
             size >= 128 || end_ - ptr + 16 - TagSize(num << 3) - 1 < size)) {
       return WriteStringOutline(num, s, ptr);
     }
     ptr = UnsafeVarint((num << 3) | 2, ptr);
-    *ptr++ = static_cast<uint8>(size);
+    *ptr++ = static_cast<uint8_t>(size);
     std::memcpy(ptr, s.data(), size);
     return ptr + size;
   }
   template <typename T>
-  uint8* WriteBytes(uint32 num, const T& s, uint8* ptr) {
+  uint8_t* WriteBytes(uint32_t num, const T& s, uint8_t* ptr) {
     return WriteString(num, s, ptr);
   }
 
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteInt32Packed(int num, const T& r, int size,
-                                                 uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteInt32Packed(int num, const T& r, int size,
+                                                 uint8_t* ptr) {
     return WriteVarintPacked(num, r, size, ptr, Encode64);
   }
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteUInt32Packed(int num, const T& r, int size,
-                                                  uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteUInt32Packed(int num, const T& r, int size,
+                                                  uint8_t* ptr) {
     return WriteVarintPacked(num, r, size, ptr, Encode32);
   }
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteSInt32Packed(int num, const T& r, int size,
-                                                  uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteSInt32Packed(int num, const T& r, int size,
+                                                  uint8_t* ptr) {
     return WriteVarintPacked(num, r, size, ptr, ZigZagEncode32);
   }
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteInt64Packed(int num, const T& r, int size,
-                                                 uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteInt64Packed(int num, const T& r, int size,
+                                                 uint8_t* ptr) {
     return WriteVarintPacked(num, r, size, ptr, Encode64);
   }
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteUInt64Packed(int num, const T& r, int size,
-                                                  uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteUInt64Packed(int num, const T& r, int size,
+                                                  uint8_t* ptr) {
     return WriteVarintPacked(num, r, size, ptr, Encode64);
   }
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteSInt64Packed(int num, const T& r, int size,
-                                                  uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteSInt64Packed(int num, const T& r, int size,
+                                                  uint8_t* ptr) {
     return WriteVarintPacked(num, r, size, ptr, ZigZagEncode64);
   }
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteEnumPacked(int num, const T& r, int size,
-                                                uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteEnumPacked(int num, const T& r, int size,
+                                                uint8_t* ptr) {
     return WriteVarintPacked(num, r, size, ptr, Encode64);
   }
 
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteFixedPacked(int num, const T& r,
-                                                 uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteFixedPacked(int num, const T& r,
+                                                 uint8_t* ptr) {
     ptr = EnsureSpace(ptr);
     constexpr auto element_size = sizeof(typename T::value_type);
     auto size = r.size() * element_size;
@@ -820,34 +821,34 @@
 
   // The number of bytes written to the stream at position ptr, relative to the
   // stream's overall position.
-  int64 ByteCount(uint8* ptr) const;
+  int64_t ByteCount(uint8_t* ptr) const;
 
 
  private:
-  uint8* end_;
-  uint8* buffer_end_ = buffer_;
-  uint8 buffer_[2 * kSlopBytes];
+  uint8_t* end_;
+  uint8_t* buffer_end_ = buffer_;
+  uint8_t buffer_[2 * kSlopBytes];
   ZeroCopyOutputStream* stream_;
   bool had_error_ = false;
   bool aliasing_enabled_ = false;  // See EnableAliasing().
   bool is_serialization_deterministic_;
 
-  uint8* EnsureSpaceFallback(uint8* ptr);
-  inline uint8* Next();
-  int Flush(uint8* ptr);
-  std::ptrdiff_t GetSize(uint8* ptr) const {
+  uint8_t* EnsureSpaceFallback(uint8_t* ptr);
+  inline uint8_t* Next();
+  int Flush(uint8_t* ptr);
+  std::ptrdiff_t GetSize(uint8_t* ptr) const {
     GOOGLE_DCHECK(ptr <= end_ + kSlopBytes);  // NOLINT
     return end_ + kSlopBytes - ptr;
   }
 
-  uint8* Error() {
+  uint8_t* Error() {
     had_error_ = true;
     // We use the patch buffer to always guarantee space to write to.
     end_ = buffer_ + kSlopBytes;
     return buffer_;
   }
 
-  static constexpr int TagSize(uint32 tag) {
+  static constexpr int TagSize(uint32_t tag) {
     return (tag < (1 << 7))    ? 1
            : (tag < (1 << 14)) ? 2
            : (tag < (1 << 21)) ? 3
@@ -855,28 +856,28 @@
                                : 5;
   }
 
-  PROTOBUF_ALWAYS_INLINE uint8* WriteTag(uint32 num, uint32 wt, uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteTag(uint32_t num, uint32_t wt, uint8_t* ptr) {
     GOOGLE_DCHECK(ptr < end_);  // NOLINT
     return UnsafeVarint((num << 3) | wt, ptr);
   }
 
-  PROTOBUF_ALWAYS_INLINE uint8* WriteLengthDelim(int num, uint32 size,
-                                                 uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteLengthDelim(int num, uint32_t size,
+                                                 uint8_t* ptr) {
     ptr = WriteTag(num, 2, ptr);
     return UnsafeWriteSize(size, ptr);
   }
 
-  uint8* WriteRawFallback(const void* data, int size, uint8* ptr);
+  uint8_t* WriteRawFallback(const void* data, int size, uint8_t* ptr);
 
-  uint8* WriteAliasedRaw(const void* data, int size, uint8* ptr);
+  uint8_t* WriteAliasedRaw(const void* data, int size, uint8_t* ptr);
 
-  uint8* WriteStringMaybeAliasedOutline(uint32 num, const std::string& s,
-                                        uint8* ptr);
-  uint8* WriteStringOutline(uint32 num, const std::string& s, uint8* ptr);
+  uint8_t* WriteStringMaybeAliasedOutline(uint32_t num, const std::string& s,
+                                        uint8_t* ptr);
+  uint8_t* WriteStringOutline(uint32_t num, const std::string& s, uint8_t* ptr);
 
   template <typename T, typename E>
-  PROTOBUF_ALWAYS_INLINE uint8* WriteVarintPacked(int num, const T& r, int size,
-                                                  uint8* ptr, const E& encode) {
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteVarintPacked(int num, const T& r, int size,
+                                                  uint8_t* ptr, const E& encode) {
     ptr = EnsureSpace(ptr);
     ptr = WriteLengthDelim(num, size, ptr);
     auto it = r.data();
@@ -888,65 +889,65 @@
     return ptr;
   }
 
-  static uint32 Encode32(uint32 v) { return v; }
-  static uint64 Encode64(uint64 v) { return v; }
-  static uint32 ZigZagEncode32(int32 v) {
-    return (static_cast<uint32>(v) << 1) ^ static_cast<uint32>(v >> 31);
+  static uint32_t Encode32(uint32_t v) { return v; }
+  static uint64_t Encode64(uint64_t v) { return v; }
+  static uint32_t ZigZagEncode32(int32_t v) {
+    return (static_cast<uint32_t>(v) << 1) ^ static_cast<uint32_t>(v >> 31);
   }
-  static uint64 ZigZagEncode64(int64 v) {
-    return (static_cast<uint64>(v) << 1) ^ static_cast<uint64>(v >> 63);
+  static uint64_t ZigZagEncode64(int64_t v) {
+    return (static_cast<uint64_t>(v) << 1) ^ static_cast<uint64_t>(v >> 63);
   }
 
   template <typename T>
-  PROTOBUF_ALWAYS_INLINE static uint8* UnsafeVarint(T value, uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE static uint8_t* UnsafeVarint(T value, uint8_t* ptr) {
     static_assert(std::is_unsigned<T>::value,
                   "Varint serialization must be unsigned");
-    ptr[0] = static_cast<uint8>(value);
+    ptr[0] = static_cast<uint8_t>(value);
     if (value < 0x80) {
       return ptr + 1;
     }
     // Turn on continuation bit in the byte we just wrote.
-    ptr[0] |= static_cast<uint8>(0x80);
+    ptr[0] |= static_cast<uint8_t>(0x80);
     value >>= 7;
-    ptr[1] = static_cast<uint8>(value);
+    ptr[1] = static_cast<uint8_t>(value);
     if (value < 0x80) {
       return ptr + 2;
     }
     ptr += 2;
     do {
       // Turn on continuation bit in the byte we just wrote.
-      ptr[-1] |= static_cast<uint8>(0x80);
+      ptr[-1] |= static_cast<uint8_t>(0x80);
       value >>= 7;
-      *ptr = static_cast<uint8>(value);
+      *ptr = static_cast<uint8_t>(value);
       ++ptr;
     } while (value >= 0x80);
     return ptr;
   }
 
-  PROTOBUF_ALWAYS_INLINE static uint8* UnsafeWriteSize(uint32 value,
-                                                       uint8* ptr) {
+  PROTOBUF_ALWAYS_INLINE static uint8_t* UnsafeWriteSize(uint32_t value,
+                                                       uint8_t* ptr) {
     while (PROTOBUF_PREDICT_FALSE(value >= 0x80)) {
-      *ptr = static_cast<uint8>(value | 0x80);
+      *ptr = static_cast<uint8_t>(value | 0x80);
       value >>= 7;
       ++ptr;
     }
-    *ptr++ = static_cast<uint8>(value);
+    *ptr++ = static_cast<uint8_t>(value);
     return ptr;
   }
 
   template <int S>
-  uint8* WriteRawLittleEndian(const void* data, int size, uint8* ptr);
+  uint8_t* WriteRawLittleEndian(const void* data, int size, uint8_t* ptr);
 #ifndef PROTOBUF_LITTLE_ENDIAN
-  uint8* WriteRawLittleEndian32(const void* data, int size, uint8* ptr);
-  uint8* WriteRawLittleEndian64(const void* data, int size, uint8* ptr);
+  uint8_t* WriteRawLittleEndian32(const void* data, int size, uint8_t* ptr);
+  uint8_t* WriteRawLittleEndian64(const void* data, int size, uint8_t* ptr);
 #endif
 
   // These methods are for CodedOutputStream. Ideally they should be private
   // but to match current behavior of CodedOutputStream as close as possible
   // we allow it some functionality.
  public:
-  uint8* SetInitialBuffer(void* data, int size) {
-    auto ptr = static_cast<uint8*>(data);
+  uint8_t* SetInitialBuffer(void* data, int size) {
+    auto ptr = static_cast<uint8_t*>(data);
     if (size > kSlopBytes) {
       end_ = ptr + size - kSlopBytes;
       buffer_end_ = nullptr;
@@ -961,28 +962,28 @@
  private:
   // Needed by CodedOutputStream HadError. HadError needs to flush the patch
   // buffers to ensure there is no error as of yet.
-  uint8* FlushAndResetBuffer(uint8*);
+  uint8_t* FlushAndResetBuffer(uint8_t*);
 
   // The following functions mimic the old CodedOutputStream behavior as close
   // as possible. They flush the current state to the stream, behave as
   // the old CodedOutputStream and then return to normal operation.
-  bool Skip(int count, uint8** pp);
-  bool GetDirectBufferPointer(void** data, int* size, uint8** pp);
-  uint8* GetDirectBufferForNBytesAndAdvance(int size, uint8** pp);
+  bool Skip(int count, uint8_t** pp);
+  bool GetDirectBufferPointer(void** data, int* size, uint8_t** pp);
+  uint8_t* GetDirectBufferForNBytesAndAdvance(int size, uint8_t** pp);
 
   friend class CodedOutputStream;
 };
 
 template <>
-inline uint8* EpsCopyOutputStream::WriteRawLittleEndian<1>(const void* data,
+inline uint8_t* EpsCopyOutputStream::WriteRawLittleEndian<1>(const void* data,
                                                            int size,
-                                                           uint8* ptr) {
+                                                           uint8_t* ptr) {
   return WriteRaw(data, size, ptr);
 }
 template <>
-inline uint8* EpsCopyOutputStream::WriteRawLittleEndian<4>(const void* data,
+inline uint8_t* EpsCopyOutputStream::WriteRawLittleEndian<4>(const void* data,
                                                            int size,
-                                                           uint8* ptr) {
+                                                           uint8_t* ptr) {
 #ifdef PROTOBUF_LITTLE_ENDIAN
   return WriteRaw(data, size, ptr);
 #else
@@ -990,9 +991,9 @@
 #endif
 }
 template <>
-inline uint8* EpsCopyOutputStream::WriteRawLittleEndian<8>(const void* data,
+inline uint8_t* EpsCopyOutputStream::WriteRawLittleEndian<8>(const void* data,
                                                            int size,
-                                                           uint8* ptr) {
+                                                           uint8_t* ptr) {
 #ifdef PROTOBUF_LITTLE_ENDIAN
   return WriteRaw(data, size, ptr);
 #else
@@ -1028,7 +1029,7 @@
 //                    CodedOutputStream::VarintSize32(strlen(text)) +
 //                    strlen(text);
 //
-//   uint8* buffer =
+//   uint8_t* buffer =
 //       coded_output->GetDirectBufferForNBytesAndAdvance(coded_size);
 //   if (buffer != nullptr) {
 //     // The output stream has enough space in the buffer: write directly to
@@ -1100,7 +1101,7 @@
   // there are not enough bytes available, returns NULL.  The return pointer is
   // invalidated as soon as any other non-const method of CodedOutputStream
   // is called.
-  inline uint8* GetDirectBufferForNBytesAndAdvance(int size) {
+  inline uint8_t* GetDirectBufferForNBytesAndAdvance(int size) {
     return impl_.GetDirectBufferForNBytesAndAdvance(size, &cur_);
   }
 
@@ -1116,72 +1117,77 @@
   // copy loops. Since this gets called by every field with string or bytes
   // type, inlining may lead to a significant amount of code bloat, with only a
   // minor performance gain.
-  static uint8* WriteRawToArray(const void* buffer, int size, uint8* target);
+  static uint8_t* WriteRawToArray(const void* buffer, int size, uint8_t* target);
 
   // Equivalent to WriteRaw(str.data(), str.size()).
   void WriteString(const std::string& str);
   // Like WriteString()  but writing directly to the target array.
-  static uint8* WriteStringToArray(const std::string& str, uint8* target);
+  static uint8_t* WriteStringToArray(const std::string& str, uint8_t* target);
   // Write the varint-encoded size of str followed by str.
-  static uint8* WriteStringWithSizeToArray(const std::string& str,
-                                           uint8* target);
+  static uint8_t* WriteStringWithSizeToArray(const std::string& str,
+                                           uint8_t* target);
 
 
   // Write a 32-bit little-endian integer.
-  void WriteLittleEndian32(uint32 value) {
+  void WriteLittleEndian32(uint32_t value) {
     cur_ = impl_.EnsureSpace(cur_);
     SetCur(WriteLittleEndian32ToArray(value, Cur()));
   }
   // Like WriteLittleEndian32()  but writing directly to the target array.
-  static uint8* WriteLittleEndian32ToArray(uint32 value, uint8* target);
+  static uint8_t* WriteLittleEndian32ToArray(uint32_t value, uint8_t* target);
   // Write a 64-bit little-endian integer.
-  void WriteLittleEndian64(uint64 value) {
+  void WriteLittleEndian64(uint64_t value) {
     cur_ = impl_.EnsureSpace(cur_);
     SetCur(WriteLittleEndian64ToArray(value, Cur()));
   }
   // Like WriteLittleEndian64()  but writing directly to the target array.
-  static uint8* WriteLittleEndian64ToArray(uint64 value, uint8* target);
+  static uint8_t* WriteLittleEndian64ToArray(uint64_t value, uint8_t* target);
 
   // Write an unsigned integer with Varint encoding.  Writing a 32-bit value
-  // is equivalent to casting it to uint64 and writing it as a 64-bit value,
+  // is equivalent to casting it to uint64_t and writing it as a 64-bit value,
   // but may be more efficient.
-  void WriteVarint32(uint32 value);
+  void WriteVarint32(uint32_t value);
   // Like WriteVarint32()  but writing directly to the target array.
-  static uint8* WriteVarint32ToArray(uint32 value, uint8* target);
+  static uint8_t* WriteVarint32ToArray(uint32_t value, uint8_t* target);
   // Like WriteVarint32()  but writing directly to the target array, and with the
   // less common-case paths being out of line rather than inlined.
-  static uint8* WriteVarint32ToArrayOutOfLine(uint32 value, uint8* target);
+  static uint8_t* WriteVarint32ToArrayOutOfLine(uint32_t value, uint8_t* target);
   // Write an unsigned integer with Varint encoding.
-  void WriteVarint64(uint64 value);
+  void WriteVarint64(uint64_t value);
   // Like WriteVarint64()  but writing directly to the target array.
-  static uint8* WriteVarint64ToArray(uint64 value, uint8* target);
+  static uint8_t* WriteVarint64ToArray(uint64_t value, uint8_t* target);
 
   // Equivalent to WriteVarint32() except when the value is negative,
   // in which case it must be sign-extended to a full 10 bytes.
-  void WriteVarint32SignExtended(int32 value);
+  void WriteVarint32SignExtended(int32_t value);
   // Like WriteVarint32SignExtended()  but writing directly to the target array.
-  static uint8* WriteVarint32SignExtendedToArray(int32 value, uint8* target);
+  static uint8_t* WriteVarint32SignExtendedToArray(int32_t value, uint8_t* target);
 
   // This is identical to WriteVarint32(), but optimized for writing tags.
   // In particular, if the input is a compile-time constant, this method
   // compiles down to a couple instructions.
   // Always inline because otherwise the aforementioned optimization can't work,
   // but GCC by default doesn't want to inline this.
-  void WriteTag(uint32 value);
+  void WriteTag(uint32_t value);
   // Like WriteTag()  but writing directly to the target array.
   PROTOBUF_ALWAYS_INLINE
-  static uint8* WriteTagToArray(uint32 value, uint8* target);
+  static uint8_t* WriteTagToArray(uint32_t value, uint8_t* target);
 
   // Returns the number of bytes needed to encode the given value as a varint.
-  static size_t VarintSize32(uint32 value);
+  static size_t VarintSize32(uint32_t value);
   // Returns the number of bytes needed to encode the given value as a varint.
-  static size_t VarintSize64(uint64 value);
+  static size_t VarintSize64(uint64_t value);
 
   // If negative, 10 bytes.  Otherwise, same as VarintSize32().
-  static size_t VarintSize32SignExtended(int32 value);
+  static size_t VarintSize32SignExtended(int32_t value);
+
+  // Same as above, plus one.  The additional one comes at no compute cost.
+  static size_t VarintSize32PlusOne(uint32_t value);
+  static size_t VarintSize64PlusOne(uint64_t value);
+  static size_t VarintSize32SignExtendedPlusOne(int32_t value);
 
   // Compile-time equivalent of VarintSize32().
-  template <uint32 Value>
+  template <uint32_t Value>
   struct StaticVarintSize32 {
     static const size_t value = (Value < (1 << 7))    ? 1
                                 : (Value < (1 << 14)) ? 2
@@ -1244,14 +1250,14 @@
   template <typename Func>
   void Serialize(const Func& func);
 
-  uint8* Cur() const { return cur_; }
-  void SetCur(uint8* ptr) { cur_ = ptr; }
+  uint8_t* Cur() const { return cur_; }
+  void SetCur(uint8_t* ptr) { cur_ = ptr; }
   EpsCopyOutputStream* EpsCopy() { return &impl_; }
 
  private:
   EpsCopyOutputStream impl_;
-  uint8* cur_;
-  int64 start_count_;
+  uint8_t* cur_;
+  int64_t start_count_;
   static std::atomic<bool> default_serialization_deterministic_;
 
   // See above.  Other projects may use "friend" to allow them to call this.
@@ -1266,7 +1272,7 @@
     default_serialization_deterministic_.store(true, std::memory_order_relaxed);
   }
   // REQUIRES: value >= 0x80, and that (value & 7f) has been written to *target.
-  static uint8* WriteVarint32ToArrayOutOfLineHelper(uint32 value, uint8* target);
+  static uint8_t* WriteVarint32ToArrayOutOfLineHelper(uint32_t value, uint8_t* target);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream);
 };
 
@@ -1274,8 +1280,8 @@
 // The vast majority of varints are only one byte.  These inline
 // methods optimize for that case.
 
-inline bool CodedInputStream::ReadVarint32(uint32* value) {
-  uint32 v = 0;
+inline bool CodedInputStream::ReadVarint32(uint32_t* value) {
+  uint32_t v = 0;
   if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
     v = *buffer_;
     if (v < 0x80) {
@@ -1284,18 +1290,18 @@
       return true;
     }
   }
-  int64 result = ReadVarint32Fallback(v);
-  *value = static_cast<uint32>(result);
+  int64_t result = ReadVarint32Fallback(v);
+  *value = static_cast<uint32_t>(result);
   return result >= 0;
 }
 
-inline bool CodedInputStream::ReadVarint64(uint64* value) {
+inline bool CodedInputStream::ReadVarint64(uint64_t* value) {
   if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) {
     *value = *buffer_;
     Advance(1);
     return true;
   }
-  std::pair<uint64, bool> p = ReadVarint64Fallback();
+  std::pair<uint64_t, bool> p = ReadVarint64Fallback();
   *value = p.first;
   return p.second;
 }
@@ -1314,40 +1320,40 @@
 }
 
 // static
-inline const uint8* CodedInputStream::ReadLittleEndian32FromArray(
-    const uint8* buffer, uint32* value) {
+inline const uint8_t* CodedInputStream::ReadLittleEndian32FromArray(
+    const uint8_t* buffer, uint32_t* value) {
 #if defined(PROTOBUF_LITTLE_ENDIAN)
   memcpy(value, buffer, sizeof(*value));
   return buffer + sizeof(*value);
 #else
-  *value = (static_cast<uint32>(buffer[0])) |
-           (static_cast<uint32>(buffer[1]) << 8) |
-           (static_cast<uint32>(buffer[2]) << 16) |
-           (static_cast<uint32>(buffer[3]) << 24);
+  *value = (static_cast<uint32_t>(buffer[0])) |
+           (static_cast<uint32_t>(buffer[1]) << 8) |
+           (static_cast<uint32_t>(buffer[2]) << 16) |
+           (static_cast<uint32_t>(buffer[3]) << 24);
   return buffer + sizeof(*value);
 #endif
 }
 // static
-inline const uint8* CodedInputStream::ReadLittleEndian64FromArray(
-    const uint8* buffer, uint64* value) {
+inline const uint8_t* CodedInputStream::ReadLittleEndian64FromArray(
+    const uint8_t* buffer, uint64_t* value) {
 #if defined(PROTOBUF_LITTLE_ENDIAN)
   memcpy(value, buffer, sizeof(*value));
   return buffer + sizeof(*value);
 #else
-  uint32 part0 = (static_cast<uint32>(buffer[0])) |
-                 (static_cast<uint32>(buffer[1]) << 8) |
-                 (static_cast<uint32>(buffer[2]) << 16) |
-                 (static_cast<uint32>(buffer[3]) << 24);
-  uint32 part1 = (static_cast<uint32>(buffer[4])) |
-                 (static_cast<uint32>(buffer[5]) << 8) |
-                 (static_cast<uint32>(buffer[6]) << 16) |
-                 (static_cast<uint32>(buffer[7]) << 24);
-  *value = static_cast<uint64>(part0) | (static_cast<uint64>(part1) << 32);
+  uint32_t part0 = (static_cast<uint32_t>(buffer[0])) |
+                 (static_cast<uint32_t>(buffer[1]) << 8) |
+                 (static_cast<uint32_t>(buffer[2]) << 16) |
+                 (static_cast<uint32_t>(buffer[3]) << 24);
+  uint32_t part1 = (static_cast<uint32_t>(buffer[4])) |
+                 (static_cast<uint32_t>(buffer[5]) << 8) |
+                 (static_cast<uint32_t>(buffer[6]) << 16) |
+                 (static_cast<uint32_t>(buffer[7]) << 24);
+  *value = static_cast<uint64_t>(part0) | (static_cast<uint64_t>(part1) << 32);
   return buffer + sizeof(*value);
 #endif
 }
 
-inline bool CodedInputStream::ReadLittleEndian32(uint32* value) {
+inline bool CodedInputStream::ReadLittleEndian32(uint32_t* value) {
 #if defined(PROTOBUF_LITTLE_ENDIAN)
   if (PROTOBUF_PREDICT_TRUE(BufferSize() >= static_cast<int>(sizeof(*value)))) {
     buffer_ = ReadLittleEndian32FromArray(buffer_, value);
@@ -1360,7 +1366,7 @@
 #endif
 }
 
-inline bool CodedInputStream::ReadLittleEndian64(uint64* value) {
+inline bool CodedInputStream::ReadLittleEndian64(uint64_t* value) {
 #if defined(PROTOBUF_LITTLE_ENDIAN)
   if (PROTOBUF_PREDICT_TRUE(BufferSize() >= static_cast<int>(sizeof(*value)))) {
     buffer_ = ReadLittleEndian64FromArray(buffer_, value);
@@ -1373,8 +1379,8 @@
 #endif
 }
 
-inline uint32 CodedInputStream::ReadTagNoLastTag() {
-  uint32 v = 0;
+inline uint32_t CodedInputStream::ReadTagNoLastTag() {
+  uint32_t v = 0;
   if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
     v = *buffer_;
     if (v < 0x80) {
@@ -1386,20 +1392,20 @@
   return v;
 }
 
-inline std::pair<uint32, bool> CodedInputStream::ReadTagWithCutoffNoLastTag(
-    uint32 cutoff) {
+inline std::pair<uint32_t, bool> CodedInputStream::ReadTagWithCutoffNoLastTag(
+    uint32_t cutoff) {
   // In performance-sensitive code we can expect cutoff to be a compile-time
   // constant, and things like "cutoff >= kMax1ByteVarint" to be evaluated at
   // compile time.
-  uint32 first_byte_or_zero = 0;
+  uint32_t first_byte_or_zero = 0;
   if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
     // Hot case: buffer_ non_empty, buffer_[0] in [1, 128).
     // TODO(gpike): Is it worth rearranging this? E.g., if the number of fields
     // is large enough then is it better to check for the two-byte case first?
     first_byte_or_zero = buffer_[0];
-    if (static_cast<int8>(buffer_[0]) > 0) {
-      const uint32 kMax1ByteVarint = 0x7f;
-      uint32 tag = buffer_[0];
+    if (static_cast<int8_t>(buffer_[0]) > 0) {
+      const uint32_t kMax1ByteVarint = 0x7f;
+      uint32_t tag = buffer_[0];
       Advance(1);
       return std::make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
     }
@@ -1408,8 +1414,8 @@
     // first byte and the second byte.
     if (cutoff >= 0x80 && PROTOBUF_PREDICT_TRUE(buffer_ + 1 < buffer_end_) &&
         PROTOBUF_PREDICT_TRUE((buffer_[0] & ~buffer_[1]) >= 0x80)) {
-      const uint32 kMax2ByteVarint = (0x7f << 7) + 0x7f;
-      uint32 tag = (1u << 7) * buffer_[1] + (buffer_[0] - 0x80);
+      const uint32_t kMax2ByteVarint = (0x7f << 7) + 0x7f;
+      uint32_t tag = (1u << 7) * buffer_[1] + (buffer_[0] - 0x80);
       Advance(2);
       // It might make sense to test for tag == 0 now, but it is so rare that
       // that we don't bother.  A varint-encoded 0 should be one byte unless
@@ -1422,11 +1428,11 @@
     }
   }
   // Slow path
-  const uint32 tag = ReadTagFallback(first_byte_or_zero);
-  return std::make_pair(tag, static_cast<uint32>(tag - 1) < cutoff);
+  const uint32_t tag = ReadTagFallback(first_byte_or_zero);
+  return std::make_pair(tag, static_cast<uint32_t>(tag - 1) < cutoff);
 }
 
-inline bool CodedInputStream::LastTagWas(uint32 expected) {
+inline bool CodedInputStream::LastTagWas(uint32_t expected) {
   return last_tag_ == expected;
 }
 
@@ -1434,7 +1440,7 @@
   return legitimate_message_end_;
 }
 
-inline bool CodedInputStream::ExpectTag(uint32 expected) {
+inline bool CodedInputStream::ExpectTag(uint32_t expected) {
   if (expected < (1 << 7)) {
     if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_) &&
         buffer_[0] == expected) {
@@ -1445,8 +1451,8 @@
     }
   } else if (expected < (1 << 14)) {
     if (PROTOBUF_PREDICT_TRUE(BufferSize() >= 2) &&
-        buffer_[0] == static_cast<uint8>(expected | 0x80) &&
-        buffer_[1] == static_cast<uint8>(expected >> 7)) {
+        buffer_[0] == static_cast<uint8_t>(expected | 0x80) &&
+        buffer_[1] == static_cast<uint8_t>(expected >> 7)) {
       Advance(2);
       return true;
     } else {
@@ -1458,15 +1464,15 @@
   }
 }
 
-inline const uint8* CodedInputStream::ExpectTagFromArray(const uint8* buffer,
-                                                         uint32 expected) {
+inline const uint8_t* CodedInputStream::ExpectTagFromArray(const uint8_t* buffer,
+                                                         uint32_t expected) {
   if (expected < (1 << 7)) {
     if (buffer[0] == expected) {
       return buffer + 1;
     }
   } else if (expected < (1 << 14)) {
-    if (buffer[0] == static_cast<uint8>(expected | 0x80) &&
-        buffer[1] == static_cast<uint8>(expected >> 7)) {
+    if (buffer[0] == static_cast<uint8_t>(expected | 0x80) &&
+        buffer[1] == static_cast<uint8_t>(expected >> 7)) {
       return buffer + 2;
     }
   }
@@ -1556,7 +1562,7 @@
   Refresh();
 }
 
-inline CodedInputStream::CodedInputStream(const uint8* buffer, int size)
+inline CodedInputStream::CodedInputStream(const uint8_t* buffer, int size)
     : buffer_(buffer),
       buffer_end_(buffer + size),
       input_(nullptr),
@@ -1592,14 +1598,14 @@
   return SkipFallback(count, original_buffer_size);
 }
 
-inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value,
-                                                      uint8* target) {
+inline uint8_t* CodedOutputStream::WriteVarint32ToArray(uint32_t value,
+                                                      uint8_t* target) {
   return EpsCopyOutputStream::UnsafeVarint(value, target);
 }
 
-inline uint8* CodedOutputStream::WriteVarint32ToArrayOutOfLine(uint32 value,
-                                                               uint8* target) {
-  target[0] = static_cast<uint8>(value);
+inline uint8_t* CodedOutputStream::WriteVarint32ToArrayOutOfLine(
+    uint32_t value, uint8_t* target) {
+  target[0] = static_cast<uint8_t>(value);
   if (value < 0x80) {
     return target + 1;
   } else {
@@ -1607,95 +1613,110 @@
   }
 }
 
-inline uint8* CodedOutputStream::WriteVarint64ToArray(uint64 value,
-                                                      uint8* target) {
+inline uint8_t* CodedOutputStream::WriteVarint64ToArray(uint64_t value,
+                                                      uint8_t* target) {
   return EpsCopyOutputStream::UnsafeVarint(value, target);
 }
 
-inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) {
-  WriteVarint64(static_cast<uint64>(value));
+inline void CodedOutputStream::WriteVarint32SignExtended(int32_t value) {
+  WriteVarint64(static_cast<uint64_t>(value));
 }
 
-inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray(
-    int32 value, uint8* target) {
-  return WriteVarint64ToArray(static_cast<uint64>(value), target);
+inline uint8_t* CodedOutputStream::WriteVarint32SignExtendedToArray(
+    int32_t value, uint8_t* target) {
+  return WriteVarint64ToArray(static_cast<uint64_t>(value), target);
 }
 
-inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value,
-                                                            uint8* target) {
+inline uint8_t* CodedOutputStream::WriteLittleEndian32ToArray(uint32_t value,
+                                                            uint8_t* target) {
 #if defined(PROTOBUF_LITTLE_ENDIAN)
   memcpy(target, &value, sizeof(value));
 #else
-  target[0] = static_cast<uint8>(value);
-  target[1] = static_cast<uint8>(value >> 8);
-  target[2] = static_cast<uint8>(value >> 16);
-  target[3] = static_cast<uint8>(value >> 24);
+  target[0] = static_cast<uint8_t>(value);
+  target[1] = static_cast<uint8_t>(value >> 8);
+  target[2] = static_cast<uint8_t>(value >> 16);
+  target[3] = static_cast<uint8_t>(value >> 24);
 #endif
   return target + sizeof(value);
 }
 
-inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value,
-                                                            uint8* target) {
+inline uint8_t* CodedOutputStream::WriteLittleEndian64ToArray(uint64_t value,
+                                                            uint8_t* target) {
 #if defined(PROTOBUF_LITTLE_ENDIAN)
   memcpy(target, &value, sizeof(value));
 #else
-  uint32 part0 = static_cast<uint32>(value);
-  uint32 part1 = static_cast<uint32>(value >> 32);
+  uint32_t part0 = static_cast<uint32_t>(value);
+  uint32_t part1 = static_cast<uint32_t>(value >> 32);
 
-  target[0] = static_cast<uint8>(part0);
-  target[1] = static_cast<uint8>(part0 >> 8);
-  target[2] = static_cast<uint8>(part0 >> 16);
-  target[3] = static_cast<uint8>(part0 >> 24);
-  target[4] = static_cast<uint8>(part1);
-  target[5] = static_cast<uint8>(part1 >> 8);
-  target[6] = static_cast<uint8>(part1 >> 16);
-  target[7] = static_cast<uint8>(part1 >> 24);
+  target[0] = static_cast<uint8_t>(part0);
+  target[1] = static_cast<uint8_t>(part0 >> 8);
+  target[2] = static_cast<uint8_t>(part0 >> 16);
+  target[3] = static_cast<uint8_t>(part0 >> 24);
+  target[4] = static_cast<uint8_t>(part1);
+  target[5] = static_cast<uint8_t>(part1 >> 8);
+  target[6] = static_cast<uint8_t>(part1 >> 16);
+  target[7] = static_cast<uint8_t>(part1 >> 24);
 #endif
   return target + sizeof(value);
 }
 
-inline void CodedOutputStream::WriteVarint32(uint32 value) {
+inline void CodedOutputStream::WriteVarint32(uint32_t value) {
   cur_ = impl_.EnsureSpace(cur_);
   SetCur(WriteVarint32ToArray(value, Cur()));
 }
 
-inline void CodedOutputStream::WriteVarint64(uint64 value) {
+inline void CodedOutputStream::WriteVarint64(uint64_t value) {
   cur_ = impl_.EnsureSpace(cur_);
   SetCur(WriteVarint64ToArray(value, Cur()));
 }
 
-inline void CodedOutputStream::WriteTag(uint32 value) { WriteVarint32(value); }
+inline void CodedOutputStream::WriteTag(uint32_t value) {
+  WriteVarint32(value);
+}
 
-inline uint8* CodedOutputStream::WriteTagToArray(uint32 value, uint8* target) {
+inline uint8_t* CodedOutputStream::WriteTagToArray(uint32_t value,
+                                                   uint8_t* target) {
   return WriteVarint32ToArray(value, target);
 }
 
-inline size_t CodedOutputStream::VarintSize32(uint32 value) {
+inline size_t CodedOutputStream::VarintSize32(uint32_t value) {
   // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1
   // Use an explicit multiplication to implement the divide of
   // a number in the 1..31 range.
   // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is
   // undefined.
-  uint32 log2value = Bits::Log2FloorNonZero(value | 0x1);
+  uint32_t log2value = Bits::Log2FloorNonZero(value | 0x1);
   return static_cast<size_t>((log2value * 9 + 73) / 64);
 }
 
-inline size_t CodedOutputStream::VarintSize64(uint64 value) {
+inline size_t CodedOutputStream::VarintSize32PlusOne(uint32_t value) {
+  // Same as above, but one more.
+  uint32_t log2value = Bits::Log2FloorNonZero(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73 + 64) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize64(uint64_t value) {
   // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1
   // Use an explicit multiplication to implement the divide of
   // a number in the 1..63 range.
   // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is
   // undefined.
-  uint32 log2value = Bits::Log2FloorNonZero64(value | 0x1);
+  uint32_t log2value = Bits::Log2FloorNonZero64(value | 0x1);
   return static_cast<size_t>((log2value * 9 + 73) / 64);
 }
 
-inline size_t CodedOutputStream::VarintSize32SignExtended(int32 value) {
-  if (value < 0) {
-    return 10;  // TODO(kenton):  Make this a symbolic constant.
-  } else {
-    return VarintSize32(static_cast<uint32>(value));
-  }
+inline size_t CodedOutputStream::VarintSize64PlusOne(uint64_t value) {
+  // Same as above, but one more.
+  uint32_t log2value = Bits::Log2FloorNonZero64(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73 + 64) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize32SignExtended(int32_t value) {
+  return VarintSize64(static_cast<uint64_t>(int64_t{value}));
+}
+
+inline size_t CodedOutputStream::VarintSize32SignExtendedPlusOne(int32_t value) {
+  return VarintSize64PlusOne(static_cast<uint64_t>(int64_t{value}));
 }
 
 inline void CodedOutputStream::WriteString(const std::string& str) {
@@ -1707,14 +1728,14 @@
   cur_ = impl_.WriteRawMaybeAliased(data, size, cur_);
 }
 
-inline uint8* CodedOutputStream::WriteRawToArray(const void* data, int size,
-                                                 uint8* target) {
+inline uint8_t* CodedOutputStream::WriteRawToArray(const void* data, int size,
+                                                 uint8_t* target) {
   memcpy(target, data, size);
   return target + size;
 }
 
-inline uint8* CodedOutputStream::WriteStringToArray(const std::string& str,
-                                                    uint8* target) {
+inline uint8_t* CodedOutputStream::WriteStringToArray(const std::string& str,
+                                                    uint8_t* target) {
   return WriteRawToArray(str.data(), static_cast<int>(str.size()), target);
 }
 
diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc
index ad6bb5f..2f1d26f 100644
--- a/src/google/protobuf/io/gzip_stream.cc
+++ b/src/google/protobuf/io/gzip_stream.cc
@@ -186,7 +186,7 @@
   return ok;
 }
 int64_t GzipInputStream::ByteCount() const {
-  int64 ret = byte_count_ + zcontext_.total_out;
+  int64_t ret = byte_count_ + zcontext_.total_out;
   if (zcontext_.next_out != NULL && output_position_ != NULL) {
     ret += reinterpret_cast<uintptr_t>(zcontext_.next_out) -
            reinterpret_cast<uintptr_t>(output_position_);
diff --git a/src/google/protobuf/io/gzip_stream.h b/src/google/protobuf/io/gzip_stream.h
index cc704b9..f0283e8 100644
--- a/src/google/protobuf/io/gzip_stream.h
+++ b/src/google/protobuf/io/gzip_stream.h
@@ -96,7 +96,7 @@
   void* output_buffer_;
   void* output_position_;
   size_t output_buffer_length_;
-  int64 byte_count_;
+  int64_t byte_count_;
 
   int Inflate(int flush);
   void DoNextOutput(const void** data, int* size);
diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc
index 129b488..6a48673 100644
--- a/src/google/protobuf/io/tokenizer.cc
+++ b/src/google/protobuf/io/tokenizer.cc
@@ -860,8 +860,8 @@
 // are given is text that the tokenizer actually parsed as a token
 // of the given type.
 
-bool Tokenizer::ParseInteger(const std::string& text, uint64 max_value,
-                             uint64* output) {
+bool Tokenizer::ParseInteger(const std::string& text, uint64_t max_value,
+                             uint64_t* output) {
   // Sadly, we can't just use strtoul() since it is only 32-bit and strtoull()
   // is non-standard.  I hate the C standard library.  :(
 
@@ -880,7 +880,7 @@
     }
   }
 
-  uint64 result = 0;
+  uint64_t result = 0;
   for (; *ptr != '\0'; ptr++) {
     int digit = DigitValue(*ptr);
     if (digit < 0 || digit >= base) {
@@ -888,7 +888,7 @@
       // token, but Tokenizer still think it's integer.
       return false;
     }
-    if (static_cast<uint64>(digit) > max_value ||
+    if (static_cast<uint64_t>(digit) > max_value ||
         result > (max_value - digit) / base) {
       // Overflow.
       return false;
@@ -929,8 +929,8 @@
 
 // Helper to append a Unicode code point to a string as UTF8, without bringing
 // in any external dependencies.
-static void AppendUTF8(uint32 code_point, std::string* output) {
-  uint32 tmp = 0;
+static void AppendUTF8(uint32_t code_point, std::string* output) {
+  uint32_t tmp = 0;
   int len = 0;
   if (code_point <= 0x7f) {
     tmp = code_point;
@@ -960,7 +960,7 @@
 
 // Try to read <len> hex digits from ptr, and stuff the numeric result into
 // *result. Returns true if that many digits were successfully consumed.
-static bool ReadHexDigits(const char* ptr, int len, uint32* result) {
+static bool ReadHexDigits(const char* ptr, int len, uint32_t* result) {
   *result = 0;
   if (len == 0) return false;
   for (const char* end = ptr + len; ptr < end; ++ptr) {
@@ -975,22 +975,22 @@
 // surrogate. These numbers are in a reserved range of Unicode code points, so
 // if we encounter such a pair we know how to parse it and convert it into a
 // single code point.
-static const uint32 kMinHeadSurrogate = 0xd800;
-static const uint32 kMaxHeadSurrogate = 0xdc00;
-static const uint32 kMinTrailSurrogate = 0xdc00;
-static const uint32 kMaxTrailSurrogate = 0xe000;
+static const uint32_t kMinHeadSurrogate = 0xd800;
+static const uint32_t kMaxHeadSurrogate = 0xdc00;
+static const uint32_t kMinTrailSurrogate = 0xdc00;
+static const uint32_t kMaxTrailSurrogate = 0xe000;
 
-static inline bool IsHeadSurrogate(uint32 code_point) {
+static inline bool IsHeadSurrogate(uint32_t code_point) {
   return (code_point >= kMinHeadSurrogate) && (code_point < kMaxHeadSurrogate);
 }
 
-static inline bool IsTrailSurrogate(uint32 code_point) {
+static inline bool IsTrailSurrogate(uint32_t code_point) {
   return (code_point >= kMinTrailSurrogate) &&
          (code_point < kMaxTrailSurrogate);
 }
 
 // Combine a head and trail surrogate into a single Unicode code point.
-static uint32 AssembleUTF16(uint32 head_surrogate, uint32 trail_surrogate) {
+static uint32_t AssembleUTF16(uint32_t head_surrogate, uint32_t trail_surrogate) {
   GOOGLE_DCHECK(IsHeadSurrogate(head_surrogate));
   GOOGLE_DCHECK(IsTrailSurrogate(trail_surrogate));
   return 0x10000 + (((head_surrogate - kMinHeadSurrogate) << 10) |
@@ -1008,7 +1008,7 @@
 // to parse that sequence. On success, returns a pointer to the first char
 // beyond that sequence, and fills in *code_point. On failure, returns ptr
 // itself.
-static const char* FetchUnicodePoint(const char* ptr, uint32* code_point) {
+static const char* FetchUnicodePoint(const char* ptr, uint32_t* code_point) {
   const char* p = ptr;
   // Fetch the code point.
   const int len = UnicodeLength(*p++);
@@ -1020,7 +1020,7 @@
   // "trail surrogate," and together they form a UTF-16 pair which decodes into
   // a single Unicode point. Trail surrogates may only use \u, not \U.
   if (IsHeadSurrogate(*code_point) && *p == '\\' && *(p + 1) == 'u') {
-    uint32 trail_surrogate;
+    uint32_t trail_surrogate;
     if (ReadHexDigits(p + 2, 4, &trail_surrogate) &&
         IsTrailSurrogate(trail_surrogate)) {
       *code_point = AssembleUTF16(*code_point, trail_surrogate);
@@ -1092,7 +1092,7 @@
         output->push_back(static_cast<char>(code));
 
       } else if (*ptr == 'u' || *ptr == 'U') {
-        uint32 unicode;
+        uint32_t unicode;
         const char* end = FetchUnicodePoint(ptr, &unicode);
         if (end == ptr) {
           // Failure: Just dump out what we saw, don't try to parse it.
diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h
index 3be00f1..ac23c2e 100644
--- a/src/google/protobuf/io/tokenizer.h
+++ b/src/google/protobuf/io/tokenizer.h
@@ -217,8 +217,8 @@
   // result.  If the text is not from a Token of type TYPE_INTEGER originally
   // parsed by a Tokenizer, the result is undefined (possibly an assert
   // failure).
-  static bool ParseInteger(const std::string& text, uint64 max_value,
-                           uint64* output);
+  static bool ParseInteger(const std::string& text, uint64_t max_value,
+                           uint64_t* output);
 
   // Options ---------------------------------------------------------
 
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc
index 52617e9..0986ea2 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl.cc
@@ -103,7 +103,13 @@
       close_on_delete_(false),
       is_closed_(false),
       errno_(0),
-      previous_seek_failed_(false) {}
+      previous_seek_failed_(false) {
+#ifndef _MSC_VER
+  int flags = fcntl(file_, F_GETFL);
+  flags &= ~O_NONBLOCK;
+  fcntl(file_, F_SETFL, flags);
+#endif
+}
 
 FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() {
   if (close_on_delete_) {
@@ -210,7 +216,7 @@
   GOOGLE_CHECK(!is_closed_);
   int total_written = 0;
 
-  const uint8* buffer_base = reinterpret_cast<const uint8*>(buffer);
+  const uint8_t* buffer_base = reinterpret_cast<const uint8_t*>(buffer);
 
   while (total_written < size) {
     int bytes;
@@ -332,12 +338,12 @@
   while (stream_count_ > 0) {
     // Assume that ByteCount() can be used to find out how much we actually
     // skipped when Skip() fails.
-    int64 target_byte_count = streams_[0]->ByteCount() + count;
+    int64_t target_byte_count = streams_[0]->ByteCount() + count;
     if (streams_[0]->Skip(count)) return true;
 
     // Hit the end of the stream.  Figure out how many more bytes we still have
     // to skip.
-    int64 final_byte_count = streams_[0]->ByteCount();
+    int64_t final_byte_count = streams_[0]->ByteCount();
     GOOGLE_DCHECK_LT(final_byte_count, target_byte_count);
     count = target_byte_count - final_byte_count;
 
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.h b/src/google/protobuf/io/zero_copy_stream_impl.h
index 0206e38..e6ba902 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl.h
@@ -311,7 +311,7 @@
   // decremented.
   ZeroCopyInputStream* const* streams_;
   int stream_count_;
-  int64 bytes_retired_;  // Bytes read from previous streams.
+  int64_t bytes_retired_;  // Bytes read from previous streams.
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream);
 };
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
index 0eeeb0e..dc4b1e9 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -56,7 +56,7 @@
 // ===================================================================
 
 ArrayInputStream::ArrayInputStream(const void* data, int size, int block_size)
-    : data_(reinterpret_cast<const uint8*>(data)),
+    : data_(reinterpret_cast<const uint8_t*>(data)),
       size_(size),
       block_size_(block_size > 0 ? block_size : size),
       position_(0),
@@ -103,7 +103,7 @@
 // ===================================================================
 
 ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
-    : data_(reinterpret_cast<uint8*>(data)),
+    : data_(reinterpret_cast<uint8_t*>(data)),
       size_(size),
       block_size_(block_size > 0 ? block_size : size),
       position_(0),
@@ -284,7 +284,7 @@
 
 void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
   if (buffer_.get() == NULL) {
-    buffer_.reset(new uint8[buffer_size_]);
+    buffer_.reset(new uint8_t[buffer_size_]);
   }
 }
 
@@ -394,7 +394,7 @@
 
 void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
   if (buffer_ == NULL) {
-    buffer_.reset(new uint8[buffer_size_]);
+    buffer_.reset(new uint8_t[buffer_size_]);
   }
 }
 
@@ -406,7 +406,7 @@
 // ===================================================================
 
 LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
-                                         int64 limit)
+                                         int64_t limit)
     : input_(input), limit_(limit) {
   prior_bytes_read_ = input_->ByteCount();
 }
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
index cfe81d2..9ee3691 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
@@ -84,7 +84,7 @@
 
 
  private:
-  const uint8* const data_;  // The byte array.
+  const uint8_t* const data_;  // The byte array.
   const int size_;           // Total size of the array.
   const int block_size_;     // How many bytes to return at a time.
 
@@ -116,7 +116,7 @@
   int64_t ByteCount() const override;
 
  private:
-  uint8* const data_;     // The byte array.
+  uint8_t* const data_;     // The byte array.
   const int size_;        // Total size of the array.
   const int block_size_;  // How many bytes to return at a time.
 
@@ -236,11 +236,11 @@
 
   // The current position of copying_stream_, relative to the point where
   // we started reading.
-  int64 position_;
+  int64_t position_;
 
   // Data is read into this buffer.  It may be NULL if no buffer is currently
   // in use.  Otherwise, it points to an array of size buffer_size_.
-  std::unique_ptr<uint8[]> buffer_;
+  std::unique_ptr<uint8_t[]> buffer_;
   const int buffer_size_;
 
   // Number of valid bytes currently in the buffer (i.e. the size last
@@ -327,11 +327,11 @@
 
   // The current position of copying_stream_, relative to the point where
   // we started writing.
-  int64 position_;
+  int64_t position_;
 
   // Data is written from this buffer.  It may be NULL if no buffer is
   // currently in use.  Otherwise, it points to an array of size buffer_size_.
-  std::unique_ptr<uint8[]> buffer_;
+  std::unique_ptr<uint8_t[]> buffer_;
   const int buffer_size_;
 
   // Number of valid bytes currently in the buffer (i.e. the size last
@@ -348,7 +348,7 @@
 // a particular byte count.
 class PROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
  public:
-  LimitingInputStream(ZeroCopyInputStream* input, int64 limit);
+  LimitingInputStream(ZeroCopyInputStream* input, int64_t limit);
   ~LimitingInputStream() override;
 
   // implements ZeroCopyInputStream ----------------------------------
@@ -360,8 +360,8 @@
 
  private:
   ZeroCopyInputStream* input_;
-  int64 limit_;  // Decreases as we go, becomes negative if we overshoot.
-  int64 prior_bytes_read_;  // Bytes read on underlying stream at construction
+  int64_t limit_;  // Decreases as we go, becomes negative if we overshoot.
+  int64_t prior_bytes_read_;  // Bytes read on underlying stream at construction
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
 };
diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc
index cc53949..822115e 100644
--- a/src/google/protobuf/io/zero_copy_stream_unittest.cc
+++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc
@@ -46,8 +46,11 @@
 //   "parametized tests" so that one set of tests can be used on all the
 //   implementations.
 
+#include <chrono>
+#include <thread>
 
 #ifndef _MSC_VER
+#include <sys/socket.h>
 #include <unistd.h>
 #endif
 #include <errno.h>
@@ -117,7 +120,7 @@
   int WriteStuff(ZeroCopyOutputStream* output);
   // Reads text from an input stream and expects it to match what
   // WriteStuff() writes.
-  void ReadStuff(ZeroCopyInputStream* input);
+  void ReadStuff(ZeroCopyInputStream* input, bool read_eof = true);
 
   // Similar to WriteStuff, but performs more sophisticated testing.
   int WriteStuffLarge(ZeroCopyOutputStream* output);
@@ -228,7 +231,7 @@
 
 // Reads text from an input stream and expects it to match what WriteStuff()
 // writes.
-void IoTest::ReadStuff(ZeroCopyInputStream* input) {
+void IoTest::ReadStuff(ZeroCopyInputStream* input, bool read_eof) {
   ReadString(input, "Hello world!\n");
   ReadString(input, "Some text.  ");
   ReadString(input, "Blah ");
@@ -240,8 +243,10 @@
 
   EXPECT_EQ(input->ByteCount(), 68);
 
-  uint8 byte;
-  EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
+  if (read_eof) {
+    uint8 byte;
+    EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
+  }
 }
 
 int IoTest::WriteStuffLarge(ZeroCopyOutputStream* output) {
@@ -759,6 +764,67 @@
   }
 }
 
+#ifndef _MSC_VER
+// This tests the FileInputStream with a non blocking file. It opens a pipe in
+// non blocking mode, then starts reading it. The writing thread starts writing
+// 100ms after that.
+TEST_F(IoTest, NonBlockingFileIo) {
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    for (int j = 0; j < kBlockSizeCount; j++) {
+      int fd[2];
+      ASSERT_EQ(pipe2(fd, O_NONBLOCK), 0);
+
+      std::mutex go_write;
+      go_write.lock();
+
+      bool done_reading = false;
+
+      std::thread write_thread([this, fd, &go_write, i]() {
+        go_write.lock();
+        go_write.unlock();
+        FileOutputStream output(fd[1], kBlockSizes[i]);
+        WriteStuff(&output);
+        EXPECT_EQ(0, output.GetErrno());
+      });
+
+      std::thread read_thread([this, fd, &done_reading, j]() {
+        FileInputStream input(fd[0], kBlockSizes[j]);
+        ReadStuff(&input, false /* read_eof */);
+        done_reading = true;
+        close(fd[0]);
+        close(fd[1]);
+        EXPECT_EQ(0, input.GetErrno());
+      });
+
+      // Sleeping is not necessary but makes the next expectation relevant: the
+      // reading thread waits for the data to be available before returning.
+      std::this_thread::sleep_for(std::chrono::milliseconds(100));
+      EXPECT_FALSE(done_reading);
+      go_write.unlock();
+      write_thread.join();
+      read_thread.join();
+      EXPECT_TRUE(done_reading);
+    }
+  }
+}
+
+TEST_F(IoTest, BlockingFileIoWithTimeout) {
+  int fd[2];
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, fd), 0);
+    struct timeval tv {
+      .tv_sec = 0, .tv_usec = 5000
+    };
+    ASSERT_EQ(setsockopt(fd[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), 0);
+    FileInputStream input(fd[0], kBlockSizes[i]);
+    uint8 byte;
+    EXPECT_EQ(ReadFromInput(&input, &byte, 1), 0);
+    EXPECT_EQ(EAGAIN, input.GetErrno());
+  }
+}
+#endif
+
 #if HAVE_ZLIB
 TEST_F(IoTest, GzipFileIo) {
   std::string filename = TestTempDir() + "/zero_copy_stream_test_file";
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index df84e1e..361d1fc 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -118,7 +118,7 @@
       return static_cast<pointer>(::operator new(n * sizeof(value_type)));
     } else {
       return reinterpret_cast<pointer>(
-          Arena::CreateArray<uint8>(arena_, n * sizeof(value_type)));
+          Arena::CreateArray<uint8_t>(arena_, n * sizeof(value_type)));
     }
   }
 
@@ -698,21 +698,18 @@
         p = FindHelper(k);
       }
       const size_type b = p.second;  // bucket number
-      Node* node;
       // If K is not key_type, make the conversion to key_type explicit.
       using TypeToInit = typename std::conditional<
           std::is_same<typename std::decay<K>::type, key_type>::value, K&&,
           key_type>::type;
-      if (alloc_.arena() == nullptr) {
-        node = new Node{value_type(static_cast<TypeToInit>(std::forward<K>(k))),
-                        nullptr};
-      } else {
-        node = Alloc<Node>(1);
-        Arena::CreateInArenaStorage(
-            const_cast<Key*>(&node->kv.first), alloc_.arena(),
-            static_cast<TypeToInit>(std::forward<K>(k)));
-        Arena::CreateInArenaStorage(&node->kv.second, alloc_.arena());
-      }
+      Node* node = Alloc<Node>(1);
+      // Even when arena is nullptr, CreateInArenaStorage is still used to
+      // ensure the arena of submessage will be consistent. Otherwise,
+      // submessage may have its own arena when message-owned arena is enabled.
+      Arena::CreateInArenaStorage(const_cast<Key*>(&node->kv.first),
+                                  alloc_.arena(),
+                                  static_cast<TypeToInit>(std::forward<K>(k)));
+      Arena::CreateInArenaStorage(&node->kv.second, alloc_.arena());
 
       iterator result = InsertUnique(b, node);
       ++num_elements_;
@@ -1026,12 +1023,12 @@
     size_type BucketNumber(const K& k) const {
       // We xor the hash value against the random seed so that we effectively
       // have a random hash function.
-      uint64 h = hash_function()(k) ^ seed_;
+      uint64_t h = hash_function()(k) ^ seed_;
 
       // We use the multiplication method to determine the bucket number from
       // the hash value. The constant kPhi (suggested by Knuth) is roughly
       // (sqrt(5) - 1) / 2 * 2^64.
-      constexpr uint64 kPhi = uint64{0x9e3779b97f4a7c15};
+      constexpr uint64_t kPhi = uint64_t{0x9e3779b97f4a7c15};
       return ((kPhi * h) >> 32) & (num_buckets_ - 1);
     }
 
@@ -1085,9 +1082,9 @@
       size_type s = reinterpret_cast<uintptr_t>(this) >> 12;
 #if defined(__x86_64__) && defined(__GNUC__) && \
     !defined(GOOGLE_PROTOBUF_NO_RDTSC)
-      uint32 hi, lo;
+      uint32_t hi, lo;
       asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
-      s += ((static_cast<uint64>(hi) << 32) | lo);
+      s += ((static_cast<uint64_t>(hi) << 32) | lo);
 #endif
       return s;
     }
diff --git a/src/google/protobuf/map_entry.h b/src/google/protobuf/map_entry.h
index 87bc000..2aec2d4 100644
--- a/src/google/protobuf/map_entry.h
+++ b/src/google/protobuf/map_entry.h
@@ -78,8 +78,8 @@
 //                         field.
 //
 // cpp type | proto type  | in-memory type | MapEntry accessor type
-// int32      TYPE_INT32    int32            int32
-// int32      TYPE_FIXED32  int32            int32
+// int32_t    TYPE_INT32    int32_t          int32_t
+// int32_t    TYPE_FIXED32  int32_t          int32_t
 // string     TYPE_STRING   ArenaStringPtr   string
 // FooEnum    TYPE_ENUM     int              int
 // FooMessage TYPE_MESSAGE  FooMessage*      FooMessage
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 609d025..7dd50e2 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -107,9 +107,9 @@
   static const int kKeyFieldNumber = 1;
   static const int kValueFieldNumber = 2;
 
-  static uint8* InternalSerialize(int field_number, const Key& key,
-                                  const Value& value, uint8* ptr,
-                                  io::EpsCopyOutputStream* stream) {
+  static uint8_t* InternalSerialize(int field_number, const Key& key,
+                                    const Value& value, uint8_t* ptr,
+                                    io::EpsCopyOutputStream* stream) {
     ptr = stream->EnsureSpace(ptr);
     ptr = WireFormatLite::WriteTagToArray(
         field_number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, ptr);
@@ -125,7 +125,7 @@
     size_t inner_length =
         2 + KeyTypeHandler::ByteSize(key) + ValueTypeHandler::ByteSize(value);
     return inner_length + io::CodedOutputStream::VarintSize32(
-                              static_cast<uint32>(inner_length));
+                              static_cast<uint32_t>(inner_length));
   }
 
   static int GetCachedSize(const Key& key, const Value& value) {
@@ -167,9 +167,9 @@
   static const int kValueFieldNumber = 2;
 
   // Constants for field tag.
-  static const uint8 kKeyTag =
+  static const uint8_t kKeyTag =
       GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kKeyFieldNumber, KeyTypeHandler::kWireType);
-  static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+  static const uint8_t kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
       kValueFieldNumber, ValueTypeHandler::kWireType);
   static const size_t kTagSize = 1;
 
@@ -229,7 +229,7 @@
 
   const char* _InternalParse(const char* ptr, ParseContext* ctx) final {
     while (!ctx->Done(&ptr)) {
-      uint32 tag;
+      uint32_t tag;
       ptr = ReadTag(ptr, &tag);
       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       if (tag == kKeyTag) {
@@ -263,8 +263,8 @@
     return size;
   }
 
-  ::google::protobuf::uint8* _InternalSerialize(::google::protobuf::uint8* ptr,
-                              io::EpsCopyOutputStream* stream) const override {
+  ::uint8_t* _InternalSerialize(
+      ::uint8_t* ptr, io::EpsCopyOutputStream* stream) const override {
     ptr = KeyTypeHandler::Write(kKeyFieldNumber, key(), ptr, stream);
     return ValueTypeHandler::Write(kValueFieldNumber, value(), ptr, stream);
   }
@@ -422,7 +422,8 @@
 
     template <typename UnknownType>
     const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
-                                        bool (*is_valid)(int), uint32 field_num,
+                                        bool (*is_valid)(int),
+                                        uint32_t field_num,
                                         InternalMetadata* metadata) {
       auto entry = NewEntry();
       ptr = entry->_InternalParse(ptr, ctx);
@@ -500,7 +501,7 @@
  public:  // Needed for constructing tables
   KeyOnMemory key_;
   ValueOnMemory value_;
-  uint32 _has_bits_[1];
+  uint32_t _has_bits_[1];
 
  private:
   friend class ::PROTOBUF_NAMESPACE_ID::Arena;
@@ -641,8 +642,8 @@
   // The proto compiler generates the offsets in this struct as if this was
   // a regular message. This way the table driven code barely notices it's
   // dealing with a map field.
-  uint32 _has_bits_;     // NOLINT
-  uint32 _cached_size_;  // NOLINT
+  uint32_t _has_bits_;     // NOLINT
+  uint32_t _cached_size_;  // NOLINT
   KeyOnMemory key_;      // NOLINT
   ValueOnMemory value_;  // NOLINT
 };
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
index d94b278..1581caf 100644
--- a/src/google/protobuf/map_field.cc
+++ b/src/google/protobuf/map_field.cc
@@ -236,15 +236,15 @@
     map_val->SetValue(value);                                \
     break;                                                   \
   }
-    HANDLE_TYPE(INT32, int32);
-    HANDLE_TYPE(INT64, int64);
-    HANDLE_TYPE(UINT32, uint32);
-    HANDLE_TYPE(UINT64, uint64);
+    HANDLE_TYPE(INT32, int32_t);
+    HANDLE_TYPE(INT64, int64_t);
+    HANDLE_TYPE(UINT32, uint32_t);
+    HANDLE_TYPE(UINT64, uint64_t);
     HANDLE_TYPE(DOUBLE, double);
     HANDLE_TYPE(FLOAT, float);
     HANDLE_TYPE(BOOL, bool);
     HANDLE_TYPE(STRING, std::string);
-    HANDLE_TYPE(ENUM, int32);
+    HANDLE_TYPE(ENUM, int32_t);
 #undef HANDLE_TYPE
     case FieldDescriptor::CPPTYPE_MESSAGE: {
       const Message& message =
@@ -543,15 +543,15 @@
     map_val.SetValue(value);                                 \
     break;                                                   \
   }
-      HANDLE_TYPE(INT32, int32, Int32);
-      HANDLE_TYPE(INT64, int64, Int64);
-      HANDLE_TYPE(UINT32, uint32, UInt32);
-      HANDLE_TYPE(UINT64, uint64, UInt64);
+      HANDLE_TYPE(INT32, int32_t, Int32);
+      HANDLE_TYPE(INT64, int64_t, Int64);
+      HANDLE_TYPE(UINT32, uint32_t, UInt32);
+      HANDLE_TYPE(UINT64, uint64_t, UInt64);
       HANDLE_TYPE(DOUBLE, double, Double);
       HANDLE_TYPE(FLOAT, float, Float);
       HANDLE_TYPE(BOOL, bool, Bool);
       HANDLE_TYPE(STRING, std::string, String);
-      HANDLE_TYPE(ENUM, int32, EnumValue);
+      HANDLE_TYPE(ENUM, int32_t, EnumValue);
 #undef HANDLE_TYPE
       case FieldDescriptor::CPPTYPE_MESSAGE: {
         const Message& message = reflection->GetMessage(*it, val_des);
@@ -586,15 +586,15 @@
     size += sizeof(TYPE) * map_size;         \
     break;                                   \
   }
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(BOOL, bool);
       HANDLE_TYPE(STRING, std::string);
-      HANDLE_TYPE(ENUM, int32);
+      HANDLE_TYPE(ENUM, int32_t);
 #undef HANDLE_TYPE
       case FieldDescriptor::CPPTYPE_MESSAGE: {
         while (it != map_.end()) {
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index 7f52cc7..6668441 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -95,19 +95,19 @@
     return type_;
   }
 
-  void SetInt64Value(int64 value) {
+  void SetInt64Value(int64_t value) {
     SetType(FieldDescriptor::CPPTYPE_INT64);
     val_.int64_value_ = value;
   }
-  void SetUInt64Value(uint64 value) {
+  void SetUInt64Value(uint64_t value) {
     SetType(FieldDescriptor::CPPTYPE_UINT64);
     val_.uint64_value_ = value;
   }
-  void SetInt32Value(int32 value) {
+  void SetInt32Value(int32_t value) {
     SetType(FieldDescriptor::CPPTYPE_INT32);
     val_.int32_value_ = value;
   }
-  void SetUInt32Value(uint32 value) {
+  void SetUInt32Value(uint32_t value) {
     SetType(FieldDescriptor::CPPTYPE_UINT32);
     val_.uint32_value_ = value;
   }
@@ -120,19 +120,19 @@
     *val_.string_value_.get_mutable() = std::move(val);
   }
 
-  int64 GetInt64Value() const {
+  int64_t GetInt64Value() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, "MapKey::GetInt64Value");
     return val_.int64_value_;
   }
-  uint64 GetUInt64Value() const {
+  uint64_t GetUInt64Value() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, "MapKey::GetUInt64Value");
     return val_.uint64_value_;
   }
-  int32 GetInt32Value() const {
+  int32_t GetInt32Value() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, "MapKey::GetInt32Value");
     return val_.int32_value_;
   }
-  uint32 GetUInt32Value() const {
+  uint32_t GetUInt32Value() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, "MapKey::GetUInt32Value");
     return val_.uint32_value_;
   }
@@ -242,10 +242,10 @@
   union KeyValue {
     KeyValue() {}
     internal::ExplicitlyConstructed<std::string> string_value_;
-    int64 int64_value_;
-    int32 int32_value_;
-    uint64 uint64_value_;
-    uint32 uint32_value_;
+    int64_t int64_value_;
+    int32_t int32_value_;
+    uint64_t uint64_value_;
+    uint32_t uint32_value_;
     bool bool_value_;
   } val_;
 
@@ -591,7 +591,7 @@
   }
   template <typename UnknownType>
   const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
-                                      bool (*is_valid)(int), uint32 field_num,
+                                      bool (*is_valid)(int), uint32_t field_num,
                                       InternalMetadata* metadata) {
     return impl_.template ParseWithEnumValidation<UnknownType>(
         ptr, ctx, is_valid, field_num, metadata);
@@ -682,25 +682,25 @@
  public:
   MapValueConstRef() : data_(nullptr), type_() {}
 
-  int64 GetInt64Value() const {
+  int64_t GetInt64Value() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64,
                "MapValueConstRef::GetInt64Value");
-    return *reinterpret_cast<int64*>(data_);
+    return *reinterpret_cast<int64_t*>(data_);
   }
-  uint64 GetUInt64Value() const {
+  uint64_t GetUInt64Value() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64,
                "MapValueConstRef::GetUInt64Value");
-    return *reinterpret_cast<uint64*>(data_);
+    return *reinterpret_cast<uint64_t*>(data_);
   }
-  int32 GetInt32Value() const {
+  int32_t GetInt32Value() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32,
                "MapValueConstRef::GetInt32Value");
-    return *reinterpret_cast<int32*>(data_);
+    return *reinterpret_cast<int32_t*>(data_);
   }
-  uint32 GetUInt32Value() const {
+  uint32_t GetUInt32Value() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32,
                "MapValueConstRef::GetUInt32Value");
-    return *reinterpret_cast<uint32*>(data_);
+    return *reinterpret_cast<uint32_t*>(data_);
   }
   bool GetBoolValue() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapValueConstRef::GetBoolValue");
@@ -774,21 +774,21 @@
  public:
   MapValueRef() {}
 
-  void SetInt64Value(int64 value) {
+  void SetInt64Value(int64_t value) {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, "MapValueRef::SetInt64Value");
-    *reinterpret_cast<int64*>(data_) = value;
+    *reinterpret_cast<int64_t*>(data_) = value;
   }
-  void SetUInt64Value(uint64 value) {
+  void SetUInt64Value(uint64_t value) {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, "MapValueRef::SetUInt64Value");
-    *reinterpret_cast<uint64*>(data_) = value;
+    *reinterpret_cast<uint64_t*>(data_) = value;
   }
-  void SetInt32Value(int32 value) {
+  void SetInt32Value(int32_t value) {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, "MapValueRef::SetInt32Value");
-    *reinterpret_cast<int32*>(data_) = value;
+    *reinterpret_cast<int32_t*>(data_) = value;
   }
-  void SetUInt32Value(uint32 value) {
+  void SetUInt32Value(uint32_t value) {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, "MapValueRef::SetUInt32Value");
-    *reinterpret_cast<uint32*>(data_) = value;
+    *reinterpret_cast<uint32_t*>(data_) = value;
   }
   void SetBoolValue(bool value) {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapValueRef::SetBoolValue");
@@ -829,15 +829,15 @@
     delete reinterpret_cast<TYPE*>(data_);   \
     break;                                   \
   }
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
       HANDLE_TYPE(DOUBLE, double);
       HANDLE_TYPE(FLOAT, float);
       HANDLE_TYPE(BOOL, bool);
       HANDLE_TYPE(STRING, std::string);
-      HANDLE_TYPE(ENUM, int32);
+      HANDLE_TYPE(ENUM, int32_t);
       HANDLE_TYPE(MESSAGE, Message);
 #undef HANDLE_TYPE
     }
diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h
index a42b4fc..35231b2 100644
--- a/src/google/protobuf/map_field_inl.h
+++ b/src/google/protobuf/map_field_inl.h
@@ -49,19 +49,19 @@
 template <typename T>
 T UnwrapMapKey(const MapKey& map_key);
 template <>
-inline int32 UnwrapMapKey<int32>(const MapKey& map_key) {
+inline int32_t UnwrapMapKey<int32_t>(const MapKey& map_key) {
   return map_key.GetInt32Value();
 }
 template <>
-inline uint32 UnwrapMapKey<uint32>(const MapKey& map_key) {
+inline uint32_t UnwrapMapKey<uint32_t>(const MapKey& map_key) {
   return map_key.GetUInt32Value();
 }
 template <>
-inline int64 UnwrapMapKey<int64>(const MapKey& map_key) {
+inline int64_t UnwrapMapKey<int64_t>(const MapKey& map_key) {
   return map_key.GetInt64Value();
 }
 template <>
-inline uint64 UnwrapMapKey<uint64>(const MapKey& map_key) {
+inline uint64_t UnwrapMapKey<uint64_t>(const MapKey& map_key) {
   return map_key.GetUInt64Value();
 }
 template <>
@@ -77,19 +77,19 @@
 template <typename T>
 inline void SetMapKey(MapKey* map_key, const T& value);
 template <>
-inline void SetMapKey<int32>(MapKey* map_key, const int32& value) {
+inline void SetMapKey<int32_t>(MapKey* map_key, const int32_t& value) {
   map_key->SetInt32Value(value);
 }
 template <>
-inline void SetMapKey<uint32>(MapKey* map_key, const uint32& value) {
+inline void SetMapKey<uint32_t>(MapKey* map_key, const uint32_t& value) {
   map_key->SetUInt32Value(value);
 }
 template <>
-inline void SetMapKey<int64>(MapKey* map_key, const int64& value) {
+inline void SetMapKey<int64_t>(MapKey* map_key, const int64_t& value) {
   map_key->SetInt64Value(value);
 }
 template <>
-inline void SetMapKey<uint64>(MapKey* map_key, const uint64& value) {
+inline void SetMapKey<uint64_t>(MapKey* map_key, const uint64_t& value) {
   map_key->SetUInt64Value(value);
 }
 template <>
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
index 46658d4..2a32106 100644
--- a/src/google/protobuf/map_field_lite.h
+++ b/src/google/protobuf/map_field_lite.h
@@ -106,7 +106,7 @@
 
   template <typename UnknownType>
   const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
-                                      bool (*is_valid)(int), uint32 field_num,
+                                      bool (*is_valid)(int), uint32_t field_num,
                                       InternalMetadata* metadata) {
     typename Derived::template Parser<MapFieldLite, Map<Key, T>> parser(this);
     return parser.template ParseWithEnumValidation<UnknownType>(
@@ -129,7 +129,7 @@
   }
   T* map_field;
   bool (*is_valid)(int);
-  uint32 field_num;
+  uint32_t field_num;
   InternalMetadata* metadata;
 };
 
@@ -138,7 +138,7 @@
 // generated code
 template <typename UnknownType, typename T>
 EnumParseWrapper<UnknownType, T> InitEnumParseWrapper(
-    T* map_field, bool (*is_valid)(int), uint32 field_num,
+    T* map_field, bool (*is_valid)(int), uint32_t field_num,
     InternalMetadata* metadata) {
   return EnumParseWrapper<UnknownType, T>{map_field, is_valid, field_num,
                                           metadata};
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index d8067f7..c9be28b 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -28,3783 +28,33 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// A hack to include windows.h first, which ensures the GetMessage macro can
-// be undefined when we include <google/protobuf/stubs/common.h>
-#if defined(_MSC_VER)
-#define _WINSOCKAPI_  // to avoid re-definition in WinSock2.h
-#define NOMINMAX      // to avoid defining min/max macros
-#include <windows.h>
-#endif  // _WIN32
-
-#include <algorithm>
-#include <map>
-#include <memory>
-#include <random>
-#include <set>
-#include <sstream>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/stringprintf.h>
-#include <google/protobuf/testing/file.h>
-#include <google/protobuf/arena_test_util.h>
 #include <google/protobuf/map_proto2_unittest.pb.h>
-#include <google/protobuf/map_test_util.h>
 #include <google/protobuf/map_unittest.pb.h>
-#include <google/protobuf/test_util.h>
+#include <google/protobuf/reflection_tester.h>
 #include <google/protobuf/test_util2.h>
-#include <google/protobuf/unittest.pb.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/tokenizer.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor_database.h>
-#include <google/protobuf/dynamic_message.h>
-#include <google/protobuf/map.h>
-#include <google/protobuf/map_field_inl.h>
-#include <google/protobuf/message.h>
-#include <google/protobuf/reflection.h>
-#include <google/protobuf/reflection_ops.h>
-#include <google/protobuf/text_format.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/util/message_differencer.h>
-#include <google/protobuf/util/time_util.h>
-#include <gmock/gmock.h>
-#include <google/protobuf/testing/googletest.h>
-#include <gtest/gtest.h>
-#include <google/protobuf/stubs/casts.h>
-#include <google/protobuf/stubs/substitute.h>
 
 
+#define BRIDGE_UNITTEST ::google::protobuf::bridge_unittest
+#define UNITTEST ::protobuf_unittest
+#define UNITTEST_IMPORT ::protobuf_unittest_import
+#define UNITTEST_PACKAGE_NAME "protobuf_unittest"
+
+// Must include after defining UNITTEST, etc.
+// clang-format off
+#include <google/protobuf/test_util.inc>
+#include <google/protobuf/map_test_util.inc>
+#include <google/protobuf/map_test.inc>
+// clang-format on
+
 // Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
 namespace protobuf {
-
-using unittest::ForeignMessage;
-using unittest::TestAllTypes;
-using unittest::TestMap;
-using unittest::TestRecursiveMapMessage;
-
-namespace internal {
-
-void MapTestForceDeterministic() {
-  io::CodedOutputStream::SetDefaultSerializationDeterministic();
-}
-
-namespace {
-
-// Map API Test =====================================================
-
-class MapImplTest : public ::testing::Test {
- protected:
-  MapImplTest()
-      : map_ptr_(new Map<int32, int32>()),
-        map_(*map_ptr_),
-        const_map_(*map_ptr_) {
-    EXPECT_TRUE(map_.empty());
-    EXPECT_EQ(0, map_.size());
-  }
-
-  void ExpectSingleElement(int32 key, int32 value) {
-    EXPECT_FALSE(map_.empty());
-    EXPECT_EQ(1, map_.size());
-    ExpectElement(key, value);
-  }
-
-  void ExpectElements(const std::map<int32, int32>& map) {
-    EXPECT_FALSE(map_.empty());
-    EXPECT_EQ(map.size(), map_.size());
-    for (std::map<int32, int32>::const_iterator it = map.begin();
-         it != map.end(); ++it) {
-      ExpectElement(it->first, it->second);
-    }
-  }
-
-  void ExpectElement(int32 key, int32 value) {
-    // Test map size is correct.
-    EXPECT_EQ(value, map_[key]);
-    EXPECT_EQ(1, map_.count(key));
-    EXPECT_TRUE(map_.contains(key));
-
-    // Check mutable at and find work correctly.
-    EXPECT_EQ(value, map_.at(key));
-    Map<int32, int32>::iterator it = map_.find(key);
-
-    // iterator dereferenceable
-    EXPECT_EQ(key, (*it).first);
-    EXPECT_EQ(value, (*it).second);
-    EXPECT_EQ(key, it->first);
-    EXPECT_EQ(value, it->second);
-
-    // iterator mutable
-    ((*it).second) = value + 1;
-    EXPECT_EQ(value + 1, map_[key]);
-    ((*it).second) = value;
-    EXPECT_EQ(value, map_[key]);
-
-    it->second = value + 1;
-    EXPECT_EQ(value + 1, map_[key]);
-    it->second = value;
-    EXPECT_EQ(value, map_[key]);
-
-    // copy constructor
-    Map<int32, int32>::iterator it_copy = it;
-    EXPECT_EQ(key, it_copy->first);
-    EXPECT_EQ(value, it_copy->second);
-
-    // Immutable API ================================================
-
-    // Check immutable at and find work correctly.
-    EXPECT_EQ(value, const_map_.at(key));
-    Map<int32, int32>::const_iterator const_it = const_map_.find(key);
-
-    // iterator dereferenceable
-    EXPECT_EQ(key, (*const_it).first);
-    EXPECT_EQ(value, (*const_it).second);
-    EXPECT_EQ(key, const_it->first);
-    EXPECT_EQ(value, const_it->second);
-
-    // copy constructor
-    Map<int32, int32>::const_iterator const_it_copy = const_it;
-    EXPECT_EQ(key, const_it_copy->first);
-    EXPECT_EQ(value, const_it_copy->second);
-  }
-
-  std::unique_ptr<Map<int32, int32> > map_ptr_;
-  Map<int32, int32>& map_;
-  const Map<int32, int32>& const_map_;
-};
-
-TEST_F(MapImplTest, OperatorBracket) {
-  int32 key = 0;
-  int32 value1 = 100;
-  int32 value2 = 101;
-
-  EXPECT_EQ(0, map_[key]);
-
-  map_[key] = value1;
-  ExpectSingleElement(key, value1);
-
-  map_[key] = value2;
-  ExpectSingleElement(key, value2);
-}
-
-struct MoveTestKey {
-  MoveTestKey(int data, int* copies) : data(data), copies(copies) {}
-
-  MoveTestKey(const MoveTestKey& other)
-      : data(other.data), copies(other.copies) {
-    ++*copies;
-  }
-
-  MoveTestKey(MoveTestKey&& other) noexcept
-      : data(other.data), copies(other.copies) {}
-
-  friend bool operator==(const MoveTestKey& lhs, const MoveTestKey& rhs) {
-    return lhs.data == rhs.data;
-  }
-  friend bool operator<(const MoveTestKey& lhs, const MoveTestKey& rhs) {
-    return lhs.data < rhs.data;
-  }
-
-  int data;
-  int* copies;
-};
-
-}  // namespace
-}  // namespace internal
-}  // namespace protobuf
-}  // namespace google
-
-namespace std {
-
-template <>  // NOLINT
-struct hash<google::protobuf::internal::MoveTestKey> {
-  size_t operator()(const google::protobuf::internal::MoveTestKey& key) const {
-    return hash<int>{}(key.data);
-  }
-};
-}  // namespace std
-
-namespace google {
-namespace protobuf {
 namespace internal {
 namespace {
 
-TEST_F(MapImplTest, OperatorBracketRValue) {
-  Arena arena;
-  for (Arena* arena_to_use : {&arena, static_cast<Arena*>(nullptr)}) {
-    int copies = 0;
-    Map<MoveTestKey, int> map(arena_to_use);
-    MoveTestKey key1(1, &copies);
-    EXPECT_EQ(copies, 0);
-    map[key1] = 0;
-    EXPECT_EQ(copies, 1);
-    map[MoveTestKey(2, &copies)] = 2;
-    EXPECT_EQ(copies, 1);
-  }
-}
-
-TEST_F(MapImplTest, OperatorBracketNonExist) {
-  int32 key = 0;
-  int32 default_value = 0;
-
-  EXPECT_EQ(default_value, map_[key]);
-  ExpectSingleElement(key, default_value);
-}
-
-TEST_F(MapImplTest, MutableAt) {
-  int32 key = 0;
-  int32 value1 = 100;
-  int32 value2 = 101;
-
-  map_[key] = value1;
-  ExpectSingleElement(key, value1);
-
-  map_.at(key) = value2;
-  ExpectSingleElement(key, value2);
-}
-
-#ifdef PROTOBUF_HAS_DEATH_TEST
-
-TEST_F(MapImplTest, MutableAtNonExistDeathTest) {
-  EXPECT_DEATH(map_.at(0), "");
-}
-
-TEST_F(MapImplTest, ImmutableAtNonExistDeathTest) {
-  EXPECT_DEATH(const_map_.at(0), "");
-}
-
-TEST_F(MapImplTest, UsageErrors) {
-  MapKey key;
-  key.SetInt64Value(1);
-  EXPECT_DEATH(key.GetUInt64Value(),
-               "Protocol Buffer map usage error:\n"
-               "MapKey::GetUInt64Value type does not match\n"
-               "  Expected : uint64\n"
-               "  Actual   : int64");
-
-  MapValueRef value;
-  EXPECT_DEATH(
-      value.SetFloatValue(0.1),
-      "Protocol Buffer map usage error:\n"
-      "MapValue[Const]*Ref::type MapValue[Const]*Ref is not initialized.");
-}
-
-#endif  // PROTOBUF_HAS_DEATH_TEST
-
-TEST_F(MapImplTest, MapKeyAssignment) {
-  MapKey from, to;
-  from.SetStringValue("abc");
-  to = from;
-  EXPECT_EQ("abc", to.GetStringValue());
-}
-
-TEST_F(MapImplTest, CountNonExist) { EXPECT_EQ(0, map_.count(0)); }
-
-TEST_F(MapImplTest, ContainNotExist) { EXPECT_FALSE(map_.contains(0)); }
-
-TEST_F(MapImplTest, ImmutableContainNotExist) {
-  EXPECT_FALSE(const_map_.contains(0));
-}
-
-TEST_F(MapImplTest, MutableFindNonExist) {
-  EXPECT_TRUE(map_.end() == map_.find(0));
-}
-
-TEST_F(MapImplTest, ImmutableFindNonExist) {
-  EXPECT_TRUE(const_map_.end() == const_map_.find(0));
-}
-
-TEST_F(MapImplTest, ConstEnd) {
-  EXPECT_TRUE(const_map_.end() == const_map_.cend());
-}
-
-TEST_F(MapImplTest, GetReferenceFromIterator) {
-  for (int i = 0; i < 10; i++) {
-    map_[i] = i;
-  }
-
-  for (Map<int32, int32>::const_iterator it = map_.cbegin();
-       it != map_.cend();) {
-    Map<int32, int32>::const_reference entry = *it++;
-    EXPECT_EQ(entry.first, entry.second);
-  }
-
-  for (Map<int32, int32>::const_iterator it = const_map_.begin();
-       it != const_map_.end();) {
-    Map<int32, int32>::const_reference entry = *it++;
-    EXPECT_EQ(entry.first, entry.second);
-  }
-
-  for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
-    Map<int32, int32>::reference entry = *it++;
-    EXPECT_EQ(entry.first + 1, ++entry.second);
-  }
-}
-
-TEST_F(MapImplTest, IteratorBasic) {
-  map_[0] = 0;
-
-  // Default constructible (per forward iterator requirements).
-  Map<int, int>::const_iterator cit;
-  Map<int, int>::iterator it;
-
-  it = map_.begin();
-  cit = it;  // Converts to const_iterator
-
-  // Can compare between them.
-  EXPECT_TRUE(it == cit);
-  EXPECT_FALSE(cit != it);
-
-  // Pre increment.
-  EXPECT_FALSE(it == ++cit);
-
-  // Post increment.
-  EXPECT_FALSE(it++ == cit);
-  EXPECT_TRUE(it == cit);
-}
-
-template <typename Iterator>
-static int64 median(Iterator i0, Iterator i1) {
-  std::vector<int64> v(i0, i1);
-  std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end());
-  return v[v.size() / 2];
-}
-
-static int64 Now() {
-  return util::TimeUtil::TimestampToNanoseconds(
-      util::TimeUtil::GetCurrentTime());
-}
-
-// Arbitrary odd integers for creating test data.
-static int k0 = 812398771;
-static int k1 = 1312938717;
-static int k2 = 1321555333;
-
-// A naive begin() implementation will cause begin() to get slower and slower
-// if one erases elements at the "front" of the hash map, and we'd like to
-// avoid that, as std::unordered_map does.
-TEST_F(MapImplTest, BeginIsFast) {
-  if (true) return;  // TODO(gpike): make this less flaky and re-enable it.
-  Map<int32, int32> map;
-  const int kTestSize = 250000;
-  // Create a random-looking map of size n.  Use non-negative integer keys.
-  uint32 frog = 123983;
-  int last_key = 0;
-  int counter = 0;
-  while (map.size() < kTestSize) {
-    frog *= static_cast<uint32>(k0);
-    frog ^= frog >> 17;
-    frog += counter++;
-    last_key =
-        static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
-    GOOGLE_DCHECK_GE(last_key, 0);
-    map[last_key] = last_key ^ 1;
-  }
-  std::vector<int64> times;
-  // We're going to do map.erase(map.begin()) over and over again.  But,
-  // just in case one iteration is fast compared to the granularity of
-  // our time keeping, we measure kChunkSize iterations per outer-loop iter.
-  const int kChunkSize = 1000;
-  GOOGLE_CHECK_EQ(kTestSize % kChunkSize, 0);
-  do {
-    const int64 start = Now();
-    for (int i = 0; i < kChunkSize; i++) {
-      map.erase(map.begin());
-    }
-    const int64 end = Now();
-    if (end > start) {
-      times.push_back(end - start);
-    }
-  } while (!map.empty());
-  if (times.size() < .99 * kTestSize / kChunkSize) {
-    GOOGLE_LOG(WARNING) << "Now() isn't helping us measure time";
-    return;
-  }
-  int64 x0 = median(times.begin(), times.begin() + 9);
-  int64 x1 = median(times.begin() + times.size() - 9, times.end());
-  GOOGLE_LOG(INFO) << "x0=" << x0 << ", x1=" << x1;
-  // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
-  // And we'll probably time out and never get here.  So, this test is
-  // intentionally loose: we check that x0 and x1 are within a factor of 8.
-  EXPECT_GE(x1, x0 / 8);
-  EXPECT_GE(x0, x1 / 8);
-}
-
-// Try to create kTestSize keys that will land in just a few buckets, and
-// time the insertions, to get a rough estimate of whether an O(n^2) worst case
-// was triggered.  This test is a hacky, but probably better than nothing.
-TEST_F(MapImplTest, HashFlood) {
-  const int kTestSize = 1024;  // must be a power of 2
-  std::set<int> s;
-  for (int i = 0; s.size() < kTestSize; i++) {
-    if ((map_.hash_function()(i) & (kTestSize - 1)) < 3) {
-      s.insert(i);
-    }
-  }
-  // Create hash table with kTestSize entries that hash flood a table with
-  // 1024 (or 512 or 2048 or ...) entries.  This assumes that map_ uses powers
-  // of 2 for table sizes, and that it's sufficient to "flood" with respect to
-  // the low bits of the output of map_.hash_function().
-  std::vector<int64> times;
-  std::set<int>::iterator it = s.begin();
-  int count = 0;
-  do {
-    const int64 start = Now();
-    map_[*it] = 0;
-    const int64 end = Now();
-    if (end > start) {
-      times.push_back(end - start);
-    }
-    ++count;
-    ++it;
-  } while (it != s.end());
-  if (times.size() < .99 * count) return;
-  int64 x0 = median(times.begin(), times.begin() + 9);
-  int64 x1 = median(times.begin() + times.size() - 9, times.end());
-  // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
-  // But we want to allow O(n log n).  A factor of 20 should be generous enough.
-  EXPECT_LE(x1, x0 * 20);
-}
-
-TEST_F(MapImplTest, CopyIteratorStressTest) {
-  std::vector<Map<int32, int32>::iterator> v;
-  const int kIters = 1e5;
-  for (uint32 i = 0; i < kIters; i++) {
-    int32 key = (3 + i * (5 + i * (-8 + i * (62 + i)))) & 0x77777777;
-    map_[key] = i;
-    v.push_back(map_.find(key));
-  }
-  for (std::vector<Map<int32, int32>::iterator>::const_iterator it = v.begin();
-       it != v.end(); it++) {
-    Map<int32, int32>::iterator i = *it;
-    ASSERT_EQ(i->first, (*it)->first);
-    ASSERT_EQ(i->second, (*it)->second);
-  }
-}
-
-template <typename T, typename U>
-static void TestValidityForAllKeysExcept(int key_to_avoid, const T& check_map,
-                                         const U& map) {
-  typedef typename U::value_type value_type;  // a key-value pair
-  for (typename U::const_iterator it = map.begin(); it != map.end(); ++it) {
-    const int key = it->first;
-    if (key == key_to_avoid) continue;
-    // All iterators relevant to this key, whether old (from check_map) or new,
-    // must point to the same memory.  So, test pointer equality here.
-    const value_type* check_val = &*check_map.find(key)->second;
-    EXPECT_EQ(check_val, &*it);
-    EXPECT_EQ(check_val, &*map.find(key));
-  }
-}
-
-// EXPECT i0 and i1 to be the same.  Advancing them should have the same effect,
-// too.
-template <typename Iter>
-static void TestEqualIterators(Iter i0, Iter i1, Iter end) {
-  const int kMaxAdvance = 10;
-  for (int i = 0; i < kMaxAdvance; i++) {
-    EXPECT_EQ(i0 == end, i1 == end);
-    if (i0 == end) return;
-    EXPECT_EQ(&*i0, &*i1) << "iter " << i;
-    ++i0;
-    ++i1;
-  }
-}
-
-template <typename IteratorType>
-static void TestOldVersusNewIterator(int skip, Map<int, int>* m) {
-  const int initial_size = m->size();
-  IteratorType it = m->begin();
-  for (int i = 0; i < skip && it != m->end(); it++, i++) {
-  }
-  if (it == m->end()) return;
-  const IteratorType old = it;
-  GOOGLE_LOG(INFO) << "skip=" << skip << ", old->first=" << old->first;
-  const int target_size =
-      initial_size < 100 ? initial_size * 5 : initial_size * 5 / 4;
-  for (int i = 0; m->size() <= target_size; i++) {
-    (*m)[i] = 0;
-  }
-  // Iterator 'old' should still work just fine despite the growth of *m.
-  const IteratorType after_growth = m->find(old->first);
-  TestEqualIterators<IteratorType>(old, after_growth, m->end());
-
-  // Now shrink the number of elements.  Do this with a mix of erases and
-  // inserts to increase the chance that the hashtable will resize to a lower
-  // number of buckets.  (But, in any case, the test is still useful.)
-  for (int i = 0; i < 2 * (target_size - initial_size); i++) {
-    if (i != old->first) {
-      m->erase(i);
-    }
-    if (((i ^ m->begin()->first) & 15) == 0) {
-      (*m)[i * 342] = i;
-    }
-  }
-  // Now, the table has grown and shrunk; test again.
-  TestEqualIterators<IteratorType>(old, m->find(old->first), m->end());
-  TestEqualIterators<IteratorType>(old, after_growth, m->end());
-}
-
-// Create and test an n-element Map, with emphasis on iterator correctness.
-static void StressTestIterators(int n) {
-  GOOGLE_LOG(INFO) << "StressTestIterators " << n;
-  GOOGLE_CHECK_GT(n, 0);
-  // Create a random-looking map of size n.  Use non-negative integer keys.
-  Map<int, int> m;
-  uint32 frog = 123987 + n;
-  int last_key = 0;
-  int counter = 0;
-  while (m.size() < n) {
-    frog *= static_cast<uint32>(k0);
-    frog ^= frog >> 17;
-    frog += counter++;
-    last_key =
-        static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
-    GOOGLE_DCHECK_GE(last_key, 0);
-    m[last_key] = last_key ^ 1;
-  }
-  // Test it.
-  ASSERT_EQ(n, m.size());
-  // Create maps of pointers and iterators.
-  // These should remain valid even if we modify m.
-  std::unordered_map<int, Map<int, int>::value_type*> mp(n);
-  std::unordered_map<int, Map<int, int>::iterator> mi(n);
-  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) {
-    mp[it->first] = &*it;
-    mi[it->first] = it;
-  }
-  ASSERT_EQ(m.size(), mi.size());
-  ASSERT_EQ(m.size(), mp.size());
-  m.erase(last_key);
-  ASSERT_EQ(n - 1, m.size());
-  TestValidityForAllKeysExcept(last_key, mp, m);
-  TestValidityForAllKeysExcept(last_key, mi, m);
-
-  m[last_key] = 0;
-  ASSERT_EQ(n, m.size());
-  // Test old iterator vs new iterator, with table modification in between.
-  TestOldVersusNewIterator<Map<int, int>::const_iterator>(n % 3, &m);
-  TestOldVersusNewIterator<Map<int, int>::iterator>(n % (1 + (n / 40)), &m);
-  // Finally, ensure erase(iterator) doesn't reorder anything, because that is
-  // what its documentation says.
-  m[last_key] = m[last_key ^ 999] = 0;
-  std::vector<Map<int, int>::iterator> v;
-  v.reserve(m.size());
-  int position_of_last_key = 0;
-  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) {
-    if (it->first == last_key) {
-      position_of_last_key = v.size();
-    }
-    v.push_back(it);
-  }
-  ASSERT_EQ(m.size(), v.size());
-  const Map<int, int>::iterator erase_result = m.erase(m.find(last_key));
-  int index = 0;
-  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it, ++index) {
-    if (index == position_of_last_key) {
-      EXPECT_EQ(&*erase_result, &*v[++index]);
-    }
-    ASSERT_EQ(&*it, &*v[index]);
-  }
-}
-
-TEST_F(MapImplTest, IteratorInvalidation) {
-  // Create a set of pseudo-random sizes to test.
-#ifndef NDEBUG
-  const int kMaxSizeToTest = 100 * 1000;
-#else
-  const int kMaxSizeToTest = 1000 * 1000;
-#endif
-  std::set<int> s;
-  int n = kMaxSizeToTest;
-  unsigned int frog = k1 + n;
-  while (n > 1 && s.size() < 25) {
-    s.insert(n);
-    n = static_cast<int>(n * 100 / (101.0 + (frog & 63)));
-    frog *= k2;
-    frog ^= frog >> 17;
-  }
-  // Ensure we test a few small sizes.
-  s.insert(1);
-  s.insert(2);
-  s.insert(3);
-  // Now, the real work.
-  for (std::set<int>::iterator i = s.begin(); i != s.end(); ++i) {
-    StressTestIterators(*i);
-  }
-}
-
-// Test that erase() revalidates iterators.
-TEST_F(MapImplTest, EraseRevalidates) {
-  map_[3] = map_[13] = map_[20] = 0;
-  const int initial_size = map_.size();
-  EXPECT_EQ(3, initial_size);
-  std::vector<Map<int, int>::iterator> v;
-  for (Map<int, int>::iterator it = map_.begin(); it != map_.end(); ++it) {
-    v.push_back(it);
-  }
-  EXPECT_EQ(initial_size, v.size());
-  for (int i = 0; map_.size() <= initial_size * 20; i++) {
-    map_[i] = 0;
-  }
-  const int larger_size = map_.size();
-  // We've greatly increased the size of the map, so it is highly likely that
-  // the following will corrupt m if erase() doesn't properly revalidate
-  // iterators passed to it.  Finishing this routine without crashing indicates
-  // success.
-  for (int i = 0; i < v.size(); i++) {
-    map_.erase(v[i]);
-  }
-  EXPECT_EQ(larger_size - v.size(), map_.size());
-}
-
-template <typename T>
-bool IsConstHelper(T& /*t*/) {  // NOLINT. We want to catch non-const refs here.
-  return false;
-}
-template <typename T>
-bool IsConstHelper(const T& /*t*/) {
-  return true;
-}
-
-TEST_F(MapImplTest, IteratorConstness) {
-  map_[0] = 0;
-  EXPECT_TRUE(IsConstHelper(*map_.cbegin()));
-  EXPECT_TRUE(IsConstHelper(*const_map_.begin()));
-  EXPECT_FALSE(IsConstHelper(*map_.begin()));
-}
-
-bool IsForwardIteratorHelper(std::forward_iterator_tag /*tag*/) { return true; }
-
-TEST_F(MapImplTest, IteratorCategory) {
-  EXPECT_TRUE(IsForwardIteratorHelper(
-      std::iterator_traits<Map<int, int>::iterator>::iterator_category()));
-  EXPECT_TRUE(IsForwardIteratorHelper(
-      std::iterator_traits<
-          Map<int, int>::const_iterator>::iterator_category()));
-}
-
-TEST_F(MapImplTest, InsertSingle) {
-  int32 key = 0;
-  int32 value1 = 100;
-  int32 value2 = 101;
-
-  // Insert a non-existed key.
-  std::pair<Map<int32, int32>::iterator, bool> result1 =
-      map_.insert(Map<int32, int32>::value_type(key, value1));
-  ExpectSingleElement(key, value1);
-
-  Map<int32, int32>::iterator it1 = result1.first;
-  EXPECT_EQ(key, it1->first);
-  EXPECT_EQ(value1, it1->second);
-  EXPECT_TRUE(result1.second);
-
-  // Insert an existed key.
-  std::pair<Map<int32, int32>::iterator, bool> result2 =
-      map_.insert(Map<int32, int32>::value_type(key, value2));
-  ExpectSingleElement(key, value1);
-
-  Map<int32, int32>::iterator it2 = result2.first;
-  EXPECT_TRUE(it1 == it2);
-  EXPECT_FALSE(result2.second);
-}
-
-TEST_F(MapImplTest, InsertByIterator) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1a = 100;
-  int32 value1b = 101;
-  int32 value2a = 200;
-  int32 value2b = 201;
-
-  std::map<int32, int32> map1;
-  map1[key1] = value1a;
-  map1[key2] = value2a;
-
-  map_.insert(map1.begin(), map1.end());
-  ExpectElements(map1);
-
-  std::map<int32, int32> map2;
-  map2[key1] = value1b;
-  map2[key2] = value2b;
-
-  map_.insert(map2.begin(), map2.end());
-  ExpectElements(map1);
-}
-
-TEST_F(MapImplTest, InsertByInitializerList) {
-  map_.insert({{1, 100}, {2, 200}});
-  ExpectElements({{1, 100}, {2, 200}});
-
-  map_.insert({{2, 201}, {3, 301}});
-  ExpectElements({{1, 100}, {2, 200}, {3, 301}});
-}
-
-TEST_F(MapImplTest, EraseSingleByKey) {
-  int32 key = 0;
-  int32 value = 100;
-
-  map_[key] = value;
-  ExpectSingleElement(key, value);
-
-  // Erase an existing key.
-  EXPECT_EQ(1, map_.erase(key));
-  EXPECT_TRUE(map_.empty());
-  EXPECT_EQ(0, map_.size());
-  EXPECT_TRUE(map_.end() == map_.find(key));
-  EXPECT_TRUE(map_.begin() == map_.end());
-
-  // Erase a non-existing key.
-  EXPECT_EQ(0, map_.erase(key));
-}
-
-TEST_F(MapImplTest, EraseMutipleByKey) {
-  // erase in one specific order to trigger corner cases
-  for (int i = 0; i < 5; i++) {
-    map_[i] = i;
-  }
-
-  map_.erase(0);
-  EXPECT_EQ(4, map_.size());
-  EXPECT_TRUE(map_.end() == map_.find(0));
-
-  map_.erase(1);
-  EXPECT_EQ(3, map_.size());
-  EXPECT_TRUE(map_.end() == map_.find(1));
-
-  map_.erase(3);
-  EXPECT_EQ(2, map_.size());
-  EXPECT_TRUE(map_.end() == map_.find(3));
-
-  map_.erase(4);
-  EXPECT_EQ(1, map_.size());
-  EXPECT_TRUE(map_.end() == map_.find(4));
-
-  map_.erase(2);
-  EXPECT_EQ(0, map_.size());
-  EXPECT_TRUE(map_.end() == map_.find(2));
-}
-
-TEST_F(MapImplTest, EraseSingleByIterator) {
-  int32 key = 0;
-  int32 value = 100;
-
-  map_[key] = value;
-  ExpectSingleElement(key, value);
-
-  Map<int32, int32>::iterator it = map_.find(key);
-  map_.erase(it);
-  EXPECT_TRUE(map_.empty());
-  EXPECT_EQ(0, map_.size());
-  EXPECT_TRUE(map_.end() == map_.find(key));
-  EXPECT_TRUE(map_.begin() == map_.end());
-}
-
-TEST_F(MapImplTest, ValidIteratorAfterErase) {
-  for (int i = 0; i < 10; i++) {
-    map_[i] = i;
-  }
-
-  int count = 0;
-
-  for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
-    count++;
-    if (it->first % 2 == 1) {
-      map_.erase(it++);
-    } else {
-      ++it;
-    }
-  }
-
-  EXPECT_EQ(10, count);
-  EXPECT_EQ(5, map_.size());
-}
-
-TEST_F(MapImplTest, EraseByIterator) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1 = 100;
-  int32 value2 = 101;
-
-  std::map<int32, int32> map;
-  map[key1] = value1;
-  map[key2] = value2;
-
-  map_.insert(map.begin(), map.end());
-  ExpectElements(map);
-
-  map_.erase(map_.begin(), map_.end());
-  EXPECT_TRUE(map_.empty());
-  EXPECT_EQ(0, map_.size());
-  EXPECT_TRUE(map_.end() == map_.find(key1));
-  EXPECT_TRUE(map_.end() == map_.find(key2));
-  EXPECT_TRUE(map_.begin() == map_.end());
-}
-
-TEST_F(MapImplTest, Clear) {
-  int32 key = 0;
-  int32 value = 100;
-
-  map_[key] = value;
-  ExpectSingleElement(key, value);
-
-  map_.clear();
-
-  EXPECT_TRUE(map_.empty());
-  EXPECT_EQ(0, map_.size());
-  EXPECT_TRUE(map_.end() == map_.find(key));
-  EXPECT_TRUE(map_.begin() == map_.end());
-}
-
-static void CopyConstructorHelper(Arena* arena, Map<int32, int32>* m) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1 = 100;
-  int32 value2 = 101;
-
-  std::map<int32, int32> map;
-  map[key1] = value1;
-  map[key2] = value2;
-
-  m->insert(map.begin(), map.end());
-
-  Map<int32, int32> other(*m);
-
-  EXPECT_EQ(2, other.size());
-  EXPECT_EQ(value1, other.at(key1));
-  EXPECT_EQ(value2, other.at(key2));
-}
-
-TEST_F(MapImplTest, CopyConstructorWithArena) {
-  Arena a;
-  CopyConstructorHelper(&a, &map_);
-}
-
-TEST_F(MapImplTest, CopyConstructorWithoutArena) {
-  CopyConstructorHelper(NULL, &map_);
-}
-
-TEST_F(MapImplTest, IterConstructor) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1 = 100;
-  int32 value2 = 101;
-
-  std::map<int32, int32> map;
-  map[key1] = value1;
-  map[key2] = value2;
-
-  Map<int32, int32> new_map(map.begin(), map.end());
-
-  EXPECT_EQ(2, new_map.size());
-  EXPECT_EQ(value1, new_map.at(key1));
-  EXPECT_EQ(value2, new_map.at(key2));
-}
-
-TEST_F(MapImplTest, Assigner) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1 = 100;
-  int32 value2 = 101;
-
-  std::map<int32, int32> map;
-  map[key1] = value1;
-  map[key2] = value2;
-
-  map_.insert(map.begin(), map.end());
-
-  Map<int32, int32> other;
-  int32 key_other = 123;
-  int32 value_other = 321;
-  other[key_other] = value_other;
-  EXPECT_EQ(1, other.size());
-
-  other = map_;
-
-  EXPECT_EQ(2, other.size());
-  EXPECT_EQ(value1, other.at(key1));
-  EXPECT_EQ(value2, other.at(key2));
-  EXPECT_TRUE(other.find(key_other) == other.end());
-
-  // Self assign
-  other = *&other;  // Avoid -Wself-assign.
-  EXPECT_EQ(2, other.size());
-  EXPECT_EQ(value1, other.at(key1));
-  EXPECT_EQ(value2, other.at(key2));
-}
-
-TEST_F(MapImplTest, Rehash) {
-  const int test_size = 50;
-  std::map<int32, int32> reference_map;
-  for (int i = 0; i < test_size; i++) {
-    reference_map[i] = i;
-  }
-  for (int i = 0; i < test_size; i++) {
-    map_[i] = reference_map[i];
-    EXPECT_EQ(reference_map[i], map_[i]);
-  }
-  for (int i = 0; i < test_size; i++) {
-    map_.erase(i);
-    EXPECT_TRUE(map_.end() == map_.find(i));
-  }
-  EXPECT_TRUE(map_.empty());
-}
-
-TEST_F(MapImplTest, EqualRange) {
-  int key = 100, key_missing = 101;
-  map_[key] = 100;
-
-  std::pair<Map<int32, int32>::iterator, Map<int32, int32>::iterator> range =
-      map_.equal_range(key);
-  EXPECT_TRUE(map_.find(key) == range.first);
-  EXPECT_TRUE(++map_.find(key) == range.second);
-
-  range = map_.equal_range(key_missing);
-  EXPECT_TRUE(map_.end() == range.first);
-  EXPECT_TRUE(map_.end() == range.second);
-
-  std::pair<Map<int32, int32>::const_iterator,
-            Map<int32, int32>::const_iterator>
-      const_range = const_map_.equal_range(key);
-  EXPECT_TRUE(const_map_.find(key) == const_range.first);
-  EXPECT_TRUE(++const_map_.find(key) == const_range.second);
-
-  const_range = const_map_.equal_range(key_missing);
-  EXPECT_TRUE(const_map_.end() == const_range.first);
-  EXPECT_TRUE(const_map_.end() == const_range.second);
-}
-
-TEST_F(MapImplTest, ConvertToStdMap) {
-  map_[100] = 101;
-  std::map<int32, int32> std_map(map_.begin(), map_.end());
-  EXPECT_EQ(1, std_map.size());
-  EXPECT_EQ(101, std_map[100]);
-}
-
-TEST_F(MapImplTest, ConvertToStdVectorOfPairs) {
-  map_[100] = 101;
-  std::vector<std::pair<int32, int32> > std_vec(map_.begin(), map_.end());
-  EXPECT_EQ(1, std_vec.size());
-  EXPECT_EQ(100, std_vec[0].first);
-  EXPECT_EQ(101, std_vec[0].second);
-}
-
-TEST_F(MapImplTest, SwapBasic) {
-  Map<int32, int32> another;
-  map_[9398] = 41999;
-  another[9398] = 41999;
-  another[8070] = 42056;
-  another.swap(map_);
-  EXPECT_THAT(another,
-              testing::UnorderedElementsAre(testing::Pair(9398, 41999)));
-  EXPECT_THAT(map_, testing::UnorderedElementsAre(testing::Pair(8070, 42056),
-                                                  testing::Pair(9398, 41999)));
-}
-
-TEST_F(MapImplTest, SwapArena) {
-  Arena arena1, arena2;
-  Map<int32, int32> m1(&arena1);
-  Map<int32, int32> m2(&arena2);
-  map_[9398] = 41999;
-  m1[9398] = 41999;
-  m1[8070] = 42056;
-  m2[10244] = 10247;
-  m2[8070] = 42056;
-  m1.swap(map_);
-  EXPECT_THAT(m1, testing::UnorderedElementsAre(testing::Pair(9398, 41999)));
-  EXPECT_THAT(map_, testing::UnorderedElementsAre(testing::Pair(8070, 42056),
-                                                  testing::Pair(9398, 41999)));
-  m2.swap(m1);
-  EXPECT_THAT(m1, testing::UnorderedElementsAre(testing::Pair(8070, 42056),
-                                                testing::Pair(10244, 10247)));
-  EXPECT_THAT(m2, testing::UnorderedElementsAre(testing::Pair(9398, 41999)));
-}
-
-TEST_F(MapImplTest, CopyAssignMapIterator) {
-  TestMap message;
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaMapReflection(&message);
-  MapIterator it1 = reflection_tester.MapBegin(&message, "map_int32_int32");
-  MapIterator it2 = reflection_tester.MapEnd(&message, "map_int32_int32");
-  it2 = it1;
-  EXPECT_EQ(it1.GetKey().GetInt32Value(), it2.GetKey().GetInt32Value());
-}
-
-TEST_F(MapImplTest, SpaceUsed) {
-  constexpr size_t kMinCap = 8;
-
-  Map<int32, int32> m;
-  // An newly constructed map should have no space used.
-  EXPECT_EQ(m.SpaceUsedExcludingSelfLong(), 0);
-
-  size_t capacity = kMinCap;
-  for (int i = 0; i < 100; ++i) {
-    m[i];
-    static constexpr double kMaxLoadFactor = .75;
-    if (m.size() >= capacity * kMaxLoadFactor) {
-      capacity *= 2;
-    }
-    EXPECT_EQ(m.SpaceUsedExcludingSelfLong(),
-              sizeof(void*) * capacity +
-                  m.size() * sizeof(std::pair<std::pair<int32, int32>, void*>));
-  }
-
-  // Test string, and non-scalar keys.
-  Map<std::string, int32> m2;
-  std::string str = "Some arbitrarily large string";
-  m2[str] = 1;
-  EXPECT_EQ(m2.SpaceUsedExcludingSelfLong(),
-            sizeof(void*) * kMinCap +
-                sizeof(std::pair<std::pair<std::string, int32>, void*>) +
-                internal::StringSpaceUsedExcludingSelfLong(str));
-
-  // Test messages, and non-scalar values.
-  Map<int32, TestAllTypes> m3;
-  m3[0].set_optional_string(str);
-  EXPECT_EQ(m3.SpaceUsedExcludingSelfLong(),
-            sizeof(void*) * kMinCap +
-                sizeof(std::pair<std::pair<int32, TestAllTypes>, void*>) +
-                m3[0].SpaceUsedLong() - sizeof(m3[0]));
-}
-
-// Attempts to verify that a map with keys a and b has a random ordering. This
-// function returns true if it succeeds in observing both possible orderings.
-bool MapOrderingIsRandom(int a, int b) {
-  bool saw_a_first = false;
-  bool saw_b_first = false;
-
-  for (int i = 0; i < 50; ++i) {
-    Map<int32, int32> m;
-    m[a] = 0;
-    m[b] = 0;
-    int32 first_element = m.begin()->first;
-    if (first_element == a) saw_a_first = true;
-    if (first_element == b) saw_b_first = true;
-    if (saw_a_first && saw_b_first) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-// This test verifies that the iteration order is reasonably random even for
-// small maps. Currently we only have sufficient randomness for debug builds and
-// builds where we can use the RDTSC instruction, so we only test for those
-// builds.
-#if defined(__x86_64__) && defined(__GNUC__) && \
-    !defined(GOOGLE_PROTOBUF_NO_RDTSC)
-TEST_F(MapImplTest, RandomOrdering) {
-  for (int i = 0; i < 10; ++i) {
-    for (int j = i + 1; j < 10; ++j) {
-      EXPECT_TRUE(MapOrderingIsRandom(i, j))
-          << "Map with keys " << i << " and " << j
-          << " has deterministic ordering";
-    }
-  }
-}
-#endif
-
-template <typename Key>
-void TestTransparent(const Key& key, const Key& miss_key) {
-  Map<std::string, int> m;
-  const auto& cm = m;
-
-  m.insert({"ABC", 1});
-
-  const auto abc_it = m.begin();
-
-  m.insert({"DEF", 2});
-
-  using testing::Pair;
-  using testing::UnorderedElementsAre;
-
-  EXPECT_EQ(m.at(key), 1);
-  EXPECT_EQ(cm.at(key), 1);
-
-#ifdef PROTOBUF_HAS_DEATH_TEST
-  EXPECT_DEATH(m.at(miss_key), "");
-  EXPECT_DEATH(cm.at(miss_key), "");
-#endif  // PROTOBUF_HAS_DEATH_TEST
-
-  EXPECT_EQ(m.count(key), 1);
-  EXPECT_EQ(cm.count(key), 1);
-  EXPECT_EQ(m.count(miss_key), 0);
-  EXPECT_EQ(cm.count(miss_key), 0);
-
-  EXPECT_EQ(m.find(key), abc_it);
-  EXPECT_EQ(cm.find(key), abc_it);
-  EXPECT_EQ(m.find(miss_key), m.end());
-  EXPECT_EQ(cm.find(miss_key), cm.end());
-
-  EXPECT_TRUE(m.contains(key));
-  EXPECT_TRUE(cm.contains(key));
-  EXPECT_FALSE(m.contains(miss_key));
-  EXPECT_FALSE(cm.contains(miss_key));
-
-  EXPECT_THAT(m.equal_range(key), Pair(abc_it, std::next(abc_it)));
-  EXPECT_THAT(cm.equal_range(key), Pair(abc_it, std::next(abc_it)));
-  EXPECT_THAT(m.equal_range(miss_key), Pair(m.end(), m.end()));
-  EXPECT_THAT(cm.equal_range(miss_key), Pair(m.end(), m.end()));
-
-  EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 1), Pair("DEF", 2)));
-  EXPECT_EQ(m.erase(key), 1);
-  EXPECT_THAT(m, UnorderedElementsAre(Pair("DEF", 2)));
-  EXPECT_EQ(m.erase(key), 0);
-  EXPECT_EQ(m.erase(miss_key), 0);
-  EXPECT_THAT(m, UnorderedElementsAre(Pair("DEF", 2)));
-
-  m[key];
-  EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 0), Pair("DEF", 2)));
-  m[key] = 1;
-  EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 1), Pair("DEF", 2)));
-}
-
-TEST_F(MapImplTest, TransparentLookupForString) {
-  TestTransparent("ABC", "LKJ");
-  TestTransparent(std::string("ABC"), std::string("LKJ"));
-#if defined(__cpp_lib_string_view)
-  TestTransparent(std::string_view("ABC"), std::string_view("LKJ"));
-#endif  // defined(__cpp_lib_string_view)
-
-  // std::reference_wrapper
-  std::string abc = "ABC", lkj = "LKJ";
-  TestTransparent(std::ref(abc), std::ref(lkj));
-  TestTransparent(std::cref(abc), std::cref(lkj));
-}
-
-TEST_F(MapImplTest, ConstInit) {
-  PROTOBUF_CONSTINIT static Map<int, int> map;  // NOLINT
-  EXPECT_TRUE(map.empty());
-}
-
-// Map Field Reflection Test ========================================
-
-static int Func(int i, int j) { return i * j; }
-
-static std::string StrFunc(int i, int j) { return StrCat(Func(i, j)); }
-
-static int Int(const std::string& value) {
-  int result = 0;
-  std::istringstream(value) >> result;
-  return result;
-}
-
-}  // namespace
-
-// This class is a friend, so no anonymous namespace.
-class MapFieldReflectionTest : public testing::Test {
- protected:
-  typedef FieldDescriptor FD;
-
-  int MapSize(const Reflection* reflection, const FieldDescriptor* field,
-              const Message& message) {
-    return reflection->MapSize(message, field);
-  }
-};
-
-namespace {
-
-TEST_F(MapFieldReflectionTest, RegularFields) {
-  TestMap message;
-  const Reflection* refl = message.GetReflection();
-  const Descriptor* desc = message.GetDescriptor();
-
-  Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
-  Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
-  Map<std::string, std::string>* map_string_string =
-      message.mutable_map_string_string();
-  Map<int32, ForeignMessage>* map_int32_foreign_message =
-      message.mutable_map_int32_foreign_message();
-
-  for (int i = 0; i < 10; ++i) {
-    (*map_int32_int32)[i] = Func(i, 1);
-    (*map_int32_double)[i] = Func(i, 2);
-    (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
-    (*map_int32_foreign_message)[i].set_c(Func(i, 6));
-  }
-
-  // Get FieldDescriptors for all the fields of interest.
-  const FieldDescriptor* fd_map_int32_int32 =
-      desc->FindFieldByName("map_int32_int32");
-  const FieldDescriptor* fd_map_int32_double =
-      desc->FindFieldByName("map_int32_double");
-  const FieldDescriptor* fd_map_string_string =
-      desc->FindFieldByName("map_string_string");
-  const FieldDescriptor* fd_map_int32_foreign_message =
-      desc->FindFieldByName("map_int32_foreign_message");
-
-  const FieldDescriptor* fd_map_int32_in32_key =
-      fd_map_int32_int32->message_type()->FindFieldByName("key");
-  const FieldDescriptor* fd_map_int32_in32_value =
-      fd_map_int32_int32->message_type()->FindFieldByName("value");
-  const FieldDescriptor* fd_map_int32_double_key =
-      fd_map_int32_double->message_type()->FindFieldByName("key");
-  const FieldDescriptor* fd_map_int32_double_value =
-      fd_map_int32_double->message_type()->FindFieldByName("value");
-  const FieldDescriptor* fd_map_string_string_key =
-      fd_map_string_string->message_type()->FindFieldByName("key");
-  const FieldDescriptor* fd_map_string_string_value =
-      fd_map_string_string->message_type()->FindFieldByName("value");
-  const FieldDescriptor* fd_map_int32_foreign_message_key =
-      fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
-  const FieldDescriptor* fd_map_int32_foreign_message_value =
-      fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
-
-  // Get RepeatedPtrField objects for all fields of interest.
-  const RepeatedPtrField<Message>& mf_int32_int32 =
-      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_int32);
-  const RepeatedPtrField<Message>& mf_int32_double =
-      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_double);
-  const RepeatedPtrField<Message>& mf_string_string =
-      refl->GetRepeatedPtrField<Message>(message, fd_map_string_string);
-  const RepeatedPtrField<Message>& mf_int32_foreign_message =
-      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_foreign_message);
-
-  // Get mutable RepeatedPtrField objects for all fields of interest.
-  RepeatedPtrField<Message>* mmf_int32_int32 =
-      refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_int32);
-  RepeatedPtrField<Message>* mmf_int32_double =
-      refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_double);
-  RepeatedPtrField<Message>* mmf_string_string =
-      refl->MutableRepeatedPtrField<Message>(&message, fd_map_string_string);
-  RepeatedPtrField<Message>* mmf_int32_foreign_message =
-      refl->MutableRepeatedPtrField<Message>(&message,
-                                             fd_map_int32_foreign_message);
-
-  // Make sure we can do gets through the RepeatedPtrField objects.
-  for (int i = 0; i < 10; ++i) {
-    {
-      // Check gets through const objects.
-      const Message& message_int32_int32 = mf_int32_int32.Get(i);
-      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
-          message_int32_int32, fd_map_int32_in32_key);
-      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
-          message_int32_int32, fd_map_int32_in32_value);
-      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
-
-      const Message& message_int32_double = mf_int32_double.Get(i);
-      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
-          message_int32_double, fd_map_int32_double_key);
-      double value_int32_double =
-          message_int32_double.GetReflection()->GetDouble(
-              message_int32_double, fd_map_int32_double_value);
-      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
-
-      const Message& message_string_string = mf_string_string.Get(i);
-      std::string key_string_string =
-          message_string_string.GetReflection()->GetString(
-              message_string_string, fd_map_string_string_key);
-      std::string value_string_string =
-          message_string_string.GetReflection()->GetString(
-              message_string_string, fd_map_string_string_value);
-      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
-
-      const Message& message_int32_message = mf_int32_foreign_message.Get(i);
-      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
-          message_int32_message, fd_map_int32_foreign_message_key);
-      const ForeignMessage& value_int32_message =
-          down_cast<const ForeignMessage&>(
-              message_int32_message.GetReflection()->GetMessage(
-                  message_int32_message, fd_map_int32_foreign_message_value));
-      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
-    }
-
-    {
-      // Check gets through mutable objects.
-      const Message& message_int32_int32 = mmf_int32_int32->Get(i);
-      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
-          message_int32_int32, fd_map_int32_in32_key);
-      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
-          message_int32_int32, fd_map_int32_in32_value);
-      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
-
-      const Message& message_int32_double = mmf_int32_double->Get(i);
-      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
-          message_int32_double, fd_map_int32_double_key);
-      double value_int32_double =
-          message_int32_double.GetReflection()->GetDouble(
-              message_int32_double, fd_map_int32_double_value);
-      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
-
-      const Message& message_string_string = mmf_string_string->Get(i);
-      std::string key_string_string =
-          message_string_string.GetReflection()->GetString(
-              message_string_string, fd_map_string_string_key);
-      std::string value_string_string =
-          message_string_string.GetReflection()->GetString(
-              message_string_string, fd_map_string_string_value);
-      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
-
-      const Message& message_int32_message = mmf_int32_foreign_message->Get(i);
-      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
-          message_int32_message, fd_map_int32_foreign_message_key);
-      const ForeignMessage& value_int32_message =
-          down_cast<const ForeignMessage&>(
-              message_int32_message.GetReflection()->GetMessage(
-                  message_int32_message, fd_map_int32_foreign_message_value));
-      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
-    }
-  }
-
-  // Do sets through the RepeatedPtrField objects.
-  for (int i = 0; i < 10; i++) {
-    {
-      Message* message_int32_int32 = mmf_int32_int32->Mutable(i);
-      int32 key_int32_int32 = message_int32_int32->GetReflection()->GetInt32(
-          *message_int32_int32, fd_map_int32_in32_key);
-      message_int32_int32->GetReflection()->SetInt32(message_int32_int32,
-                                                     fd_map_int32_in32_value,
-                                                     Func(key_int32_int32, -1));
-
-      Message* message_int32_double = mmf_int32_double->Mutable(i);
-      int32 key_int32_double = message_int32_double->GetReflection()->GetInt32(
-          *message_int32_double, fd_map_int32_double_key);
-      message_int32_double->GetReflection()->SetDouble(
-          message_int32_double, fd_map_int32_double_value,
-          Func(key_int32_double, -2));
-
-      Message* message_string_string = mmf_string_string->Mutable(i);
-      std::string key_string_string =
-          message_string_string->GetReflection()->GetString(
-              *message_string_string, fd_map_string_string_key);
-      message_string_string->GetReflection()->SetString(
-          message_string_string, fd_map_string_string_value,
-          StrFunc(Int(key_string_string), -5));
-
-      Message* message_int32_message = mmf_int32_foreign_message->Mutable(i);
-      int32 key_int32_message =
-          message_int32_message->GetReflection()->GetInt32(
-              *message_int32_message, fd_map_int32_foreign_message_key);
-      ForeignMessage* value_int32_message = down_cast<ForeignMessage*>(
-          message_int32_message->GetReflection()->MutableMessage(
-              message_int32_message, fd_map_int32_foreign_message_value));
-      value_int32_message->set_c(Func(key_int32_message, -6));
-    }
-  }
-
-  // Check gets through mutable objects.
-  for (int i = 0; i < 10; i++) {
-    EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
-    EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
-    EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
-    EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
-  }
-}
-
-TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) {
-  TestMap message;
-  const Reflection* refl = message.GetReflection();
-  const Descriptor* desc = message.GetDescriptor();
-
-  Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
-  Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
-  Map<std::string, std::string>* map_string_string =
-      message.mutable_map_string_string();
-  Map<int32, ForeignMessage>* map_int32_foreign_message =
-      message.mutable_map_int32_foreign_message();
-
-  for (int i = 0; i < 10; ++i) {
-    (*map_int32_int32)[i] = Func(i, 1);
-    (*map_int32_double)[i] = Func(i, 2);
-    (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
-    (*map_int32_foreign_message)[i].set_c(Func(i, 6));
-  }
-
-  // Get FieldDescriptors for all the fields of interest.
-  const FieldDescriptor* fd_map_int32_int32 =
-      desc->FindFieldByName("map_int32_int32");
-  const FieldDescriptor* fd_map_int32_double =
-      desc->FindFieldByName("map_int32_double");
-  const FieldDescriptor* fd_map_string_string =
-      desc->FindFieldByName("map_string_string");
-  const FieldDescriptor* fd_map_int32_foreign_message =
-      desc->FindFieldByName("map_int32_foreign_message");
-
-  const FieldDescriptor* fd_map_int32_in32_key =
-      fd_map_int32_int32->message_type()->FindFieldByName("key");
-  const FieldDescriptor* fd_map_int32_in32_value =
-      fd_map_int32_int32->message_type()->FindFieldByName("value");
-  const FieldDescriptor* fd_map_int32_double_key =
-      fd_map_int32_double->message_type()->FindFieldByName("key");
-  const FieldDescriptor* fd_map_int32_double_value =
-      fd_map_int32_double->message_type()->FindFieldByName("value");
-  const FieldDescriptor* fd_map_string_string_key =
-      fd_map_string_string->message_type()->FindFieldByName("key");
-  const FieldDescriptor* fd_map_string_string_value =
-      fd_map_string_string->message_type()->FindFieldByName("value");
-  const FieldDescriptor* fd_map_int32_foreign_message_key =
-      fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
-  const FieldDescriptor* fd_map_int32_foreign_message_value =
-      fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
-
-  // Get RepeatedFieldRef objects for all fields of interest.
-  const RepeatedFieldRef<Message> mf_int32_int32 =
-      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_int32);
-  const RepeatedFieldRef<Message> mf_int32_double =
-      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_double);
-  const RepeatedFieldRef<Message> mf_string_string =
-      refl->GetRepeatedFieldRef<Message>(message, fd_map_string_string);
-  const RepeatedFieldRef<Message> mf_int32_foreign_message =
-      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_foreign_message);
-
-  // Get mutable RepeatedFieldRef objects for all fields of interest.
-  const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
-      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_int32);
-  const MutableRepeatedFieldRef<Message> mmf_int32_double =
-      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_double);
-  const MutableRepeatedFieldRef<Message> mmf_string_string =
-      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_string_string);
-  const MutableRepeatedFieldRef<Message> mmf_int32_foreign_message =
-      refl->GetMutableRepeatedFieldRef<Message>(&message,
-                                                fd_map_int32_foreign_message);
-
-  // Get entry default instances
-  std::unique_ptr<Message> entry_int32_int32(
-      MessageFactory::generated_factory()
-          ->GetPrototype(fd_map_int32_int32->message_type())
-          ->New(message.GetArena()));
-  std::unique_ptr<Message> entry_int32_double(
-      MessageFactory::generated_factory()
-          ->GetPrototype(fd_map_int32_double->message_type())
-          ->New(message.GetArena()));
-  std::unique_ptr<Message> entry_string_string(
-      MessageFactory::generated_factory()
-          ->GetPrototype(fd_map_string_string->message_type())
-          ->New(message.GetArena()));
-  std::unique_ptr<Message> entry_int32_foreign_message(
-      MessageFactory::generated_factory()
-          ->GetPrototype(fd_map_int32_foreign_message->message_type())
-          ->New(message.GetArena()));
-
-  EXPECT_EQ(10, mf_int32_int32.size());
-  EXPECT_EQ(10, mmf_int32_int32.size());
-  EXPECT_EQ(10, mf_int32_double.size());
-  EXPECT_EQ(10, mmf_int32_double.size());
-  EXPECT_EQ(10, mf_string_string.size());
-  EXPECT_EQ(10, mmf_string_string.size());
-  EXPECT_EQ(10, mf_int32_foreign_message.size());
-  EXPECT_EQ(10, mmf_int32_foreign_message.size());
-
-  EXPECT_FALSE(mf_int32_int32.empty());
-  EXPECT_FALSE(mmf_int32_int32.empty());
-  EXPECT_FALSE(mf_int32_double.empty());
-  EXPECT_FALSE(mmf_int32_double.empty());
-  EXPECT_FALSE(mf_string_string.empty());
-  EXPECT_FALSE(mmf_string_string.empty());
-  EXPECT_FALSE(mf_int32_foreign_message.empty());
-  EXPECT_FALSE(mmf_int32_foreign_message.empty());
-
-  // Make sure we can do gets through the RepeatedFieldRef objects.
-  for (int i = 0; i < 10; ++i) {
-    {
-      // Check gets through const objects.
-      const Message& message_int32_int32 =
-          mf_int32_int32.Get(i, entry_int32_int32.get());
-      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
-          message_int32_int32, fd_map_int32_in32_key);
-      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
-          message_int32_int32, fd_map_int32_in32_value);
-      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
-
-      const Message& message_int32_double =
-          mf_int32_double.Get(i, entry_int32_double.get());
-      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
-          message_int32_double, fd_map_int32_double_key);
-      double value_int32_double =
-          message_int32_double.GetReflection()->GetDouble(
-              message_int32_double, fd_map_int32_double_value);
-      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
-
-      const Message& message_string_string =
-          mf_string_string.Get(i, entry_string_string.get());
-      std::string key_string_string =
-          message_string_string.GetReflection()->GetString(
-              message_string_string, fd_map_string_string_key);
-      std::string value_string_string =
-          message_string_string.GetReflection()->GetString(
-              message_string_string, fd_map_string_string_value);
-      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
-
-      const Message& message_int32_message =
-          mf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
-      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
-          message_int32_message, fd_map_int32_foreign_message_key);
-      const ForeignMessage& value_int32_message =
-          down_cast<const ForeignMessage&>(
-              message_int32_message.GetReflection()->GetMessage(
-                  message_int32_message, fd_map_int32_foreign_message_value));
-      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
-    }
-
-    {
-      // Check gets through mutable objects.
-      const Message& message_int32_int32 =
-          mmf_int32_int32.Get(i, entry_int32_int32.get());
-      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
-          message_int32_int32, fd_map_int32_in32_key);
-      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
-          message_int32_int32, fd_map_int32_in32_value);
-      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
-
-      const Message& message_int32_double =
-          mmf_int32_double.Get(i, entry_int32_double.get());
-      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
-          message_int32_double, fd_map_int32_double_key);
-      double value_int32_double =
-          message_int32_double.GetReflection()->GetDouble(
-              message_int32_double, fd_map_int32_double_value);
-      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
-
-      const Message& message_string_string =
-          mmf_string_string.Get(i, entry_string_string.get());
-      std::string key_string_string =
-          message_string_string.GetReflection()->GetString(
-              message_string_string, fd_map_string_string_key);
-      std::string value_string_string =
-          message_string_string.GetReflection()->GetString(
-              message_string_string, fd_map_string_string_value);
-      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
-
-      const Message& message_int32_message =
-          mmf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
-      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
-          message_int32_message, fd_map_int32_foreign_message_key);
-      const ForeignMessage& value_int32_message =
-          down_cast<const ForeignMessage&>(
-              message_int32_message.GetReflection()->GetMessage(
-                  message_int32_message, fd_map_int32_foreign_message_value));
-      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
-    }
-  }
-
-  // Make sure we can do sets through the RepeatedFieldRef objects.
-  for (int i = 0; i < 10; i++) {
-    const Message& message_int32_int32 =
-        mmf_int32_int32.Get(i, entry_int32_int32.get());
-    int key = message_int32_int32.GetReflection()->GetInt32(
-        message_int32_int32, fd_map_int32_in32_key);
-
-    entry_int32_int32->GetReflection()->SetInt32(
-        entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
-        key);
-    entry_int32_int32->GetReflection()->SetInt32(
-        entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
-        Func(key, -1));
-    entry_int32_double->GetReflection()->SetInt32(
-        entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
-        key);
-    entry_int32_double->GetReflection()->SetDouble(
-        entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
-        Func(key, -2));
-    entry_string_string->GetReflection()->SetString(
-        entry_string_string.get(),
-        fd_map_string_string->message_type()->field(0), StrFunc(key, 1));
-    entry_string_string->GetReflection()->SetString(
-        entry_string_string.get(),
-        fd_map_string_string->message_type()->field(1), StrFunc(key, -5));
-    entry_int32_foreign_message->GetReflection()->SetInt32(
-        entry_int32_foreign_message.get(),
-        fd_map_int32_foreign_message->message_type()->field(0), key);
-    Message* value_message =
-        entry_int32_foreign_message->GetReflection()->MutableMessage(
-            entry_int32_foreign_message.get(),
-            fd_map_int32_foreign_message->message_type()->field(1));
-    value_message->GetReflection()->SetInt32(
-        value_message, value_message->GetDescriptor()->FindFieldByName("c"),
-        Func(key, -6));
-
-    mmf_int32_int32.Set(i, *entry_int32_int32);
-    mmf_int32_double.Set(i, *entry_int32_double);
-    mmf_string_string.Set(i, *entry_string_string);
-    mmf_int32_foreign_message.Set(i, *entry_int32_foreign_message);
-  }
-
-  for (int i = 0; i < 10; i++) {
-    EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
-    EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
-    EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
-    EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
-  }
-
-  // Test iterators.
-  {
-    int index = 0;
-    std::unordered_map<int32, int32> result;
-    for (RepeatedFieldRef<Message>::iterator it = mf_int32_int32.begin();
-         it != mf_int32_int32.end(); ++it) {
-      const Message& message = *it;
-      int32 key =
-          message.GetReflection()->GetInt32(message, fd_map_int32_in32_key);
-      int32 value =
-          message.GetReflection()->GetInt32(message, fd_map_int32_in32_value);
-      result[key] = value;
-      ++index;
-    }
-    EXPECT_EQ(10, index);
-    for (std::unordered_map<int32, int32>::const_iterator it = result.begin();
-         it != result.end(); ++it) {
-      EXPECT_EQ(message.map_int32_int32().at(it->first), it->second);
-    }
-  }
-
-  {
-    int index = 0;
-    std::unordered_map<int32, double> result;
-    for (RepeatedFieldRef<Message>::iterator it = mf_int32_double.begin();
-         it != mf_int32_double.end(); ++it) {
-      const Message& message = *it;
-      int32 key =
-          message.GetReflection()->GetInt32(message, fd_map_int32_double_key);
-      double value = message.GetReflection()->GetDouble(
-          message, fd_map_int32_double_value);
-      result[key] = value;
-      ++index;
-    }
-    EXPECT_EQ(10, index);
-    for (std::unordered_map<int32, double>::const_iterator it = result.begin();
-         it != result.end(); ++it) {
-      EXPECT_EQ(message.map_int32_double().at(it->first), it->second);
-    }
-  }
-
-  {
-    int index = 0;
-    std::unordered_map<std::string, std::string> result;
-    for (RepeatedFieldRef<Message>::iterator it = mf_string_string.begin();
-         it != mf_string_string.end(); ++it) {
-      const Message& message = *it;
-      std::string key =
-          message.GetReflection()->GetString(message, fd_map_string_string_key);
-      std::string value = message.GetReflection()->GetString(
-          message, fd_map_string_string_value);
-      result[key] = value;
-      ++index;
-    }
-    EXPECT_EQ(10, index);
-    for (std::unordered_map<std::string, std::string>::const_iterator it =
-             result.begin();
-         it != result.end(); ++it) {
-      EXPECT_EQ(message.map_string_string().at(it->first), it->second);
-    }
-  }
-
-  {
-    int index = 0;
-    std::map<int32, ForeignMessage> result;
-    for (RepeatedFieldRef<Message>::iterator it =
-             mf_int32_foreign_message.begin();
-         it != mf_int32_foreign_message.end(); ++it) {
-      const Message& message = *it;
-      int32 key = message.GetReflection()->GetInt32(
-          message, fd_map_int32_foreign_message_key);
-      const ForeignMessage& sub_message =
-          down_cast<const ForeignMessage&>(message.GetReflection()->GetMessage(
-              message, fd_map_int32_foreign_message_value));
-      result[key].MergeFrom(sub_message);
-      ++index;
-    }
-    EXPECT_EQ(10, index);
-    for (std::map<int32, ForeignMessage>::const_iterator it = result.begin();
-         it != result.end(); ++it) {
-      EXPECT_EQ(message.map_int32_foreign_message().at(it->first).c(),
-                it->second.c());
-    }
-  }
-
-  // Test MutableRepeatedFieldRef::Add()
-  entry_int32_int32->GetReflection()->SetInt32(
-      entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
-      4321);
-  entry_int32_int32->GetReflection()->SetInt32(
-      entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
-      1234);
-  mmf_int32_int32.Add(*entry_int32_int32);
-  EXPECT_EQ(1234, message.map_int32_int32().at(4321));
-
-  entry_int32_double->GetReflection()->SetInt32(
-      entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
-      4321);
-  entry_int32_double->GetReflection()->SetDouble(
-      entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
-      1234.0);
-  mmf_int32_double.Add(*entry_int32_double);
-  EXPECT_EQ(1234.0, message.map_int32_double().at(4321));
-
-  entry_string_string->GetReflection()->SetString(
-      entry_string_string.get(), fd_map_string_string->message_type()->field(0),
-      "4321");
-  entry_string_string->GetReflection()->SetString(
-      entry_string_string.get(), fd_map_string_string->message_type()->field(1),
-      "1234");
-  mmf_string_string.Add(*entry_string_string);
-  EXPECT_EQ("1234", message.map_string_string().at("4321"));
-
-  entry_int32_foreign_message->GetReflection()->SetInt32(
-      entry_int32_foreign_message.get(),
-      fd_map_int32_foreign_message->message_type()->field(0), 4321);
-  Message* value_message =
-      entry_int32_foreign_message->GetReflection()->MutableMessage(
-          entry_int32_foreign_message.get(),
-          fd_map_int32_foreign_message->message_type()->field(1));
-  ForeignMessage foreign_message;
-  foreign_message.set_c(1234);
-  value_message->CopyFrom(foreign_message);
-
-  mmf_int32_foreign_message.Add(*entry_int32_foreign_message);
-  EXPECT_EQ(1234, message.map_int32_foreign_message().at(4321).c());
-
-  // Test Reflection::AddAllocatedMessage
-  Message* free_entry_string_string =
-      MessageFactory::generated_factory()
-          ->GetPrototype(fd_map_string_string->message_type())
-          ->New();
-  entry_string_string->GetReflection()->SetString(
-      free_entry_string_string, fd_map_string_string->message_type()->field(0),
-      "4321");
-  entry_string_string->GetReflection()->SetString(
-      free_entry_string_string, fd_map_string_string->message_type()->field(1),
-      "1234");
-  refl->AddAllocatedMessage(&message, fd_map_string_string,
-                            free_entry_string_string);
-
-  // Test MutableRepeatedFieldRef::RemoveLast()
-  mmf_int32_int32.RemoveLast();
-  mmf_int32_double.RemoveLast();
-  mmf_string_string.RemoveLast();
-  mmf_int32_foreign_message.RemoveLast();
-  EXPECT_EQ(10, message.map_int32_int32().size());
-  EXPECT_EQ(10, message.map_int32_double().size());
-  EXPECT_EQ(11, message.map_string_string().size());
-  EXPECT_EQ(10, message.map_int32_foreign_message().size());
-
-  // Test MutableRepeatedFieldRef::SwapElements()
-  {
-    const Message& message0a = mmf_int32_int32.Get(0, entry_int32_int32.get());
-    int32 int32_value0a =
-        message0a.GetReflection()->GetInt32(message0a, fd_map_int32_in32_value);
-    const Message& message9a = mmf_int32_int32.Get(9, entry_int32_int32.get());
-    int32 int32_value9a =
-        message9a.GetReflection()->GetInt32(message9a, fd_map_int32_in32_value);
-
-    mmf_int32_int32.SwapElements(0, 9);
-
-    const Message& message0b = mmf_int32_int32.Get(0, entry_int32_int32.get());
-    int32 int32_value0b =
-        message0b.GetReflection()->GetInt32(message0b, fd_map_int32_in32_value);
-    const Message& message9b = mmf_int32_int32.Get(9, entry_int32_int32.get());
-    int32 int32_value9b =
-        message9b.GetReflection()->GetInt32(message9b, fd_map_int32_in32_value);
-
-    EXPECT_EQ(int32_value9a, int32_value0b);
-    EXPECT_EQ(int32_value0a, int32_value9b);
-  }
-
-  {
-    const Message& message0a =
-        mmf_int32_double.Get(0, entry_int32_double.get());
-    double double_value0a = message0a.GetReflection()->GetDouble(
-        message0a, fd_map_int32_double_value);
-    const Message& message9a =
-        mmf_int32_double.Get(9, entry_int32_double.get());
-    double double_value9a = message9a.GetReflection()->GetDouble(
-        message9a, fd_map_int32_double_value);
-
-    mmf_int32_double.SwapElements(0, 9);
-
-    const Message& message0b =
-        mmf_int32_double.Get(0, entry_int32_double.get());
-    double double_value0b = message0b.GetReflection()->GetDouble(
-        message0b, fd_map_int32_double_value);
-    const Message& message9b =
-        mmf_int32_double.Get(9, entry_int32_double.get());
-    double double_value9b = message9b.GetReflection()->GetDouble(
-        message9b, fd_map_int32_double_value);
-
-    EXPECT_EQ(double_value9a, double_value0b);
-    EXPECT_EQ(double_value0a, double_value9b);
-  }
-
-  {
-    const Message& message0a =
-        mmf_string_string.Get(0, entry_string_string.get());
-    std::string string_value0a = message0a.GetReflection()->GetString(
-        message0a, fd_map_string_string_value);
-    const Message& message9a =
-        mmf_string_string.Get(9, entry_string_string.get());
-    std::string string_value9a = message9a.GetReflection()->GetString(
-        message9a, fd_map_string_string_value);
-
-    mmf_string_string.SwapElements(0, 9);
-
-    const Message& message0b =
-        mmf_string_string.Get(0, entry_string_string.get());
-    std::string string_value0b = message0b.GetReflection()->GetString(
-        message0b, fd_map_string_string_value);
-    const Message& message9b =
-        mmf_string_string.Get(9, entry_string_string.get());
-    std::string string_value9b = message9b.GetReflection()->GetString(
-        message9b, fd_map_string_string_value);
-
-    EXPECT_EQ(string_value9a, string_value0b);
-    EXPECT_EQ(string_value0a, string_value9b);
-  }
-
-  {
-    const Message& message0a =
-        mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
-    const ForeignMessage& sub_message0a =
-        down_cast<const ForeignMessage&>(message0a.GetReflection()->GetMessage(
-            message0a, fd_map_int32_foreign_message_value));
-    int32 int32_value0a = sub_message0a.c();
-    const Message& message9a =
-        mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
-    const ForeignMessage& sub_message9a =
-        down_cast<const ForeignMessage&>(message9a.GetReflection()->GetMessage(
-            message9a, fd_map_int32_foreign_message_value));
-    int32 int32_value9a = sub_message9a.c();
-
-    mmf_int32_foreign_message.SwapElements(0, 9);
-
-    const Message& message0b =
-        mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
-    const ForeignMessage& sub_message0b =
-        down_cast<const ForeignMessage&>(message0b.GetReflection()->GetMessage(
-            message0b, fd_map_int32_foreign_message_value));
-    int32 int32_value0b = sub_message0b.c();
-    const Message& message9b =
-        mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
-    const ForeignMessage& sub_message9b =
-        down_cast<const ForeignMessage&>(message9b.GetReflection()->GetMessage(
-            message9b, fd_map_int32_foreign_message_value));
-    int32 int32_value9b = sub_message9b.c();
-
-    EXPECT_EQ(int32_value9a, int32_value0b);
-    EXPECT_EQ(int32_value0a, int32_value9b);
-  }
-
-  // TODO(b/181148674): After supporting arena agnostic delete or let map entry
-  // handle heap allocation, this could be removed.
-  if (message.GetArena() != nullptr) {
-    entry_int32_int32.release();
-    entry_int32_double.release();
-    entry_string_string.release();
-    entry_int32_foreign_message.release();
-  }
-}
-
-TEST_F(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
-  // Set-up message content.
-  TestMap m0, m1, m2;
-  for (int i = 0; i < 10; ++i) {
-    (*m0.mutable_map_int32_int32())[i] = Func(i, 1);
-    (*m0.mutable_map_int32_double())[i] = Func(i, 2);
-    (*m0.mutable_map_string_string())[StrFunc(i, 1)] = StrFunc(i, 5);
-    (*m0.mutable_map_int32_foreign_message())[i].set_c(Func(i, 6));
-    (*m1.mutable_map_int32_int32())[i + 10] = Func(i, 11);
-    (*m1.mutable_map_int32_double())[i + 10] = Func(i, 12);
-    (*m1.mutable_map_string_string())[StrFunc(i + 10, 1)] = StrFunc(i, 15);
-    (*m1.mutable_map_int32_foreign_message())[i + 10].set_c(Func(i, 16));
-    (*m2.mutable_map_int32_int32())[i + 20] = Func(i, 21);
-    (*m2.mutable_map_int32_double())[i + 20] = Func(i, 22);
-    (*m2.mutable_map_string_string())[StrFunc(i + 20, 1)] = StrFunc(i, 25);
-    (*m2.mutable_map_int32_foreign_message())[i + 20].set_c(Func(i, 26));
-  }
-
-  const Reflection* refl = m0.GetReflection();
-  const Descriptor* desc = m0.GetDescriptor();
-
-  // Get FieldDescriptors for all the fields of interest.
-  const FieldDescriptor* fd_map_int32_int32 =
-      desc->FindFieldByName("map_int32_int32");
-  const FieldDescriptor* fd_map_int32_double =
-      desc->FindFieldByName("map_int32_double");
-  const FieldDescriptor* fd_map_string_string =
-      desc->FindFieldByName("map_string_string");
-  const FieldDescriptor* fd_map_int32_foreign_message =
-      desc->FindFieldByName("map_int32_foreign_message");
-
-  // Get MutableRepeatedFieldRef objects for all fields of interest.
-  const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
-      refl->GetMutableRepeatedFieldRef<Message>(&m0, fd_map_int32_int32);
-  const MutableRepeatedFieldRef<Message> mmf_int32_double =
-      refl->GetMutableRepeatedFieldRef<Message>(&m0, fd_map_int32_double);
-  const MutableRepeatedFieldRef<Message> mmf_string_string =
-      refl->GetMutableRepeatedFieldRef<Message>(&m0, fd_map_string_string);
-  const MutableRepeatedFieldRef<Message> mmf_int32_foreign_message =
-      refl->GetMutableRepeatedFieldRef<Message>(&m0,
-                                                fd_map_int32_foreign_message);
-
-  // Test MutableRepeatedRef::CopyFrom
-  mmf_int32_int32.CopyFrom(
-      refl->GetRepeatedFieldRef<Message>(m1, fd_map_int32_int32));
-  mmf_int32_double.CopyFrom(
-      refl->GetRepeatedFieldRef<Message>(m1, fd_map_int32_double));
-  mmf_string_string.CopyFrom(
-      refl->GetRepeatedFieldRef<Message>(m1, fd_map_string_string));
-  mmf_int32_foreign_message.CopyFrom(
-      refl->GetRepeatedFieldRef<Message>(m1, fd_map_int32_foreign_message));
-
-  for (int i = 0; i < 10; ++i) {
-    EXPECT_EQ(Func(i, 11), m0.map_int32_int32().at(i + 10));
-    EXPECT_EQ(Func(i, 12), m0.map_int32_double().at(i + 10));
-    EXPECT_EQ(StrFunc(i, 15), m0.map_string_string().at(StrFunc(i + 10, 1)));
-    EXPECT_EQ(Func(i, 16), m0.map_int32_foreign_message().at(i + 10).c());
-  }
-
-  // Test MutableRepeatedRef::MergeFrom
-  mmf_int32_int32.MergeFrom(
-      refl->GetRepeatedFieldRef<Message>(m2, fd_map_int32_int32));
-  mmf_int32_double.MergeFrom(
-      refl->GetRepeatedFieldRef<Message>(m2, fd_map_int32_double));
-  mmf_string_string.MergeFrom(
-      refl->GetRepeatedFieldRef<Message>(m2, fd_map_string_string));
-  mmf_int32_foreign_message.MergeFrom(
-      refl->GetRepeatedFieldRef<Message>(m2, fd_map_int32_foreign_message));
-  for (int i = 0; i < 10; ++i) {
-    EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
-    EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
-    EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
-    EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
-  }
-
-  // Test MutableRepeatedRef::Swap
-  // Swap between m0 and m2.
-  mmf_int32_int32.Swap(
-      refl->GetMutableRepeatedFieldRef<Message>(&m2, fd_map_int32_int32));
-  mmf_int32_double.Swap(
-      refl->GetMutableRepeatedFieldRef<Message>(&m2, fd_map_int32_double));
-  mmf_string_string.Swap(
-      refl->GetMutableRepeatedFieldRef<Message>(&m2, fd_map_string_string));
-  mmf_int32_foreign_message.Swap(refl->GetMutableRepeatedFieldRef<Message>(
-      &m2, fd_map_int32_foreign_message));
-  for (int i = 0; i < 10; ++i) {
-    // Check the content of m0.
-    EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
-    EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
-    EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
-    EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
-
-    // Check the content of m2.
-    EXPECT_EQ(Func(i, 11), m2.map_int32_int32().at(i + 10));
-    EXPECT_EQ(Func(i, 12), m2.map_int32_double().at(i + 10));
-    EXPECT_EQ(StrFunc(i, 15), m2.map_string_string().at(StrFunc(i + 10, 1)));
-    EXPECT_EQ(Func(i, 16), m2.map_int32_foreign_message().at(i + 10).c());
-    EXPECT_EQ(Func(i, 21), m2.map_int32_int32().at(i + 20));
-    EXPECT_EQ(Func(i, 22), m2.map_int32_double().at(i + 20));
-    EXPECT_EQ(StrFunc(i, 25), m2.map_string_string().at(StrFunc(i + 20, 1)));
-    EXPECT_EQ(Func(i, 26), m2.map_int32_foreign_message().at(i + 20).c());
-  }
-
-  // TODO(teboring): add test for duplicated key
-}
-
-TEST_F(MapFieldReflectionTest, MapSizeWithDuplicatedKey) {
-  // Dynamic Message
-  {
-    DynamicMessageFactory factory;
-    std::unique_ptr<Message> message(
-        factory.GetPrototype(unittest::TestMap::descriptor())->New());
-    const Reflection* reflection = message->GetReflection();
-    const FieldDescriptor* field =
-        unittest::TestMap::descriptor()->FindFieldByName("map_int32_int32");
-
-    Message* entry1 = reflection->AddMessage(message.get(), field);
-    Message* entry2 = reflection->AddMessage(message.get(), field);
-
-    const Reflection* entry_reflection = entry1->GetReflection();
-    const FieldDescriptor* key_field =
-        entry1->GetDescriptor()->FindFieldByName("key");
-    entry_reflection->SetInt32(entry1, key_field, 1);
-    entry_reflection->SetInt32(entry2, key_field, 1);
-
-    EXPECT_EQ(2, reflection->FieldSize(*message, field));
-    EXPECT_EQ(1, MapSize(reflection, field, *message));
-    EXPECT_EQ(2, reflection->FieldSize(*message, field));
-  }
-
-  // Generated Message
-  {
-    unittest::TestMap message;
-    const Reflection* reflection = message.GetReflection();
-    const FieldDescriptor* field =
-        message.GetDescriptor()->FindFieldByName("map_int32_int32");
-
-    Message* entry1 = reflection->AddMessage(&message, field);
-    Message* entry2 = reflection->AddMessage(&message, field);
-
-    const Reflection* entry_reflection = entry1->GetReflection();
-    const FieldDescriptor* key_field =
-        entry1->GetDescriptor()->FindFieldByName("key");
-    entry_reflection->SetInt32(entry1, key_field, 1);
-    entry_reflection->SetInt32(entry2, key_field, 1);
-
-    EXPECT_EQ(2, reflection->FieldSize(message, field));
-    EXPECT_EQ(1, MapSize(reflection, field, message));
-  }
-}
-
-TEST_F(MapFieldReflectionTest, UninitializedEntry) {
-  unittest::TestRequiredMessageMap message;
-  const Reflection* reflection = message.GetReflection();
-  const FieldDescriptor* field =
-      message.GetDescriptor()->FindFieldByName("map_field");
-  auto entry = reflection->AddMessage(&message, field);
-  EXPECT_FALSE(entry->IsInitialized());
-  EXPECT_FALSE(message.IsInitialized());
-}
-
-class MyMapEntry
-    : public internal::MapEntry<MyMapEntry, ::google::protobuf::int32, ::google::protobuf::int32,
-                                internal::WireFormatLite::TYPE_INT32,
-                                internal::WireFormatLite::TYPE_INT32> {
- public:
-  constexpr MyMapEntry() {}
-  MyMapEntry(Arena*) { std::abort(); }
-  Metadata GetMetadata() const override { std::abort(); }
-  static bool ValidateKey(void*) { return true; }
-  static bool ValidateValue(void*) { return true; }
-};
-
-class MyMapEntryLite
-    : public internal::MapEntryLite<MyMapEntryLite, ::google::protobuf::int32, ::google::protobuf::int32,
-                                    internal::WireFormatLite::TYPE_INT32,
-                                    internal::WireFormatLite::TYPE_INT32> {
- public:
-  constexpr MyMapEntryLite() {}
-  explicit MyMapEntryLite(Arena*) { std::abort(); }
-  static bool ValidateKey(void*) { return true; }
-  static bool ValidateValue(void*) { return true; }
-};
-
-TEST(MapEntryTest, ConstInit) {
-  // This verifies that `MapEntry`, `MapEntryLite` and `MapEntryImpl` can be
-  // constant initialized.
-  PROTOBUF_CONSTINIT static MyMapEntry entry{};
-  EXPECT_NE(entry.SpaceUsed(), 0);
-
-  PROTOBUF_CONSTINIT static MyMapEntryLite entry_lite{};  // NOLINT
-  EXPECT_TRUE(entry_lite.IsInitialized());
-}
-
-// Generated Message Test ===========================================
-
-TEST(GeneratedMapFieldTest, Accessors) {
-  unittest::TestMap message;
-
-  MapTestUtil::SetMapFields(&message);
-  MapTestUtil::ExpectMapFieldsSet(message);
-
-  MapTestUtil::ModifyMapFields(&message);
-  MapTestUtil::ExpectMapFieldsModified(message);
-}
-
-TEST(GeneratedMapFieldTest, SetMapFieldsInitialized) {
-  unittest::TestMap message;
-
-  MapTestUtil::SetMapFieldsInitialized(&message);
-  MapTestUtil::ExpectMapFieldsSetInitialized(message);
-}
-
-TEST(GeneratedMapFieldTest, Proto2SetMapFieldsInitialized) {
-  unittest::TestEnumMap message;
-  EXPECT_EQ(unittest::PROTO2_MAP_ENUM_FOO,
-            (*message.mutable_known_map_field())[0]);
-}
-
-TEST(GeneratedMapFieldTest, Clear) {
-  unittest::TestMap message;
-
-  MapTestUtil::SetMapFields(&message);
-  message.Clear();
-  MapTestUtil::ExpectClear(message);
-}
-
-TEST(GeneratedMapFieldTest, ClearMessageMap) {
-  unittest::TestMessageMap message;
-
-  // Creates a TestAllTypes with default value
-  TestUtil::ExpectClear((*message.mutable_map_int32_message())[0]);
-}
-
-TEST(GeneratedMapFieldTest, CopyFrom) {
-  unittest::TestMap message1, message2;
-
-  MapTestUtil::SetMapFields(&message1);
-  message2.CopyFrom(message1);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-
-  // Copying from self should be a no-op.
-  message2.CopyFrom(message2);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(GeneratedMapFieldTest, CopyFromMessageMap) {
-  unittest::TestMessageMap message1, message2;
-
-  (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
-  (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
-
-  message1.CopyFrom(message2);
-
-  // Checks repeated field is overwritten.
-  EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
-  EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
-}
-
-TEST(GeneratedMapFieldTest, SwapWithEmpty) {
-  unittest::TestMap message1, message2;
-
-  MapTestUtil::SetMapFields(&message1);
-  MapTestUtil::ExpectMapFieldsSet(message1);
-  MapTestUtil::ExpectClear(message2);
-
-  message1.Swap(&message2);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-  MapTestUtil::ExpectClear(message1);
-}
-
-TEST(GeneratedMapFieldTest, SwapWithSelf) {
-  unittest::TestMap message;
-
-  MapTestUtil::SetMapFields(&message);
-  MapTestUtil::ExpectMapFieldsSet(message);
-
-  message.Swap(&message);
-  MapTestUtil::ExpectMapFieldsSet(message);
-}
-
-TEST(GeneratedMapFieldTest, SwapWithOther) {
-  unittest::TestMap message1, message2;
-
-  MapTestUtil::SetMapFields(&message1);
-  MapTestUtil::SetMapFields(&message2);
-  MapTestUtil::ModifyMapFields(&message2);
-
-  message1.Swap(&message2);
-  MapTestUtil::ExpectMapFieldsModified(message1);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(GeneratedMapFieldTest, CopyConstructor) {
-  unittest::TestMap message1;
-  MapTestUtil::SetMapFields(&message1);
-
-  unittest::TestMap message2(message1);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(GeneratedMapFieldTest, CopyAssignmentOperator) {
-  unittest::TestMap message1;
-  MapTestUtil::SetMapFields(&message1);
-
-  unittest::TestMap message2;
-  message2 = message1;
-  MapTestUtil::ExpectMapFieldsSet(message2);
-
-  // Make sure that self-assignment does something sane.
-  message2.operator=(message2);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || PROTOBUF_RTTI
-TEST(GeneratedMapFieldTest, UpcastCopyFrom) {
-  // Test the CopyFrom method that takes in the generic const Message&
-  // parameter.
-  unittest::TestMap message1, message2;
-
-  MapTestUtil::SetMapFields(&message1);
-
-  const Message* source = implicit_cast<const Message*>(&message1);
-  message2.CopyFrom(*source);
-
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-#endif
-
-#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
-
-TEST(GeneratedMapFieldTest, CopyFromDynamicMessage) {
-  // Test copying from a DynamicMessage, which must fall back to using
-  // reflection.
-  unittest::TestMap message2;
-
-  // Construct a new version of the dynamic message via the factory.
-  DynamicMessageFactory factory;
-  std::unique_ptr<Message> message1;
-  message1.reset(factory.GetPrototype(unittest::TestMap::descriptor())->New());
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaReflection(message1.get());
-  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
-  message2.CopyFrom(*message1);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(GeneratedMapFieldTest, CopyFromDynamicMessageMapReflection) {
-  unittest::TestMap message2;
-
-  // Construct a new version of the dynamic message via the factory.
-  DynamicMessageFactory factory;
-  std::unique_ptr<Message> message1;
-  message1.reset(factory.GetPrototype(unittest::TestMap::descriptor())->New());
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaMapReflection(message1.get());
-  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
-  message2.CopyFrom(*message1);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(GeneratedMapFieldTest, DynamicMessageMergeFromDynamicMessage) {
-  // Construct two dynamic message and sets via map reflection.
-  DynamicMessageFactory factory;
-  std::unique_ptr<Message> message1;
-  message1.reset(factory.GetPrototype(unittest::TestMap::descriptor())->New());
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaMapReflection(message1.get());
-
-  // message2 is created by same factory.
-  std::unique_ptr<Message> message2;
-  message2.reset(factory.GetPrototype(unittest::TestMap::descriptor())->New());
-  reflection_tester.SetMapFieldsViaMapReflection(message2.get());
-
-  // message3 is created by different factory.
-  DynamicMessageFactory factory3;
-  std::unique_ptr<Message> message3;
-  message3.reset(factory3.GetPrototype(unittest::TestMap::descriptor())->New());
-  reflection_tester.SetMapFieldsViaMapReflection(message3.get());
-
-  message2->MergeFrom(*message1);
-  message3->MergeFrom(*message1);
-
-  // Test MergeFrom does not sync to repeated fields and
-  // there is no duplicate keys in text format.
-  std::string output1, output2, output3;
-  TextFormat::PrintToString(*message1, &output1);
-  TextFormat::PrintToString(*message2, &output2);
-  TextFormat::PrintToString(*message3, &output3);
-  EXPECT_EQ(output1, output2);
-  EXPECT_EQ(output1, output3);
-}
-
-TEST(GeneratedMapFieldTest, DynamicMessageCopyFrom) {
-  // Test copying to a DynamicMessage, which must fall back to using reflection.
-  unittest::TestMap message2;
-  MapTestUtil::SetMapFields(&message2);
-
-  // Construct a new version of the dynamic message via the factory.
-  DynamicMessageFactory factory;
-  std::unique_ptr<Message> message1;
-  message1.reset(factory.GetPrototype(unittest::TestMap::descriptor())->New());
-
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  message1->MergeFrom(message2);
-  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
-}
-
-TEST(GeneratedMapFieldTest, DynamicMessageCopyFromMapReflection) {
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  unittest::TestMap message2;
-  reflection_tester.SetMapFieldsViaMapReflection(&message2);
-
-  // Construct a dynamic message via the factory.
-  DynamicMessageFactory factory;
-  std::unique_ptr<Message> message1;
-  message1.reset(factory.GetPrototype(unittest::TestMap::descriptor())->New());
-
-  message1->MergeFrom(message2);
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
-  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
-}
-
-TEST(GeneratedMapFieldTest, SyncDynamicMapWithRepeatedField) {
-  // Construct a dynamic message via the factory.
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  DynamicMessageFactory factory;
-  std::unique_ptr<Message> message;
-  message.reset(factory.GetPrototype(unittest::TestMap::descriptor())->New());
-  reflection_tester.SetMapFieldsViaReflection(message.get());
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message.get());
-  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
-}
-
-#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
-
-TEST(GeneratedMapFieldTest, NonEmptyMergeFrom) {
-  unittest::TestMap message1, message2;
-
-  MapTestUtil::SetMapFields(&message1);
-
-  // This field will test merging into an empty spot.
-  (*message2.mutable_map_int32_int32())[1] = 1;
-  message1.mutable_map_int32_int32()->erase(1);
-
-  // This tests overwriting.
-  (*message2.mutable_map_int32_double())[1] = 1;
-  (*message1.mutable_map_int32_double())[1] = 2;
-
-  message1.MergeFrom(message2);
-  MapTestUtil::ExpectMapFieldsSet(message1);
-
-  // Test reflection MergeFrom does not sync to repeated field
-  // and there is no duplicated keys.
-  MapTestUtil::SetMapFields(&message1);
-  MapTestUtil::SetMapFields(&message2);
-
-  message2.MergeFrom(message1);
-
-  std::string output1, output2;
-  TextFormat::PrintToString(message1, &output1);
-  TextFormat::PrintToString(message2, &output2);
-  EXPECT_EQ(output1, output2);
-}
-
-TEST(GeneratedMapFieldTest, MergeFromMessageMap) {
-  unittest::TestMessageMap message1, message2;
-
-  (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
-  (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
-
-  message1.MergeFrom(message2);
-
-  // Checks repeated field is overwritten.
-  EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
-  EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
-}
-
-// Test the generated SerializeWithCachedSizesToArray()
-TEST(GeneratedMapFieldTest, SerializationToArray) {
-  unittest::TestMap message1, message2;
-  std::string data;
-  MapTestUtil::SetMapFields(&message1);
-  size_t size = message1.ByteSizeLong();
-  data.resize(size);
-  uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data));
-  uint8* end = message1.SerializeWithCachedSizesToArray(start);
-  EXPECT_EQ(size, end - start);
-  EXPECT_TRUE(message2.ParseFromString(data));
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-// Test the generated SerializeWithCachedSizes()
-TEST(GeneratedMapFieldTest, SerializationToStream) {
-  unittest::TestMap message1, message2;
-  MapTestUtil::SetMapFields(&message1);
-  size_t size = message1.ByteSizeLong();
-  std::string data;
-  data.resize(size);
-  {
-    // Allow the output stream to buffer only one byte at a time.
-    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
-    io::CodedOutputStream output_stream(&array_stream);
-    message1.SerializeWithCachedSizes(&output_stream);
-    EXPECT_FALSE(output_stream.HadError());
-    EXPECT_EQ(size, output_stream.ByteCount());
-  }
-  EXPECT_TRUE(message2.ParseFromString(data));
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(GeneratedMapFieldTest, ParseFailsIfMalformed) {
-  unittest::TestMapSubmessage o, p;
-  auto m = o.mutable_test_map()->mutable_map_int32_foreign_message();
-  (*m)[0].set_c(-1);
-  std::string serialized;
-  EXPECT_TRUE(o.SerializeToString(&serialized));
-
-  // Should parse correctly.
-  EXPECT_TRUE(p.ParseFromString(serialized));
-
-  // Overwriting the last byte to 0xFF results in malformed wire.
-  serialized[serialized.size() - 1] = 0xFF;
-  EXPECT_FALSE(p.ParseFromString(serialized));
-}
-
-
-TEST(GeneratedMapFieldTest, SameTypeMaps) {
-  const Descriptor* map1 = unittest::TestSameTypeMap::descriptor()
-                               ->FindFieldByName("map1")
-                               ->message_type();
-  const Descriptor* map2 = unittest::TestSameTypeMap::descriptor()
-                               ->FindFieldByName("map2")
-                               ->message_type();
-
-  const Message* map1_entry =
-      MessageFactory::generated_factory()->GetPrototype(map1);
-  const Message* map2_entry =
-      MessageFactory::generated_factory()->GetPrototype(map2);
-
-  EXPECT_EQ(map1, map1_entry->GetDescriptor());
-  EXPECT_EQ(map2, map2_entry->GetDescriptor());
-}
-
-TEST(GeneratedMapFieldTest, Proto2UnknownEnum) {
-  unittest::TestEnumMapPlusExtra from;
-  (*from.mutable_known_map_field())[0] = unittest::E_PROTO2_MAP_ENUM_FOO;
-  (*from.mutable_unknown_map_field())[0] = unittest::E_PROTO2_MAP_ENUM_EXTRA;
-  std::string data;
-  from.SerializeToString(&data);
-
-  unittest::TestEnumMap to;
-  EXPECT_TRUE(to.ParseFromString(data));
-  EXPECT_EQ(0, to.unknown_map_field().size());
-  const UnknownFieldSet& unknown_field_set =
-      to.GetReflection()->GetUnknownFields(to);
-  EXPECT_EQ(1, unknown_field_set.field_count());
-  EXPECT_EQ(1, to.known_map_field().size());
-  EXPECT_EQ(unittest::PROTO2_MAP_ENUM_FOO, to.known_map_field().at(0));
-
-  data.clear();
-  from.Clear();
-  to.SerializeToString(&data);
-  EXPECT_TRUE(from.ParseFromString(data));
-  EXPECT_EQ(0, from.GetReflection()->GetUnknownFields(from).field_count());
-  EXPECT_EQ(1, from.known_map_field().size());
-  EXPECT_EQ(unittest::E_PROTO2_MAP_ENUM_FOO, from.known_map_field().at(0));
-  EXPECT_EQ(1, from.unknown_map_field().size());
-  EXPECT_EQ(unittest::E_PROTO2_MAP_ENUM_EXTRA, from.unknown_map_field().at(0));
-}
-
-TEST(GeneratedMapFieldTest, StandardWireFormat) {
-  unittest::TestMap message;
-  std::string data = "\x0A\x04\x08\x01\x10\x01";
-
-  EXPECT_TRUE(message.ParseFromString(data));
-  EXPECT_EQ(1, message.map_int32_int32().size());
-  EXPECT_EQ(1, message.map_int32_int32().at(1));
-}
-
-TEST(GeneratedMapFieldTest, UnorderedWireFormat) {
-  unittest::TestMap message;
-
-  // put value before key in wire format
-  std::string data = "\x0A\x04\x10\x01\x08\x02";
-
-  EXPECT_TRUE(message.ParseFromString(data));
-  EXPECT_EQ(1, message.map_int32_int32().size());
-  ASSERT_NE(message.map_int32_int32().find(2), message.map_int32_int32().end());
-  EXPECT_EQ(1, message.map_int32_int32().at(2));
-}
-
-TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat) {
-  unittest::TestMap message;
-
-  // Two key fields in wire format
-  std::string data = "\x0A\x06\x08\x01\x08\x02\x10\x01";
-
-  EXPECT_TRUE(message.ParseFromString(data));
-  EXPECT_EQ(1, message.map_int32_int32().size());
-  EXPECT_EQ(1, message.map_int32_int32().at(2));
-
-  // A similar test, but with a map from int to a message type.
-  // Again, we want to be sure that the "second one wins" when
-  // there are two separate entries with the same key.
-  const int key = 99;
-  unittest::TestRequiredMessageMap map_message;
-  unittest::TestRequired with_dummy4;
-  with_dummy4.set_a(0);
-  with_dummy4.set_b(0);
-  with_dummy4.set_c(0);
-  with_dummy4.set_dummy4(11);
-  (*map_message.mutable_map_field())[key] = with_dummy4;
-  std::string s = map_message.SerializeAsString();
-  unittest::TestRequired with_dummy5;
-  with_dummy5.set_a(0);
-  with_dummy5.set_b(0);
-  with_dummy5.set_c(0);
-  with_dummy5.set_dummy5(12);
-  (*map_message.mutable_map_field())[key] = with_dummy5;
-  std::string both = s + map_message.SerializeAsString();
-  // We don't expect a merge now.  The "second one wins."
-  ASSERT_TRUE(map_message.ParseFromString(both));
-  ASSERT_EQ(1, map_message.map_field().size());
-  ASSERT_EQ(1, map_message.map_field().count(key));
-  EXPECT_EQ(0, map_message.map_field().find(key)->second.a());
-  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
-  EXPECT_EQ(0, map_message.map_field().find(key)->second.c());
-  EXPECT_FALSE(map_message.map_field().find(key)->second.has_dummy4());
-  ASSERT_TRUE(map_message.map_field().find(key)->second.has_dummy5());
-  EXPECT_EQ(12, map_message.map_field().find(key)->second.dummy5());
-}
-
-// Exhaustive combinations of keys, values, and junk in any order.
-// This re-tests some of the things tested above, but if it fails
-// it's more work to determine what went wrong, so it isn't necessarily
-// bad that we have the simpler tests too.
-TEST(GeneratedMapFieldTest, KeysValuesUnknownsWireFormat) {
-  unittest::TestMap message;
-  const int kMaxNumKeysAndValuesAndJunk = 4;
-  const char kKeyTag = 0x08;
-  const char kValueTag = 0x10;
-  const char kJunkTag = 0x20;
-  for (int items = 0; items <= kMaxNumKeysAndValuesAndJunk; items++) {
-    std::string data = "\x0A";
-    // Encode length of what will follow.
-    data.push_back(items * 2);
-    static const int kBitsOfIPerItem = 4;
-    static const int mask = (1 << kBitsOfIPerItem) - 1;
-    // Each iteration of the following is a test.  It uses i as bit vector
-    // encoding the keys and values to put in the wire format.
-    for (int i = 0; i < (1 << (items * kBitsOfIPerItem)); i++) {
-      std::string wire_format = data;
-      int expected_key = 0;
-      int expected_value = 0;
-      for (int k = i, j = 0; j < items; j++, k >>= kBitsOfIPerItem) {
-        bool is_key = k & 0x1;
-        bool is_value = !is_key && (k & 0x2);
-        wire_format.push_back(is_key ? kKeyTag
-                                     : is_value ? kValueTag : kJunkTag);
-        char c = static_cast<char>(k & mask) >> 2;  // One char after the tag.
-        wire_format.push_back(c);
-        if (is_key) expected_key = static_cast<int>(c);
-        if (is_value) expected_value = static_cast<int>(c);
-        bool res = message.ParseFromString(wire_format);
-        bool expect_success = true;
-        // Unfortunately the old map parser accepts malformed input, the new
-        // parser accepts only correct input.
-        if (j != items - 1) expect_success = false;
-        if (expect_success) {
-          ASSERT_TRUE(res);
-          ASSERT_EQ(1, message.map_int32_int32().size());
-          ASSERT_EQ(expected_key, message.map_int32_int32().begin()->first);
-          ASSERT_EQ(expected_value, message.map_int32_int32().begin()->second);
-        } else {
-          ASSERT_FALSE(res);
-        }
-      }
-    }
-  }
-}
-
-TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) {
-  unittest::TestMap message;
-
-  // Two value fields in wire format
-  std::string data = "\x0A\x06\x08\x01\x10\x01\x10\x02";
-
-  EXPECT_TRUE(message.ParseFromString(data));
-  EXPECT_EQ(1, message.map_int32_int32().size());
-  EXPECT_EQ(2, message.map_int32_int32().at(1));
-}
-
-TEST(GeneratedMapFieldTest, MissedKeyWireFormat) {
-  unittest::TestMap message;
-
-  // No key field in wire format
-  std::string data = "\x0A\x02\x10\x01";
-
-  EXPECT_TRUE(message.ParseFromString(data));
-  EXPECT_EQ(1, message.map_int32_int32().size());
-  ASSERT_NE(message.map_int32_int32().find(0), message.map_int32_int32().end());
-  EXPECT_EQ(1, message.map_int32_int32().at(0));
-}
-
-TEST(GeneratedMapFieldTest, MissedValueWireFormat) {
-  unittest::TestMap message;
-
-  // No value field in wire format
-  std::string data = "\x0A\x02\x08\x01";
-
-  EXPECT_TRUE(message.ParseFromString(data));
-  EXPECT_EQ(1, message.map_int32_int32().size());
-  ASSERT_NE(message.map_int32_int32().find(1), message.map_int32_int32().end());
-  EXPECT_EQ(0, message.map_int32_int32().at(1));
-}
-
-TEST(GeneratedMapFieldTest, MissedValueTextFormat) {
-  unittest::TestMap message;
-
-  // No value field in text format
-  std::string text =
-      "map_int32_foreign_message {\n"
-      "  key: 1234567890\n"
-      "}";
-
-  EXPECT_TRUE(TextFormat::ParseFromString(text, &message));
-  EXPECT_EQ(1, message.map_int32_foreign_message().size());
-  EXPECT_EQ(11, message.ByteSizeLong());
-}
-
-TEST(GeneratedMapFieldTest, UnknownFieldWireFormat) {
-  unittest::TestMap message;
-
-  // Unknown field in wire format
-  std::string data = "\x0A\x06\x08\x02\x10\x03\x18\x01";
-
-  EXPECT_TRUE(message.ParseFromString(data));
-  EXPECT_EQ(1, message.map_int32_int32().size());
-  EXPECT_EQ(3, message.map_int32_int32().at(2));
-}
-
-TEST(GeneratedMapFieldTest, CorruptedWireFormat) {
-  unittest::TestMap message;
-
-  // corrupted data in wire format
-  std::string data = "\x0A\x06\x08\x02\x11\x03";
-
-  EXPECT_FALSE(message.ParseFromString(data));
-}
-
-TEST(GeneratedMapFieldTest, IsInitialized) {
-  unittest::TestRequiredMessageMap map_message;
-
-  // Add an uninitialized message.
-  (*map_message.mutable_map_field())[0];
-  EXPECT_FALSE(map_message.IsInitialized());
-
-  // Initialize uninitialized message
-  (*map_message.mutable_map_field())[0].set_a(0);
-  (*map_message.mutable_map_field())[0].set_b(0);
-  (*map_message.mutable_map_field())[0].set_c(0);
-  EXPECT_TRUE(map_message.IsInitialized());
-}
-
-TEST(GeneratedMapFieldTest, SpaceUsed) {
-  unittest::TestRequiredMessageMap map_message;
-  const size_t initial = map_message.SpaceUsed();
-  const size_t space_used_message = unittest::TestRequired().SpaceUsed();
-
-  auto& m = *map_message.mutable_map_field();
-  constexpr int kNumValues = 100;
-  for (int i = 0; i < kNumValues; ++i) {
-    m[i];
-  }
-
-  // The exact value will depend on internal state, like collisions,
-  // so we can't predict it. But we can predict a lower bound.
-  size_t lower_bound =
-      initial + kNumValues * (space_used_message + sizeof(int32) +
-                              /* Node::next */ sizeof(void*) +
-                              /* table entry */ sizeof(void*));
-
-  EXPECT_LE(lower_bound, map_message.SpaceUsed());
-}
-
-TEST(GeneratedMapFieldTest, MessagesMustMerge) {
-  unittest::TestRequiredMessageMap map_message;
-
-  unittest::TestRequired with_dummy4;
-  with_dummy4.set_a(97);
-  with_dummy4.set_b(91);
-  with_dummy4.set_dummy4(98);
-  EXPECT_FALSE(with_dummy4.IsInitialized());
-  (*map_message.mutable_map_field())[0] = with_dummy4;
-  EXPECT_FALSE(map_message.IsInitialized());
-
-  unittest::TestRequired with_dummy5;
-  with_dummy5.set_b(0);
-  with_dummy5.set_c(33);
-  with_dummy5.set_dummy5(99);
-  EXPECT_FALSE(with_dummy5.IsInitialized());
-  (*map_message.mutable_map_field())[0] = with_dummy5;
-  EXPECT_FALSE(map_message.IsInitialized());
-
-  // The wire format of MapEntry is straightforward (*) and can be manually
-  // constructed to force merging of two uninitialized messages that would
-  // result in an initialized message.
-  //
-  // (*) http://google3/net/proto2/internal/map_test.cc?l=2433&rcl=310012028
-  std::string dummy4_s = with_dummy4.SerializePartialAsString();
-  std::string dummy5_s = with_dummy5.SerializePartialAsString();
-  int payload_size = dummy4_s.size() + dummy5_s.size();
-  // Makes sure the payload size fits into one byte.
-  ASSERT_LT(payload_size, 128);
-
-  std::string s(6, 0);
-  char* p = &s[0];
-  *p++ = WireFormatLite::MakeTag(1, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
-  // Length: 2B for key tag & val and 2B for val tag and length of the following
-  // payload.
-  *p++ = 4 + payload_size;
-  *p++ = WireFormatLite::MakeTag(1, WireFormatLite::WIRETYPE_VARINT);
-  *p++ = 0;
-  *p++ = WireFormatLite::MakeTag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
-  *p++ = payload_size;
-  StrAppend(&s, dummy4_s, dummy5_s);
-
-  // Test key then value then value.
-  int key = 0;
-  ASSERT_TRUE(map_message.ParseFromString(s));
-  ASSERT_EQ(1, map_message.map_field().size());
-  ASSERT_EQ(1, map_message.map_field().count(key));
-  EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
-  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
-  EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
-  EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
-  EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
-
-  // Test key then value then value then key.
-  s.push_back(s[2]);  // Copy the key's tag.
-  key = 19;
-  s.push_back(key);  // Second key is 19 instead of 0.
-  s[1] += 2;         // Adjust encoded size.
-  ASSERT_TRUE(map_message.ParseFromString(s));
-  ASSERT_EQ(1, map_message.map_field().size());
-  ASSERT_EQ(1, map_message.map_field().count(key));
-  EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
-  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
-  EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
-  EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
-  EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
-}
-
-// Generated Message Reflection Test ================================
-
-TEST(GeneratedMapFieldReflectionTest, SpaceUsed) {
-  unittest::TestMap message;
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaReflection(&message);
-
-  EXPECT_LT(0, message.GetReflection()->SpaceUsedLong(message));
-}
-
-TEST(GeneratedMapFieldReflectionTest, Accessors) {
-  // Set every field to a unique value then go back and check all those
-  // values.
-  unittest::TestMap message;
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaReflection(&message);
-  MapTestUtil::ExpectMapFieldsSet(message);
-  reflection_tester.ExpectMapFieldsSetViaReflection(message);
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message);
-
-  reflection_tester.ModifyMapFieldsViaReflection(&message);
-  MapTestUtil::ExpectMapFieldsModified(message);
-}
-
-TEST(GeneratedMapFieldReflectionTest, Swap) {
-  unittest::TestMap message1;
-  unittest::TestMap message2;
-
-  MapTestUtil::SetMapFields(&message1);
-
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
-
-  MapTestUtil::ExpectClear(message1);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(GeneratedMapFieldReflectionTest, SwapWithBothSet) {
-  unittest::TestMap message1;
-  unittest::TestMap message2;
-
-  MapTestUtil::SetMapFields(&message1);
-  MapTestUtil::SetMapFields(&message2);
-  MapTestUtil::ModifyMapFields(&message2);
-
-  const Reflection* reflection = message1.GetReflection();
-  reflection->Swap(&message1, &message2);
-
-  MapTestUtil::ExpectMapFieldsModified(message1);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(GeneratedMapFieldReflectionTest, SwapFields) {
-  unittest::TestMap message1;
-  unittest::TestMap message2;
-
-  MapTestUtil::SetMapFields(&message2);
-
-  std::vector<const FieldDescriptor*> fields;
-  const Reflection* reflection = message1.GetReflection();
-  reflection->ListFields(message2, &fields);
-  reflection->SwapFields(&message1, &message2, fields);
-
-  MapTestUtil::ExpectMapFieldsSet(message1);
-  MapTestUtil::ExpectClear(message2);
-}
-
-TEST(GeneratedMapFieldReflectionTest, ClearField) {
-  unittest::TestMap message;
-  MapTestUtil::SetMapFields(&message);
-  MapTestUtil::ExpectMapFieldsSet(message);
-
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.ClearMapFieldsViaReflection(&message);
-  reflection_tester.ExpectClearViaReflection(message);
-  reflection_tester.ExpectClearViaReflectionIterator(&message);
-}
-
-TEST(GeneratedMapFieldReflectionTest, RemoveLast) {
-  unittest::TestMap message;
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-
-  MapTestUtil::SetMapFields(&message);
-  MapTestUtil::ExpectMapsSize(message, 2);
-  std::vector<const Message*> expected_entries =
-      MapTestUtil::GetMapEntries(message, 0);
-
-  reflection_tester.RemoveLastMapsViaReflection(&message);
-
-  MapTestUtil::ExpectMapsSize(message, 1);
-  std::vector<const Message*> remained_entries =
-      MapTestUtil::GetMapEntries(message, 0);
-  EXPECT_TRUE(expected_entries == remained_entries);
-}
-
-TEST(GeneratedMapFieldReflectionTest, ReleaseLast) {
-  unittest::TestMap message;
-  const Descriptor* descriptor = message.GetDescriptor();
-  MapReflectionTester reflection_tester(descriptor);
-
-  MapTestUtil::SetMapFields(&message);
-
-  MapTestUtil::ExpectMapsSize(message, 2);
-
-  reflection_tester.ReleaseLastMapsViaReflection(&message);
-
-  MapTestUtil::ExpectMapsSize(message, 1);
-
-  // Now test that we actually release the right message.
-  message.Clear();
-  MapTestUtil::SetMapFields(&message);
-
-  MapTestUtil::ExpectMapsSize(message, 2);
-  std::vector<const Message*> expect_last =
-      MapTestUtil::GetMapEntries(message, 1);
-  std::vector<const Message*> release_last =
-      MapTestUtil::GetMapEntriesFromRelease(&message);
-  MapTestUtil::ExpectMapsSize(message, 1);
-  EXPECT_TRUE(expect_last == release_last);
-  for (std::vector<const Message*>::iterator it = release_last.begin();
-       it != release_last.end(); ++it) {
-    delete *it;
-  }
-}
-
-TEST(GeneratedMapFieldReflectionTest, SwapElements) {
-  unittest::TestMap message;
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-
-  MapTestUtil::SetMapFields(&message);
-
-  // Get pointers of map entries at their original position
-  std::vector<const Message*> entries0 = MapTestUtil::GetMapEntries(message, 0);
-  std::vector<const Message*> entries1 = MapTestUtil::GetMapEntries(message, 1);
-
-  // Swap the first time.
-  reflection_tester.SwapMapsViaReflection(&message);
-
-  // Get pointer of map entry after swap once.
-  std::vector<const Message*> entries0_once =
-      MapTestUtil::GetMapEntries(message, 0);
-  std::vector<const Message*> entries1_once =
-      MapTestUtil::GetMapEntries(message, 1);
-
-  // Test map entries are swapped.
-  MapTestUtil::ExpectMapsSize(message, 2);
-  EXPECT_TRUE(entries0 == entries1_once);
-  EXPECT_TRUE(entries1 == entries0_once);
-
-  // Swap the second time.
-  reflection_tester.SwapMapsViaReflection(&message);
-
-  // Get pointer of map entry after swap once.
-  std::vector<const Message*> entries0_twice =
-      MapTestUtil::GetMapEntries(message, 0);
-  std::vector<const Message*> entries1_twice =
-      MapTestUtil::GetMapEntries(message, 1);
-
-  // Test map entries are swapped back.
-  MapTestUtil::ExpectMapsSize(message, 2);
-  EXPECT_TRUE(entries0 == entries0_twice);
-  EXPECT_TRUE(entries1 == entries1_twice);
-}
-
-TEST(GeneratedMapFieldReflectionTest, MutableUnknownFields) {
-  unittest::TestMap message;
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
-}
-
-TEST(GeneratedMapFieldReflectionTest, EmbedProto2Message) {
-  unittest::TestMessageMap message;
-
-  const FieldDescriptor* map_field =
-      unittest::TestMessageMap::descriptor()->FindFieldByName(
-          "map_int32_message");
-  const FieldDescriptor* value =
-      map_field->message_type()->FindFieldByName("value");
-
-  Message* entry_message =
-      message.GetReflection()->AddMessage(&message, map_field);
-  EXPECT_EQ(
-      &entry_message->GetReflection()->GetMessage(*entry_message, value),
-      reinterpret_cast<const Message*>(&TestAllTypes::default_instance()));
-
-  Message* proto2_message =
-      entry_message->GetReflection()->MutableMessage(entry_message, value);
-  EXPECT_EQ(unittest::TestAllTypes::descriptor(),
-            proto2_message->GetDescriptor());
-  ASSERT_EQ(1, message.map_int32_message().size());
-}
-
-TEST(GeneratedMapFieldReflectionTest, MergeFromClearMapEntry) {
-  unittest::TestMap message;
-  const FieldDescriptor* map_field =
-      unittest::TestMap::descriptor()->FindFieldByName("map_int32_int32");
-  const FieldDescriptor* key =
-      map_field->message_type()->FindFieldByName("key");
-  const FieldDescriptor* value =
-      map_field->message_type()->FindFieldByName("value");
-
-  Message* entry_message1 =
-      message.GetReflection()->AddMessage(&message, map_field);
-  EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
-  EXPECT_FALSE(
-      entry_message1->GetReflection()->HasField(*entry_message1, value));
-
-  Message* entry_message2 =
-      message.GetReflection()->AddMessage(&message, map_field);
-  EXPECT_FALSE(entry_message2->GetReflection()->HasField(*entry_message2, key));
-  EXPECT_FALSE(
-      entry_message2->GetReflection()->HasField(*entry_message2, value));
-
-  entry_message1->MergeFrom(*entry_message2);
-  EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
-  EXPECT_FALSE(
-      entry_message1->GetReflection()->HasField(*entry_message1, value));
-}
-
-TEST(GeneratedMapFieldReflectionTest, MapEntryClear) {
-  unittest::TestMap message;
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
-}
-
-TEST(GeneratedMapFieldReflectionTest, Proto2MapEntryClear) {
-  unittest::TestEnumMap message;
-  const Descriptor* descriptor = message.GetDescriptor();
-  const FieldDescriptor* field_descriptor =
-      descriptor->FindFieldByName("known_map_field");
-  const FieldDescriptor* value_descriptor =
-      field_descriptor->message_type()->FindFieldByName("value");
-  Message* sub_message =
-      message.GetReflection()->AddMessage(&message, field_descriptor);
-  EXPECT_EQ(0, sub_message->GetReflection()->GetEnumValue(*sub_message,
-                                                          value_descriptor));
-}
-
-// Map Reflection API Test =========================================
-
-TEST(GeneratedMapFieldReflectionTest, SetViaMapReflection) {
-  unittest::TestMap message;
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaMapReflection(&message);
-  reflection_tester.ExpectMapFieldsSetViaReflection(message);
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message);
-}
-
-// Dynamic Message Test =============================================
-
-class MapFieldInDynamicMessageTest : public testing::Test {
- protected:
-  const DescriptorPool* pool_;
-  DynamicMessageFactory factory_;
-  const Descriptor* map_descriptor_;
-  const Descriptor* recursive_map_descriptor_;
-  const Message* map_prototype_;
-
-  MapFieldInDynamicMessageTest()
-      : pool_(DescriptorPool::generated_pool()), factory_(pool_) {}
-
-  virtual void SetUp() {
-    map_descriptor_ = pool_->FindMessageTypeByName("protobuf_unittest.TestMap");
-    recursive_map_descriptor_ =
-        pool_->FindMessageTypeByName("protobuf_unittest.TestRecursiveMapMessage");
-    ASSERT_TRUE(map_descriptor_ != NULL);
-    ASSERT_TRUE(recursive_map_descriptor_ != NULL);
-    map_prototype_ = factory_.GetPrototype(map_descriptor_);
-  }
-};
-
-TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) {
-  // Check that all fields have independent offsets by setting each
-  // one to a unique value then checking that they all still have those
-  // unique values (i.e. they don't stomp each other).
-  std::unique_ptr<Message> message(map_prototype_->New());
-  MapReflectionTester reflection_tester(map_descriptor_);
-
-  reflection_tester.SetMapFieldsViaReflection(message.get());
-  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
-}
-
-TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) {
-  // Check that map fields work properly.
-  std::unique_ptr<Message> message(map_prototype_->New());
-
-  // Check set functions.
-  MapReflectionTester reflection_tester(map_descriptor_);
-  reflection_tester.SetMapFieldsViaMapReflection(message.get());
-  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
-}
-
-TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) {
-  // Test that SpaceUsedLong() works properly
-
-  // Since we share the implementation with generated messages, we don't need
-  // to test very much here.  Just make sure it appears to be working.
-
-  std::unique_ptr<Message> message(map_prototype_->New());
-  MapReflectionTester reflection_tester(map_descriptor_);
-
-  int initial_space_used = message->SpaceUsedLong();
-
-  reflection_tester.SetMapFieldsViaReflection(message.get());
-  EXPECT_LT(initial_space_used, message->SpaceUsedLong());
-}
-
-TEST_F(MapFieldInDynamicMessageTest, RecursiveMap) {
-  TestRecursiveMapMessage from;
-  (*from.mutable_a())[""];
-  std::string data = from.SerializeAsString();
-  std::unique_ptr<Message> to(
-      factory_.GetPrototype(recursive_map_descriptor_)->New());
-  ASSERT_TRUE(to->ParseFromString(data));
-}
-
-TEST_F(MapFieldInDynamicMessageTest, MapValueReferernceValidAfterSerialize) {
-  std::unique_ptr<Message> message(map_prototype_->New());
-  MapReflectionTester reflection_tester(map_descriptor_);
-  reflection_tester.SetMapFieldsViaMapReflection(message.get());
-
-  // Get value reference before serialization, so that we know the value is from
-  // map.
-  MapKey map_key;
-  MapValueRef map_val;
-  map_key.SetInt32Value(0);
-  reflection_tester.GetMapValueViaMapReflection(
-      message.get(), "map_int32_foreign_message", map_key, &map_val);
-  Message* submsg = map_val.MutableMessageValue();
-
-  // In previous implementation, calling SerializeToString will cause syncing
-  // from map to repeated field, which will invalidate the submsg we previously
-  // got.
-  std::string data;
-  message->SerializeToString(&data);
-
-  const Reflection* submsg_reflection = submsg->GetReflection();
-  const Descriptor* submsg_desc = submsg->GetDescriptor();
-  const FieldDescriptor* submsg_field = submsg_desc->FindFieldByName("c");
-  submsg_reflection->SetInt32(submsg, submsg_field, 128);
-
-  message->SerializeToString(&data);
-  TestMap to;
-  to.ParseFromString(data);
-  EXPECT_EQ(128, to.map_int32_foreign_message().at(0).c());
-}
-
-TEST_F(MapFieldInDynamicMessageTest, MapEntryReferernceValidAfterSerialize) {
-  std::unique_ptr<Message> message(map_prototype_->New());
-  MapReflectionTester reflection_tester(map_descriptor_);
-  reflection_tester.SetMapFieldsViaReflection(message.get());
-
-  // Get map entry before serialization, so that we know the it is from
-  // repeated field.
-  Message* map_entry = reflection_tester.GetMapEntryViaReflection(
-      message.get(), "map_int32_foreign_message", 0);
-  const Reflection* map_entry_reflection = map_entry->GetReflection();
-  const Descriptor* map_entry_desc = map_entry->GetDescriptor();
-  const FieldDescriptor* value_field = map_entry_desc->FindFieldByName("value");
-  Message* submsg =
-      map_entry_reflection->MutableMessage(map_entry, value_field);
-
-  // In previous implementation, calling SerializeToString will cause syncing
-  // from repeated field to map, which will invalidate the map_entry we
-  // previously got.
-  std::string data;
-  message->SerializeToString(&data);
-
-  const Reflection* submsg_reflection = submsg->GetReflection();
-  const Descriptor* submsg_desc = submsg->GetDescriptor();
-  const FieldDescriptor* submsg_field = submsg_desc->FindFieldByName("c");
-  submsg_reflection->SetInt32(submsg, submsg_field, 128);
-
-  message->SerializeToString(&data);
-  TestMap to;
-  to.ParseFromString(data);
-  EXPECT_EQ(128, to.map_int32_foreign_message().at(0).c());
-}
-
-// ReflectionOps Test ===============================================
-
-TEST(ReflectionOpsForMapFieldTest, MapSanityCheck) {
-  unittest::TestMap message;
-
-  MapTestUtil::SetMapFields(&message);
-  MapTestUtil::ExpectMapFieldsSet(message);
-}
-
-TEST(ReflectionOpsForMapFieldTest, MapCopy) {
-  unittest::TestMap message, message2;
-
-  MapTestUtil::SetMapFields(&message);
-
-  ReflectionOps::Copy(message, &message2);
-
-  MapTestUtil::ExpectMapFieldsSet(message2);
-
-  // Copying from self should be a no-op.
-  ReflectionOps::Copy(message2, &message2);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(ReflectionOpsForMapFieldTest, MergeMap) {
-  // Note:  Copy is implemented in terms of Merge() so technically the Copy
-  //   test already tested most of this.
-
-  unittest::TestMap message, message2;
-
-  MapTestUtil::SetMapFields(&message);
-
-  ReflectionOps::Merge(message2, &message);
-
-  MapTestUtil::ExpectMapFieldsSet(message);
-}
-
-TEST(ReflectionOpsForMapFieldTest, ClearMap) {
-  unittest::TestMap message;
-
-  MapTestUtil::SetMapFields(&message);
-
-  ReflectionOps::Clear(&message);
-
-  MapTestUtil::ExpectClear(message);
-}
-
-TEST(ReflectionOpsForMapFieldTest, MapDiscardUnknownFields) {
-  unittest::TestMap message;
-  MapTestUtil::SetMapFields(&message);
-
-  // Set some unknown fields in message.
-  message.GetReflection()->MutableUnknownFields(&message)->AddVarint(123456,
-                                                                     654321);
-
-  // Discard them.
-  ReflectionOps::DiscardUnknownFields(&message);
-  MapTestUtil::ExpectMapFieldsSet(message);
-
-  EXPECT_EQ(0,
-            message.GetReflection()->GetUnknownFields(message).field_count());
-}
-
-TEST(ReflectionOpsForMapFieldTest, IsInitialized) {
-  unittest::TestRequiredMessageMap map_message;
-
-  // Add an uninitialized message.
-  (*map_message.mutable_map_field())[0];
-  EXPECT_FALSE(ReflectionOps::IsInitialized(map_message));
-
-  // Initialize uninitialized message
-  (*map_message.mutable_map_field())[0].set_a(0);
-  (*map_message.mutable_map_field())[0].set_b(0);
-  (*map_message.mutable_map_field())[0].set_c(0);
-  EXPECT_TRUE(ReflectionOps::IsInitialized(map_message));
-}
-
-// Wire Format Test =================================================
-
-TEST(WireFormatForMapFieldTest, ParseMap) {
-  unittest::TestMap source, dest;
-  std::string data;
-
-  // Serialize using the generated code.
-  MapTestUtil::SetMapFields(&source);
-  source.SerializeToString(&data);
-
-  // Parse using WireFormat.
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream input(&raw_input);
-  WireFormat::ParseAndMergePartial(&input, &dest);
-
-  // Check.
-  MapTestUtil::ExpectMapFieldsSet(dest);
-}
-
-TEST(WireFormatForMapFieldTest, MapByteSize) {
-  unittest::TestMap message;
-  MapTestUtil::SetMapFields(&message);
-
-  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
-  message.Clear();
-  EXPECT_EQ(0, message.ByteSizeLong());
-  EXPECT_EQ(0, WireFormat::ByteSize(message));
-}
-
-TEST(WireFormatForMapFieldTest, SerializeMap) {
-  unittest::TestMap message;
-  std::string generated_data;
-  std::string dynamic_data;
-
-  MapTestUtil::SetMapFields(&message);
-
-  // Serialize using the generated code.
-  {
-    message.ByteSizeLong();
-    io::StringOutputStream raw_output(&generated_data);
-    io::CodedOutputStream output(&raw_output);
-    message.SerializeWithCachedSizes(&output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Serialize using WireFormat.
-  {
-    io::StringOutputStream raw_output(&dynamic_data);
-    io::CodedOutputStream output(&raw_output);
-    size_t size = WireFormat::ByteSize(message);
-    WireFormat::SerializeWithCachedSizes(message, size, &output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Should parse to the same message.
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
-}
-
-TEST(WireFormatForMapFieldTest, SerializeMapDynamicMessage) {
-  DynamicMessageFactory factory;
-  std::unique_ptr<Message> dynamic_message;
-  dynamic_message.reset(
-      factory.GetPrototype(unittest::TestMap::descriptor())->New());
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaReflection(dynamic_message.get());
-  reflection_tester.ExpectMapFieldsSetViaReflection(*dynamic_message);
-
-  unittest::TestMap generated_message;
-  MapTestUtil::SetMapFields(&generated_message);
-  MapTestUtil::ExpectMapFieldsSet(generated_message);
-
-  std::string generated_data;
-  std::string dynamic_data;
-
-  // Serialize.
-  generated_message.SerializeToString(&generated_data);
-  dynamic_message->SerializeToString(&dynamic_data);
-
-  // Because map serialization doesn't guarantee order, we just compare
-  // serialized size here. This is enough to tell dynamic message doesn't miss
-  // anything in serialization.
-  EXPECT_TRUE(dynamic_data.size() == generated_data.size());
-}
-
-TEST(WireFormatForMapFieldTest, MapByteSizeDynamicMessage) {
-  DynamicMessageFactory factory;
-  std::unique_ptr<Message> dynamic_message;
-  dynamic_message.reset(
-      factory.GetPrototype(unittest::TestMap::descriptor())->New());
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaReflection(dynamic_message.get());
-  reflection_tester.ExpectMapFieldsSetViaReflection(*dynamic_message);
-  std::string expected_serialized_data;
-  dynamic_message->SerializeToString(&expected_serialized_data);
-  int expected_size = expected_serialized_data.size();
-  EXPECT_EQ(dynamic_message->ByteSizeLong(), expected_size);
-
-  std::unique_ptr<Message> message2;
-  message2.reset(factory.GetPrototype(unittest::TestMap::descriptor())->New());
-  reflection_tester.SetMapFieldsViaMapReflection(message2.get());
-
-  const FieldDescriptor* field =
-      unittest::TestMap::descriptor()->FindFieldByName("map_int32_int32");
-  const Reflection* reflection = dynamic_message->GetReflection();
-
-  // Force the map field to mark with STATE_MODIFIED_REPEATED
-  reflection->RemoveLast(dynamic_message.get(), field);
-  dynamic_message->MergeFrom(*message2);
-  dynamic_message->MergeFrom(*message2);
-  // The map field is marked as STATE_MODIFIED_REPEATED, ByteSizeLong() will use
-  // repeated field which have duplicate keys to calculate.
-  size_t duplicate_size = dynamic_message->ByteSizeLong();
-  EXPECT_TRUE(duplicate_size > expected_size);
-  std::string duplicate_serialized_data;
-  dynamic_message->SerializeToString(&duplicate_serialized_data);
-  EXPECT_EQ(dynamic_message->ByteSizeLong(), duplicate_serialized_data.size());
-
-  // Force the map field to mark with map CLEAN
-  EXPECT_EQ(reflection_tester.MapSize(*dynamic_message, "map_int32_int32"), 2);
-  // The map field is marked as CLEAN, ByteSizeLong() will use map which do not
-  // have duplicate keys to calculate.
-  int size = dynamic_message->ByteSizeLong();
-  EXPECT_EQ(expected_size, size);
-
-  // Protobuf used to have a bug for serialize when map it marked CLEAN. It used
-  // repeated field to calculate ByteSizeLong but use map to serialize the real
-  // data, thus the ByteSizeLong may bigger than real serialized size. A crash
-  // might be happen at SerializeToString(). Or an "unexpected end group"
-  // warning was raised at parse back if user use SerializeWithCachedSizes()
-  // which avoids size check at serialize.
-  std::string serialized_data;
-  dynamic_message->SerializeToString(&serialized_data);
-  EXPECT_EQ(serialized_data, expected_serialized_data);
-  dynamic_message->ParseFromString(serialized_data);
-}
-
-TEST(WireFormatForMapFieldTest, MapParseHelpers) {
-  std::string data;
-
-  {
-    // Set up.
-    protobuf_unittest::TestMap message;
-    MapTestUtil::SetMapFields(&message);
-    message.SerializeToString(&data);
-  }
-
-  {
-    // Test ParseFromString.
-    protobuf_unittest::TestMap message;
-    EXPECT_TRUE(message.ParseFromString(data));
-    MapTestUtil::ExpectMapFieldsSet(message);
-  }
-
-  {
-    // Test ParseFromIstream.
-    protobuf_unittest::TestMap message;
-    std::stringstream stream(data);
-    EXPECT_TRUE(message.ParseFromIstream(&stream));
-    EXPECT_TRUE(stream.eof());
-    MapTestUtil::ExpectMapFieldsSet(message);
-  }
-
-  {
-    // Test ParseFromBoundedZeroCopyStream.
-    std::string data_with_junk(data);
-    data_with_junk.append("some junk on the end");
-    io::ArrayInputStream stream(data_with_junk.data(), data_with_junk.size());
-    protobuf_unittest::TestMap message;
-    EXPECT_TRUE(message.ParseFromBoundedZeroCopyStream(&stream, data.size()));
-    MapTestUtil::ExpectMapFieldsSet(message);
-  }
-
-  {
-    // Test that ParseFromBoundedZeroCopyStream fails (but doesn't crash) if
-    // EOF is reached before the expected number of bytes.
-    io::ArrayInputStream stream(data.data(), data.size());
-    protobuf_unittest::TestAllTypes message;
-    EXPECT_FALSE(
-        message.ParseFromBoundedZeroCopyStream(&stream, data.size() + 1));
-  }
-}
-
-// Deterministic Serialization Test ==========================================
-
-template <typename T>
-static std::string DeterministicSerializationWithSerializePartialToCodedStream(
-    const T& t) {
-  const size_t size = t.ByteSizeLong();
-  std::string result(size, '\0');
-  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size);
-  io::CodedOutputStream output_stream(&array_stream);
-  output_stream.SetSerializationDeterministic(true);
-  t.SerializePartialToCodedStream(&output_stream);
-  EXPECT_FALSE(output_stream.HadError());
-  EXPECT_EQ(size, output_stream.ByteCount());
-  return result;
-}
-
-template <typename T>
-static std::string DeterministicSerializationWithSerializeToCodedStream(
-    const T& t) {
-  const size_t size = t.ByteSizeLong();
-  std::string result(size, '\0');
-  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size);
-  io::CodedOutputStream output_stream(&array_stream);
-  output_stream.SetSerializationDeterministic(true);
-  t.SerializeToCodedStream(&output_stream);
-  EXPECT_FALSE(output_stream.HadError());
-  EXPECT_EQ(size, output_stream.ByteCount());
-  return result;
-}
-
-template <typename T>
-static std::string DeterministicSerialization(const T& t) {
-  const size_t size = t.ByteSizeLong();
-  std::string result(size, '\0');
-  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size);
-  {
-    io::CodedOutputStream output_stream(&array_stream);
-    output_stream.SetSerializationDeterministic(true);
-    t.SerializeWithCachedSizes(&output_stream);
-    EXPECT_FALSE(output_stream.HadError());
-    EXPECT_EQ(size, output_stream.ByteCount());
-  }
-  EXPECT_EQ(result, DeterministicSerializationWithSerializeToCodedStream(t));
-  EXPECT_EQ(result,
-            DeterministicSerializationWithSerializePartialToCodedStream(t));
-  return result;
-}
-
-// Helper for MapSerializationTest.  Return a 7-bit ASCII string.
-static std::string ConstructKey(uint64 n) {
-  std::string s(n % static_cast<uint64>(9), '\0');
-  if (s.empty()) {
-    return StrCat(n);
-  } else {
-    while (n != 0) {
-      s[n % s.size()] = (n >> 10) & 0x7f;
-      n /= 888;
-    }
-    return s;
-  }
-}
-
-TEST(MapSerializationTest, Deterministic) {
-  const int kIters = 25;
-  protobuf_unittest::TestMaps t;
-  protobuf_unittest::TestIntIntMap inner;
-  (*inner.mutable_m())[0] = (*inner.mutable_m())[10] =
-      (*inner.mutable_m())[-200] = 0;
-  uint64 frog = 9;
-  const uint64 multiplier = 0xa29cd16f;
-  for (int i = 0; i < kIters; i++) {
-    const int32 i32 = static_cast<int32>(frog & 0xffffffff);
-    const uint32 u32 = static_cast<uint32>(i32) * 91919;
-    const int64 i64 = static_cast<int64>(frog);
-    const uint64 u64 = frog * static_cast<uint64>(187321);
-    const bool b = i32 > 0;
-    const std::string s = ConstructKey(frog);
-    (*inner.mutable_m())[i] = i32;
-    (*t.mutable_m_int32())[i32] = (*t.mutable_m_sint32())[i32] =
-        (*t.mutable_m_sfixed32())[i32] = inner;
-    (*t.mutable_m_uint32())[u32] = (*t.mutable_m_fixed32())[u32] = inner;
-    (*t.mutable_m_int64())[i64] = (*t.mutable_m_sint64())[i64] =
-        (*t.mutable_m_sfixed64())[i64] = inner;
-    (*t.mutable_m_uint64())[u64] = (*t.mutable_m_fixed64())[u64] = inner;
-    (*t.mutable_m_bool())[b] = inner;
-    (*t.mutable_m_string())[s] = inner;
-    (*t.mutable_m_string())[s + std::string(1 << (u32 % static_cast<uint32>(9)),
-                                            b)] = inner;
-    inner.mutable_m()->erase(i);
-    frog = frog * multiplier + i;
-    frog ^= (frog >> 41);
-  }
-
-  // Verifies if two consecutive calls to deterministic serialization produce
-  // the same bytes. Deterministic serialization means the same serialization
-  // bytes in the same binary.
-  const std::string s1 = DeterministicSerialization(t);
-  const std::string s2 = DeterministicSerialization(t);
-  EXPECT_EQ(s1, s2);
-
-  protobuf_unittest::TestMaps u;
-  EXPECT_TRUE(u.ParseFromString(s1));
-  EXPECT_TRUE(util::MessageDifferencer::Equals(u, t));
-}
-
-TEST(MapSerializationTest, DeterministicSubmessage) {
-  protobuf_unittest::TestSubmessageMaps p;
-  protobuf_unittest::TestMaps t;
-  const std::string filename = "golden_message_maps";
-  std::string golden;
-  GOOGLE_CHECK_OK(File::GetContents(
-      TestUtil::GetTestDataPath("net/proto2/internal/testdata/" + filename),
-      &golden, true));
-  t.ParseFromString(golden);
-  *(p.mutable_m()) = t;
-  std::vector<std::string> v;
-  // Use multiple attempts to increase the chance of a failure if something is
-  // buggy.  For example, each separate copy of a map might use a different
-  // randomly-chosen hash function.
-  const int kAttempts = 10;
-  for (int i = 0; i < kAttempts; i++) {
-    protobuf_unittest::TestSubmessageMaps q(p);
-    ASSERT_EQ(DeterministicSerialization(q), DeterministicSerialization(p));
-  }
-}
-
-// Text Format Test =================================================
-
-TEST(TextFormatMapTest, SerializeAndParse) {
-  unittest::TestMap source;
-  unittest::TestMap dest;
-  MapTestUtil::SetMapFields(&source);
-  std::string output;
-
-  // Test compact ASCII
-  TextFormat::Printer printer;
-  printer.PrintToString(source, &output);
-  TextFormat::Parser parser;
-  EXPECT_TRUE(parser.ParseFromString(output, &dest));
-  MapTestUtil::ExpectMapFieldsSet(dest);
-}
-
-TEST(TextFormatMapTest, DynamicMessage) {
-  TestMap prototype;
-  DynamicMessageFactory factory;
-  std::unique_ptr<Message> message(
-      factory.GetPrototype(prototype.GetDescriptor())->New());
-  MapReflectionTester tester(message->GetDescriptor());
-  tester.SetMapFieldsViaReflection(message.get());
-
-  std::string expected_text;
-  GOOGLE_CHECK_OK(
-      File::GetContents(TestUtil::GetTestDataPath("net/proto2/internal/"
-                                                  "testdata/map_test_data.txt"),
-                        &expected_text, true));
-
-  CleanStringLineEndings(&expected_text, false);
-  EXPECT_EQ(message->DebugString(), expected_text);
-}
-
-TEST(TextFormatMapTest, Sorted) {
-  unittest::TestMap message;
-  MapReflectionTester tester(message.GetDescriptor());
-  tester.SetMapFieldsViaReflection(&message);
-
-  std::string expected_text;
-  GOOGLE_CHECK_OK(
-      File::GetContents(TestUtil::GetTestDataPath("net/proto2/internal/"
-                                                  "testdata/map_test_data.txt"),
-                        &expected_text, true));
-
-  CleanStringLineEndings(&expected_text, false);
-  EXPECT_EQ(message.DebugString(), expected_text);
-
-  // Test again on the reverse order.
-  unittest::TestMap message2;
-  tester.SetMapFieldsViaReflection(&message2);
-  tester.SwapMapsViaReflection(&message2);
-  EXPECT_EQ(message2.DebugString(), expected_text);
-}
-
-TEST(TextFormatMapTest, ParseCorruptedString) {
-  std::string serialized_message;
-  GOOGLE_CHECK_OK(
-      File::GetContents(TestUtil::GetTestDataPath(
-                            "net/proto2/internal/testdata/golden_message_maps"),
-                        &serialized_message, true));
-  protobuf_unittest::TestMaps message;
-  GOOGLE_CHECK(message.ParseFromString(serialized_message));
-  TestParseCorruptedString<protobuf_unittest::TestMaps, true>(message);
-  TestParseCorruptedString<protobuf_unittest::TestMaps, false>(message);
-}
-
-// Previously, serializing to text format will disable iterator from generated
-// API. Now, the iterator can be still used even after serializing to text
-// format.
-TEST(TextFormatMapTest, NoDisableIterator) {
-  unittest::TestMap source;
-  (*source.mutable_map_int32_int32())[1] = 1;
-
-  // Get iterator.
-  Map<int32, int32>::iterator iter = source.mutable_map_int32_int32()->find(1);
-
-  // Serialize message to text format, which will invalidate the previous
-  // iterator previously.
-  std::string output;
-  TextFormat::Printer printer;
-  printer.PrintToString(source, &output);
-
-  // Modify map via the iterator (invalidated in previous implementation.).
-  iter->second = 2;
-
-  // In previous implementation, the new change won't be reflected in text
-  // format, because the previous iterator has been invalidated.
-  output.clear();
-  printer.PrintToString(source, &output);
-  std::string expected =
-      "map_int32_int32 {\n"
-      "  key: 1\n"
-      "  value: 2\n"
-      "}\n";
-  EXPECT_EQ(output, expected);
-}
-
-// Previously, serializing to text format will disable iterator from reflection
-// API.
-TEST(TextFormatMapTest, NoDisableReflectionIterator) {
-  unittest::TestMap source;
-  (*source.mutable_map_int32_int32())[1] = 1;
-
-  // Get iterator. This will also sync internal repeated field with map inside
-  // of MapField.
-  const Reflection* reflection = source.GetReflection();
-  const FieldDescriptor* field_desc =
-      source.GetDescriptor()->FindFieldByName("map_int32_int32");
-  RepeatedPtrField<Message>* map_field =
-      reflection->MutableRepeatedPtrField<Message>(&source, field_desc);
-  RepeatedPtrField<Message>::iterator iter = map_field->begin();
-
-  // Serialize message to text format, which will invalidate the previous
-  // iterator previously.
-  std::string output;
-  TextFormat::Printer printer;
-  printer.PrintToString(source, &output);
-
-  // Modify map via the iterator (invalidated in previous implementation.).
-  const Reflection* map_entry_reflection = iter->GetReflection();
-  const FieldDescriptor* value_field_desc =
-      iter->GetDescriptor()->FindFieldByName("value");
-  map_entry_reflection->SetInt32(&(*iter), value_field_desc, 2);
-  GOOGLE_LOG(INFO) << iter->DebugString();
-
-  // In previous implementation, the new change won't be reflected in text
-  // format, because the previous iterator has been invalidated.
-  output.clear();
-  printer.PrintToString(source, &output);
-  std::string expected =
-      "map_int32_int32 {\n"
-      "  key: 1\n"
-      "  value: 2\n"
-      "}\n";
-  EXPECT_EQ(output, expected);
-}
-
-
-// arena support =================================================
-TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) {
-  // Allocate a large initial block to avoid mallocs during hooked test.
-  std::vector<char> arena_block(128 * 1024);
-  ArenaOptions options;
-  options.initial_block = &arena_block[0];
-  options.initial_block_size = arena_block.size();
-  Arena arena(options);
-  std::string data;
-  data.reserve(128 * 1024);
-
-  {
-    // TODO(teboring): Enable no heap check when ArenaStringPtr is used in map.
-    // NoHeapChecker no_heap;
-
-    unittest::TestArenaMap* from =
-        Arena::CreateMessage<unittest::TestArenaMap>(&arena);
-    MapTestUtil::SetArenaMapFields(from);
-    from->SerializeToString(&data);
-
-    unittest::TestArenaMap* to =
-        Arena::CreateMessage<unittest::TestArenaMap>(&arena);
-    to->ParseFromString(data);
-    MapTestUtil::ExpectArenaMapFieldsSet(*to);
-  }
-}
-
-// Use text format parsing and serializing to test reflection api.
-TEST(ArenaTest, ReflectionInTextFormat) {
-  Arena arena;
-  std::string data;
-
-  TextFormat::Printer printer;
-  TextFormat::Parser parser;
-
-  unittest::TestArenaMap* from =
-      Arena::CreateMessage<unittest::TestArenaMap>(&arena);
-  unittest::TestArenaMap* to =
-      Arena::CreateMessage<unittest::TestArenaMap>(&arena);
-
-  MapTestUtil::SetArenaMapFields(from);
-  printer.PrintToString(*from, &data);
-
-  EXPECT_TRUE(parser.ParseFromString(data, to));
-  MapTestUtil::ExpectArenaMapFieldsSet(*to);
-}
-
-// Make sure the memory allocated for string in map is deallocated.
-TEST(ArenaTest, StringMapNoLeak) {
-  Arena arena;
-  unittest::TestArenaMap* message =
-      Arena::CreateMessage<unittest::TestArenaMap>(&arena);
-  std::string data;
-  // String with length less than 16 will not be allocated from heap.
-  int original_capacity = data.capacity();
-  while (data.capacity() <= original_capacity) {
-    data.append("a");
-  }
-  (*message->mutable_map_string_string())[data] = data;
-  // We rely on heap checkers to detect memory leak for us.
-  ASSERT_FALSE(message == NULL);
-}
-
-TEST(ArenaTest, IsInitialized) {
-  // Allocate a large initial polluted block.
-  std::vector<char> arena_block(128 * 1024);
-  std::fill(arena_block.begin(), arena_block.end(), '\xff');
-
-  ArenaOptions options;
-  options.initial_block = &arena_block[0];
-  options.initial_block_size = arena_block.size();
-  Arena arena(options);
-
-  unittest::TestArenaMap* message =
-      Arena::CreateMessage<unittest::TestArenaMap>(&arena);
-  EXPECT_EQ(0, (*message->mutable_map_int32_int32())[0]);
-}
-
-TEST(ArenaTest, DynamicMapFieldOnArena) {
-  Arena arena;
-  unittest::TestMap message2;
-
-  DynamicMessageFactory factory;
-  Message* message1 =
-      factory.GetPrototype(unittest::TestMap::descriptor())->New(&arena);
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  reflection_tester.SetMapFieldsViaReflection(message1);
-  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1);
-  message2.CopyFrom(*message1);
-  MapTestUtil::ExpectMapFieldsSet(message2);
-}
-
-TEST(ArenaTest, DynamicMapFieldOnArenaMemoryLeak) {
-  auto* desc = unittest::TestMap::descriptor();
-  auto* field = desc->FindFieldByName("map_int32_int32");
-
-  Arena arena;
-  DynamicMessageFactory factory;
-  auto* message = factory.GetPrototype(desc)->New(&arena);
-  auto* reflection = message->GetReflection();
-  reflection->AddMessage(message, field);
-
-  // Force internal syncing, which initializes the mutex.
-  MapReflectionTester reflection_tester(unittest::TestMap::descriptor());
-  int size = reflection_tester.MapSize(*message, "map_int32_int32");
-  EXPECT_EQ(size, 1);
-}
-
-TEST(MoveTest, MoveConstructorWorks) {
-  Map<int32, TestAllTypes> original_map;
-  original_map[42].mutable_optional_nested_message()->set_bb(42);
-  original_map[43].mutable_optional_nested_message()->set_bb(43);
-  const auto* nested_msg42_ptr = &original_map[42].optional_nested_message();
-  const auto* nested_msg43_ptr = &original_map[43].optional_nested_message();
-
-  Map<int32, TestAllTypes> moved_to_map(std::move(original_map));
-  EXPECT_TRUE(original_map.empty());
-  EXPECT_EQ(2, moved_to_map.size());
-  EXPECT_EQ(42, moved_to_map[42].optional_nested_message().bb());
-  EXPECT_EQ(43, moved_to_map[43].optional_nested_message().bb());
-  // This test takes advantage of the fact that pointers are swapped, so there
-  // should be pointer stability.
-  EXPECT_EQ(nested_msg42_ptr, &moved_to_map[42].optional_nested_message());
-  EXPECT_EQ(nested_msg43_ptr, &moved_to_map[43].optional_nested_message());
-}
-
-TEST(MoveTest, MoveAssignmentWorks) {
-  Map<int32, TestAllTypes> original_map;
-  original_map[42].mutable_optional_nested_message()->set_bb(42);
-  original_map[43].mutable_optional_nested_message()->set_bb(43);
-  const auto* nested_msg42_ptr = &original_map[42].optional_nested_message();
-  const auto* nested_msg43_ptr = &original_map[43].optional_nested_message();
 
-  Map<int32, TestAllTypes> moved_to_map = std::move(original_map);
-  EXPECT_TRUE(original_map.empty());
-  EXPECT_EQ(2, moved_to_map.size());
-  EXPECT_EQ(42, moved_to_map[42].optional_nested_message().bb());
-  EXPECT_EQ(43, moved_to_map[43].optional_nested_message().bb());
-  // This test takes advantage of the fact that pointers are swapped, so there
-  // should be pointer stability.
-  EXPECT_EQ(nested_msg42_ptr, &moved_to_map[42].optional_nested_message());
-  EXPECT_EQ(nested_msg43_ptr, &moved_to_map[43].optional_nested_message());
-}
 
 
 }  // namespace
diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc
new file mode 100644
index 0000000..4e8304f
--- /dev/null
+++ b/src/google/protobuf/map_test.inc
@@ -0,0 +1,3852 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A hack to include windows.h first, which ensures the GetMessage macro can
+// be undefined when we include <google/protobuf/stubs/common.h>
+#if defined(_MSC_VER)
+#define _WINSOCKAPI_  // to avoid re-definition in WinSock2.h
+#define NOMINMAX      // to avoid defining min/max macros
+#include <windows.h>
+#endif  // _WIN32
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <random>
+#include <set>
+#include <sstream>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/test_util2.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/util/time_util.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/substitute.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+using UNITTEST::ForeignMessage;
+using UNITTEST::TestAllTypes;
+using UNITTEST::TestMap;
+using UNITTEST::TestRecursiveMapMessage;
+
+namespace internal {
+
+void MapTestForceDeterministic() {
+  io::CodedOutputStream::SetDefaultSerializationDeterministic();
+}
+
+namespace {
+
+// Map API Test =====================================================
+
+class MapImplTest : public ::testing::Test {
+ protected:
+  MapImplTest()
+      : map_ptr_(new Map<int32, int32>()),
+        map_(*map_ptr_),
+        const_map_(*map_ptr_) {
+    EXPECT_TRUE(map_.empty());
+    EXPECT_EQ(0, map_.size());
+  }
+
+  void ExpectSingleElement(int32 key, int32 value) {
+    EXPECT_FALSE(map_.empty());
+    EXPECT_EQ(1, map_.size());
+    ExpectElement(key, value);
+  }
+
+  void ExpectElements(const std::map<int32, int32>& map) {
+    EXPECT_FALSE(map_.empty());
+    EXPECT_EQ(map.size(), map_.size());
+    for (std::map<int32, int32>::const_iterator it = map.begin();
+         it != map.end(); ++it) {
+      ExpectElement(it->first, it->second);
+    }
+  }
+
+  void ExpectElement(int32 key, int32 value) {
+    // Test map size is correct.
+    EXPECT_EQ(value, map_[key]);
+    EXPECT_EQ(1, map_.count(key));
+    EXPECT_TRUE(map_.contains(key));
+
+    // Check mutable at and find work correctly.
+    EXPECT_EQ(value, map_.at(key));
+    Map<int32, int32>::iterator it = map_.find(key);
+
+    // iterator dereferenceable
+    EXPECT_EQ(key, (*it).first);
+    EXPECT_EQ(value, (*it).second);
+    EXPECT_EQ(key, it->first);
+    EXPECT_EQ(value, it->second);
+
+    // iterator mutable
+    ((*it).second) = value + 1;
+    EXPECT_EQ(value + 1, map_[key]);
+    ((*it).second) = value;
+    EXPECT_EQ(value, map_[key]);
+
+    it->second = value + 1;
+    EXPECT_EQ(value + 1, map_[key]);
+    it->second = value;
+    EXPECT_EQ(value, map_[key]);
+
+    // copy constructor
+    Map<int32, int32>::iterator it_copy = it;
+    EXPECT_EQ(key, it_copy->first);
+    EXPECT_EQ(value, it_copy->second);
+
+    // Immutable API ================================================
+
+    // Check immutable at and find work correctly.
+    EXPECT_EQ(value, const_map_.at(key));
+    Map<int32, int32>::const_iterator const_it = const_map_.find(key);
+
+    // iterator dereferenceable
+    EXPECT_EQ(key, (*const_it).first);
+    EXPECT_EQ(value, (*const_it).second);
+    EXPECT_EQ(key, const_it->first);
+    EXPECT_EQ(value, const_it->second);
+
+    // copy constructor
+    Map<int32, int32>::const_iterator const_it_copy = const_it;
+    EXPECT_EQ(key, const_it_copy->first);
+    EXPECT_EQ(value, const_it_copy->second);
+  }
+
+  std::unique_ptr<Map<int32, int32> > map_ptr_;
+  Map<int32, int32>& map_;
+  const Map<int32, int32>& const_map_;
+};
+
+TEST_F(MapImplTest, OperatorBracket) {
+  int32 key = 0;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  EXPECT_EQ(0, map_[key]);
+
+  map_[key] = value1;
+  ExpectSingleElement(key, value1);
+
+  map_[key] = value2;
+  ExpectSingleElement(key, value2);
+}
+
+struct MoveTestKey {
+  MoveTestKey(int data, int* copies) : data(data), copies(copies) {}
+
+  MoveTestKey(const MoveTestKey& other)
+      : data(other.data), copies(other.copies) {
+    ++*copies;
+  }
+
+  MoveTestKey(MoveTestKey&& other) noexcept
+      : data(other.data), copies(other.copies) {}
+
+  friend bool operator==(const MoveTestKey& lhs, const MoveTestKey& rhs) {
+    return lhs.data == rhs.data;
+  }
+  friend bool operator<(const MoveTestKey& lhs, const MoveTestKey& rhs) {
+    return lhs.data < rhs.data;
+  }
+
+  int data;
+  int* copies;
+};
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+namespace std {
+
+template <>  // NOLINT
+struct hash<google::protobuf::internal::MoveTestKey> {
+  size_t operator()(const google::protobuf::internal::MoveTestKey& key) const {
+    return hash<int>{}(key.data);
+  }
+};
+}  // namespace std
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST_F(MapImplTest, OperatorBracketRValue) {
+  Arena arena;
+  for (Arena* arena_to_use : {&arena, static_cast<Arena*>(nullptr)}) {
+    int copies = 0;
+    Map<MoveTestKey, int> map(arena_to_use);
+    MoveTestKey key1(1, &copies);
+    EXPECT_EQ(copies, 0);
+    map[key1] = 0;
+    EXPECT_EQ(copies, 1);
+    map[MoveTestKey(2, &copies)] = 2;
+    EXPECT_EQ(copies, 1);
+  }
+}
+
+TEST_F(MapImplTest, OperatorBracketNonExist) {
+  int32 key = 0;
+  int32 default_value = 0;
+
+  EXPECT_EQ(default_value, map_[key]);
+  ExpectSingleElement(key, default_value);
+}
+
+TEST_F(MapImplTest, MutableAt) {
+  int32 key = 0;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  map_[key] = value1;
+  ExpectSingleElement(key, value1);
+
+  map_.at(key) = value2;
+  ExpectSingleElement(key, value2);
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+TEST_F(MapImplTest, MutableAtNonExistDeathTest) {
+  EXPECT_DEATH(map_.at(0), "");
+}
+
+TEST_F(MapImplTest, ImmutableAtNonExistDeathTest) {
+  EXPECT_DEATH(const_map_.at(0), "");
+}
+
+TEST_F(MapImplTest, UsageErrors) {
+  MapKey key;
+  key.SetInt64Value(1);
+  EXPECT_DEATH(key.GetUInt64Value(),
+               "Protocol Buffer map usage error:\n"
+               "MapKey::GetUInt64Value type does not match\n"
+               "  Expected : uint64\n"
+               "  Actual   : int64");
+
+  MapValueRef value;
+  EXPECT_DEATH(
+      value.SetFloatValue(0.1),
+      "Protocol Buffer map usage error:\n"
+      "MapValue[Const]*Ref::type MapValue[Const]*Ref is not initialized.");
+}
+
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+TEST_F(MapImplTest, MapKeyAssignment) {
+  MapKey from, to;
+  from.SetStringValue("abc");
+  to = from;
+  EXPECT_EQ("abc", to.GetStringValue());
+}
+
+TEST_F(MapImplTest, CountNonExist) { EXPECT_EQ(0, map_.count(0)); }
+
+TEST_F(MapImplTest, ContainNotExist) { EXPECT_FALSE(map_.contains(0)); }
+
+TEST_F(MapImplTest, ImmutableContainNotExist) {
+  EXPECT_FALSE(const_map_.contains(0));
+}
+
+TEST_F(MapImplTest, MutableFindNonExist) {
+  EXPECT_TRUE(map_.end() == map_.find(0));
+}
+
+TEST_F(MapImplTest, ImmutableFindNonExist) {
+  EXPECT_TRUE(const_map_.end() == const_map_.find(0));
+}
+
+TEST_F(MapImplTest, ConstEnd) {
+  EXPECT_TRUE(const_map_.end() == const_map_.cend());
+}
+
+TEST_F(MapImplTest, GetReferenceFromIterator) {
+  for (int i = 0; i < 10; i++) {
+    map_[i] = i;
+  }
+
+  for (Map<int32, int32>::const_iterator it = map_.cbegin();
+       it != map_.cend();) {
+    Map<int32, int32>::const_reference entry = *it++;
+    EXPECT_EQ(entry.first, entry.second);
+  }
+
+  for (Map<int32, int32>::const_iterator it = const_map_.begin();
+       it != const_map_.end();) {
+    Map<int32, int32>::const_reference entry = *it++;
+    EXPECT_EQ(entry.first, entry.second);
+  }
+
+  for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
+    Map<int32, int32>::reference entry = *it++;
+    EXPECT_EQ(entry.first + 1, ++entry.second);
+  }
+}
+
+TEST_F(MapImplTest, IteratorBasic) {
+  map_[0] = 0;
+
+  // Default constructible (per forward iterator requirements).
+  Map<int, int>::const_iterator cit;
+  Map<int, int>::iterator it;
+
+  it = map_.begin();
+  cit = it;  // Converts to const_iterator
+
+  // Can compare between them.
+  EXPECT_TRUE(it == cit);
+  EXPECT_FALSE(cit != it);
+
+  // Pre increment.
+  EXPECT_FALSE(it == ++cit);
+
+  // Post increment.
+  EXPECT_FALSE(it++ == cit);
+  EXPECT_TRUE(it == cit);
+}
+
+template <typename Iterator>
+static int64 median(Iterator i0, Iterator i1) {
+  std::vector<int64> v(i0, i1);
+  std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end());
+  return v[v.size() / 2];
+}
+
+static int64 Now() {
+  return util::TimeUtil::TimestampToNanoseconds(
+      util::TimeUtil::GetCurrentTime());
+}
+
+// Arbitrary odd integers for creating test data.
+static int k0 = 812398771;
+static int k1 = 1312938717;
+static int k2 = 1321555333;
+
+// A naive begin() implementation will cause begin() to get slower and slower
+// if one erases elements at the "front" of the hash map, and we'd like to
+// avoid that, as std::unordered_map does.
+TEST_F(MapImplTest, BeginIsFast) {
+  if (true) return;  // TODO(gpike): make this less flaky and re-enable it.
+  Map<int32, int32> map;
+  const int kTestSize = 250000;
+  // Create a random-looking map of size n.  Use non-negative integer keys.
+  uint32 frog = 123983;
+  int last_key = 0;
+  int counter = 0;
+  while (map.size() < kTestSize) {
+    frog *= static_cast<uint32>(k0);
+    frog ^= frog >> 17;
+    frog += counter++;
+    last_key =
+        static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
+    GOOGLE_DCHECK_GE(last_key, 0);
+    map[last_key] = last_key ^ 1;
+  }
+  std::vector<int64> times;
+  // We're going to do map.erase(map.begin()) over and over again.  But,
+  // just in case one iteration is fast compared to the granularity of
+  // our time keeping, we measure kChunkSize iterations per outer-loop iter.
+  const int kChunkSize = 1000;
+  GOOGLE_CHECK_EQ(kTestSize % kChunkSize, 0);
+  do {
+    const int64 start = Now();
+    for (int i = 0; i < kChunkSize; i++) {
+      map.erase(map.begin());
+    }
+    const int64 end = Now();
+    if (end > start) {
+      times.push_back(end - start);
+    }
+  } while (!map.empty());
+  if (times.size() < .99 * kTestSize / kChunkSize) {
+    GOOGLE_LOG(WARNING) << "Now() isn't helping us measure time";
+    return;
+  }
+  int64 x0 = median(times.begin(), times.begin() + 9);
+  int64 x1 = median(times.begin() + times.size() - 9, times.end());
+  GOOGLE_LOG(INFO) << "x0=" << x0 << ", x1=" << x1;
+  // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
+  // And we'll probably time out and never get here.  So, this test is
+  // intentionally loose: we check that x0 and x1 are within a factor of 8.
+  EXPECT_GE(x1, x0 / 8);
+  EXPECT_GE(x0, x1 / 8);
+}
+
+// Try to create kTestSize keys that will land in just a few buckets, and
+// time the insertions, to get a rough estimate of whether an O(n^2) worst case
+// was triggered.  This test is a hacky, but probably better than nothing.
+TEST_F(MapImplTest, HashFlood) {
+  const int kTestSize = 1024;  // must be a power of 2
+  std::set<int> s;
+  for (int i = 0; s.size() < kTestSize; i++) {
+    if ((map_.hash_function()(i) & (kTestSize - 1)) < 3) {
+      s.insert(i);
+    }
+  }
+  // Create hash table with kTestSize entries that hash flood a table with
+  // 1024 (or 512 or 2048 or ...) entries.  This assumes that map_ uses powers
+  // of 2 for table sizes, and that it's sufficient to "flood" with respect to
+  // the low bits of the output of map_.hash_function().
+  std::vector<int64> times;
+  std::set<int>::iterator it = s.begin();
+  int count = 0;
+  do {
+    const int64 start = Now();
+    map_[*it] = 0;
+    const int64 end = Now();
+    if (end > start) {
+      times.push_back(end - start);
+    }
+    ++count;
+    ++it;
+  } while (it != s.end());
+  if (times.size() < .99 * count) return;
+  int64 x0 = median(times.begin(), times.begin() + 9);
+  int64 x1 = median(times.begin() + times.size() - 9, times.end());
+  // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
+  // But we want to allow O(n log n).  A factor of 20 should be generous enough.
+  EXPECT_LE(x1, x0 * 20);
+}
+
+TEST_F(MapImplTest, CopyIteratorStressTest) {
+  std::vector<Map<int32, int32>::iterator> v;
+  const int kIters = 1e5;
+  for (uint32 i = 0; i < kIters; i++) {
+    int32 key = (3 + i * (5 + i * (-8 + i * (62 + i)))) & 0x77777777;
+    map_[key] = i;
+    v.push_back(map_.find(key));
+  }
+  for (std::vector<Map<int32, int32>::iterator>::const_iterator it = v.begin();
+       it != v.end(); it++) {
+    Map<int32, int32>::iterator i = *it;
+    ASSERT_EQ(i->first, (*it)->first);
+    ASSERT_EQ(i->second, (*it)->second);
+  }
+}
+
+template <typename T, typename U>
+static void TestValidityForAllKeysExcept(int key_to_avoid, const T& check_map,
+                                         const U& map) {
+  typedef typename U::value_type value_type;  // a key-value pair
+  for (typename U::const_iterator it = map.begin(); it != map.end(); ++it) {
+    const int key = it->first;
+    if (key == key_to_avoid) continue;
+    // All iterators relevant to this key, whether old (from check_map) or new,
+    // must point to the same memory.  So, test pointer equality here.
+    const value_type* check_val = &*check_map.find(key)->second;
+    EXPECT_EQ(check_val, &*it);
+    EXPECT_EQ(check_val, &*map.find(key));
+  }
+}
+
+// EXPECT i0 and i1 to be the same.  Advancing them should have the same effect,
+// too.
+template <typename Iter>
+static void TestEqualIterators(Iter i0, Iter i1, Iter end) {
+  const int kMaxAdvance = 10;
+  for (int i = 0; i < kMaxAdvance; i++) {
+    EXPECT_EQ(i0 == end, i1 == end);
+    if (i0 == end) return;
+    EXPECT_EQ(&*i0, &*i1) << "iter " << i;
+    ++i0;
+    ++i1;
+  }
+}
+
+template <typename IteratorType>
+static void TestOldVersusNewIterator(int skip, Map<int, int>* m) {
+  const int initial_size = m->size();
+  IteratorType it = m->begin();
+  for (int i = 0; i < skip && it != m->end(); it++, i++) {
+  }
+  if (it == m->end()) return;
+  const IteratorType old = it;
+  GOOGLE_LOG(INFO) << "skip=" << skip << ", old->first=" << old->first;
+  const int target_size =
+      initial_size < 100 ? initial_size * 5 : initial_size * 5 / 4;
+  for (int i = 0; m->size() <= target_size; i++) {
+    (*m)[i] = 0;
+  }
+  // Iterator 'old' should still work just fine despite the growth of *m.
+  const IteratorType after_growth = m->find(old->first);
+  TestEqualIterators<IteratorType>(old, after_growth, m->end());
+
+  // Now shrink the number of elements.  Do this with a mix of erases and
+  // inserts to increase the chance that the hashtable will resize to a lower
+  // number of buckets.  (But, in any case, the test is still useful.)
+  for (int i = 0; i < 2 * (target_size - initial_size); i++) {
+    if (i != old->first) {
+      m->erase(i);
+    }
+    if (((i ^ m->begin()->first) & 15) == 0) {
+      (*m)[i * 342] = i;
+    }
+  }
+  // Now, the table has grown and shrunk; test again.
+  TestEqualIterators<IteratorType>(old, m->find(old->first), m->end());
+  TestEqualIterators<IteratorType>(old, after_growth, m->end());
+}
+
+// Create and test an n-element Map, with emphasis on iterator correctness.
+static void StressTestIterators(int n) {
+  GOOGLE_LOG(INFO) << "StressTestIterators " << n;
+  GOOGLE_CHECK_GT(n, 0);
+  // Create a random-looking map of size n.  Use non-negative integer keys.
+  Map<int, int> m;
+  uint32 frog = 123987 + n;
+  int last_key = 0;
+  int counter = 0;
+  while (m.size() < n) {
+    frog *= static_cast<uint32>(k0);
+    frog ^= frog >> 17;
+    frog += counter++;
+    last_key =
+        static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
+    GOOGLE_DCHECK_GE(last_key, 0);
+    m[last_key] = last_key ^ 1;
+  }
+  // Test it.
+  ASSERT_EQ(n, m.size());
+  // Create maps of pointers and iterators.
+  // These should remain valid even if we modify m.
+  std::unordered_map<int, Map<int, int>::value_type*> mp(n);
+  std::unordered_map<int, Map<int, int>::iterator> mi(n);
+  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) {
+    mp[it->first] = &*it;
+    mi[it->first] = it;
+  }
+  ASSERT_EQ(m.size(), mi.size());
+  ASSERT_EQ(m.size(), mp.size());
+  m.erase(last_key);
+  ASSERT_EQ(n - 1, m.size());
+  TestValidityForAllKeysExcept(last_key, mp, m);
+  TestValidityForAllKeysExcept(last_key, mi, m);
+
+  m[last_key] = 0;
+  ASSERT_EQ(n, m.size());
+  // Test old iterator vs new iterator, with table modification in between.
+  TestOldVersusNewIterator<Map<int, int>::const_iterator>(n % 3, &m);
+  TestOldVersusNewIterator<Map<int, int>::iterator>(n % (1 + (n / 40)), &m);
+  // Finally, ensure erase(iterator) doesn't reorder anything, because that is
+  // what its documentation says.
+  m[last_key] = m[last_key ^ 999] = 0;
+  std::vector<Map<int, int>::iterator> v;
+  v.reserve(m.size());
+  int position_of_last_key = 0;
+  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) {
+    if (it->first == last_key) {
+      position_of_last_key = v.size();
+    }
+    v.push_back(it);
+  }
+  ASSERT_EQ(m.size(), v.size());
+  const Map<int, int>::iterator erase_result = m.erase(m.find(last_key));
+  int index = 0;
+  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it, ++index) {
+    if (index == position_of_last_key) {
+      EXPECT_EQ(&*erase_result, &*v[++index]);
+    }
+    ASSERT_EQ(&*it, &*v[index]);
+  }
+}
+
+TEST_F(MapImplTest, IteratorInvalidation) {
+  // Create a set of pseudo-random sizes to test.
+#ifndef NDEBUG
+  const int kMaxSizeToTest = 100 * 1000;
+#else
+  const int kMaxSizeToTest = 1000 * 1000;
+#endif
+  std::set<int> s;
+  int n = kMaxSizeToTest;
+  unsigned int frog = k1 + n;
+  while (n > 1 && s.size() < 25) {
+    s.insert(n);
+    n = static_cast<int>(n * 100 / (101.0 + (frog & 63)));
+    frog *= k2;
+    frog ^= frog >> 17;
+  }
+  // Ensure we test a few small sizes.
+  s.insert(1);
+  s.insert(2);
+  s.insert(3);
+  // Now, the real work.
+  for (std::set<int>::iterator i = s.begin(); i != s.end(); ++i) {
+    StressTestIterators(*i);
+  }
+}
+
+// Test that erase() revalidates iterators.
+TEST_F(MapImplTest, EraseRevalidates) {
+  map_[3] = map_[13] = map_[20] = 0;
+  const int initial_size = map_.size();
+  EXPECT_EQ(3, initial_size);
+  std::vector<Map<int, int>::iterator> v;
+  for (Map<int, int>::iterator it = map_.begin(); it != map_.end(); ++it) {
+    v.push_back(it);
+  }
+  EXPECT_EQ(initial_size, v.size());
+  for (int i = 0; map_.size() <= initial_size * 20; i++) {
+    map_[i] = 0;
+  }
+  const int larger_size = map_.size();
+  // We've greatly increased the size of the map, so it is highly likely that
+  // the following will corrupt m if erase() doesn't properly revalidate
+  // iterators passed to it.  Finishing this routine without crashing indicates
+  // success.
+  for (int i = 0; i < v.size(); i++) {
+    map_.erase(v[i]);
+  }
+  EXPECT_EQ(larger_size - v.size(), map_.size());
+}
+
+template <typename T>
+bool IsConstHelper(T& /*t*/) {  // NOLINT. We want to catch non-const refs here.
+  return false;
+}
+template <typename T>
+bool IsConstHelper(const T& /*t*/) {
+  return true;
+}
+
+TEST_F(MapImplTest, IteratorConstness) {
+  map_[0] = 0;
+  EXPECT_TRUE(IsConstHelper(*map_.cbegin()));
+  EXPECT_TRUE(IsConstHelper(*const_map_.begin()));
+  EXPECT_FALSE(IsConstHelper(*map_.begin()));
+}
+
+bool IsForwardIteratorHelper(std::forward_iterator_tag /*tag*/) { return true; }
+
+TEST_F(MapImplTest, IteratorCategory) {
+  EXPECT_TRUE(IsForwardIteratorHelper(
+      std::iterator_traits<Map<int, int>::iterator>::iterator_category()));
+  EXPECT_TRUE(IsForwardIteratorHelper(
+      std::iterator_traits<
+          Map<int, int>::const_iterator>::iterator_category()));
+}
+
+TEST_F(MapImplTest, InsertSingle) {
+  int32 key = 0;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  // Insert a non-existed key.
+  std::pair<Map<int32, int32>::iterator, bool> result1 =
+      map_.insert(Map<int32, int32>::value_type(key, value1));
+  ExpectSingleElement(key, value1);
+
+  Map<int32, int32>::iterator it1 = result1.first;
+  EXPECT_EQ(key, it1->first);
+  EXPECT_EQ(value1, it1->second);
+  EXPECT_TRUE(result1.second);
+
+  // Insert an existed key.
+  std::pair<Map<int32, int32>::iterator, bool> result2 =
+      map_.insert(Map<int32, int32>::value_type(key, value2));
+  ExpectSingleElement(key, value1);
+
+  Map<int32, int32>::iterator it2 = result2.first;
+  EXPECT_TRUE(it1 == it2);
+  EXPECT_FALSE(result2.second);
+}
+
+TEST_F(MapImplTest, InsertByIterator) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1a = 100;
+  int32 value1b = 101;
+  int32 value2a = 200;
+  int32 value2b = 201;
+
+  std::map<int32, int32> map1;
+  map1[key1] = value1a;
+  map1[key2] = value2a;
+
+  map_.insert(map1.begin(), map1.end());
+  ExpectElements(map1);
+
+  std::map<int32, int32> map2;
+  map2[key1] = value1b;
+  map2[key2] = value2b;
+
+  map_.insert(map2.begin(), map2.end());
+  ExpectElements(map1);
+}
+
+TEST_F(MapImplTest, InsertByInitializerList) {
+  map_.insert({{1, 100}, {2, 200}});
+  ExpectElements({{1, 100}, {2, 200}});
+
+  map_.insert({{2, 201}, {3, 301}});
+  ExpectElements({{1, 100}, {2, 200}, {3, 301}});
+}
+
+TEST_F(MapImplTest, EraseSingleByKey) {
+  int32 key = 0;
+  int32 value = 100;
+
+  map_[key] = value;
+  ExpectSingleElement(key, value);
+
+  // Erase an existing key.
+  EXPECT_EQ(1, map_.erase(key));
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key));
+  EXPECT_TRUE(map_.begin() == map_.end());
+
+  // Erase a non-existing key.
+  EXPECT_EQ(0, map_.erase(key));
+}
+
+TEST_F(MapImplTest, EraseMutipleByKey) {
+  // erase in one specific order to trigger corner cases
+  for (int i = 0; i < 5; i++) {
+    map_[i] = i;
+  }
+
+  map_.erase(0);
+  EXPECT_EQ(4, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(0));
+
+  map_.erase(1);
+  EXPECT_EQ(3, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(1));
+
+  map_.erase(3);
+  EXPECT_EQ(2, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(3));
+
+  map_.erase(4);
+  EXPECT_EQ(1, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(4));
+
+  map_.erase(2);
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(2));
+}
+
+TEST_F(MapImplTest, EraseSingleByIterator) {
+  int32 key = 0;
+  int32 value = 100;
+
+  map_[key] = value;
+  ExpectSingleElement(key, value);
+
+  Map<int32, int32>::iterator it = map_.find(key);
+  map_.erase(it);
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key));
+  EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+TEST_F(MapImplTest, ValidIteratorAfterErase) {
+  for (int i = 0; i < 10; i++) {
+    map_[i] = i;
+  }
+
+  int count = 0;
+
+  for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
+    count++;
+    if (it->first % 2 == 1) {
+      map_.erase(it++);
+    } else {
+      ++it;
+    }
+  }
+
+  EXPECT_EQ(10, count);
+  EXPECT_EQ(5, map_.size());
+}
+
+TEST_F(MapImplTest, EraseByIterator) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  std::map<int32, int32> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  map_.insert(map.begin(), map.end());
+  ExpectElements(map);
+
+  map_.erase(map_.begin(), map_.end());
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key1));
+  EXPECT_TRUE(map_.end() == map_.find(key2));
+  EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+TEST_F(MapImplTest, Clear) {
+  int32 key = 0;
+  int32 value = 100;
+
+  map_[key] = value;
+  ExpectSingleElement(key, value);
+
+  map_.clear();
+
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key));
+  EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+static void CopyConstructorHelper(Arena* arena, Map<int32, int32>* m) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  std::map<int32, int32> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  m->insert(map.begin(), map.end());
+
+  Map<int32, int32> other(*m);
+
+  EXPECT_EQ(2, other.size());
+  EXPECT_EQ(value1, other.at(key1));
+  EXPECT_EQ(value2, other.at(key2));
+}
+
+TEST_F(MapImplTest, CopyConstructorWithArena) {
+  Arena a;
+  CopyConstructorHelper(&a, &map_);
+}
+
+TEST_F(MapImplTest, CopyConstructorWithoutArena) {
+  CopyConstructorHelper(NULL, &map_);
+}
+
+TEST_F(MapImplTest, IterConstructor) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  std::map<int32, int32> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  Map<int32, int32> new_map(map.begin(), map.end());
+
+  EXPECT_EQ(2, new_map.size());
+  EXPECT_EQ(value1, new_map.at(key1));
+  EXPECT_EQ(value2, new_map.at(key2));
+}
+
+TEST_F(MapImplTest, Assigner) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  std::map<int32, int32> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  map_.insert(map.begin(), map.end());
+
+  Map<int32, int32> other;
+  int32 key_other = 123;
+  int32 value_other = 321;
+  other[key_other] = value_other;
+  EXPECT_EQ(1, other.size());
+
+  other = map_;
+
+  EXPECT_EQ(2, other.size());
+  EXPECT_EQ(value1, other.at(key1));
+  EXPECT_EQ(value2, other.at(key2));
+  EXPECT_TRUE(other.find(key_other) == other.end());
+
+  // Self assign
+  other = *&other;  // Avoid -Wself-assign.
+  EXPECT_EQ(2, other.size());
+  EXPECT_EQ(value1, other.at(key1));
+  EXPECT_EQ(value2, other.at(key2));
+}
+
+TEST_F(MapImplTest, Rehash) {
+  const int test_size = 50;
+  std::map<int32, int32> reference_map;
+  for (int i = 0; i < test_size; i++) {
+    reference_map[i] = i;
+  }
+  for (int i = 0; i < test_size; i++) {
+    map_[i] = reference_map[i];
+    EXPECT_EQ(reference_map[i], map_[i]);
+  }
+  for (int i = 0; i < test_size; i++) {
+    map_.erase(i);
+    EXPECT_TRUE(map_.end() == map_.find(i));
+  }
+  EXPECT_TRUE(map_.empty());
+}
+
+TEST_F(MapImplTest, EqualRange) {
+  int key = 100, key_missing = 101;
+  map_[key] = 100;
+
+  std::pair<Map<int32, int32>::iterator, Map<int32, int32>::iterator> range =
+      map_.equal_range(key);
+  EXPECT_TRUE(map_.find(key) == range.first);
+  EXPECT_TRUE(++map_.find(key) == range.second);
+
+  range = map_.equal_range(key_missing);
+  EXPECT_TRUE(map_.end() == range.first);
+  EXPECT_TRUE(map_.end() == range.second);
+
+  std::pair<Map<int32, int32>::const_iterator,
+            Map<int32, int32>::const_iterator>
+      const_range = const_map_.equal_range(key);
+  EXPECT_TRUE(const_map_.find(key) == const_range.first);
+  EXPECT_TRUE(++const_map_.find(key) == const_range.second);
+
+  const_range = const_map_.equal_range(key_missing);
+  EXPECT_TRUE(const_map_.end() == const_range.first);
+  EXPECT_TRUE(const_map_.end() == const_range.second);
+}
+
+TEST_F(MapImplTest, ConvertToStdMap) {
+  map_[100] = 101;
+  std::map<int32, int32> std_map(map_.begin(), map_.end());
+  EXPECT_EQ(1, std_map.size());
+  EXPECT_EQ(101, std_map[100]);
+}
+
+TEST_F(MapImplTest, ConvertToStdVectorOfPairs) {
+  map_[100] = 101;
+  std::vector<std::pair<int32, int32> > std_vec(map_.begin(), map_.end());
+  EXPECT_EQ(1, std_vec.size());
+  EXPECT_EQ(100, std_vec[0].first);
+  EXPECT_EQ(101, std_vec[0].second);
+}
+
+TEST_F(MapImplTest, SwapBasic) {
+  Map<int32, int32> another;
+  map_[9398] = 41999;
+  another[9398] = 41999;
+  another[8070] = 42056;
+  another.swap(map_);
+  EXPECT_THAT(another,
+              testing::UnorderedElementsAre(testing::Pair(9398, 41999)));
+  EXPECT_THAT(map_, testing::UnorderedElementsAre(testing::Pair(8070, 42056),
+                                                  testing::Pair(9398, 41999)));
+}
+
+TEST_F(MapImplTest, SwapArena) {
+  Arena arena1, arena2;
+  Map<int32, int32> m1(&arena1);
+  Map<int32, int32> m2(&arena2);
+  map_[9398] = 41999;
+  m1[9398] = 41999;
+  m1[8070] = 42056;
+  m2[10244] = 10247;
+  m2[8070] = 42056;
+  m1.swap(map_);
+  EXPECT_THAT(m1, testing::UnorderedElementsAre(testing::Pair(9398, 41999)));
+  EXPECT_THAT(map_, testing::UnorderedElementsAre(testing::Pair(8070, 42056),
+                                                  testing::Pair(9398, 41999)));
+  m2.swap(m1);
+  EXPECT_THAT(m1, testing::UnorderedElementsAre(testing::Pair(8070, 42056),
+                                                testing::Pair(10244, 10247)));
+  EXPECT_THAT(m2, testing::UnorderedElementsAre(testing::Pair(9398, 41999)));
+}
+
+TEST_F(MapImplTest, CopyAssignMapIterator) {
+  TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&message);
+  MapIterator it1 = reflection_tester.MapBegin(&message, "map_int32_int32");
+  MapIterator it2 = reflection_tester.MapEnd(&message, "map_int32_int32");
+  it2 = it1;
+  EXPECT_EQ(it1.GetKey().GetInt32Value(), it2.GetKey().GetInt32Value());
+}
+
+TEST_F(MapImplTest, SpaceUsed) {
+  constexpr size_t kMinCap = 8;
+
+  Map<int32, int32> m;
+  // An newly constructed map should have no space used.
+  EXPECT_EQ(m.SpaceUsedExcludingSelfLong(), 0);
+
+  size_t capacity = kMinCap;
+  for (int i = 0; i < 100; ++i) {
+    m[i];
+    static constexpr double kMaxLoadFactor = .75;
+    if (m.size() >= capacity * kMaxLoadFactor) {
+      capacity *= 2;
+    }
+    EXPECT_EQ(m.SpaceUsedExcludingSelfLong(),
+              sizeof(void*) * capacity +
+                  m.size() * sizeof(std::pair<std::pair<int32, int32>, void*>));
+  }
+
+  // Test string, and non-scalar keys.
+  Map<std::string, int32> m2;
+  std::string str = "Some arbitrarily large string";
+  m2[str] = 1;
+  EXPECT_EQ(m2.SpaceUsedExcludingSelfLong(),
+            sizeof(void*) * kMinCap +
+                sizeof(std::pair<std::pair<std::string, int32>, void*>) +
+                internal::StringSpaceUsedExcludingSelfLong(str));
+
+  // Test messages, and non-scalar values.
+  Map<int32, TestAllTypes> m3;
+  m3[0].set_optional_string(str);
+  EXPECT_EQ(m3.SpaceUsedExcludingSelfLong(),
+            sizeof(void*) * kMinCap +
+                sizeof(std::pair<std::pair<int32, TestAllTypes>, void*>) +
+                m3[0].SpaceUsedLong() - sizeof(m3[0]));
+}
+
+// Attempts to verify that a map with keys a and b has a random ordering. This
+// function returns true if it succeeds in observing both possible orderings.
+bool MapOrderingIsRandom(int a, int b) {
+  bool saw_a_first = false;
+  bool saw_b_first = false;
+  std::vector<Map<int32, int32>> v(50);
+  for (int i = 0; i < 50; ++i) {
+    Map<int32, int32>& m = v[i];
+    m[a] = 0;
+    m[b] = 0;
+    int32 first_element = m.begin()->first;
+    if (first_element == a) saw_a_first = true;
+    if (first_element == b) saw_b_first = true;
+    if (saw_a_first && saw_b_first) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// This test verifies that the iteration order is reasonably random even for
+// small maps. Currently we only have sufficient randomness for debug builds and
+// builds where we can use the RDTSC instruction, so we only test for those
+// builds.
+#if defined(__x86_64__) && defined(__GNUC__) && \
+    !defined(GOOGLE_PROTOBUF_NO_RDTSC)
+TEST_F(MapImplTest, RandomOrdering) {
+  for (int i = 0; i < 10; ++i) {
+    for (int j = i + 1; j < 10; ++j) {
+      EXPECT_TRUE(MapOrderingIsRandom(i, j))
+          << "Map with keys " << i << " and " << j
+          << " has deterministic ordering";
+    }
+  }
+}
+#endif
+
+template <typename Key>
+void TestTransparent(const Key& key, const Key& miss_key) {
+  Map<std::string, int> m;
+  const auto& cm = m;
+
+  m.insert({"ABC", 1});
+
+  const auto abc_it = m.begin();
+
+  m.insert({"DEF", 2});
+
+  using testing::Pair;
+  using testing::UnorderedElementsAre;
+
+  EXPECT_EQ(m.at(key), 1);
+  EXPECT_EQ(cm.at(key), 1);
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+  EXPECT_DEATH(m.at(miss_key), "");
+  EXPECT_DEATH(cm.at(miss_key), "");
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+  EXPECT_EQ(m.count(key), 1);
+  EXPECT_EQ(cm.count(key), 1);
+  EXPECT_EQ(m.count(miss_key), 0);
+  EXPECT_EQ(cm.count(miss_key), 0);
+
+  EXPECT_EQ(m.find(key), abc_it);
+  EXPECT_EQ(cm.find(key), abc_it);
+  EXPECT_EQ(m.find(miss_key), m.end());
+  EXPECT_EQ(cm.find(miss_key), cm.end());
+
+  EXPECT_TRUE(m.contains(key));
+  EXPECT_TRUE(cm.contains(key));
+  EXPECT_FALSE(m.contains(miss_key));
+  EXPECT_FALSE(cm.contains(miss_key));
+
+  EXPECT_THAT(m.equal_range(key), Pair(abc_it, std::next(abc_it)));
+  EXPECT_THAT(cm.equal_range(key), Pair(abc_it, std::next(abc_it)));
+  EXPECT_THAT(m.equal_range(miss_key), Pair(m.end(), m.end()));
+  EXPECT_THAT(cm.equal_range(miss_key), Pair(m.end(), m.end()));
+
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 1), Pair("DEF", 2)));
+  EXPECT_EQ(m.erase(key), 1);
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("DEF", 2)));
+  EXPECT_EQ(m.erase(key), 0);
+  EXPECT_EQ(m.erase(miss_key), 0);
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("DEF", 2)));
+
+  m[key];
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 0), Pair("DEF", 2)));
+  m[key] = 1;
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 1), Pair("DEF", 2)));
+}
+
+TEST_F(MapImplTest, TransparentLookupForString) {
+  TestTransparent("ABC", "LKJ");
+  TestTransparent(std::string("ABC"), std::string("LKJ"));
+#if defined(__cpp_lib_string_view)
+  TestTransparent(std::string_view("ABC"), std::string_view("LKJ"));
+#endif  // defined(__cpp_lib_string_view)
+
+  // std::reference_wrapper
+  std::string abc = "ABC", lkj = "LKJ";
+  TestTransparent(std::ref(abc), std::ref(lkj));
+  TestTransparent(std::cref(abc), std::cref(lkj));
+}
+
+TEST_F(MapImplTest, ConstInit) {
+  PROTOBUF_CONSTINIT static Map<int, int> map;  // NOLINT
+  EXPECT_TRUE(map.empty());
+}
+
+// Map Field Reflection Test ========================================
+
+static int Func(int i, int j) { return i * j; }
+
+static std::string StrFunc(int i, int j) { return StrCat(Func(i, j)); }
+
+static int Int(const std::string& value) {
+  int result = 0;
+  std::istringstream(value) >> result;
+  return result;
+}
+
+}  // namespace
+
+// This class is a friend, so no anonymous namespace.
+class MapFieldReflectionTest : public testing::Test {
+ protected:
+  typedef FieldDescriptor FD;
+
+  int MapSize(const Reflection* reflection, const FieldDescriptor* field,
+              const Message& message) {
+    return reflection->MapSize(message, field);
+  }
+};
+
+namespace {
+
+TEST_F(MapFieldReflectionTest, RegularFields) {
+  TestMap message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
+  Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
+  Map<std::string, std::string>* map_string_string =
+      message.mutable_map_string_string();
+  Map<int32, ForeignMessage>* map_int32_foreign_message =
+      message.mutable_map_int32_foreign_message();
+
+  for (int i = 0; i < 10; ++i) {
+    (*map_int32_int32)[i] = Func(i, 1);
+    (*map_int32_double)[i] = Func(i, 2);
+    (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
+    (*map_int32_foreign_message)[i].set_c(Func(i, 6));
+  }
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_map_int32_int32 =
+      desc->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* fd_map_int32_double =
+      desc->FindFieldByName("map_int32_double");
+  const FieldDescriptor* fd_map_string_string =
+      desc->FindFieldByName("map_string_string");
+  const FieldDescriptor* fd_map_int32_foreign_message =
+      desc->FindFieldByName("map_int32_foreign_message");
+
+  const FieldDescriptor* fd_map_int32_in32_key =
+      fd_map_int32_int32->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_in32_value =
+      fd_map_int32_int32->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_int32_double_key =
+      fd_map_int32_double->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_double_value =
+      fd_map_int32_double->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_string_string_key =
+      fd_map_string_string->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_string_string_value =
+      fd_map_string_string->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_int32_foreign_message_key =
+      fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_foreign_message_value =
+      fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
+
+  // Get RepeatedPtrField objects for all fields of interest.
+  const RepeatedPtrField<Message>& mf_int32_int32 =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_int32);
+  const RepeatedPtrField<Message>& mf_int32_double =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_double);
+  const RepeatedPtrField<Message>& mf_string_string =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_string_string);
+  const RepeatedPtrField<Message>& mf_int32_foreign_message =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_foreign_message);
+
+  // Get mutable RepeatedPtrField objects for all fields of interest.
+  RepeatedPtrField<Message>* mmf_int32_int32 =
+      refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_int32);
+  RepeatedPtrField<Message>* mmf_int32_double =
+      refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_double);
+  RepeatedPtrField<Message>* mmf_string_string =
+      refl->MutableRepeatedPtrField<Message>(&message, fd_map_string_string);
+  RepeatedPtrField<Message>* mmf_int32_foreign_message =
+      refl->MutableRepeatedPtrField<Message>(&message,
+                                             fd_map_int32_foreign_message);
+
+  // Make sure we can do gets through the RepeatedPtrField objects.
+  for (int i = 0; i < 10; ++i) {
+    {
+      // Check gets through const objects.
+      const Message& message_int32_int32 = mf_int32_int32.Get(i);
+      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double = mf_int32_double.Get(i);
+      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string = mf_string_string.Get(i);
+      std::string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      std::string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message = mf_int32_foreign_message.Get(i);
+      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+          message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()->GetMessage(
+                  message_int32_message, fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+
+    {
+      // Check gets through mutable objects.
+      const Message& message_int32_int32 = mmf_int32_int32->Get(i);
+      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double = mmf_int32_double->Get(i);
+      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string = mmf_string_string->Get(i);
+      std::string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      std::string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message = mmf_int32_foreign_message->Get(i);
+      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+          message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()->GetMessage(
+                  message_int32_message, fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+  }
+
+  // Do sets through the RepeatedPtrField objects.
+  for (int i = 0; i < 10; i++) {
+    {
+      Message* message_int32_int32 = mmf_int32_int32->Mutable(i);
+      int32 key_int32_int32 = message_int32_int32->GetReflection()->GetInt32(
+          *message_int32_int32, fd_map_int32_in32_key);
+      message_int32_int32->GetReflection()->SetInt32(message_int32_int32,
+                                                     fd_map_int32_in32_value,
+                                                     Func(key_int32_int32, -1));
+
+      Message* message_int32_double = mmf_int32_double->Mutable(i);
+      int32 key_int32_double = message_int32_double->GetReflection()->GetInt32(
+          *message_int32_double, fd_map_int32_double_key);
+      message_int32_double->GetReflection()->SetDouble(
+          message_int32_double, fd_map_int32_double_value,
+          Func(key_int32_double, -2));
+
+      Message* message_string_string = mmf_string_string->Mutable(i);
+      std::string key_string_string =
+          message_string_string->GetReflection()->GetString(
+              *message_string_string, fd_map_string_string_key);
+      message_string_string->GetReflection()->SetString(
+          message_string_string, fd_map_string_string_value,
+          StrFunc(Int(key_string_string), -5));
+
+      Message* message_int32_message = mmf_int32_foreign_message->Mutable(i);
+      int32 key_int32_message =
+          message_int32_message->GetReflection()->GetInt32(
+              *message_int32_message, fd_map_int32_foreign_message_key);
+      ForeignMessage* value_int32_message = down_cast<ForeignMessage*>(
+          message_int32_message->GetReflection()->MutableMessage(
+              message_int32_message, fd_map_int32_foreign_message_value));
+      value_int32_message->set_c(Func(key_int32_message, -6));
+    }
+  }
+
+  // Check gets through mutable objects.
+  for (int i = 0; i < 10; i++) {
+    EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
+    EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
+    EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
+    EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
+  }
+}
+
+TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) {
+  TestMap message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
+  Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
+  Map<std::string, std::string>* map_string_string =
+      message.mutable_map_string_string();
+  Map<int32, ForeignMessage>* map_int32_foreign_message =
+      message.mutable_map_int32_foreign_message();
+
+  for (int i = 0; i < 10; ++i) {
+    (*map_int32_int32)[i] = Func(i, 1);
+    (*map_int32_double)[i] = Func(i, 2);
+    (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
+    (*map_int32_foreign_message)[i].set_c(Func(i, 6));
+  }
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_map_int32_int32 =
+      desc->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* fd_map_int32_double =
+      desc->FindFieldByName("map_int32_double");
+  const FieldDescriptor* fd_map_string_string =
+      desc->FindFieldByName("map_string_string");
+  const FieldDescriptor* fd_map_int32_foreign_message =
+      desc->FindFieldByName("map_int32_foreign_message");
+
+  const FieldDescriptor* fd_map_int32_in32_key =
+      fd_map_int32_int32->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_in32_value =
+      fd_map_int32_int32->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_int32_double_key =
+      fd_map_int32_double->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_double_value =
+      fd_map_int32_double->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_string_string_key =
+      fd_map_string_string->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_string_string_value =
+      fd_map_string_string->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_int32_foreign_message_key =
+      fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_foreign_message_value =
+      fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
+
+  // Get RepeatedFieldRef objects for all fields of interest.
+  const RepeatedFieldRef<Message> mf_int32_int32 =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_int32);
+  const RepeatedFieldRef<Message> mf_int32_double =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_double);
+  const RepeatedFieldRef<Message> mf_string_string =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_string_string);
+  const RepeatedFieldRef<Message> mf_int32_foreign_message =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_foreign_message);
+
+  // Get mutable RepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
+      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_int32);
+  const MutableRepeatedFieldRef<Message> mmf_int32_double =
+      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_double);
+  const MutableRepeatedFieldRef<Message> mmf_string_string =
+      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_string_string);
+  const MutableRepeatedFieldRef<Message> mmf_int32_foreign_message =
+      refl->GetMutableRepeatedFieldRef<Message>(&message,
+                                                fd_map_int32_foreign_message);
+
+  // Get entry default instances
+  std::unique_ptr<Message> entry_int32_int32(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_int32_int32->message_type())
+          ->New(message.GetArena()));
+  std::unique_ptr<Message> entry_int32_double(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_int32_double->message_type())
+          ->New(message.GetArena()));
+  std::unique_ptr<Message> entry_string_string(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_string_string->message_type())
+          ->New(message.GetArena()));
+  std::unique_ptr<Message> entry_int32_foreign_message(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_int32_foreign_message->message_type())
+          ->New(message.GetArena()));
+
+  EXPECT_EQ(10, mf_int32_int32.size());
+  EXPECT_EQ(10, mmf_int32_int32.size());
+  EXPECT_EQ(10, mf_int32_double.size());
+  EXPECT_EQ(10, mmf_int32_double.size());
+  EXPECT_EQ(10, mf_string_string.size());
+  EXPECT_EQ(10, mmf_string_string.size());
+  EXPECT_EQ(10, mf_int32_foreign_message.size());
+  EXPECT_EQ(10, mmf_int32_foreign_message.size());
+
+  EXPECT_FALSE(mf_int32_int32.empty());
+  EXPECT_FALSE(mmf_int32_int32.empty());
+  EXPECT_FALSE(mf_int32_double.empty());
+  EXPECT_FALSE(mmf_int32_double.empty());
+  EXPECT_FALSE(mf_string_string.empty());
+  EXPECT_FALSE(mmf_string_string.empty());
+  EXPECT_FALSE(mf_int32_foreign_message.empty());
+  EXPECT_FALSE(mmf_int32_foreign_message.empty());
+
+  // Make sure we can do gets through the RepeatedFieldRef objects.
+  for (int i = 0; i < 10; ++i) {
+    {
+      // Check gets through const objects.
+      const Message& message_int32_int32 =
+          mf_int32_int32.Get(i, entry_int32_int32.get());
+      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double =
+          mf_int32_double.Get(i, entry_int32_double.get());
+      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string =
+          mf_string_string.Get(i, entry_string_string.get());
+      std::string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      std::string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message =
+          mf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
+      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+          message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()->GetMessage(
+                  message_int32_message, fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+
+    {
+      // Check gets through mutable objects.
+      const Message& message_int32_int32 =
+          mmf_int32_int32.Get(i, entry_int32_int32.get());
+      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double =
+          mmf_int32_double.Get(i, entry_int32_double.get());
+      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string =
+          mmf_string_string.Get(i, entry_string_string.get());
+      std::string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      std::string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message =
+          mmf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
+      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+          message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()->GetMessage(
+                  message_int32_message, fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+  }
+
+  // Make sure we can do sets through the RepeatedFieldRef objects.
+  for (int i = 0; i < 10; i++) {
+    const Message& message_int32_int32 =
+        mmf_int32_int32.Get(i, entry_int32_int32.get());
+    int key = message_int32_int32.GetReflection()->GetInt32(
+        message_int32_int32, fd_map_int32_in32_key);
+
+    entry_int32_int32->GetReflection()->SetInt32(
+        entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
+        key);
+    entry_int32_int32->GetReflection()->SetInt32(
+        entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
+        Func(key, -1));
+    entry_int32_double->GetReflection()->SetInt32(
+        entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
+        key);
+    entry_int32_double->GetReflection()->SetDouble(
+        entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
+        Func(key, -2));
+    entry_string_string->GetReflection()->SetString(
+        entry_string_string.get(),
+        fd_map_string_string->message_type()->field(0), StrFunc(key, 1));
+    entry_string_string->GetReflection()->SetString(
+        entry_string_string.get(),
+        fd_map_string_string->message_type()->field(1), StrFunc(key, -5));
+    entry_int32_foreign_message->GetReflection()->SetInt32(
+        entry_int32_foreign_message.get(),
+        fd_map_int32_foreign_message->message_type()->field(0), key);
+    Message* value_message =
+        entry_int32_foreign_message->GetReflection()->MutableMessage(
+            entry_int32_foreign_message.get(),
+            fd_map_int32_foreign_message->message_type()->field(1));
+    value_message->GetReflection()->SetInt32(
+        value_message, value_message->GetDescriptor()->FindFieldByName("c"),
+        Func(key, -6));
+
+    mmf_int32_int32.Set(i, *entry_int32_int32);
+    mmf_int32_double.Set(i, *entry_int32_double);
+    mmf_string_string.Set(i, *entry_string_string);
+    mmf_int32_foreign_message.Set(i, *entry_int32_foreign_message);
+  }
+
+  for (int i = 0; i < 10; i++) {
+    EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
+    EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
+    EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
+    EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
+  }
+
+  // Test iterators.
+  {
+    int index = 0;
+    std::unordered_map<int32, int32> result;
+    for (RepeatedFieldRef<Message>::iterator it = mf_int32_int32.begin();
+         it != mf_int32_int32.end(); ++it) {
+      const Message& message = *it;
+      int32 key =
+          message.GetReflection()->GetInt32(message, fd_map_int32_in32_key);
+      int32 value =
+          message.GetReflection()->GetInt32(message, fd_map_int32_in32_value);
+      result[key] = value;
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (std::unordered_map<int32, int32>::const_iterator it = result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_int32_int32().at(it->first), it->second);
+    }
+  }
+
+  {
+    int index = 0;
+    std::unordered_map<int32, double> result;
+    for (RepeatedFieldRef<Message>::iterator it = mf_int32_double.begin();
+         it != mf_int32_double.end(); ++it) {
+      const Message& message = *it;
+      int32 key =
+          message.GetReflection()->GetInt32(message, fd_map_int32_double_key);
+      double value = message.GetReflection()->GetDouble(
+          message, fd_map_int32_double_value);
+      result[key] = value;
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (std::unordered_map<int32, double>::const_iterator it = result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_int32_double().at(it->first), it->second);
+    }
+  }
+
+  {
+    int index = 0;
+    std::unordered_map<std::string, std::string> result;
+    for (RepeatedFieldRef<Message>::iterator it = mf_string_string.begin();
+         it != mf_string_string.end(); ++it) {
+      const Message& message = *it;
+      std::string key =
+          message.GetReflection()->GetString(message, fd_map_string_string_key);
+      std::string value = message.GetReflection()->GetString(
+          message, fd_map_string_string_value);
+      result[key] = value;
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (std::unordered_map<std::string, std::string>::const_iterator it =
+             result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_string_string().at(it->first), it->second);
+    }
+  }
+
+  {
+    int index = 0;
+    std::map<int32, ForeignMessage> result;
+    for (RepeatedFieldRef<Message>::iterator it =
+             mf_int32_foreign_message.begin();
+         it != mf_int32_foreign_message.end(); ++it) {
+      const Message& message = *it;
+      int32 key = message.GetReflection()->GetInt32(
+          message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& sub_message =
+          down_cast<const ForeignMessage&>(message.GetReflection()->GetMessage(
+              message, fd_map_int32_foreign_message_value));
+      result[key].MergeFrom(sub_message);
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (std::map<int32, ForeignMessage>::const_iterator it = result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_int32_foreign_message().at(it->first).c(),
+                it->second.c());
+    }
+  }
+
+  // Test MutableRepeatedFieldRef::Add()
+  entry_int32_int32->GetReflection()->SetInt32(
+      entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
+      4321);
+  entry_int32_int32->GetReflection()->SetInt32(
+      entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
+      1234);
+  mmf_int32_int32.Add(*entry_int32_int32);
+  EXPECT_EQ(1234, message.map_int32_int32().at(4321));
+
+  entry_int32_double->GetReflection()->SetInt32(
+      entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
+      4321);
+  entry_int32_double->GetReflection()->SetDouble(
+      entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
+      1234.0);
+  mmf_int32_double.Add(*entry_int32_double);
+  EXPECT_EQ(1234.0, message.map_int32_double().at(4321));
+
+  entry_string_string->GetReflection()->SetString(
+      entry_string_string.get(), fd_map_string_string->message_type()->field(0),
+      "4321");
+  entry_string_string->GetReflection()->SetString(
+      entry_string_string.get(), fd_map_string_string->message_type()->field(1),
+      "1234");
+  mmf_string_string.Add(*entry_string_string);
+  EXPECT_EQ("1234", message.map_string_string().at("4321"));
+
+  entry_int32_foreign_message->GetReflection()->SetInt32(
+      entry_int32_foreign_message.get(),
+      fd_map_int32_foreign_message->message_type()->field(0), 4321);
+  Message* value_message =
+      entry_int32_foreign_message->GetReflection()->MutableMessage(
+          entry_int32_foreign_message.get(),
+          fd_map_int32_foreign_message->message_type()->field(1));
+  ForeignMessage foreign_message;
+  foreign_message.set_c(1234);
+  value_message->CopyFrom(foreign_message);
+
+  mmf_int32_foreign_message.Add(*entry_int32_foreign_message);
+  EXPECT_EQ(1234, message.map_int32_foreign_message().at(4321).c());
+
+  // Test Reflection::AddAllocatedMessage
+  Message* free_entry_string_string =
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_string_string->message_type())
+          ->New();
+  entry_string_string->GetReflection()->SetString(
+      free_entry_string_string, fd_map_string_string->message_type()->field(0),
+      "4321");
+  entry_string_string->GetReflection()->SetString(
+      free_entry_string_string, fd_map_string_string->message_type()->field(1),
+      "1234");
+  refl->AddAllocatedMessage(&message, fd_map_string_string,
+                            free_entry_string_string);
+
+  // Test MutableRepeatedFieldRef::RemoveLast()
+  mmf_int32_int32.RemoveLast();
+  mmf_int32_double.RemoveLast();
+  mmf_string_string.RemoveLast();
+  mmf_int32_foreign_message.RemoveLast();
+  EXPECT_EQ(10, message.map_int32_int32().size());
+  EXPECT_EQ(10, message.map_int32_double().size());
+  EXPECT_EQ(11, message.map_string_string().size());
+  EXPECT_EQ(10, message.map_int32_foreign_message().size());
+
+  // Test MutableRepeatedFieldRef::SwapElements()
+  {
+    const Message& message0a = mmf_int32_int32.Get(0, entry_int32_int32.get());
+    int32 int32_value0a =
+        message0a.GetReflection()->GetInt32(message0a, fd_map_int32_in32_value);
+    const Message& message9a = mmf_int32_int32.Get(9, entry_int32_int32.get());
+    int32 int32_value9a =
+        message9a.GetReflection()->GetInt32(message9a, fd_map_int32_in32_value);
+
+    mmf_int32_int32.SwapElements(0, 9);
+
+    const Message& message0b = mmf_int32_int32.Get(0, entry_int32_int32.get());
+    int32 int32_value0b =
+        message0b.GetReflection()->GetInt32(message0b, fd_map_int32_in32_value);
+    const Message& message9b = mmf_int32_int32.Get(9, entry_int32_int32.get());
+    int32 int32_value9b =
+        message9b.GetReflection()->GetInt32(message9b, fd_map_int32_in32_value);
+
+    EXPECT_EQ(int32_value9a, int32_value0b);
+    EXPECT_EQ(int32_value0a, int32_value9b);
+  }
+
+  {
+    const Message& message0a =
+        mmf_int32_double.Get(0, entry_int32_double.get());
+    double double_value0a = message0a.GetReflection()->GetDouble(
+        message0a, fd_map_int32_double_value);
+    const Message& message9a =
+        mmf_int32_double.Get(9, entry_int32_double.get());
+    double double_value9a = message9a.GetReflection()->GetDouble(
+        message9a, fd_map_int32_double_value);
+
+    mmf_int32_double.SwapElements(0, 9);
+
+    const Message& message0b =
+        mmf_int32_double.Get(0, entry_int32_double.get());
+    double double_value0b = message0b.GetReflection()->GetDouble(
+        message0b, fd_map_int32_double_value);
+    const Message& message9b =
+        mmf_int32_double.Get(9, entry_int32_double.get());
+    double double_value9b = message9b.GetReflection()->GetDouble(
+        message9b, fd_map_int32_double_value);
+
+    EXPECT_EQ(double_value9a, double_value0b);
+    EXPECT_EQ(double_value0a, double_value9b);
+  }
+
+  {
+    const Message& message0a =
+        mmf_string_string.Get(0, entry_string_string.get());
+    std::string string_value0a = message0a.GetReflection()->GetString(
+        message0a, fd_map_string_string_value);
+    const Message& message9a =
+        mmf_string_string.Get(9, entry_string_string.get());
+    std::string string_value9a = message9a.GetReflection()->GetString(
+        message9a, fd_map_string_string_value);
+
+    mmf_string_string.SwapElements(0, 9);
+
+    const Message& message0b =
+        mmf_string_string.Get(0, entry_string_string.get());
+    std::string string_value0b = message0b.GetReflection()->GetString(
+        message0b, fd_map_string_string_value);
+    const Message& message9b =
+        mmf_string_string.Get(9, entry_string_string.get());
+    std::string string_value9b = message9b.GetReflection()->GetString(
+        message9b, fd_map_string_string_value);
+
+    EXPECT_EQ(string_value9a, string_value0b);
+    EXPECT_EQ(string_value0a, string_value9b);
+  }
+
+  {
+    const Message& message0a =
+        mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message0a =
+        down_cast<const ForeignMessage&>(message0a.GetReflection()->GetMessage(
+            message0a, fd_map_int32_foreign_message_value));
+    int32 int32_value0a = sub_message0a.c();
+    const Message& message9a =
+        mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message9a =
+        down_cast<const ForeignMessage&>(message9a.GetReflection()->GetMessage(
+            message9a, fd_map_int32_foreign_message_value));
+    int32 int32_value9a = sub_message9a.c();
+
+    mmf_int32_foreign_message.SwapElements(0, 9);
+
+    const Message& message0b =
+        mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message0b =
+        down_cast<const ForeignMessage&>(message0b.GetReflection()->GetMessage(
+            message0b, fd_map_int32_foreign_message_value));
+    int32 int32_value0b = sub_message0b.c();
+    const Message& message9b =
+        mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message9b =
+        down_cast<const ForeignMessage&>(message9b.GetReflection()->GetMessage(
+            message9b, fd_map_int32_foreign_message_value));
+    int32 int32_value9b = sub_message9b.c();
+
+    EXPECT_EQ(int32_value9a, int32_value0b);
+    EXPECT_EQ(int32_value0a, int32_value9b);
+  }
+
+  // TODO(b/181148674): After supporting arena agnostic delete or let map entry
+  // handle heap allocation, this could be removed.
+  if (message.GetArena() != nullptr) {
+    entry_int32_int32.release();
+    entry_int32_double.release();
+    entry_string_string.release();
+    entry_int32_foreign_message.release();
+  }
+}
+
+TEST_F(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
+  // Set-up message content.
+  TestMap m0, m1, m2;
+  for (int i = 0; i < 10; ++i) {
+    (*m0.mutable_map_int32_int32())[i] = Func(i, 1);
+    (*m0.mutable_map_int32_double())[i] = Func(i, 2);
+    (*m0.mutable_map_string_string())[StrFunc(i, 1)] = StrFunc(i, 5);
+    (*m0.mutable_map_int32_foreign_message())[i].set_c(Func(i, 6));
+    (*m1.mutable_map_int32_int32())[i + 10] = Func(i, 11);
+    (*m1.mutable_map_int32_double())[i + 10] = Func(i, 12);
+    (*m1.mutable_map_string_string())[StrFunc(i + 10, 1)] = StrFunc(i, 15);
+    (*m1.mutable_map_int32_foreign_message())[i + 10].set_c(Func(i, 16));
+    (*m2.mutable_map_int32_int32())[i + 20] = Func(i, 21);
+    (*m2.mutable_map_int32_double())[i + 20] = Func(i, 22);
+    (*m2.mutable_map_string_string())[StrFunc(i + 20, 1)] = StrFunc(i, 25);
+    (*m2.mutable_map_int32_foreign_message())[i + 20].set_c(Func(i, 26));
+  }
+
+  const Reflection* refl = m0.GetReflection();
+  const Descriptor* desc = m0.GetDescriptor();
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_map_int32_int32 =
+      desc->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* fd_map_int32_double =
+      desc->FindFieldByName("map_int32_double");
+  const FieldDescriptor* fd_map_string_string =
+      desc->FindFieldByName("map_string_string");
+  const FieldDescriptor* fd_map_int32_foreign_message =
+      desc->FindFieldByName("map_int32_foreign_message");
+
+  // Get MutableRepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
+      refl->GetMutableRepeatedFieldRef<Message>(&m0, fd_map_int32_int32);
+  const MutableRepeatedFieldRef<Message> mmf_int32_double =
+      refl->GetMutableRepeatedFieldRef<Message>(&m0, fd_map_int32_double);
+  const MutableRepeatedFieldRef<Message> mmf_string_string =
+      refl->GetMutableRepeatedFieldRef<Message>(&m0, fd_map_string_string);
+  const MutableRepeatedFieldRef<Message> mmf_int32_foreign_message =
+      refl->GetMutableRepeatedFieldRef<Message>(&m0,
+                                                fd_map_int32_foreign_message);
+
+  // Test MutableRepeatedRef::CopyFrom
+  mmf_int32_int32.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(m1, fd_map_int32_int32));
+  mmf_int32_double.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(m1, fd_map_int32_double));
+  mmf_string_string.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(m1, fd_map_string_string));
+  mmf_int32_foreign_message.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(m1, fd_map_int32_foreign_message));
+
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 11), m0.map_int32_int32().at(i + 10));
+    EXPECT_EQ(Func(i, 12), m0.map_int32_double().at(i + 10));
+    EXPECT_EQ(StrFunc(i, 15), m0.map_string_string().at(StrFunc(i + 10, 1)));
+    EXPECT_EQ(Func(i, 16), m0.map_int32_foreign_message().at(i + 10).c());
+  }
+
+  // Test MutableRepeatedRef::MergeFrom
+  mmf_int32_int32.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(m2, fd_map_int32_int32));
+  mmf_int32_double.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(m2, fd_map_int32_double));
+  mmf_string_string.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(m2, fd_map_string_string));
+  mmf_int32_foreign_message.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(m2, fd_map_int32_foreign_message));
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
+    EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
+    EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
+    EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
+  }
+
+  // Test MutableRepeatedRef::Swap
+  // Swap between m0 and m2.
+  mmf_int32_int32.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(&m2, fd_map_int32_int32));
+  mmf_int32_double.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(&m2, fd_map_int32_double));
+  mmf_string_string.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(&m2, fd_map_string_string));
+  mmf_int32_foreign_message.Swap(refl->GetMutableRepeatedFieldRef<Message>(
+      &m2, fd_map_int32_foreign_message));
+  for (int i = 0; i < 10; ++i) {
+    // Check the content of m0.
+    EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
+    EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
+    EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
+    EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
+
+    // Check the content of m2.
+    EXPECT_EQ(Func(i, 11), m2.map_int32_int32().at(i + 10));
+    EXPECT_EQ(Func(i, 12), m2.map_int32_double().at(i + 10));
+    EXPECT_EQ(StrFunc(i, 15), m2.map_string_string().at(StrFunc(i + 10, 1)));
+    EXPECT_EQ(Func(i, 16), m2.map_int32_foreign_message().at(i + 10).c());
+    EXPECT_EQ(Func(i, 21), m2.map_int32_int32().at(i + 20));
+    EXPECT_EQ(Func(i, 22), m2.map_int32_double().at(i + 20));
+    EXPECT_EQ(StrFunc(i, 25), m2.map_string_string().at(StrFunc(i + 20, 1)));
+    EXPECT_EQ(Func(i, 26), m2.map_int32_foreign_message().at(i + 20).c());
+  }
+
+  // TODO(teboring): add test for duplicated key
+}
+
+TEST_F(MapFieldReflectionTest, MapSizeWithDuplicatedKey) {
+  // Dynamic Message
+  {
+    DynamicMessageFactory factory;
+    std::unique_ptr<Message> message(
+        factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+    const Reflection* reflection = message->GetReflection();
+    const FieldDescriptor* field =
+        UNITTEST::TestMap::descriptor()->FindFieldByName("map_int32_int32");
+
+    Message* entry1 = reflection->AddMessage(message.get(), field);
+    Message* entry2 = reflection->AddMessage(message.get(), field);
+
+    const Reflection* entry_reflection = entry1->GetReflection();
+    const FieldDescriptor* key_field =
+        entry1->GetDescriptor()->FindFieldByName("key");
+    entry_reflection->SetInt32(entry1, key_field, 1);
+    entry_reflection->SetInt32(entry2, key_field, 1);
+
+    EXPECT_EQ(2, reflection->FieldSize(*message, field));
+    EXPECT_EQ(1, MapSize(reflection, field, *message));
+    EXPECT_EQ(2, reflection->FieldSize(*message, field));
+  }
+
+  // Generated Message
+  {
+    UNITTEST::TestMap message;
+    const Reflection* reflection = message.GetReflection();
+    const FieldDescriptor* field =
+        message.GetDescriptor()->FindFieldByName("map_int32_int32");
+
+    Message* entry1 = reflection->AddMessage(&message, field);
+    Message* entry2 = reflection->AddMessage(&message, field);
+
+    const Reflection* entry_reflection = entry1->GetReflection();
+    const FieldDescriptor* key_field =
+        entry1->GetDescriptor()->FindFieldByName("key");
+    entry_reflection->SetInt32(entry1, key_field, 1);
+    entry_reflection->SetInt32(entry2, key_field, 1);
+
+    EXPECT_EQ(2, reflection->FieldSize(message, field));
+    EXPECT_EQ(1, MapSize(reflection, field, message));
+  }
+}
+
+TEST_F(MapFieldReflectionTest, UninitializedEntry) {
+  UNITTEST::TestRequiredMessageMap message;
+  const Reflection* reflection = message.GetReflection();
+  const FieldDescriptor* field =
+      message.GetDescriptor()->FindFieldByName("map_field");
+  auto entry = reflection->AddMessage(&message, field);
+  EXPECT_FALSE(entry->IsInitialized());
+  EXPECT_FALSE(message.IsInitialized());
+}
+
+class MyMapEntry
+    : public internal::MapEntry<MyMapEntry, ::google::protobuf::int32, ::google::protobuf::int32,
+                                internal::WireFormatLite::TYPE_INT32,
+                                internal::WireFormatLite::TYPE_INT32> {
+ public:
+  constexpr MyMapEntry() {}
+  MyMapEntry(Arena*) { std::abort(); }
+  Metadata GetMetadata() const override { std::abort(); }
+  static bool ValidateKey(void*) { return true; }
+  static bool ValidateValue(void*) { return true; }
+};
+
+class MyMapEntryLite
+    : public internal::MapEntryLite<MyMapEntryLite, ::google::protobuf::int32, ::google::protobuf::int32,
+                                    internal::WireFormatLite::TYPE_INT32,
+                                    internal::WireFormatLite::TYPE_INT32> {
+ public:
+  constexpr MyMapEntryLite() {}
+  explicit MyMapEntryLite(Arena*) { std::abort(); }
+  static bool ValidateKey(void*) { return true; }
+  static bool ValidateValue(void*) { return true; }
+};
+
+TEST(MapEntryTest, ConstInit) {
+  // This verifies that `MapEntry`, `MapEntryLite` and `MapEntryImpl` can be
+  // constant initialized.
+  PROTOBUF_CONSTINIT static MyMapEntry entry{};
+  EXPECT_NE(entry.SpaceUsed(), 0);
+
+  PROTOBUF_CONSTINIT static MyMapEntryLite entry_lite{};  // NOLINT
+  EXPECT_TRUE(entry_lite.IsInitialized());
+}
+
+// Generated Message Test ===========================================
+
+TEST(GeneratedMapFieldTest, Accessors) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  MapTestUtil::ModifyMapFields(&message);
+  MapTestUtil::ExpectMapFieldsModified(message);
+}
+
+TEST(GeneratedMapFieldTest, SetMapFieldsInitialized) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFieldsInitialized(&message);
+  MapTestUtil::ExpectMapFieldsSetInitialized(message);
+}
+
+TEST(GeneratedMapFieldTest, Proto2SetMapFieldsInitialized) {
+  UNITTEST::TestEnumMap message;
+  EXPECT_EQ(UNITTEST::PROTO2_MAP_ENUM_FOO,
+            (*message.mutable_known_map_field())[0]);
+}
+
+TEST(GeneratedMapFieldTest, Clear) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  message.Clear();
+  MapTestUtil::ExpectClear(message);
+}
+
+TEST(GeneratedMapFieldTest, ClearMessageMap) {
+  UNITTEST::TestMessageMap message;
+
+  // Creates a TestAllTypes with default value
+  TestUtil::ExpectClear((*message.mutable_map_int32_message())[0]);
+}
+
+TEST(GeneratedMapFieldTest, CopyFrom) {
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  message2.CopyFrom(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+
+  // Copying from self should be a no-op.
+  message2.CopyFrom(message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyFromMessageMap) {
+  UNITTEST::TestMessageMap message1, message2;
+
+  (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+  (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+  message1.CopyFrom(message2);
+
+  // Checks repeated field is overwritten.
+  EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+  EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+}
+
+TEST(GeneratedMapFieldTest, SwapWithEmpty) {
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::ExpectMapFieldsSet(message1);
+  MapTestUtil::ExpectClear(message2);
+
+  message1.Swap(&message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+  MapTestUtil::ExpectClear(message1);
+}
+
+TEST(GeneratedMapFieldTest, SwapWithSelf) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  message.Swap(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(GeneratedMapFieldTest, SwapWithOther) {
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::SetMapFields(&message2);
+  MapTestUtil::ModifyMapFields(&message2);
+
+  message1.Swap(&message2);
+  MapTestUtil::ExpectMapFieldsModified(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyConstructor) {
+  UNITTEST::TestMap message1;
+  MapTestUtil::SetMapFields(&message1);
+
+  UNITTEST::TestMap message2(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyAssignmentOperator) {
+  UNITTEST::TestMap message1;
+  MapTestUtil::SetMapFields(&message1);
+
+  UNITTEST::TestMap message2;
+  message2 = message1;
+  MapTestUtil::ExpectMapFieldsSet(message2);
+
+  // Make sure that self-assignment does something sane.
+  message2.operator=(message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || PROTOBUF_RTTI
+TEST(GeneratedMapFieldTest, UpcastCopyFrom) {
+  // Test the CopyFrom method that takes in the generic const Message&
+  // parameter.
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+
+  const Message* source = implicit_cast<const Message*>(&message1);
+  message2.CopyFrom(*source);
+
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+#endif
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GeneratedMapFieldTest, CopyFromDynamicMessage) {
+  // Test copying from a DynamicMessage, which must fall back to using
+  // reflection.
+  UNITTEST::TestMap message2;
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(message1.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+  message2.CopyFrom(*message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyFromDynamicMessageMapReflection) {
+  UNITTEST::TestMap message2;
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(message1.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+  message2.CopyFrom(*message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, DynamicMessageMergeFromDynamicMessage) {
+  // Construct two dynamic message and sets via map reflection.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(message1.get());
+
+  // message2 is created by same factory.
+  std::unique_ptr<Message> message2;
+  message2.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaMapReflection(message2.get());
+
+  // message3 is created by different factory.
+  DynamicMessageFactory factory3;
+  std::unique_ptr<Message> message3;
+  message3.reset(factory3.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaMapReflection(message3.get());
+
+  message2->MergeFrom(*message1);
+  message3->MergeFrom(*message1);
+
+  // Test MergeFrom does not sync to repeated fields and
+  // there is no duplicate keys in text format.
+  std::string output1, output2, output3;
+  TextFormat::PrintToString(*message1, &output1);
+  TextFormat::PrintToString(*message2, &output2);
+  TextFormat::PrintToString(*message3, &output3);
+  EXPECT_EQ(output1, output2);
+  EXPECT_EQ(output1, output3);
+}
+
+TEST(GeneratedMapFieldTest, DynamicMessageCopyFrom) {
+  // Test copying to a DynamicMessage, which must fall back to using reflection.
+  UNITTEST::TestMap message2;
+  MapTestUtil::SetMapFields(&message2);
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  message1->MergeFrom(message2);
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+}
+
+TEST(GeneratedMapFieldTest, DynamicMessageCopyFromMapReflection) {
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  UNITTEST::TestMap message2;
+  reflection_tester.SetMapFieldsViaMapReflection(&message2);
+
+  // Construct a dynamic message via the factory.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+
+  message1->MergeFrom(message2);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+}
+
+TEST(GeneratedMapFieldTest, SyncDynamicMapWithRepeatedField) {
+  // Construct a dynamic message via the factory.
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message;
+  message.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GeneratedMapFieldTest, NonEmptyMergeFrom) {
+  UNITTEST::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+
+  // This field will test merging into an empty spot.
+  (*message2.mutable_map_int32_int32())[1] = 1;
+  message1.mutable_map_int32_int32()->erase(1);
+
+  // This tests overwriting.
+  (*message2.mutable_map_int32_double())[1] = 1;
+  (*message1.mutable_map_int32_double())[1] = 2;
+
+  message1.MergeFrom(message2);
+  MapTestUtil::ExpectMapFieldsSet(message1);
+
+  // Test reflection MergeFrom does not sync to repeated field
+  // and there is no duplicated keys.
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::SetMapFields(&message2);
+
+  message2.MergeFrom(message1);
+
+  std::string output1, output2;
+  TextFormat::PrintToString(message1, &output1);
+  TextFormat::PrintToString(message2, &output2);
+  EXPECT_EQ(output1, output2);
+}
+
+TEST(GeneratedMapFieldTest, MergeFromMessageMap) {
+  UNITTEST::TestMessageMap message1, message2;
+
+  (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+  (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+  message1.MergeFrom(message2);
+
+  // Checks repeated field is overwritten.
+  EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+  EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+}
+
+// Test the generated SerializeWithCachedSizesToArray()
+TEST(GeneratedMapFieldTest, SerializationToArray) {
+  UNITTEST::TestMap message1, message2;
+  std::string data;
+  MapTestUtil::SetMapFields(&message1);
+  size_t size = message1.ByteSizeLong();
+  data.resize(size);
+  uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data));
+  uint8* end = message1.SerializeWithCachedSizesToArray(start);
+  EXPECT_EQ(size, end - start);
+  EXPECT_TRUE(message2.ParseFromString(data));
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+// Test the generated SerializeWithCachedSizes()
+TEST(GeneratedMapFieldTest, SerializationToStream) {
+  UNITTEST::TestMap message1, message2;
+  MapTestUtil::SetMapFields(&message1);
+  size_t size = message1.ByteSizeLong();
+  std::string data;
+  data.resize(size);
+  {
+    // Allow the output stream to buffer only one byte at a time.
+    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1);
+    io::CodedOutputStream output_stream(&array_stream);
+    message1.SerializeWithCachedSizes(&output_stream);
+    EXPECT_FALSE(output_stream.HadError());
+    EXPECT_EQ(size, output_stream.ByteCount());
+  }
+  EXPECT_TRUE(message2.ParseFromString(data));
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, ParseFailsIfMalformed) {
+  UNITTEST::TestMapSubmessage o, p;
+  auto m = o.mutable_test_map()->mutable_map_int32_foreign_message();
+  (*m)[0].set_c(-1);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p.ParseFromString(serialized));
+
+  // Overwriting the last byte to 0xFF results in malformed wire.
+  serialized[serialized.size() - 1] = 0xFF;
+  EXPECT_FALSE(p.ParseFromString(serialized));
+}
+
+
+TEST(GeneratedMapFieldTest, SameTypeMaps) {
+  const Descriptor* map1 = UNITTEST::TestSameTypeMap::descriptor()
+                               ->FindFieldByName("map1")
+                               ->message_type();
+  const Descriptor* map2 = UNITTEST::TestSameTypeMap::descriptor()
+                               ->FindFieldByName("map2")
+                               ->message_type();
+
+  const Message* map1_entry =
+      MessageFactory::generated_factory()->GetPrototype(map1);
+  const Message* map2_entry =
+      MessageFactory::generated_factory()->GetPrototype(map2);
+
+  EXPECT_EQ(map1, map1_entry->GetDescriptor());
+  EXPECT_EQ(map2, map2_entry->GetDescriptor());
+}
+
+TEST(GeneratedMapFieldTest, Proto2UnknownEnum) {
+  UNITTEST::TestEnumMapPlusExtra from;
+  (*from.mutable_known_map_field())[0] = UNITTEST::E_PROTO2_MAP_ENUM_FOO;
+  (*from.mutable_unknown_map_field())[0] = UNITTEST::E_PROTO2_MAP_ENUM_EXTRA;
+  std::string data;
+  from.SerializeToString(&data);
+
+  UNITTEST::TestEnumMap to;
+  EXPECT_TRUE(to.ParseFromString(data));
+  EXPECT_EQ(0, to.unknown_map_field().size());
+  const UnknownFieldSet& unknown_field_set =
+      to.GetReflection()->GetUnknownFields(to);
+  EXPECT_EQ(1, unknown_field_set.field_count());
+  EXPECT_EQ(1, to.known_map_field().size());
+  EXPECT_EQ(UNITTEST::PROTO2_MAP_ENUM_FOO, to.known_map_field().at(0));
+
+  data.clear();
+  from.Clear();
+  to.SerializeToString(&data);
+  EXPECT_TRUE(from.ParseFromString(data));
+  EXPECT_EQ(0, from.GetReflection()->GetUnknownFields(from).field_count());
+  EXPECT_EQ(1, from.known_map_field().size());
+  EXPECT_EQ(UNITTEST::E_PROTO2_MAP_ENUM_FOO, from.known_map_field().at(0));
+  EXPECT_EQ(1, from.unknown_map_field().size());
+  EXPECT_EQ(UNITTEST::E_PROTO2_MAP_ENUM_EXTRA, from.unknown_map_field().at(0));
+}
+
+TEST(GeneratedMapFieldTest, StandardWireFormat) {
+  UNITTEST::TestMap message;
+  std::string data = "\x0A\x04\x08\x01\x10\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(1, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, UnorderedWireFormat) {
+  UNITTEST::TestMap message;
+
+  // put value before key in wire format
+  std::string data = "\x0A\x04\x10\x01\x08\x02";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  ASSERT_NE(message.map_int32_int32().find(2), message.map_int32_int32().end());
+  EXPECT_EQ(1, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat) {
+  UNITTEST::TestMap message;
+
+  // Two key fields in wire format
+  std::string data = "\x0A\x06\x08\x01\x08\x02\x10\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(1, message.map_int32_int32().at(2));
+
+  // A similar test, but with a map from int to a message type.
+  // Again, we want to be sure that the "second one wins" when
+  // there are two separate entries with the same key.
+  const int key = 99;
+  UNITTEST::TestRequiredMessageMap map_message;
+  UNITTEST::TestRequired with_dummy4;
+  with_dummy4.set_a(0);
+  with_dummy4.set_b(0);
+  with_dummy4.set_c(0);
+  with_dummy4.set_dummy4(11);
+  (*map_message.mutable_map_field())[key] = with_dummy4;
+  std::string s = map_message.SerializeAsString();
+  UNITTEST::TestRequired with_dummy5;
+  with_dummy5.set_a(0);
+  with_dummy5.set_b(0);
+  with_dummy5.set_c(0);
+  with_dummy5.set_dummy5(12);
+  (*map_message.mutable_map_field())[key] = with_dummy5;
+  std::string both = s + map_message.SerializeAsString();
+  // We don't expect a merge now.  The "second one wins."
+  ASSERT_TRUE(map_message.ParseFromString(both));
+  ASSERT_EQ(1, map_message.map_field().size());
+  ASSERT_EQ(1, map_message.map_field().count(key));
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.a());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.c());
+  EXPECT_FALSE(map_message.map_field().find(key)->second.has_dummy4());
+  ASSERT_TRUE(map_message.map_field().find(key)->second.has_dummy5());
+  EXPECT_EQ(12, map_message.map_field().find(key)->second.dummy5());
+}
+
+// Exhaustive combinations of keys, values, and junk in any order.
+// This re-tests some of the things tested above, but if it fails
+// it's more work to determine what went wrong, so it isn't necessarily
+// bad that we have the simpler tests too.
+TEST(GeneratedMapFieldTest, KeysValuesUnknownsWireFormat) {
+  UNITTEST::TestMap message;
+  const int kMaxNumKeysAndValuesAndJunk = 4;
+  const char kKeyTag = 0x08;
+  const char kValueTag = 0x10;
+  const char kJunkTag = 0x20;
+  for (int items = 0; items <= kMaxNumKeysAndValuesAndJunk; items++) {
+    std::string data = "\x0A";
+    // Encode length of what will follow.
+    data.push_back(items * 2);
+    static const int kBitsOfIPerItem = 4;
+    static const int mask = (1 << kBitsOfIPerItem) - 1;
+    // Each iteration of the following is a test.  It uses i as bit vector
+    // encoding the keys and values to put in the wire format.
+    for (int i = 0; i < (1 << (items * kBitsOfIPerItem)); i++) {
+      std::string wire_format = data;
+      int expected_key = 0;
+      int expected_value = 0;
+      for (int k = i, j = 0; j < items; j++, k >>= kBitsOfIPerItem) {
+        bool is_key = k & 0x1;
+        bool is_value = !is_key && (k & 0x2);
+        wire_format.push_back(is_key ? kKeyTag
+                                     : is_value ? kValueTag : kJunkTag);
+        char c = static_cast<char>(k & mask) >> 2;  // One char after the tag.
+        wire_format.push_back(c);
+        if (is_key) expected_key = static_cast<int>(c);
+        if (is_value) expected_value = static_cast<int>(c);
+        bool res = message.ParseFromString(wire_format);
+        bool expect_success = true;
+        // Unfortunately the old map parser accepts malformed input, the new
+        // parser accepts only correct input.
+        if (j != items - 1) expect_success = false;
+        if (expect_success) {
+          ASSERT_TRUE(res);
+          ASSERT_EQ(1, message.map_int32_int32().size());
+          ASSERT_EQ(expected_key, message.map_int32_int32().begin()->first);
+          ASSERT_EQ(expected_value, message.map_int32_int32().begin()->second);
+        } else {
+          ASSERT_FALSE(res);
+        }
+      }
+    }
+  }
+}
+
+TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) {
+  UNITTEST::TestMap message;
+
+  // Two value fields in wire format
+  std::string data = "\x0A\x06\x08\x01\x10\x01\x10\x02";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(2, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, MissedKeyWireFormat) {
+  UNITTEST::TestMap message;
+
+  // No key field in wire format
+  std::string data = "\x0A\x02\x10\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  ASSERT_NE(message.map_int32_int32().find(0), message.map_int32_int32().end());
+  EXPECT_EQ(1, message.map_int32_int32().at(0));
+}
+
+TEST(GeneratedMapFieldTest, MissedValueWireFormat) {
+  UNITTEST::TestMap message;
+
+  // No value field in wire format
+  std::string data = "\x0A\x02\x08\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  ASSERT_NE(message.map_int32_int32().find(1), message.map_int32_int32().end());
+  EXPECT_EQ(0, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, MissedValueTextFormat) {
+  UNITTEST::TestMap message;
+
+  // No value field in text format
+  std::string text =
+      "map_int32_foreign_message {\n"
+      "  key: 1234567890\n"
+      "}";
+
+  EXPECT_TRUE(TextFormat::ParseFromString(text, &message));
+  EXPECT_EQ(1, message.map_int32_foreign_message().size());
+  EXPECT_EQ(11, message.ByteSizeLong());
+}
+
+TEST(GeneratedMapFieldTest, UnknownFieldWireFormat) {
+  UNITTEST::TestMap message;
+
+  // Unknown field in wire format
+  std::string data = "\x0A\x06\x08\x02\x10\x03\x18\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(3, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, CorruptedWireFormat) {
+  UNITTEST::TestMap message;
+
+  // corrupted data in wire format
+  std::string data = "\x0A\x06\x08\x02\x11\x03";
+
+  EXPECT_FALSE(message.ParseFromString(data));
+}
+
+TEST(GeneratedMapFieldTest, IsInitialized) {
+  UNITTEST::TestRequiredMessageMap map_message;
+
+  // Add an uninitialized message.
+  (*map_message.mutable_map_field())[0];
+  EXPECT_FALSE(map_message.IsInitialized());
+
+  // Initialize uninitialized message
+  (*map_message.mutable_map_field())[0].set_a(0);
+  (*map_message.mutable_map_field())[0].set_b(0);
+  (*map_message.mutable_map_field())[0].set_c(0);
+  EXPECT_TRUE(map_message.IsInitialized());
+}
+
+TEST(GeneratedMapFieldTest, SpaceUsed) {
+  UNITTEST::TestRequiredMessageMap map_message;
+  const size_t initial = map_message.SpaceUsed();
+  const size_t space_used_message = UNITTEST::TestRequired().SpaceUsed();
+
+  auto& m = *map_message.mutable_map_field();
+  constexpr int kNumValues = 100;
+  for (int i = 0; i < kNumValues; ++i) {
+    m[i];
+  }
+
+  // The exact value will depend on internal state, like collisions,
+  // so we can't predict it. But we can predict a lower bound.
+  size_t lower_bound =
+      initial + kNumValues * (space_used_message + sizeof(int32) +
+                              /* Node::next */ sizeof(void*) +
+                              /* table entry */ sizeof(void*));
+
+  EXPECT_LE(lower_bound, map_message.SpaceUsed());
+}
+
+TEST(GeneratedMapFieldTest, MessagesMustMerge) {
+  UNITTEST::TestRequiredMessageMap map_message;
+
+  UNITTEST::TestRequired with_dummy4;
+  with_dummy4.set_a(97);
+  with_dummy4.set_b(91);
+  with_dummy4.set_dummy4(98);
+  EXPECT_FALSE(with_dummy4.IsInitialized());
+  (*map_message.mutable_map_field())[0] = with_dummy4;
+  EXPECT_FALSE(map_message.IsInitialized());
+
+  UNITTEST::TestRequired with_dummy5;
+  with_dummy5.set_b(0);
+  with_dummy5.set_c(33);
+  with_dummy5.set_dummy5(99);
+  EXPECT_FALSE(with_dummy5.IsInitialized());
+  (*map_message.mutable_map_field())[0] = with_dummy5;
+  EXPECT_FALSE(map_message.IsInitialized());
+
+  // The wire format of MapEntry is straightforward (*) and can be manually
+  // constructed to force merging of two uninitialized messages that would
+  // result in an initialized message.
+  //
+  // (*) http://google3/net/proto2/internal/map_test.cc?l=2433&rcl=310012028
+  std::string dummy4_s = with_dummy4.SerializePartialAsString();
+  std::string dummy5_s = with_dummy5.SerializePartialAsString();
+  int payload_size = dummy4_s.size() + dummy5_s.size();
+  // Makes sure the payload size fits into one byte.
+  ASSERT_LT(payload_size, 128);
+
+  std::string s(6, 0);
+  char* p = &s[0];
+  *p++ = WireFormatLite::MakeTag(1, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+  // Length: 2B for key tag & val and 2B for val tag and length of the following
+  // payload.
+  *p++ = 4 + payload_size;
+  *p++ = WireFormatLite::MakeTag(1, WireFormatLite::WIRETYPE_VARINT);
+  *p++ = 0;
+  *p++ = WireFormatLite::MakeTag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+  *p++ = payload_size;
+  StrAppend(&s, dummy4_s, dummy5_s);
+
+  // Test key then value then value.
+  int key = 0;
+  ASSERT_TRUE(map_message.ParseFromString(s));
+  ASSERT_EQ(1, map_message.map_field().size());
+  ASSERT_EQ(1, map_message.map_field().count(key));
+  EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+  EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
+  EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
+  EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
+
+  // Test key then value then value then key.
+  s.push_back(s[2]);  // Copy the key's tag.
+  key = 19;
+  s.push_back(key);  // Second key is 19 instead of 0.
+  s[1] += 2;         // Adjust encoded size.
+  ASSERT_TRUE(map_message.ParseFromString(s));
+  ASSERT_EQ(1, map_message.map_field().size());
+  ASSERT_EQ(1, map_message.map_field().count(key));
+  EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+  EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
+  EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
+  EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
+}
+
+// Generated Message Reflection Test ================================
+
+TEST(GeneratedMapFieldReflectionTest, SpaceUsed) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(&message);
+
+  EXPECT_LT(0, message.GetReflection()->SpaceUsedLong(message));
+}
+
+TEST(GeneratedMapFieldReflectionTest, Accessors) {
+  // Set every field to a unique value then go back and check all those
+  // values.
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+  reflection_tester.ExpectMapFieldsSetViaReflection(message);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message);
+
+  reflection_tester.ModifyMapFieldsViaReflection(&message);
+  MapTestUtil::ExpectMapFieldsModified(message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, Swap) {
+  UNITTEST::TestMap message1;
+  UNITTEST::TestMap message2;
+
+  MapTestUtil::SetMapFields(&message1);
+
+  const Reflection* reflection = message1.GetReflection();
+  reflection->Swap(&message1, &message2);
+
+  MapTestUtil::ExpectClear(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapWithBothSet) {
+  UNITTEST::TestMap message1;
+  UNITTEST::TestMap message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::SetMapFields(&message2);
+  MapTestUtil::ModifyMapFields(&message2);
+
+  const Reflection* reflection = message1.GetReflection();
+  reflection->Swap(&message1, &message2);
+
+  MapTestUtil::ExpectMapFieldsModified(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapFields) {
+  UNITTEST::TestMap message1;
+  UNITTEST::TestMap message2;
+
+  MapTestUtil::SetMapFields(&message2);
+
+  std::vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1.GetReflection();
+  reflection->ListFields(message2, &fields);
+  reflection->SwapFields(&message1, &message2, fields);
+
+  MapTestUtil::ExpectMapFieldsSet(message1);
+  MapTestUtil::ExpectClear(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ClearField) {
+  UNITTEST::TestMap message;
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.ClearMapFieldsViaReflection(&message);
+  reflection_tester.ExpectClearViaReflection(message);
+  reflection_tester.ExpectClearViaReflectionIterator(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, RemoveLast) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapsSize(message, 2);
+  std::vector<const Message*> expected_entries =
+      MapTestUtil::GetMapEntries(message, 0);
+
+  reflection_tester.RemoveLastMapsViaReflection(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 1);
+  std::vector<const Message*> remained_entries =
+      MapTestUtil::GetMapEntries(message, 0);
+  EXPECT_TRUE(expected_entries == remained_entries);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ReleaseLast) {
+  UNITTEST::TestMap message;
+  const Descriptor* descriptor = message.GetDescriptor();
+  MapReflectionTester reflection_tester(descriptor);
+
+  MapTestUtil::SetMapFields(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 2);
+
+  reflection_tester.ReleaseLastMapsViaReflection(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 1);
+
+  // Now test that we actually release the right message.
+  message.Clear();
+  MapTestUtil::SetMapFields(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 2);
+  std::vector<const Message*> expect_last =
+      MapTestUtil::GetMapEntries(message, 1);
+  std::vector<const Message*> release_last =
+      MapTestUtil::GetMapEntriesFromRelease(&message);
+  MapTestUtil::ExpectMapsSize(message, 1);
+  EXPECT_TRUE(expect_last == release_last);
+  for (std::vector<const Message*>::iterator it = release_last.begin();
+       it != release_last.end(); ++it) {
+    delete *it;
+  }
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapElements) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+
+  MapTestUtil::SetMapFields(&message);
+
+  // Get pointers of map entries at their original position
+  std::vector<const Message*> entries0 = MapTestUtil::GetMapEntries(message, 0);
+  std::vector<const Message*> entries1 = MapTestUtil::GetMapEntries(message, 1);
+
+  // Swap the first time.
+  reflection_tester.SwapMapsViaReflection(&message);
+
+  // Get pointer of map entry after swap once.
+  std::vector<const Message*> entries0_once =
+      MapTestUtil::GetMapEntries(message, 0);
+  std::vector<const Message*> entries1_once =
+      MapTestUtil::GetMapEntries(message, 1);
+
+  // Test map entries are swapped.
+  MapTestUtil::ExpectMapsSize(message, 2);
+  EXPECT_TRUE(entries0 == entries1_once);
+  EXPECT_TRUE(entries1 == entries0_once);
+
+  // Swap the second time.
+  reflection_tester.SwapMapsViaReflection(&message);
+
+  // Get pointer of map entry after swap once.
+  std::vector<const Message*> entries0_twice =
+      MapTestUtil::GetMapEntries(message, 0);
+  std::vector<const Message*> entries1_twice =
+      MapTestUtil::GetMapEntries(message, 1);
+
+  // Test map entries are swapped back.
+  MapTestUtil::ExpectMapsSize(message, 2);
+  EXPECT_TRUE(entries0 == entries0_twice);
+  EXPECT_TRUE(entries1 == entries1_twice);
+}
+
+TEST(GeneratedMapFieldReflectionTest, MutableUnknownFields) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, EmbedProto2Message) {
+  UNITTEST::TestMessageMap message;
+
+  const FieldDescriptor* map_field =
+      UNITTEST::TestMessageMap::descriptor()->FindFieldByName(
+          "map_int32_message");
+  const FieldDescriptor* value =
+      map_field->message_type()->FindFieldByName("value");
+
+  Message* entry_message =
+      message.GetReflection()->AddMessage(&message, map_field);
+  EXPECT_EQ(
+      &entry_message->GetReflection()->GetMessage(*entry_message, value),
+      reinterpret_cast<const Message*>(&TestAllTypes::default_instance()));
+
+  Message* proto2_message =
+      entry_message->GetReflection()->MutableMessage(entry_message, value);
+  EXPECT_EQ(UNITTEST::TestAllTypes::descriptor(),
+            proto2_message->GetDescriptor());
+  ASSERT_EQ(1, message.map_int32_message().size());
+}
+
+TEST(GeneratedMapFieldReflectionTest, MergeFromClearMapEntry) {
+  UNITTEST::TestMap message;
+  const FieldDescriptor* map_field =
+      UNITTEST::TestMap::descriptor()->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* key =
+      map_field->message_type()->FindFieldByName("key");
+  const FieldDescriptor* value =
+      map_field->message_type()->FindFieldByName("value");
+
+  Message* entry_message1 =
+      message.GetReflection()->AddMessage(&message, map_field);
+  EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
+  EXPECT_FALSE(
+      entry_message1->GetReflection()->HasField(*entry_message1, value));
+
+  Message* entry_message2 =
+      message.GetReflection()->AddMessage(&message, map_field);
+  EXPECT_FALSE(entry_message2->GetReflection()->HasField(*entry_message2, key));
+  EXPECT_FALSE(
+      entry_message2->GetReflection()->HasField(*entry_message2, value));
+
+  entry_message1->MergeFrom(*entry_message2);
+  EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
+  EXPECT_FALSE(
+      entry_message1->GetReflection()->HasField(*entry_message1, value));
+}
+
+TEST(GeneratedMapFieldReflectionTest, MapEntryClear) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, Proto2MapEntryClear) {
+  UNITTEST::TestEnumMap message;
+  const Descriptor* descriptor = message.GetDescriptor();
+  const FieldDescriptor* field_descriptor =
+      descriptor->FindFieldByName("known_map_field");
+  const FieldDescriptor* value_descriptor =
+      field_descriptor->message_type()->FindFieldByName("value");
+  Message* sub_message =
+      message.GetReflection()->AddMessage(&message, field_descriptor);
+  EXPECT_EQ(0, sub_message->GetReflection()->GetEnumValue(*sub_message,
+                                                          value_descriptor));
+}
+
+// Map Reflection API Test =========================================
+
+TEST(GeneratedMapFieldReflectionTest, SetViaMapReflection) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&message);
+  reflection_tester.ExpectMapFieldsSetViaReflection(message);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message);
+}
+
+// Dynamic Message Test =============================================
+
+class MapFieldInDynamicMessageTest : public testing::Test {
+ protected:
+  const DescriptorPool* pool_;
+  DynamicMessageFactory factory_;
+  const Descriptor* map_descriptor_;
+  const Descriptor* recursive_map_descriptor_;
+  const Message* map_prototype_;
+
+  MapFieldInDynamicMessageTest()
+      : pool_(DescriptorPool::generated_pool()), factory_(pool_) {}
+
+  virtual void SetUp() {
+    map_descriptor_ = pool_->FindMessageTypeByName(
+        std::string(UNITTEST_PACKAGE_NAME) + ".TestMap");
+    recursive_map_descriptor_ = pool_->FindMessageTypeByName(
+        std::string(UNITTEST_PACKAGE_NAME) + ".TestRecursiveMapMessage");
+    ASSERT_TRUE(map_descriptor_ != NULL);
+    ASSERT_TRUE(recursive_map_descriptor_ != NULL);
+    map_prototype_ = factory_.GetPrototype(map_descriptor_);
+  }
+};
+
+TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) {
+  // Check that all fields have independent offsets by setting each
+  // one to a unique value then checking that they all still have those
+  // unique values (i.e. they don't stomp each other).
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) {
+  // Check that map fields work properly.
+  std::unique_ptr<Message> message(map_prototype_->New());
+
+  // Check set functions.
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) {
+  // Test that SpaceUsedLong() works properly
+
+  // Since we share the implementation with generated messages, we don't need
+  // to test very much here.  Just make sure it appears to be working.
+
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+
+  int initial_space_used = message->SpaceUsedLong();
+
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+  EXPECT_LT(initial_space_used, message->SpaceUsedLong());
+}
+
+TEST_F(MapFieldInDynamicMessageTest, RecursiveMap) {
+  TestRecursiveMapMessage from;
+  (*from.mutable_a())[""];
+  std::string data = from.SerializeAsString();
+  std::unique_ptr<Message> to(
+      factory_.GetPrototype(recursive_map_descriptor_)->New());
+  ASSERT_TRUE(to->ParseFromString(data));
+}
+
+TEST_F(MapFieldInDynamicMessageTest, MapValueReferernceValidAfterSerialize) {
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(message.get());
+
+  // Get value reference before serialization, so that we know the value is from
+  // map.
+  MapKey map_key;
+  MapValueRef map_val;
+  map_key.SetInt32Value(0);
+  reflection_tester.GetMapValueViaMapReflection(
+      message.get(), "map_int32_foreign_message", map_key, &map_val);
+  Message* submsg = map_val.MutableMessageValue();
+
+  // In previous implementation, calling SerializeToString will cause syncing
+  // from map to repeated field, which will invalidate the submsg we previously
+  // got.
+  std::string data;
+  message->SerializeToString(&data);
+
+  const Reflection* submsg_reflection = submsg->GetReflection();
+  const Descriptor* submsg_desc = submsg->GetDescriptor();
+  const FieldDescriptor* submsg_field = submsg_desc->FindFieldByName("c");
+  submsg_reflection->SetInt32(submsg, submsg_field, 128);
+
+  message->SerializeToString(&data);
+  TestMap to;
+  to.ParseFromString(data);
+  EXPECT_EQ(128, to.map_int32_foreign_message().at(0).c());
+}
+
+TEST_F(MapFieldInDynamicMessageTest, MapEntryReferernceValidAfterSerialize) {
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+
+  // Get map entry before serialization, so that we know the it is from
+  // repeated field.
+  Message* map_entry = reflection_tester.GetMapEntryViaReflection(
+      message.get(), "map_int32_foreign_message", 0);
+  const Reflection* map_entry_reflection = map_entry->GetReflection();
+  const Descriptor* map_entry_desc = map_entry->GetDescriptor();
+  const FieldDescriptor* value_field = map_entry_desc->FindFieldByName("value");
+  Message* submsg =
+      map_entry_reflection->MutableMessage(map_entry, value_field);
+
+  // In previous implementation, calling SerializeToString will cause syncing
+  // from repeated field to map, which will invalidate the map_entry we
+  // previously got.
+  std::string data;
+  message->SerializeToString(&data);
+
+  const Reflection* submsg_reflection = submsg->GetReflection();
+  const Descriptor* submsg_desc = submsg->GetDescriptor();
+  const FieldDescriptor* submsg_field = submsg_desc->FindFieldByName("c");
+  submsg_reflection->SetInt32(submsg, submsg_field, 128);
+
+  message->SerializeToString(&data);
+  TestMap to;
+  to.ParseFromString(data);
+  EXPECT_EQ(128, to.map_int32_foreign_message().at(0).c());
+}
+
+// ReflectionOps Test ===============================================
+
+TEST(ReflectionOpsForMapFieldTest, MapSanityCheck) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MapCopy) {
+  UNITTEST::TestMap message, message2;
+
+  MapTestUtil::SetMapFields(&message);
+
+  ReflectionOps::Copy(message, &message2);
+
+  MapTestUtil::ExpectMapFieldsSet(message2);
+
+  // Copying from self should be a no-op.
+  ReflectionOps::Copy(message2, &message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MergeMap) {
+  // Note:  Copy is implemented in terms of Merge() so technically the Copy
+  //   test already tested most of this.
+
+  UNITTEST::TestMap message, message2;
+
+  MapTestUtil::SetMapFields(&message);
+
+  ReflectionOps::Merge(message2, &message);
+
+  MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, ClearMap) {
+  UNITTEST::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+
+  ReflectionOps::Clear(&message);
+
+  MapTestUtil::ExpectClear(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MapDiscardUnknownFields) {
+  UNITTEST::TestMap message;
+  MapTestUtil::SetMapFields(&message);
+
+  // Set some unknown fields in message.
+  message.GetReflection()->MutableUnknownFields(&message)->AddVarint(123456,
+                                                                     654321);
+
+  // Discard them.
+  ReflectionOps::DiscardUnknownFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  EXPECT_EQ(0,
+            message.GetReflection()->GetUnknownFields(message).field_count());
+}
+
+TEST(ReflectionOpsForMapFieldTest, IsInitialized) {
+  UNITTEST::TestRequiredMessageMap map_message;
+
+  // Add an uninitialized message.
+  (*map_message.mutable_map_field())[0];
+  EXPECT_FALSE(ReflectionOps::IsInitialized(map_message));
+
+  // Initialize uninitialized message
+  (*map_message.mutable_map_field())[0].set_a(0);
+  (*map_message.mutable_map_field())[0].set_b(0);
+  (*map_message.mutable_map_field())[0].set_c(0);
+  EXPECT_TRUE(ReflectionOps::IsInitialized(map_message));
+}
+
+// Wire Format Test =================================================
+
+TEST(WireFormatForMapFieldTest, ParseMap) {
+  UNITTEST::TestMap source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  MapTestUtil::SetMapFields(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  MapTestUtil::ExpectMapFieldsSet(dest);
+}
+
+TEST(WireFormatForMapFieldTest, MapByteSize) {
+  UNITTEST::TestMap message;
+  MapTestUtil::SetMapFields(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatForMapFieldTest, SerializeMap) {
+  UNITTEST::TestMap message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  MapTestUtil::SetMapFields(&message);
+
+  // Serialize using the generated code.
+  {
+    message.ByteSizeLong();
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    size_t size = WireFormat::ByteSize(message);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatForMapFieldTest, SerializeMapDynamicMessage) {
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> dynamic_message;
+  dynamic_message.reset(
+      factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(dynamic_message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*dynamic_message);
+
+  UNITTEST::TestMap generated_message;
+  MapTestUtil::SetMapFields(&generated_message);
+  MapTestUtil::ExpectMapFieldsSet(generated_message);
+
+  std::string generated_data;
+  std::string dynamic_data;
+
+  // Serialize.
+  generated_message.SerializeToString(&generated_data);
+  dynamic_message->SerializeToString(&dynamic_data);
+
+  // Because map serialization doesn't guarantee order, we just compare
+  // serialized size here. This is enough to tell dynamic message doesn't miss
+  // anything in serialization.
+  EXPECT_TRUE(dynamic_data.size() == generated_data.size());
+}
+
+TEST(WireFormatForMapFieldTest, MapByteSizeDynamicMessage) {
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> dynamic_message;
+  dynamic_message.reset(
+      factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(dynamic_message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*dynamic_message);
+  std::string expected_serialized_data;
+  dynamic_message->SerializeToString(&expected_serialized_data);
+  int expected_size = expected_serialized_data.size();
+  EXPECT_EQ(dynamic_message->ByteSizeLong(), expected_size);
+  TestMap expected_message;
+  expected_message.ParseFromString(expected_serialized_data);
+
+  std::unique_ptr<Message> message2;
+  message2.reset(factory.GetPrototype(UNITTEST::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaMapReflection(message2.get());
+
+  const FieldDescriptor* field =
+      UNITTEST::TestMap::descriptor()->FindFieldByName("map_int32_int32");
+  const Reflection* reflection = dynamic_message->GetReflection();
+
+  // Force the map field to mark with STATE_MODIFIED_REPEATED
+  reflection->RemoveLast(dynamic_message.get(), field);
+  dynamic_message->MergeFrom(*message2);
+  dynamic_message->MergeFrom(*message2);
+  // The map field is marked as STATE_MODIFIED_REPEATED, ByteSizeLong() will use
+  // repeated field which have duplicate keys to calculate.
+  size_t duplicate_size = dynamic_message->ByteSizeLong();
+  EXPECT_TRUE(duplicate_size > expected_size);
+  std::string duplicate_serialized_data;
+  dynamic_message->SerializeToString(&duplicate_serialized_data);
+  EXPECT_EQ(dynamic_message->ByteSizeLong(), duplicate_serialized_data.size());
+
+  // Force the map field to mark with map CLEAN
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_int32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_int32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int64_int64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_uint32_uint32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_uint64_uint64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_sint32_sint32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_sint64_sint64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_fixed32_fixed32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_fixed64_fixed64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_sfixed32_sfixed32"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_sfixed64_sfixed64"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_float"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_double"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_bool_bool"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_string_string"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_bytes"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(
+      *dynamic_message, "map_int32_enum"), 2);
+  EXPECT_EQ(reflection_tester.MapSize(*dynamic_message, "map_int32_foreign_message"), 2);
+  // The map field is marked as CLEAN, ByteSizeLong() will use map which do not
+  // have duplicate keys to calculate.
+  int size = dynamic_message->ByteSizeLong();
+  EXPECT_EQ(expected_size, size);
+
+  // Protobuf used to have a bug for serialize when map it marked CLEAN. It used
+  // repeated field to calculate ByteSizeLong but use map to serialize the real
+  // data, thus the ByteSizeLong may bigger than real serialized size. A crash
+  // might be happen at SerializeToString(). Or an "unexpected end group"
+  // warning was raised at parse back if user use SerializeWithCachedSizes()
+  // which avoids size check at serialize.
+  std::string serialized_data;
+  dynamic_message->SerializeToString(&serialized_data);
+  EXPECT_TRUE(dynamic_message->ParseFromString(serialized_data));
+}
+
+TEST(WireFormatForMapFieldTest, MapParseHelpers) {
+  std::string data;
+
+  {
+    // Set up.
+    UNITTEST::TestMap message;
+    MapTestUtil::SetMapFields(&message);
+    message.SerializeToString(&data);
+  }
+
+  {
+    // Test ParseFromString.
+    UNITTEST::TestMap message;
+    EXPECT_TRUE(message.ParseFromString(data));
+    MapTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // Test ParseFromIstream.
+    UNITTEST::TestMap message;
+    std::stringstream stream(data);
+    EXPECT_TRUE(message.ParseFromIstream(&stream));
+    EXPECT_TRUE(stream.eof());
+    MapTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // Test ParseFromBoundedZeroCopyStream.
+    std::string data_with_junk(data);
+    data_with_junk.append("some junk on the end");
+    io::ArrayInputStream stream(data_with_junk.data(), data_with_junk.size());
+    UNITTEST::TestMap message;
+    EXPECT_TRUE(message.ParseFromBoundedZeroCopyStream(&stream, data.size()));
+    MapTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // Test that ParseFromBoundedZeroCopyStream fails (but doesn't crash) if
+    // EOF is reached before the expected number of bytes.
+    io::ArrayInputStream stream(data.data(), data.size());
+    UNITTEST::TestAllTypes message;
+    EXPECT_FALSE(
+        message.ParseFromBoundedZeroCopyStream(&stream, data.size() + 1));
+  }
+}
+
+// Deterministic Serialization Test ==========================================
+
+template <typename T>
+static std::string DeterministicSerializationWithSerializePartialToCodedStream(
+    const T& t) {
+  const size_t size = t.ByteSizeLong();
+  std::string result(size, '\0');
+  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size);
+  io::CodedOutputStream output_stream(&array_stream);
+  output_stream.SetSerializationDeterministic(true);
+  t.SerializePartialToCodedStream(&output_stream);
+  EXPECT_FALSE(output_stream.HadError());
+  EXPECT_EQ(size, output_stream.ByteCount());
+  return result;
+}
+
+template <typename T>
+static std::string DeterministicSerializationWithSerializeToCodedStream(
+    const T& t) {
+  const size_t size = t.ByteSizeLong();
+  std::string result(size, '\0');
+  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size);
+  io::CodedOutputStream output_stream(&array_stream);
+  output_stream.SetSerializationDeterministic(true);
+  t.SerializeToCodedStream(&output_stream);
+  EXPECT_FALSE(output_stream.HadError());
+  EXPECT_EQ(size, output_stream.ByteCount());
+  return result;
+}
+
+template <typename T>
+static std::string DeterministicSerialization(const T& t) {
+  const size_t size = t.ByteSizeLong();
+  std::string result(size, '\0');
+  io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size);
+  {
+    io::CodedOutputStream output_stream(&array_stream);
+    output_stream.SetSerializationDeterministic(true);
+    t.SerializeWithCachedSizes(&output_stream);
+    EXPECT_FALSE(output_stream.HadError());
+    EXPECT_EQ(size, output_stream.ByteCount());
+  }
+  EXPECT_EQ(result, DeterministicSerializationWithSerializeToCodedStream(t));
+  EXPECT_EQ(result,
+            DeterministicSerializationWithSerializePartialToCodedStream(t));
+  return result;
+}
+
+// Helper for MapSerializationTest.  Return a 7-bit ASCII string.
+static std::string ConstructKey(uint64 n) {
+  std::string s(n % static_cast<uint64>(9), '\0');
+  if (s.empty()) {
+    return StrCat(n);
+  } else {
+    while (n != 0) {
+      s[n % s.size()] = (n >> 10) & 0x7f;
+      n /= 888;
+    }
+    return s;
+  }
+}
+
+TEST(MapSerializationTest, Deterministic) {
+  const int kIters = 25;
+  UNITTEST::TestMaps t;
+  UNITTEST::TestIntIntMap inner;
+  (*inner.mutable_m())[0] = (*inner.mutable_m())[10] =
+      (*inner.mutable_m())[-200] = 0;
+  uint64 frog = 9;
+  const uint64 multiplier = 0xa29cd16f;
+  for (int i = 0; i < kIters; i++) {
+    const int32 i32 = static_cast<int32>(frog & 0xffffffff);
+    const uint32 u32 = static_cast<uint32>(i32) * 91919;
+    const int64 i64 = static_cast<int64>(frog);
+    const uint64 u64 = frog * static_cast<uint64>(187321);
+    const bool b = i32 > 0;
+    const std::string s = ConstructKey(frog);
+    (*inner.mutable_m())[i] = i32;
+    (*t.mutable_m_int32())[i32] = (*t.mutable_m_sint32())[i32] =
+        (*t.mutable_m_sfixed32())[i32] = inner;
+    (*t.mutable_m_uint32())[u32] = (*t.mutable_m_fixed32())[u32] = inner;
+    (*t.mutable_m_int64())[i64] = (*t.mutable_m_sint64())[i64] =
+        (*t.mutable_m_sfixed64())[i64] = inner;
+    (*t.mutable_m_uint64())[u64] = (*t.mutable_m_fixed64())[u64] = inner;
+    (*t.mutable_m_bool())[b] = inner;
+    (*t.mutable_m_string())[s] = inner;
+    (*t.mutable_m_string())[s + std::string(1 << (u32 % static_cast<uint32>(9)),
+                                            b)] = inner;
+    inner.mutable_m()->erase(i);
+    frog = frog * multiplier + i;
+    frog ^= (frog >> 41);
+  }
+
+  // Verifies if two consecutive calls to deterministic serialization produce
+  // the same bytes. Deterministic serialization means the same serialization
+  // bytes in the same binary.
+  const std::string s1 = DeterministicSerialization(t);
+  const std::string s2 = DeterministicSerialization(t);
+  EXPECT_EQ(s1, s2);
+
+  UNITTEST::TestMaps u;
+  EXPECT_TRUE(u.ParseFromString(s1));
+  EXPECT_TRUE(util::MessageDifferencer::Equals(u, t));
+}
+
+TEST(MapSerializationTest, DeterministicSubmessage) {
+  UNITTEST::TestSubmessageMaps p;
+  UNITTEST::TestMaps t;
+  const std::string filename = "golden_message_maps";
+  std::string golden;
+  GOOGLE_CHECK_OK(File::GetContents(
+      TestUtil::GetTestDataPath("net/proto2/internal/testdata/" + filename),
+      &golden, true));
+  t.ParseFromString(golden);
+  *(p.mutable_m()) = t;
+  std::vector<std::string> v;
+  // Use multiple attempts to increase the chance of a failure if something is
+  // buggy.  For example, each separate copy of a map might use a different
+  // randomly-chosen hash function.
+  const int kAttempts = 10;
+  for (int i = 0; i < kAttempts; i++) {
+    UNITTEST::TestSubmessageMaps q(p);
+    ASSERT_EQ(DeterministicSerialization(q), DeterministicSerialization(p));
+  }
+}
+
+// Text Format Test =================================================
+
+TEST(TextFormatMapTest, SerializeAndParse) {
+  UNITTEST::TestMap source;
+  UNITTEST::TestMap dest;
+  MapTestUtil::SetMapFields(&source);
+  std::string output;
+
+  // Test compact ASCII
+  TextFormat::Printer printer;
+  printer.PrintToString(source, &output);
+  TextFormat::Parser parser;
+  EXPECT_TRUE(parser.ParseFromString(output, &dest));
+  MapTestUtil::ExpectMapFieldsSet(dest);
+}
+
+TEST(TextFormatMapTest, DynamicMessage) {
+  TestMap prototype;
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message(
+      factory.GetPrototype(prototype.GetDescriptor())->New());
+  MapReflectionTester tester(message->GetDescriptor());
+  tester.SetMapFieldsViaReflection(message.get());
+
+  std::string expected_text;
+  GOOGLE_CHECK_OK(
+      File::GetContents(TestUtil::GetTestDataPath("net/proto2/internal/"
+                                                  "testdata/map_test_data.txt"),
+                        &expected_text, true));
+
+  CleanStringLineEndings(&expected_text, false);
+  EXPECT_EQ(message->DebugString(), expected_text);
+}
+
+TEST(TextFormatMapTest, Sorted) {
+  UNITTEST::TestMap message;
+  MapReflectionTester tester(message.GetDescriptor());
+  tester.SetMapFieldsViaReflection(&message);
+
+  std::string expected_text;
+  GOOGLE_CHECK_OK(
+      File::GetContents(TestUtil::GetTestDataPath("net/proto2/internal/"
+                                                  "testdata/map_test_data.txt"),
+                        &expected_text, true));
+
+  CleanStringLineEndings(&expected_text, false);
+  EXPECT_EQ(message.DebugString(), expected_text);
+
+  // Test again on the reverse order.
+  UNITTEST::TestMap message2;
+  tester.SetMapFieldsViaReflection(&message2);
+  tester.SwapMapsViaReflection(&message2);
+  EXPECT_EQ(message2.DebugString(), expected_text);
+}
+
+TEST(TextFormatMapTest, ParseCorruptedString) {
+  std::string serialized_message;
+  GOOGLE_CHECK_OK(
+      File::GetContents(TestUtil::GetTestDataPath(
+                            "net/proto2/internal/testdata/golden_message_maps"),
+                        &serialized_message, true));
+  UNITTEST::TestMaps message;
+  GOOGLE_CHECK(message.ParseFromString(serialized_message));
+  TestParseCorruptedString<UNITTEST::TestMaps, true>(message);
+  TestParseCorruptedString<UNITTEST::TestMaps, false>(message);
+}
+
+// Previously, serializing to text format will disable iterator from generated
+// API. Now, the iterator can be still used even after serializing to text
+// format.
+TEST(TextFormatMapTest, NoDisableIterator) {
+  UNITTEST::TestMap source;
+  (*source.mutable_map_int32_int32())[1] = 1;
+
+  // Get iterator.
+  Map<int32, int32>::iterator iter = source.mutable_map_int32_int32()->find(1);
+
+  // Serialize message to text format, which will invalidate the previous
+  // iterator previously.
+  std::string output;
+  TextFormat::Printer printer;
+  printer.PrintToString(source, &output);
+
+  // Modify map via the iterator (invalidated in previous implementation.).
+  iter->second = 2;
+
+  // In previous implementation, the new change won't be reflected in text
+  // format, because the previous iterator has been invalidated.
+  output.clear();
+  printer.PrintToString(source, &output);
+  std::string expected =
+      "map_int32_int32 {\n"
+      "  key: 1\n"
+      "  value: 2\n"
+      "}\n";
+  EXPECT_EQ(output, expected);
+}
+
+// Previously, serializing to text format will disable iterator from reflection
+// API.
+TEST(TextFormatMapTest, NoDisableReflectionIterator) {
+  UNITTEST::TestMap source;
+  (*source.mutable_map_int32_int32())[1] = 1;
+
+  // Get iterator. This will also sync internal repeated field with map inside
+  // of MapField.
+  const Reflection* reflection = source.GetReflection();
+  const FieldDescriptor* field_desc =
+      source.GetDescriptor()->FindFieldByName("map_int32_int32");
+  RepeatedPtrField<Message>* map_field =
+      reflection->MutableRepeatedPtrField<Message>(&source, field_desc);
+  RepeatedPtrField<Message>::iterator iter = map_field->begin();
+
+  // Serialize message to text format, which will invalidate the previous
+  // iterator previously.
+  std::string output;
+  TextFormat::Printer printer;
+  printer.PrintToString(source, &output);
+
+  // Modify map via the iterator (invalidated in previous implementation.).
+  const Reflection* map_entry_reflection = iter->GetReflection();
+  const FieldDescriptor* value_field_desc =
+      iter->GetDescriptor()->FindFieldByName("value");
+  map_entry_reflection->SetInt32(&(*iter), value_field_desc, 2);
+  GOOGLE_LOG(INFO) << iter->DebugString();
+
+  // In previous implementation, the new change won't be reflected in text
+  // format, because the previous iterator has been invalidated.
+  output.clear();
+  printer.PrintToString(source, &output);
+  std::string expected =
+      "map_int32_int32 {\n"
+      "  key: 1\n"
+      "  value: 2\n"
+      "}\n";
+  EXPECT_EQ(output, expected);
+}
+
+// arena support =================================================
+TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) {
+  // Allocate a large initial block to avoid mallocs during hooked test.
+  std::vector<char> arena_block(128 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+  std::string data;
+  data.reserve(128 * 1024);
+
+  {
+    // TODO(teboring): Enable no heap check when ArenaStringPtr is used in map.
+    // NoHeapChecker no_heap;
+
+    UNITTEST::TestArenaMap* from =
+        Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+    MapTestUtil::SetArenaMapFields(from);
+    from->SerializeToString(&data);
+
+    UNITTEST::TestArenaMap* to =
+        Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+    to->ParseFromString(data);
+    MapTestUtil::ExpectArenaMapFieldsSet(*to);
+  }
+}
+
+TEST(ArenaTest, SubmessageOnSameArena) {
+  Arena arena;
+  for (Arena* arena_to_use : {&arena, static_cast<Arena*>(nullptr)}) {
+    ArenaHolder<UNITTEST::TestArenaMap> m(arena_to_use);
+    auto* subm = &(*m->mutable_map_int32_foreign_message())[0];
+    EXPECT_EQ(subm->GetArena(), arena_to_use);
+  }
+}
+
+// Use text format parsing and serializing to test reflection api.
+TEST(ArenaTest, ReflectionInTextFormat) {
+  Arena arena;
+  std::string data;
+
+  TextFormat::Printer printer;
+  TextFormat::Parser parser;
+
+  UNITTEST::TestArenaMap* from =
+      Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+  UNITTEST::TestArenaMap* to =
+      Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+
+  MapTestUtil::SetArenaMapFields(from);
+  printer.PrintToString(*from, &data);
+
+  EXPECT_TRUE(parser.ParseFromString(data, to));
+  MapTestUtil::ExpectArenaMapFieldsSet(*to);
+}
+
+// Make sure the memory allocated for string in map is deallocated.
+TEST(ArenaTest, StringMapNoLeak) {
+  Arena arena;
+  UNITTEST::TestArenaMap* message =
+      Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+  std::string data;
+  // String with length less than 16 will not be allocated from heap.
+  int original_capacity = data.capacity();
+  while (data.capacity() <= original_capacity) {
+    data.append("a");
+  }
+  (*message->mutable_map_string_string())[data] = data;
+  // We rely on heap checkers to detect memory leak for us.
+  ASSERT_FALSE(message == NULL);
+}
+
+TEST(ArenaTest, IsInitialized) {
+  // Allocate a large initial polluted block.
+  std::vector<char> arena_block(128 * 1024);
+  std::fill(arena_block.begin(), arena_block.end(), '\xff');
+
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+
+  UNITTEST::TestArenaMap* message =
+      Arena::CreateMessage<UNITTEST::TestArenaMap>(&arena);
+  EXPECT_EQ(0, (*message->mutable_map_int32_int32())[0]);
+}
+
+TEST(ArenaTest, DynamicMapFieldOnArena) {
+  Arena arena;
+  UNITTEST::TestMap message2;
+
+  DynamicMessageFactory factory;
+  Message* message1 =
+      factory.GetPrototype(UNITTEST::TestMap::descriptor())->New(&arena);
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(message1);
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1);
+  message2.CopyFrom(*message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(ArenaTest, DynamicMapFieldOnArenaMemoryLeak) {
+  auto* desc = UNITTEST::TestMap::descriptor();
+  auto* field = desc->FindFieldByName("map_int32_int32");
+
+  Arena arena;
+  DynamicMessageFactory factory;
+  auto* message = factory.GetPrototype(desc)->New(&arena);
+  auto* reflection = message->GetReflection();
+  reflection->AddMessage(message, field);
+
+  // Force internal syncing, which initializes the mutex.
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  int size = reflection_tester.MapSize(*message, "map_int32_int32");
+  EXPECT_EQ(size, 1);
+}
+
+TEST(MoveTest, MoveConstructorWorks) {
+  Map<int32, TestAllTypes> original_map;
+  original_map[42].mutable_optional_nested_message()->set_bb(42);
+  original_map[43].mutable_optional_nested_message()->set_bb(43);
+  const auto* nested_msg42_ptr = &original_map[42].optional_nested_message();
+  const auto* nested_msg43_ptr = &original_map[43].optional_nested_message();
+
+  Map<int32, TestAllTypes> moved_to_map(std::move(original_map));
+  EXPECT_TRUE(original_map.empty());
+  EXPECT_EQ(2, moved_to_map.size());
+  EXPECT_EQ(42, moved_to_map[42].optional_nested_message().bb());
+  EXPECT_EQ(43, moved_to_map[43].optional_nested_message().bb());
+  // This test takes advantage of the fact that pointers are swapped, so there
+  // should be pointer stability.
+  EXPECT_EQ(nested_msg42_ptr, &moved_to_map[42].optional_nested_message());
+  EXPECT_EQ(nested_msg43_ptr, &moved_to_map[43].optional_nested_message());
+}
+
+TEST(MoveTest, MoveAssignmentWorks) {
+  Map<int32, TestAllTypes> original_map;
+  original_map[42].mutable_optional_nested_message()->set_bb(42);
+  original_map[43].mutable_optional_nested_message()->set_bb(43);
+  const auto* nested_msg42_ptr = &original_map[42].optional_nested_message();
+  const auto* nested_msg43_ptr = &original_map[43].optional_nested_message();
+
+  Map<int32, TestAllTypes> moved_to_map = std::move(original_map);
+  EXPECT_TRUE(original_map.empty());
+  EXPECT_EQ(2, moved_to_map.size());
+  EXPECT_EQ(42, moved_to_map[42].optional_nested_message().bb());
+  EXPECT_EQ(43, moved_to_map[43].optional_nested_message().bb());
+  // This test takes advantage of the fact that pointers are swapped, so there
+  // should be pointer stability.
+  EXPECT_EQ(nested_msg42_ptr, &moved_to_map[42].optional_nested_message());
+  EXPECT_EQ(nested_msg43_ptr, &moved_to_map[43].optional_nested_message());
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h
index c3b84d1..f3215db 100644
--- a/src/google/protobuf/map_test_util.h
+++ b/src/google/protobuf/map_test_util.h
@@ -32,1607 +32,15 @@
 #define GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
 
 #include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/reflection_tester.h>
 
 #define UNITTEST ::protobuf_unittest
-// Must define UNITTEST before including map_test_util.inc.
+#define BRIDGE_UNITTEST ::google::protobuf::bridge_unittest
+
+// Must be included after defining UNITTEST, etc.
 #include <google/protobuf/map_test_util.inc>
+
 #undef UNITTEST
-
-#include <google/protobuf/port_def.inc>
-
-namespace google {
-namespace protobuf {
-
-namespace unittest = ::protobuf_unittest;
-
-
-// Like above, but use the reflection interface.
-class MapReflectionTester {
- public:
-  // base_descriptor must be a descriptor for TestMap, which is used for
-  // MapReflectionTester to fetch the FieldDescriptors needed to use the
-  // reflection interface.
-  explicit MapReflectionTester(const Descriptor* base_descriptor);
-
-  void SetMapFieldsViaReflection(Message* message);
-  void SetMapFieldsViaMapReflection(Message* message);
-  void ClearMapFieldsViaReflection(Message* message);
-  void ModifyMapFieldsViaReflection(Message* message);
-  void RemoveLastMapsViaReflection(Message* message);
-  void ReleaseLastMapsViaReflection(Message* message);
-  void SwapMapsViaReflection(Message* message);
-  void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message);
-  void ExpectMapFieldsSetViaReflection(const Message& message);
-  void ExpectMapFieldsSetViaReflectionIterator(Message* message);
-  void ExpectClearViaReflection(const Message& message);
-  void ExpectClearViaReflectionIterator(Message* message);
-  void GetMapValueViaMapReflection(Message* message,
-                                   const std::string& field_name,
-                                   const MapKey& map_key, MapValueRef* map_val);
-  Message* GetMapEntryViaReflection(Message* message,
-                                    const std::string& field_name, int index);
-  MapIterator MapBegin(Message* message, const std::string& field_name);
-  MapIterator MapEnd(Message* message, const std::string& field_name);
-  int MapSize(const Message& message, const std::string& field_name);
-
- private:
-  const FieldDescriptor* F(const std::string& name);
-
-  const Descriptor* base_descriptor_;
-
-  const EnumValueDescriptor* map_enum_bar_;
-  const EnumValueDescriptor* map_enum_baz_;
-  const EnumValueDescriptor* map_enum_foo_;
-
-  const FieldDescriptor* foreign_c_;
-  const FieldDescriptor* map_int32_int32_key_;
-  const FieldDescriptor* map_int32_int32_val_;
-  const FieldDescriptor* map_int64_int64_key_;
-  const FieldDescriptor* map_int64_int64_val_;
-  const FieldDescriptor* map_uint32_uint32_key_;
-  const FieldDescriptor* map_uint32_uint32_val_;
-  const FieldDescriptor* map_uint64_uint64_key_;
-  const FieldDescriptor* map_uint64_uint64_val_;
-  const FieldDescriptor* map_sint32_sint32_key_;
-  const FieldDescriptor* map_sint32_sint32_val_;
-  const FieldDescriptor* map_sint64_sint64_key_;
-  const FieldDescriptor* map_sint64_sint64_val_;
-  const FieldDescriptor* map_fixed32_fixed32_key_;
-  const FieldDescriptor* map_fixed32_fixed32_val_;
-  const FieldDescriptor* map_fixed64_fixed64_key_;
-  const FieldDescriptor* map_fixed64_fixed64_val_;
-  const FieldDescriptor* map_sfixed32_sfixed32_key_;
-  const FieldDescriptor* map_sfixed32_sfixed32_val_;
-  const FieldDescriptor* map_sfixed64_sfixed64_key_;
-  const FieldDescriptor* map_sfixed64_sfixed64_val_;
-  const FieldDescriptor* map_int32_float_key_;
-  const FieldDescriptor* map_int32_float_val_;
-  const FieldDescriptor* map_int32_double_key_;
-  const FieldDescriptor* map_int32_double_val_;
-  const FieldDescriptor* map_bool_bool_key_;
-  const FieldDescriptor* map_bool_bool_val_;
-  const FieldDescriptor* map_string_string_key_;
-  const FieldDescriptor* map_string_string_val_;
-  const FieldDescriptor* map_int32_bytes_key_;
-  const FieldDescriptor* map_int32_bytes_val_;
-  const FieldDescriptor* map_int32_enum_key_;
-  const FieldDescriptor* map_int32_enum_val_;
-  const FieldDescriptor* map_int32_foreign_message_key_;
-  const FieldDescriptor* map_int32_foreign_message_val_;
-};
-
-inline MapReflectionTester::MapReflectionTester(
-    const Descriptor* base_descriptor)
-    : base_descriptor_(base_descriptor) {
-  const DescriptorPool* pool = base_descriptor->file()->pool();
-  std::string package = base_descriptor->file()->package();
-
-  map_enum_foo_ = pool->FindEnumValueByName(package + ".MAP_ENUM_FOO");
-  map_enum_bar_ = pool->FindEnumValueByName(package + ".MAP_ENUM_BAR");
-  map_enum_baz_ = pool->FindEnumValueByName(package + ".MAP_ENUM_BAZ");
-
-  foreign_c_ = pool->FindFieldByName(package + ".ForeignMessage.c");
-  map_int32_int32_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32Int32Entry.key");
-  map_int32_int32_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32Int32Entry.value");
-  map_int64_int64_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt64Int64Entry.key");
-  map_int64_int64_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt64Int64Entry.value");
-  map_uint32_uint32_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapUint32Uint32Entry.key");
-  map_uint32_uint32_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapUint32Uint32Entry.value");
-  map_uint64_uint64_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapUint64Uint64Entry.key");
-  map_uint64_uint64_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapUint64Uint64Entry.value");
-  map_sint32_sint32_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapSint32Sint32Entry.key");
-  map_sint32_sint32_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapSint32Sint32Entry.value");
-  map_sint64_sint64_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapSint64Sint64Entry.key");
-  map_sint64_sint64_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapSint64Sint64Entry.value");
-  map_fixed32_fixed32_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapFixed32Fixed32Entry.key");
-  map_fixed32_fixed32_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapFixed32Fixed32Entry.value");
-  map_fixed64_fixed64_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapFixed64Fixed64Entry.key");
-  map_fixed64_fixed64_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapFixed64Fixed64Entry.value");
-  map_sfixed32_sfixed32_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapSfixed32Sfixed32Entry.key");
-  map_sfixed32_sfixed32_val_ = pool->FindFieldByName(
-      package + ".TestMap.MapSfixed32Sfixed32Entry.value");
-  map_sfixed64_sfixed64_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapSfixed64Sfixed64Entry.key");
-  map_sfixed64_sfixed64_val_ = pool->FindFieldByName(
-      package + ".TestMap.MapSfixed64Sfixed64Entry.value");
-  map_int32_float_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32FloatEntry.key");
-  map_int32_float_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32FloatEntry.value");
-  map_int32_double_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32DoubleEntry.key");
-  map_int32_double_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32DoubleEntry.value");
-  map_bool_bool_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapBoolBoolEntry.key");
-  map_bool_bool_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapBoolBoolEntry.value");
-  map_string_string_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapStringStringEntry.key");
-  map_string_string_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapStringStringEntry.value");
-  map_int32_bytes_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32BytesEntry.key");
-  map_int32_bytes_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32BytesEntry.value");
-  map_int32_enum_key_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32EnumEntry.key");
-  map_int32_enum_val_ =
-      pool->FindFieldByName(package + ".TestMap.MapInt32EnumEntry.value");
-  map_int32_foreign_message_key_ = pool->FindFieldByName(
-      package + ".TestMap.MapInt32ForeignMessageEntry.key");
-  map_int32_foreign_message_val_ = pool->FindFieldByName(
-      package + ".TestMap.MapInt32ForeignMessageEntry.value");
-
-  EXPECT_FALSE(map_enum_foo_ == nullptr);
-  EXPECT_FALSE(map_enum_bar_ == nullptr);
-  EXPECT_FALSE(map_enum_baz_ == nullptr);
-  EXPECT_FALSE(map_int32_int32_key_ == nullptr);
-  EXPECT_FALSE(map_int32_int32_val_ == nullptr);
-  EXPECT_FALSE(map_int64_int64_key_ == nullptr);
-  EXPECT_FALSE(map_int64_int64_val_ == nullptr);
-  EXPECT_FALSE(map_uint32_uint32_key_ == nullptr);
-  EXPECT_FALSE(map_uint32_uint32_val_ == nullptr);
-  EXPECT_FALSE(map_uint64_uint64_key_ == nullptr);
-  EXPECT_FALSE(map_uint64_uint64_val_ == nullptr);
-  EXPECT_FALSE(map_sint32_sint32_key_ == nullptr);
-  EXPECT_FALSE(map_sint32_sint32_val_ == nullptr);
-  EXPECT_FALSE(map_sint64_sint64_key_ == nullptr);
-  EXPECT_FALSE(map_sint64_sint64_val_ == nullptr);
-  EXPECT_FALSE(map_fixed32_fixed32_key_ == nullptr);
-  EXPECT_FALSE(map_fixed32_fixed32_val_ == nullptr);
-  EXPECT_FALSE(map_fixed64_fixed64_key_ == nullptr);
-  EXPECT_FALSE(map_fixed64_fixed64_val_ == nullptr);
-  EXPECT_FALSE(map_sfixed32_sfixed32_key_ == nullptr);
-  EXPECT_FALSE(map_sfixed32_sfixed32_val_ == nullptr);
-  EXPECT_FALSE(map_sfixed64_sfixed64_key_ == nullptr);
-  EXPECT_FALSE(map_sfixed64_sfixed64_val_ == nullptr);
-  EXPECT_FALSE(map_int32_float_key_ == nullptr);
-  EXPECT_FALSE(map_int32_float_val_ == nullptr);
-  EXPECT_FALSE(map_int32_double_key_ == nullptr);
-  EXPECT_FALSE(map_int32_double_val_ == nullptr);
-  EXPECT_FALSE(map_bool_bool_key_ == nullptr);
-  EXPECT_FALSE(map_bool_bool_val_ == nullptr);
-  EXPECT_FALSE(map_string_string_key_ == nullptr);
-  EXPECT_FALSE(map_string_string_val_ == nullptr);
-  EXPECT_FALSE(map_int32_bytes_key_ == nullptr);
-  EXPECT_FALSE(map_int32_bytes_val_ == nullptr);
-  EXPECT_FALSE(map_int32_enum_key_ == nullptr);
-  EXPECT_FALSE(map_int32_enum_val_ == nullptr);
-  EXPECT_FALSE(map_int32_foreign_message_key_ == nullptr);
-  EXPECT_FALSE(map_int32_foreign_message_val_ == nullptr);
-
-  std::vector<const FieldDescriptor*> all_map_descriptors = {
-      map_int32_int32_key_,
-      map_int32_int32_val_,
-      map_int64_int64_key_,
-      map_int64_int64_val_,
-      map_uint32_uint32_key_,
-      map_uint32_uint32_val_,
-      map_uint64_uint64_key_,
-      map_uint64_uint64_val_,
-      map_sint32_sint32_key_,
-      map_sint32_sint32_val_,
-      map_sint64_sint64_key_,
-      map_sint64_sint64_val_,
-      map_fixed32_fixed32_key_,
-      map_fixed32_fixed32_val_,
-      map_fixed64_fixed64_key_,
-      map_fixed64_fixed64_val_,
-      map_sfixed32_sfixed32_key_,
-      map_sfixed32_sfixed32_val_,
-      map_sfixed64_sfixed64_key_,
-      map_sfixed64_sfixed64_val_,
-      map_int32_float_key_,
-      map_int32_float_val_,
-      map_int32_double_key_,
-      map_int32_double_val_,
-      map_bool_bool_key_,
-      map_bool_bool_val_,
-      map_string_string_key_,
-      map_string_string_val_,
-      map_int32_bytes_key_,
-      map_int32_bytes_val_,
-      map_int32_enum_key_,
-      map_int32_enum_val_,
-      map_int32_foreign_message_key_,
-      map_int32_foreign_message_val_};
-  for (const FieldDescriptor* fdesc : all_map_descriptors) {
-    GOOGLE_CHECK(fdesc->containing_type() != nullptr) << fdesc->name();
-    if (fdesc->name() == "key") {
-      EXPECT_EQ(fdesc->containing_type()->map_key(), fdesc);
-    } else {
-      EXPECT_EQ(fdesc->name(), "value");
-      EXPECT_EQ(fdesc->containing_type()->map_value(), fdesc);
-    }
-  }
-}
-
-// Shorthand to get a FieldDescriptor for a field of unittest::TestMap.
-inline const FieldDescriptor* MapReflectionTester::F(const std::string& name) {
-  const FieldDescriptor* result = nullptr;
-  result = base_descriptor_->FindFieldByName(name);
-  GOOGLE_CHECK(result != nullptr);
-  return result;
-}
-
-inline void MapReflectionTester::SetMapFieldsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  Message* sub_message = nullptr;
-  Message* sub_foreign_message = nullptr;
-
-  // Add first element.
-  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 0);
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 0);
-
-  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
-  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 0);
-  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 0);
-
-  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
-  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
-                                          0);
-  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
-                                          0);
-
-  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
-  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
-                                          0);
-  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
-                                          0);
-
-  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
-                                         0);
-  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
-                                         0);
-
-  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
-  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
-                                         0);
-  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
-                                         0);
-
-  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
-  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
-                                          0);
-  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
-                                          0);
-
-  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
-  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
-                                          0);
-  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
-                                          0);
-
-  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_sfixed32_sfixed32_key_, 0);
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_sfixed32_sfixed32_val_, 0);
-
-  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
-  sub_message->GetReflection()->SetInt64(sub_message,
-                                         map_sfixed64_sfixed64_key_, 0);
-  sub_message->GetReflection()->SetInt64(sub_message,
-                                         map_sfixed64_sfixed64_val_, 0);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_float"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 0);
-  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
-                                         0.0);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_double"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 0);
-  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
-                                          0.0);
-
-  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
-  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, false);
-  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, false);
-
-  sub_message = reflection->AddMessage(message, F("map_string_string"));
-  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
-                                          "0");
-  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
-                                          "0");
-
-  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 0);
-  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
-                                          "0");
-
-  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 0);
-  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
-                                        map_enum_bar_);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_int32_foreign_message_key_, 0);
-  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
-      sub_message, map_int32_foreign_message_val_, nullptr);
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 0);
-
-  // Add second element
-  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 1);
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 1);
-
-  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
-  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 1);
-  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 1);
-
-  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
-  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
-                                          1);
-  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
-                                          1);
-
-  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
-  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
-                                          1);
-  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
-                                          1);
-
-  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
-                                         1);
-  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
-                                         1);
-
-  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
-  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
-                                         1);
-  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
-                                         1);
-
-  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
-  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
-                                          1);
-  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
-                                          1);
-
-  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
-  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
-                                          1);
-  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
-                                          1);
-
-  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_sfixed32_sfixed32_key_, 1);
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_sfixed32_sfixed32_val_, 1);
-
-  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
-  sub_message->GetReflection()->SetInt64(sub_message,
-                                         map_sfixed64_sfixed64_key_, 1);
-  sub_message->GetReflection()->SetInt64(sub_message,
-                                         map_sfixed64_sfixed64_val_, 1);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_float"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 1);
-  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
-                                         1.0);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_double"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 1);
-  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
-                                          1.0);
-
-  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
-  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, true);
-  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, true);
-
-  sub_message = reflection->AddMessage(message, F("map_string_string"));
-  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
-                                          "1");
-  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
-                                          "1");
-
-  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 1);
-  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
-                                          "1");
-
-  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 1);
-  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
-                                        map_enum_baz_);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_int32_foreign_message_key_, 1);
-  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
-      sub_message, map_int32_foreign_message_val_, nullptr);
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 1);
-}
-
-inline void MapReflectionTester::SetMapFieldsViaMapReflection(
-    Message* message) {
-  const Reflection* reflection = message->GetReflection();
-
-  Message* sub_foreign_message = nullptr;
-  MapValueRef map_val;
-  MapValueConstRef map_val_const;
-
-  // Add first element.
-  MapKey map_key;
-  map_key.SetInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_int32"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                 map_key, &map_val));
-  map_val.SetInt32Value(0);
-
-  map_key.SetInt64Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int64_int64"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                 map_key, &map_val));
-  map_val.SetInt64Value(0);
-
-  map_key.SetUInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_uint32_uint32"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_uint32_uint32"), map_key, &map_val));
-  map_val.SetUInt32Value(0);
-
-  map_key.SetUInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_uint64_uint64"), map_key, &map_val));
-  map_val.SetUInt64Value(0);
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sint32_sint32"), map_key, &map_val));
-  map_val.SetInt32Value(0);
-
-  map_key.SetInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sint64_sint64"), map_key, &map_val));
-  map_val.SetInt64Value(0);
-
-  map_key.SetUInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_fixed32_fixed32"), map_key, &map_val));
-  map_val.SetUInt32Value(0);
-
-  map_key.SetUInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_fixed64_fixed64"), map_key, &map_val));
-  map_val.SetUInt64Value(0);
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sfixed32_sfixed32"), map_key, &map_val));
-  map_val.SetInt32Value(0);
-
-  map_key.SetInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sfixed64_sfixed64"), map_key, &map_val));
-  map_val.SetInt64Value(0);
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_float"),
-                                                 map_key, &map_val));
-  map_val.SetFloatValue(0.0);
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_double"),
-                                                 map_key, &map_val));
-  map_val.SetDoubleValue(0.0);
-
-  map_key.SetBoolValue(false);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_bool_bool"), map_key,
-                                          &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_bool_bool"),
-                                                 map_key, &map_val));
-  map_val.SetBoolValue(false);
-
-  map_key.SetStringValue("0");
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_string_string"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_string_string"), map_key, &map_val));
-  map_val.SetStringValue("0");
-
-  map_key.SetInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_bytes"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"),
-                                                 map_key, &map_val));
-  map_val.SetStringValue("0");
-
-  map_key.SetInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_enum"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_enum"),
-                                                 map_key, &map_val));
-  map_val.SetEnumValue(map_enum_bar_->number());
-
-  map_key.SetInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(
-      *message, F("map_int32_foreign_message"), map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_int32_foreign_message"), map_key, &map_val));
-  sub_foreign_message = map_val.MutableMessageValue();
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 0);
-
-  // Add second element
-  map_key.SetInt32Value(1);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                 map_key, &map_val));
-  map_val.SetInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                  map_key, &map_val));
-
-  map_key.SetInt64Value(1);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                 map_key, &map_val));
-  map_val.SetInt64Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                  map_key, &map_val));
-
-  map_key.SetUInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_uint32_uint32"), map_key,
-                                     &map_val);
-  map_val.SetUInt32Value(1);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(1);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
-                                     &map_val);
-  map_val.SetInt32Value(1);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
-                                     &map_val);
-  map_val.SetInt64Value(1);
-
-  map_key.SetUInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
-                                     &map_val);
-  map_val.SetUInt32Value(1);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(1);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
-                                     map_key, &map_val);
-  map_val.SetInt32Value(1);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
-                                     map_key, &map_val);
-  map_val.SetInt64Value(1);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
-                                     &map_val);
-  map_val.SetFloatValue(1.0);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
-                                     &map_val);
-  map_val.SetDoubleValue(1.0);
-
-  map_key.SetBoolValue(true);
-  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
-                                     &map_val);
-  map_val.SetBoolValue(true);
-
-  map_key.SetStringValue("1");
-  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("1");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("1");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
-                                     &map_val);
-  map_val.SetEnumValue(map_enum_baz_->number());
-
-  map_key.SetInt32Value(1);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_int32_foreign_message"), map_key, &map_val));
-  sub_foreign_message = map_val.MutableMessageValue();
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 1);
-}
-
-inline void MapReflectionTester::GetMapValueViaMapReflection(
-    Message* message, const std::string& field_name, const MapKey& map_key,
-    MapValueRef* map_val) {
-  const Reflection* reflection = message->GetReflection();
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F(field_name),
-                                                  map_key, map_val));
-}
-
-inline Message* MapReflectionTester::GetMapEntryViaReflection(
-    Message* message, const std::string& field_name, int index) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->MutableRepeatedMessage(message, F(field_name), index);
-}
-
-inline MapIterator MapReflectionTester::MapBegin(
-    Message* message, const std::string& field_name) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->MapBegin(message, F(field_name));
-}
-
-inline MapIterator MapReflectionTester::MapEnd(Message* message,
-                                               const std::string& field_name) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->MapEnd(message, F(field_name));
-}
-
-inline int MapReflectionTester::MapSize(const Message& message,
-                                        const std::string& field_name) {
-  const Reflection* reflection = message.GetReflection();
-  return reflection->MapSize(message, F(field_name));
-}
-
-inline void MapReflectionTester::ClearMapFieldsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-
-  reflection->ClearField(message, F("map_int32_int32"));
-  reflection->ClearField(message, F("map_int64_int64"));
-  reflection->ClearField(message, F("map_uint32_uint32"));
-  reflection->ClearField(message, F("map_uint64_uint64"));
-  reflection->ClearField(message, F("map_sint32_sint32"));
-  reflection->ClearField(message, F("map_sint64_sint64"));
-  reflection->ClearField(message, F("map_fixed32_fixed32"));
-  reflection->ClearField(message, F("map_fixed64_fixed64"));
-  reflection->ClearField(message, F("map_sfixed32_sfixed32"));
-  reflection->ClearField(message, F("map_sfixed64_sfixed64"));
-  reflection->ClearField(message, F("map_int32_float"));
-  reflection->ClearField(message, F("map_int32_double"));
-  reflection->ClearField(message, F("map_bool_bool"));
-  reflection->ClearField(message, F("map_string_string"));
-  reflection->ClearField(message, F("map_int32_bytes"));
-  reflection->ClearField(message, F("map_int32_enum"));
-  reflection->ClearField(message, F("map_int32_foreign_message"));
-}
-
-inline void MapReflectionTester::ModifyMapFieldsViaReflection(
-    Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  MapValueRef map_val;
-  Message* sub_foreign_message;
-
-  // Modify the second element
-  MapKey map_key;
-  map_key.SetInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                  map_key, &map_val));
-  map_val.SetInt32Value(2);
-
-  map_key.SetInt64Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                  map_key, &map_val));
-  map_val.SetInt64Value(2);
-
-  map_key.SetUInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
-      message, F("map_uint32_uint32"), map_key, &map_val));
-  map_val.SetUInt32Value(2);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(2);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
-                                     &map_val);
-  map_val.SetInt32Value(2);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
-                                     &map_val);
-  map_val.SetInt64Value(2);
-
-  map_key.SetUInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
-                                     &map_val);
-  map_val.SetUInt32Value(2);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(2);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
-                                     map_key, &map_val);
-  map_val.SetInt32Value(2);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
-                                     map_key, &map_val);
-  map_val.SetInt64Value(2);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
-                                     &map_val);
-  map_val.SetFloatValue(2.0);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
-                                     &map_val);
-  map_val.SetDoubleValue(2.0);
-
-  map_key.SetBoolValue(true);
-  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
-                                     &map_val);
-  map_val.SetBoolValue(false);
-
-  map_key.SetStringValue("1");
-  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("2");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("2");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
-                                     &map_val);
-  map_val.SetEnumValue(map_enum_foo_->number());
-
-  map_key.SetInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
-      message, F("map_int32_foreign_message"), map_key, &map_val));
-  sub_foreign_message = map_val.MutableMessageValue();
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 2);
-}
-
-inline void MapReflectionTester::RemoveLastMapsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-
-  std::vector<const FieldDescriptor*> output;
-  reflection->ListFields(*message, &output);
-  for (int i = 0; i < output.size(); ++i) {
-    const FieldDescriptor* field = output[i];
-    if (!field->is_repeated()) continue;
-    reflection->RemoveLast(message, field);
-  }
-}
-
-inline void MapReflectionTester::ReleaseLastMapsViaReflection(
-    Message* message) {
-  const Reflection* reflection = message->GetReflection();
-
-  std::vector<const FieldDescriptor*> output;
-  reflection->ListFields(*message, &output);
-  for (int i = 0; i < output.size(); ++i) {
-    const FieldDescriptor* field = output[i];
-    if (!field->is_repeated()) continue;
-    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
-
-    Message* released = reflection->ReleaseLast(message, field);
-    ASSERT_TRUE(released != nullptr)
-        << "ReleaseLast returned nullptr for: " << field->name();
-    delete released;
-  }
-}
-
-inline void MapReflectionTester::SwapMapsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  std::vector<const FieldDescriptor*> output;
-  reflection->ListFields(*message, &output);
-  for (int i = 0; i < output.size(); ++i) {
-    const FieldDescriptor* field = output[i];
-    if (!field->is_repeated()) continue;
-    reflection->SwapElements(message, field, 0, 1);
-  }
-}
-
-inline void MapReflectionTester::MutableUnknownFieldsOfMapFieldsViaReflection(
-    Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  Message* sub_message = nullptr;
-
-  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_int32_float"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_int32_double"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_string_string"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              nullptr);
-}
-
-inline void MapReflectionTester::ExpectMapFieldsSetViaReflection(
-    const Message& message) {
-  std::string scratch;
-  const Reflection* reflection = message.GetReflection();
-  const Message* sub_message;
-  MapKey map_key;
-  MapValueConstRef map_value_const_ref;
-
-  // -----------------------------------------------------------------
-
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_int32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int64_int64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint32_uint32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint64_uint64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint32_sint32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint64_sint64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed32_fixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed64_fixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_float")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_double")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_bool_bool")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_string_string")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_bytes")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_enum")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_foreign_message")));
-
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      // Check with RepeatedField Reflection
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_int32_key_);
-      int32 val = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_int32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_TRUE(
-          reflection->ContainsMapKey(message, F("map_int32_int32"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_int32"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetInt32Value(), val);
-    }
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      // Check with RepeatedField Reflection
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i);
-      int64 key = sub_message->GetReflection()->GetInt64(*sub_message,
-                                                         map_int64_int64_key_);
-      int64 val = sub_message->GetReflection()->GetInt64(*sub_message,
-                                                         map_int64_int64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt64Value(key);
-      EXPECT_TRUE(
-          reflection->ContainsMapKey(message, F("map_int64_int64"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int64_int64"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetInt64Value(), val);
-    }
-  }
-  {
-    std::map<uint32, uint32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      // Check with RepeatedField Reflection
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i);
-      uint32 key = sub_message->GetReflection()->GetUInt32(
-          *sub_message, map_uint32_uint32_key_);
-      uint32 val = sub_message->GetReflection()->GetUInt32(
-          *sub_message, map_uint32_uint32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetUInt32Value(key);
-      EXPECT_TRUE(
-          reflection->ContainsMapKey(message, F("map_uint32_uint32"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint32_uint32"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetUInt32Value(), val);
-    }
-  }
-  {
-    std::map<uint64, uint64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i);
-      uint64 key = sub_message->GetReflection()->GetUInt64(
-          *sub_message, map_uint64_uint64_key_);
-      uint64 val = sub_message->GetReflection()->GetUInt64(
-          *sub_message, map_uint64_uint64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetUInt64Value(key);
-      EXPECT_TRUE(
-          reflection->ContainsMapKey(message, F("map_uint64_uint64"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint64_uint64"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetUInt64Value(), val);
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_sint32_sint32_key_);
-      int32 val = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_sint32_sint32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_sint32_sint32"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint32_sint32"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetInt32Value(), val);
-    }
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i);
-      int64 key = sub_message->GetReflection()->GetInt64(
-          *sub_message, map_sint64_sint64_key_);
-      int64 val = sub_message->GetReflection()->GetInt64(
-          *sub_message, map_sint64_sint64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt64Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_sint64_sint64"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint64_sint64"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetInt64Value(), val);
-    }
-  }
-  {
-    std::map<uint32, uint32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_fixed32_fixed32"), i);
-      uint32 key = sub_message->GetReflection()->GetUInt32(
-          *sub_message, map_fixed32_fixed32_key_);
-      uint32 val = sub_message->GetReflection()->GetUInt32(
-          *sub_message, map_fixed32_fixed32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetUInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_fixed32_fixed32"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_fixed32_fixed32"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetUInt32Value(), val);
-    }
-  }
-  {
-    std::map<uint64, uint64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_fixed64_fixed64"), i);
-      uint64 key = sub_message->GetReflection()->GetUInt64(
-          *sub_message, map_fixed64_fixed64_key_);
-      uint64 val = sub_message->GetReflection()->GetUInt64(
-          *sub_message, map_fixed64_fixed64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetUInt64Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_fixed64_fixed64"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_fixed64_fixed64"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetUInt64Value(), val);
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message = &reflection->GetRepeatedMessage(
-          message, F("map_sfixed32_sfixed32"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_sfixed32_sfixed32_key_);
-      int32 val = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_sfixed32_sfixed32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_sfixed32_sfixed32"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(
-          message, F("map_sfixed32_sfixed32"), map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetInt32Value(), val);
-    }
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message = &reflection->GetRepeatedMessage(
-          message, F("map_sfixed64_sfixed64"), i);
-      int64 key = sub_message->GetReflection()->GetInt64(
-          *sub_message, map_sfixed64_sfixed64_key_);
-      int64 val = sub_message->GetReflection()->GetInt64(
-          *sub_message, map_sfixed64_sfixed64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt64Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_sfixed64_sfixed64"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(
-          message, F("map_sfixed64_sfixed64"), map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetInt64Value(), val);
-    }
-  }
-  {
-    std::map<int32, float> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_float"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_float_key_);
-      float val = sub_message->GetReflection()->GetFloat(*sub_message,
-                                                         map_int32_float_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_float"),
-                                                 map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_float"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetFloatValue(), val);
-    }
-  }
-  {
-    std::map<int32, double> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_double"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_double_key_);
-      double val = sub_message->GetReflection()->GetDouble(
-          *sub_message, map_int32_double_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_double"),
-                                                 map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_double"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetDoubleValue(), val);
-    }
-  }
-  {
-    std::map<bool, bool> map;
-    map[false] = false;
-    map[true] = true;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i);
-      bool key = sub_message->GetReflection()->GetBool(*sub_message,
-                                                       map_bool_bool_key_);
-      bool val = sub_message->GetReflection()->GetBool(*sub_message,
-                                                       map_bool_bool_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetBoolValue(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_bool_bool"),
-                                                 map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_bool_bool"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetBoolValue(), val);
-    }
-  }
-  {
-    std::map<std::string, std::string> map;
-    map["0"] = "0";
-    map["1"] = "1";
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_string_string"), i);
-      std::string key = sub_message->GetReflection()->GetString(
-          *sub_message, map_string_string_key_);
-      std::string val = sub_message->GetReflection()->GetString(
-          *sub_message, map_string_string_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetStringValue(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_string_string"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_string_string"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetStringValue(), val);
-    }
-  }
-  {
-    std::map<int32, std::string> map;
-    map[0] = "0";
-    map[1] = "1";
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_bytes_key_);
-      std::string val = sub_message->GetReflection()->GetString(
-          *sub_message, map_int32_bytes_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_bytes"),
-                                                 map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_bytes"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetStringValue(), val);
-    }
-  }
-  {
-    std::map<int32, const EnumValueDescriptor*> map;
-    map[0] = map_enum_bar_;
-    map[1] = map_enum_baz_;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_enum"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_enum_key_);
-      const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum(
-          *sub_message, map_int32_enum_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_enum"),
-                                                 map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_enum"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(map_value_const_ref.GetEnumValue(), val->number());
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message = &reflection->GetRepeatedMessage(
-          message, F("map_int32_foreign_message"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_int32_foreign_message_key_);
-      const Message& foreign_message = sub_message->GetReflection()->GetMessage(
-          *sub_message, map_int32_foreign_message_val_);
-      int32 val = foreign_message.GetReflection()->GetInt32(foreign_message,
-                                                            foreign_c_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_int32_foreign_message"), map_key));
-      EXPECT_TRUE(reflection->LookupMapValue(message,
-                                             F("map_int32_foreign_message"),
-                                             map_key, &map_value_const_ref));
-      EXPECT_EQ(foreign_message.GetReflection()->GetInt32(
-                    map_value_const_ref.GetMessageValue(), foreign_c_),
-                val);
-    }
-  }
-}
-
-inline void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator(
-    Message* message) {
-  std::string scratch;
-  std::string serialized;
-  const Reflection* reflection = message->GetReflection();
-
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_int32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int64_int64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint32_uint32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint64_uint64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint32_sint32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint64_sint64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed32_fixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed64_fixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed32_sfixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed64_sfixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_float")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_double")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_bool_bool")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_string_string")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_bytes")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_enum")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_foreign_message")));
-
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    int size = 0;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_int32"));
-         iter != reflection->MapEnd(message, F("map_int32_int32"));
-         ++iter, ++size) {
-      // Check const methods do not invalidate map.
-      message->DebugString();
-      message->ShortDebugString();
-      message->SerializeToString(&serialized);
-      message->SpaceUsedLong();
-      message->ByteSizeLong();
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetInt32Value());
-    }
-    EXPECT_EQ(size, 2);
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int64_int64"));
-         iter != reflection->MapEnd(message, F("map_int64_int64")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
-                iter.GetValueRef().GetInt64Value());
-    }
-  }
-  {
-    std::map<uint32, uint32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_uint32_uint32"));
-         iter != reflection->MapEnd(message, F("map_uint32_uint32")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
-                iter.GetValueRef().GetUInt32Value());
-    }
-  }
-  {
-    std::map<uint64, uint64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_uint64_uint64"));
-         iter != reflection->MapEnd(message, F("map_uint64_uint64")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
-                iter.GetValueRef().GetUInt64Value());
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_sint32_sint32"));
-         iter != reflection->MapEnd(message, F("map_sint32_sint32")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetInt32Value());
-    }
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_sint64_sint64"));
-         iter != reflection->MapEnd(message, F("map_sint64_sint64")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
-                iter.GetValueRef().GetInt64Value());
-    }
-  }
-  {
-    std::map<uint32, uint32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_fixed32_fixed32"));
-         iter != reflection->MapEnd(message, F("map_fixed32_fixed32"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
-                iter.GetValueRef().GetUInt32Value());
-    }
-  }
-  {
-    std::map<uint64, uint64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_fixed64_fixed64"));
-         iter != reflection->MapEnd(message, F("map_fixed64_fixed64"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
-                iter.GetValueRef().GetUInt64Value());
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_sfixed32_sfixed32"));
-         iter != reflection->MapEnd(message, F("map_sfixed32_sfixed32"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetInt32Value());
-    }
-  }
-  {
-    std::map<int32, float> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_float"));
-         iter != reflection->MapEnd(message, F("map_int32_float")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetFloatValue());
-    }
-  }
-  {
-    std::map<int32, double> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_int32_double"));
-         iter != reflection->MapEnd(message, F("map_int32_double")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetDoubleValue());
-    }
-  }
-  {
-    std::map<bool, bool> map;
-    map[false] = false;
-    map[true] = true;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_bool_bool"));
-         iter != reflection->MapEnd(message, F("map_bool_bool")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetBoolValue()],
-                iter.GetValueRef().GetBoolValue());
-    }
-  }
-  {
-    std::map<std::string, std::string> map;
-    map["0"] = "0";
-    map["1"] = "1";
-    int size = 0;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_string_string"));
-         iter != reflection->MapEnd(message, F("map_string_string"));
-         ++iter, ++size) {
-      // Check const methods do not invalidate map.
-      message->DebugString();
-      message->ShortDebugString();
-      message->SerializeToString(&serialized);
-      message->SpaceUsedLong();
-      message->ByteSizeLong();
-      EXPECT_EQ(map[iter.GetKey().GetStringValue()],
-                iter.GetValueRef().GetStringValue());
-    }
-    EXPECT_EQ(size, 2);
-  }
-  {
-    std::map<int32, std::string> map;
-    map[0] = "0";
-    map[1] = "1";
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_bytes"));
-         iter != reflection->MapEnd(message, F("map_int32_bytes")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetStringValue());
-    }
-  }
-  {
-    std::map<int32, const EnumValueDescriptor*> map;
-    map[0] = map_enum_bar_;
-    map[1] = map_enum_baz_;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_enum"));
-         iter != reflection->MapEnd(message, F("map_int32_enum")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()]->number(),
-                iter.GetValueRef().GetEnumValue());
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    int size = 0;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_int32_foreign_message"));
-         iter != reflection->MapEnd(message, F("map_int32_foreign_message"));
-         ++iter, ++size) {
-      // Check const methods do not invalidate map.
-      message->DebugString();
-      message->ShortDebugString();
-      message->SerializeToString(&serialized);
-      message->SpaceUsedLong();
-      message->ByteSizeLong();
-      const Message& sub_message = iter.GetValueRef().GetMessageValue();
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                sub_message.GetReflection()->GetInt32(sub_message, foreign_c_));
-    }
-    EXPECT_EQ(size, 2);
-  }
-}
-
-inline void MapReflectionTester::ExpectClearViaReflection(
-    const Message& message) {
-  const Reflection* reflection = message.GetReflection();
-  // Map fields are empty.
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_int32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int64_int64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint32_uint32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint64_uint64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint32_sint32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint64_sint64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed32_fixed32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed64_fixed64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_float")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_double")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_bool_bool")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_string_string")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_bytes")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_enum")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message")));
-  EXPECT_TRUE(reflection->GetMapData(message, F("map_int32_foreign_message"))
-                  ->IsMapValid());
-}
-
-inline void MapReflectionTester::ExpectClearViaReflectionIterator(
-    Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_int32")) ==
-              reflection->MapEnd(message, F("map_int32_int32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int64_int64")) ==
-              reflection->MapEnd(message, F("map_int64_int64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint32_uint32")) ==
-              reflection->MapEnd(message, F("map_uint32_uint32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint64_uint64")) ==
-              reflection->MapEnd(message, F("map_uint64_uint64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint32_sint32")) ==
-              reflection->MapEnd(message, F("map_sint32_sint32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint64_sint64")) ==
-              reflection->MapEnd(message, F("map_sint64_sint64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed32_fixed32")) ==
-              reflection->MapEnd(message, F("map_fixed32_fixed32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed64_fixed64")) ==
-              reflection->MapEnd(message, F("map_fixed64_fixed64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed32_sfixed32")) ==
-              reflection->MapEnd(message, F("map_sfixed32_sfixed32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed64_sfixed64")) ==
-              reflection->MapEnd(message, F("map_sfixed64_sfixed64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_float")) ==
-              reflection->MapEnd(message, F("map_int32_float")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_double")) ==
-              reflection->MapEnd(message, F("map_int32_double")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_bool_bool")) ==
-              reflection->MapEnd(message, F("map_bool_bool")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_string_string")) ==
-              reflection->MapEnd(message, F("map_string_string")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_bytes")) ==
-              reflection->MapEnd(message, F("map_int32_bytes")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_enum")) ==
-              reflection->MapEnd(message, F("map_int32_enum")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_foreign_message")) ==
-              reflection->MapEnd(message, F("map_int32_foreign_message")));
-}
-
-}  // namespace protobuf
-}  // namespace google
-
-#include <google/protobuf/port_undef.inc>
+#undef BRIDGE_UNITTEST
 
 #endif  // GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index e718790..7f2892b 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -28,8 +28,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#ifndef GOOGLE_PROTOBUF_TYPE_HANDLER_H__
-#define GOOGLE_PROTOBUF_TYPE_HANDLER_H__
+#ifndef GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
+#define GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
 
 #include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
@@ -100,19 +100,19 @@
 TYPE_TRAITS(MESSAGE, Type, LENGTH_DELIMITED, true, false)
 TYPE_TRAITS(STRING, ArenaStringPtr, LENGTH_DELIMITED, false, false)
 TYPE_TRAITS(BYTES, ArenaStringPtr, LENGTH_DELIMITED, false, false)
-TYPE_TRAITS(INT64, int64, VARINT, false, false)
-TYPE_TRAITS(UINT64, uint64, VARINT, false, false)
-TYPE_TRAITS(INT32, int32, VARINT, false, false)
-TYPE_TRAITS(UINT32, uint32, VARINT, false, false)
-TYPE_TRAITS(SINT64, int64, VARINT, false, false)
-TYPE_TRAITS(SINT32, int32, VARINT, false, false)
+TYPE_TRAITS(INT64, int64_t, VARINT, false, false)
+TYPE_TRAITS(UINT64, uint64_t, VARINT, false, false)
+TYPE_TRAITS(INT32, int32_t, VARINT, false, false)
+TYPE_TRAITS(UINT32, uint32_t, VARINT, false, false)
+TYPE_TRAITS(SINT64, int64_t, VARINT, false, false)
+TYPE_TRAITS(SINT32, int32_t, VARINT, false, false)
 TYPE_TRAITS(ENUM, int, VARINT, false, true)
 TYPE_TRAITS(DOUBLE, double, FIXED64, false, false)
 TYPE_TRAITS(FLOAT, float, FIXED32, false, false)
-TYPE_TRAITS(FIXED64, uint64, FIXED64, false, false)
-TYPE_TRAITS(FIXED32, uint32, FIXED32, false, false)
-TYPE_TRAITS(SFIXED64, int64, FIXED64, false, false)
-TYPE_TRAITS(SFIXED32, int32, FIXED32, false, false)
+TYPE_TRAITS(FIXED64, uint64_t, FIXED64, false, false)
+TYPE_TRAITS(FIXED32, uint32_t, FIXED32, false, false)
+TYPE_TRAITS(SFIXED64, int64_t, FIXED64, false, false)
+TYPE_TRAITS(SFIXED32, int32_t, FIXED32, false, false)
 TYPE_TRAITS(BOOL, bool, VARINT, false, false)
 
 #undef TYPE_TRAITS
@@ -149,8 +149,8 @@
   static inline const char* Read(const char* ptr, ParseContext* ctx,
                                  MapEntryAccessorType* value);
 
-  static inline uint8* Write(int field, const MapEntryAccessorType& value,
-                             uint8* ptr, io::EpsCopyOutputStream* stream);
+  static inline uint8_t* Write(int field, const MapEntryAccessorType& value,
+                               uint8_t* ptr, io::EpsCopyOutputStream* stream);
 
   // Functions to manipulate data on memory. ========================
   static inline const Type& GetExternalReference(const Type* value);
@@ -170,46 +170,47 @@
   static inline bool IsInitialized(Type* value);
 };
 
-#define MAP_HANDLER(FieldType)                                                \
-  template <typename Type>                                                    \
-  class MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type> {              \
-   public:                                                                    \
-    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
-                                            Type>::MapEntryAccessorType       \
-        MapEntryAccessorType;                                                 \
-    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
-                                            Type>::TypeOnMemory TypeOnMemory; \
-    static const WireFormatLite::WireType kWireType =                         \
-        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,              \
-                               Type>::kWireType;                              \
-    static const bool kIsMessage =                                            \
-        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,              \
-                               Type>::kIsMessage;                             \
-    static const bool kIsEnum =                                               \
-        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,              \
-                               Type>::kIsEnum;                                \
-    static inline int ByteSize(const MapEntryAccessorType& value);            \
-    static inline int GetCachedSize(const MapEntryAccessorType& value);       \
-    static inline bool Read(io::CodedInputStream* input,                      \
-                            MapEntryAccessorType* value);                     \
-    static inline const char* Read(const char* begin, ParseContext* ctx,      \
-                                   MapEntryAccessorType* value);              \
-    static inline uint8* Write(int field, const MapEntryAccessorType& value,  \
-                               uint8* ptr, io::EpsCopyOutputStream* stream);  \
-    static inline const MapEntryAccessorType& GetExternalReference(           \
-        const TypeOnMemory& value);                                           \
-    static inline void DeleteNoArena(const TypeOnMemory& x);                  \
-    static inline void Merge(const MapEntryAccessorType& from,                \
-                             TypeOnMemory* to, Arena* arena);                 \
-    static inline void Clear(TypeOnMemory* value, Arena* arena);              \
-    static inline size_t SpaceUsedInMapEntryLong(const TypeOnMemory& value);  \
-    static inline const MapEntryAccessorType& DefaultIfNotInitialized(        \
-        const TypeOnMemory& value);                                           \
-    static inline bool IsInitialized(const TypeOnMemory& value);              \
-    static void DeleteNoArena(TypeOnMemory& value);                           \
-    static constexpr TypeOnMemory Constinit();                                \
-    static inline MapEntryAccessorType* EnsureMutable(TypeOnMemory* value,    \
-                                                      Arena* arena);          \
+#define MAP_HANDLER(FieldType)                                                 \
+  template <typename Type>                                                     \
+  class MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type> {               \
+   public:                                                                     \
+    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,  \
+                                            Type>::MapEntryAccessorType        \
+        MapEntryAccessorType;                                                  \
+    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,  \
+                                            Type>::TypeOnMemory TypeOnMemory;  \
+    static const WireFormatLite::WireType kWireType =                          \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,               \
+                               Type>::kWireType;                               \
+    static const bool kIsMessage =                                             \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,               \
+                               Type>::kIsMessage;                              \
+    static const bool kIsEnum =                                                \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,               \
+                               Type>::kIsEnum;                                 \
+    static inline int ByteSize(const MapEntryAccessorType& value);             \
+    static inline int GetCachedSize(const MapEntryAccessorType& value);        \
+    static inline bool Read(io::CodedInputStream* input,                       \
+                            MapEntryAccessorType* value);                      \
+    static inline const char* Read(const char* begin, ParseContext* ctx,       \
+                                   MapEntryAccessorType* value);               \
+    static inline uint8_t* Write(int field, const MapEntryAccessorType& value, \
+                                 uint8_t* ptr,                                 \
+                                 io::EpsCopyOutputStream* stream);             \
+    static inline const MapEntryAccessorType& GetExternalReference(            \
+        const TypeOnMemory& value);                                            \
+    static inline void DeleteNoArena(const TypeOnMemory& x);                   \
+    static inline void Merge(const MapEntryAccessorType& from,                 \
+                             TypeOnMemory* to, Arena* arena);                  \
+    static inline void Clear(TypeOnMemory* value, Arena* arena);               \
+    static inline size_t SpaceUsedInMapEntryLong(const TypeOnMemory& value);   \
+    static inline const MapEntryAccessorType& DefaultIfNotInitialized(         \
+        const TypeOnMemory& value);                                            \
+    static inline bool IsInitialized(const TypeOnMemory& value);               \
+    static void DeleteNoArena(TypeOnMemory& value);                            \
+    static constexpr TypeOnMemory Constinit();                                 \
+    static inline MapEntryAccessorType* EnsureMutable(TypeOnMemory* value,     \
+                                                      Arena* arena);           \
   };
 MAP_HANDLER(STRING)
 MAP_HANDLER(BYTES)
@@ -317,33 +318,35 @@
 #undef GET_FIXED_CACHED_SIZE
 
 template <typename Type>
-inline uint8* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write(
-    int field, const MapEntryAccessorType& value, uint8* ptr,
+inline uint8_t* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write(
+    int field, const MapEntryAccessorType& value, uint8_t* ptr,
     io::EpsCopyOutputStream* stream) {
   ptr = stream->EnsureSpace(ptr);
   return WireFormatLite::InternalWriteMessage(field, value, ptr, stream);
 }
 
-#define WRITE_METHOD(FieldType, DeclaredType)                                  \
-  template <typename Type>                                                     \
-  inline uint8* MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write( \
-      int field, const MapEntryAccessorType& value, uint8* ptr,                \
-      io::EpsCopyOutputStream* stream) {                                       \
-    ptr = stream->EnsureSpace(ptr);                                            \
-    return stream->Write##DeclaredType(field, value, ptr);                     \
+#define WRITE_METHOD(FieldType, DeclaredType)                     \
+  template <typename Type>                                        \
+  inline uint8_t*                                                 \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write(  \
+      int field, const MapEntryAccessorType& value, uint8_t* ptr, \
+      io::EpsCopyOutputStream* stream) {                          \
+    ptr = stream->EnsureSpace(ptr);                               \
+    return stream->Write##DeclaredType(field, value, ptr);        \
   }
 
 WRITE_METHOD(STRING, String)
 WRITE_METHOD(BYTES, Bytes)
 
 #undef WRITE_METHOD
-#define WRITE_METHOD(FieldType, DeclaredType)                                  \
-  template <typename Type>                                                     \
-  inline uint8* MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write( \
-      int field, const MapEntryAccessorType& value, uint8* ptr,                \
-      io::EpsCopyOutputStream* stream) {                                       \
-    ptr = stream->EnsureSpace(ptr);                                            \
-    return WireFormatLite::Write##DeclaredType##ToArray(field, value, ptr);    \
+#define WRITE_METHOD(FieldType, DeclaredType)                               \
+  template <typename Type>                                                  \
+  inline uint8_t*                                                           \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write(            \
+      int field, const MapEntryAccessorType& value, uint8_t* ptr,           \
+      io::EpsCopyOutputStream* stream) {                                    \
+    ptr = stream->EnsureSpace(ptr);                                         \
+    return WireFormatLite::Write##DeclaredType##ToArray(field, value, ptr); \
   }
 
 WRITE_METHOD(INT64, Int64)
@@ -403,23 +406,23 @@
   return ctx->ReadString(ptr, size, value);
 }
 
-inline const char* ReadINT64(const char* ptr, int64* value) {
-  return VarintParse(ptr, reinterpret_cast<uint64*>(value));
+inline const char* ReadINT64(const char* ptr, int64_t* value) {
+  return VarintParse(ptr, reinterpret_cast<uint64_t*>(value));
 }
-inline const char* ReadUINT64(const char* ptr, uint64* value) {
+inline const char* ReadUINT64(const char* ptr, uint64_t* value) {
   return VarintParse(ptr, value);
 }
-inline const char* ReadINT32(const char* ptr, int32* value) {
-  return VarintParse(ptr, reinterpret_cast<uint32*>(value));
+inline const char* ReadINT32(const char* ptr, int32_t* value) {
+  return VarintParse(ptr, reinterpret_cast<uint32_t*>(value));
 }
-inline const char* ReadUINT32(const char* ptr, uint32* value) {
+inline const char* ReadUINT32(const char* ptr, uint32_t* value) {
   return VarintParse(ptr, value);
 }
-inline const char* ReadSINT64(const char* ptr, int64* value) {
+inline const char* ReadSINT64(const char* ptr, int64_t* value) {
   *value = ReadVarintZigZag64(&ptr);
   return ptr;
 }
-inline const char* ReadSINT32(const char* ptr, int32* value) {
+inline const char* ReadSINT32(const char* ptr, int32_t* value) {
   *value = ReadVarintZigZag32(&ptr);
   return ptr;
 }
@@ -444,16 +447,16 @@
 inline const char* ReadDOUBLE(const char* ptr, double* value) {
   return ReadUnaligned(ptr, value);
 }
-inline const char* ReadFIXED64(const char* ptr, uint64* value) {
+inline const char* ReadFIXED64(const char* ptr, uint64_t* value) {
   return ReadUnaligned(ptr, value);
 }
-inline const char* ReadFIXED32(const char* ptr, uint32* value) {
+inline const char* ReadFIXED32(const char* ptr, uint32_t* value) {
   return ReadUnaligned(ptr, value);
 }
-inline const char* ReadSFIXED64(const char* ptr, int64* value) {
+inline const char* ReadSFIXED64(const char* ptr, int64_t* value) {
   return ReadUnaligned(ptr, value);
 }
-inline const char* ReadSFIXED32(const char* ptr, int32* value) {
+inline const char* ReadSFIXED32(const char* ptr, int32_t* value) {
   return ReadUnaligned(ptr, value);
 }
 
@@ -685,4 +688,4 @@
 }  // namespace protobuf
 }  // namespace google
 
-#endif  // GOOGLE_PROTOBUF_TYPE_HANDLER_H__
+#endif  // GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 744bbc6..9c8c648 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -166,8 +166,8 @@
   return WireFormat::_InternalParse(this, ptr, ctx);
 }
 
-uint8* Message::_InternalSerialize(uint8* target,
-                                   io::EpsCopyOutputStream* stream) const {
+uint8_t* Message::_InternalSerialize(uint8_t* target,
+                                     io::EpsCopyOutputStream* stream) const {
   return WireFormat::_InternalSerialize(*this, target, stream);
 }
 
@@ -183,15 +183,111 @@
                 "Must implement one or the other.";
 }
 
+size_t Message::ComputeUnknownFieldsSize(
+    size_t total_size, internal::CachedSize* cached_size) const {
+  total_size += WireFormat::ComputeUnknownFieldsSize(
+      _internal_metadata_.unknown_fields<UnknownFieldSet>(
+          UnknownFieldSet::default_instance));
+  cached_size->Set(internal::ToCachedSize(total_size));
+  return total_size;
+}
+
+size_t Message::MaybeComputeUnknownFieldsSize(
+    size_t total_size, internal::CachedSize* cached_size) const {
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ComputeUnknownFieldsSize(total_size, cached_size);
+  }
+  cached_size->Set(internal::ToCachedSize(total_size));
+  return total_size;
+}
+
 size_t Message::SpaceUsedLong() const {
   return GetReflection()->SpaceUsedLong(*this);
 }
 
-uint64 Message::GetInvariantPerBuild(uint64 salt) {
+uint64_t Message::GetInvariantPerBuild(uint64_t salt) {
   return salt;
 }
 
 // =============================================================================
+// ZeroFieldsBase
+
+namespace internal {
+
+void ZeroFieldsBase::Clear() {
+  _internal_metadata_.Clear<UnknownFieldSet>();  //
+}
+
+ZeroFieldsBase::~ZeroFieldsBase() {
+  if (GetArenaForAllocation() != nullptr) return;
+  _internal_metadata_.Delete<UnknownFieldSet>();
+}
+
+size_t ZeroFieldsBase::ByteSizeLong() const {
+  return MaybeComputeUnknownFieldsSize(0, &_cached_size_);
+}
+
+const char* ZeroFieldsBase::_InternalParse(const char* ptr,
+                                           internal::ParseContext* ctx) {
+#define CHK_(x)                       \
+  if (PROTOBUF_PREDICT_FALSE(!(x))) { \
+    goto failure;                     \
+  }
+
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = internal::ReadTag(ptr, &tag);
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag, _internal_metadata_.mutable_unknown_fields<UnknownFieldSet>(), ptr,
+        ctx);
+    CHK_(ptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+::uint8_t* ZeroFieldsBase::_InternalSerialize(
+    ::uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<UnknownFieldSet>(
+            UnknownFieldSet::default_instance),
+        target, stream);
+  }
+  return target;
+}
+
+void ZeroFieldsBase::MergeImpl(Message* to_param, const Message& from_param) {
+  auto* to = static_cast<ZeroFieldsBase*>(to_param);
+  const auto* from = static_cast<const ZeroFieldsBase*>(&from_param);
+  GOOGLE_DCHECK_NE(from, to);
+  to->_internal_metadata_.MergeFrom<UnknownFieldSet>(from->_internal_metadata_);
+}
+
+void ZeroFieldsBase::CopyImpl(Message* to_param, const Message& from_param) {
+  auto* to = static_cast<ZeroFieldsBase*>(to_param);
+  const auto* from = static_cast<const ZeroFieldsBase*>(&from_param);
+  if (from == to) return;
+  to->_internal_metadata_.Clear<UnknownFieldSet>();
+  to->_internal_metadata_.MergeFrom<UnknownFieldSet>(from->_internal_metadata_);
+}
+
+void ZeroFieldsBase::InternalSwap(ZeroFieldsBase* other) {
+  _internal_metadata_.Swap<UnknownFieldSet>(&other->_internal_metadata_);
+}
+
+}  // namespace internal
+
+// =============================================================================
 // MessageFactory
 
 MessageFactory::~MessageFactory() {}
@@ -325,14 +421,14 @@
 #define HANDLE_PRIMITIVE_TYPE(TYPE, type) \
   case FieldDescriptor::CPPTYPE_##TYPE:   \
     return GetSingleton<internal::RepeatedFieldPrimitiveAccessor<type> >();
-    HANDLE_PRIMITIVE_TYPE(INT32, int32)
-    HANDLE_PRIMITIVE_TYPE(UINT32, uint32)
-    HANDLE_PRIMITIVE_TYPE(INT64, int64)
-    HANDLE_PRIMITIVE_TYPE(UINT64, uint64)
+    HANDLE_PRIMITIVE_TYPE(INT32, int32_t)
+    HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t)
+    HANDLE_PRIMITIVE_TYPE(INT64, int64_t)
+    HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t)
     HANDLE_PRIMITIVE_TYPE(FLOAT, float)
     HANDLE_PRIMITIVE_TYPE(DOUBLE, double)
     HANDLE_PRIMITIVE_TYPE(BOOL, bool)
-    HANDLE_PRIMITIVE_TYPE(ENUM, int32)
+    HANDLE_PRIMITIVE_TYPE(ENUM, int32_t)
 #undef HANDLE_PRIMITIVE_TYPE
     case FieldDescriptor::CPPTYPE_STRING:
       switch (field->options().ctype()) {
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index df8e895..b4fa705 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -120,6 +120,7 @@
 #include <google/protobuf/arena.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/port.h>
 
@@ -144,6 +145,7 @@
 // Defined in other files.
 class AssignDescriptorsHelper;
 class DynamicMessageFactory;
+class DynamicMessageReflectionHelper;
 class GeneratedMessageReflectionTestHelper;
 class MapKey;
 class MapValueConstRef;
@@ -155,6 +157,7 @@
 struct DescriptorTable;
 class MapFieldBase;
 class SwapFieldHelper;
+class CachedSize;
 }
 class UnknownFieldSet;  // unknown_field_set.h
 namespace io {
@@ -201,18 +204,18 @@
 
 namespace internal {
 template <class To>
-inline To* GetPointerAtOffset(Message* message, uint32 offset) {
+inline To* GetPointerAtOffset(Message* message, uint32_t offset) {
   return reinterpret_cast<To*>(reinterpret_cast<char*>(message) + offset);
 }
 
 template <class To>
-const To* GetConstPointerAtOffset(const Message* message, uint32 offset) {
+const To* GetConstPointerAtOffset(const Message* message, uint32_t offset) {
   return reinterpret_cast<const To*>(reinterpret_cast<const char*>(message) +
                                      offset);
 }
 
 template <class To>
-const To& GetConstRefAtOffset(const Message& message, uint32 offset) {
+const To& GetConstRefAtOffset(const Message& message, uint32_t offset) {
   return *GetConstPointerAtOffset<To>(&message, offset);
 }
 
@@ -333,8 +336,8 @@
   const char* _InternalParse(const char* ptr,
                              internal::ParseContext* ctx) override;
   size_t ByteSizeLong() const override;
-  uint8* _InternalSerialize(uint8* target,
-                            io::EpsCopyOutputStream* stream) const override;
+  uint8_t* _InternalSerialize(uint8_t* target,
+                              io::EpsCopyOutputStream* stream) const override;
 
  private:
   // This is called only by the default implementation of ByteSize(), to
@@ -388,16 +391,50 @@
 
   inline explicit Message(Arena* arena, bool is_message_owned = false)
       : MessageLite(arena, is_message_owned) {}
+  size_t ComputeUnknownFieldsSize(size_t total_size,
+                                  internal::CachedSize* cached_size) const;
+  size_t MaybeComputeUnknownFieldsSize(size_t total_size,
+                                       internal::CachedSize* cached_size) const;
 
 
  protected:
-  static uint64 GetInvariantPerBuild(uint64 salt);
+  static uint64_t GetInvariantPerBuild(uint64_t salt);
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message);
 };
 
 namespace internal {
+// To save code size, protos without any fields are derived from ZeroFieldsBase
+// rather than Message.
+class PROTOBUF_EXPORT ZeroFieldsBase : public Message {
+ public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final { return true; }
+  size_t ByteSizeLong() const final;
+  int GetCachedSize() const final { return _cached_size_.Get(); }
+  const char* _InternalParse(const char* ptr,
+                             internal::ParseContext* ctx) final;
+  ::uint8_t* _InternalSerialize(::uint8_t* target,
+                                io::EpsCopyOutputStream* stream) const final;
+
+ protected:
+  constexpr ZeroFieldsBase() {}
+  explicit ZeroFieldsBase(Arena* arena, bool is_message_owned)
+      : Message(arena, is_message_owned) {}
+  ZeroFieldsBase(const ZeroFieldsBase&) = delete;
+  ZeroFieldsBase& operator=(const ZeroFieldsBase&) = delete;
+  ~ZeroFieldsBase() override;
+
+  void SetCachedSize(int size) const final { _cached_size_.Set(size); }
+
+  static void MergeImpl(Message* to, const Message& from);
+  static void CopyImpl(Message* to, const Message& from);
+  void InternalSwap(ZeroFieldsBase* other);
+
+  mutable internal::CachedSize _cached_size_;
+};
+
 // Forward-declare interfaces used to implement RepeatedFieldRef.
 // These are protobuf internals that users shouldn't care about.
 class RepeatedFieldAccessor;
@@ -503,6 +540,12 @@
   PROTOBUF_MUST_USE_RESULT Message* ReleaseLast(
       Message* message, const FieldDescriptor* field) const;
 
+  // Similar to ReleaseLast() without internal safety and ownershp checks. This
+  // method should only be used when the objects are on the same arena or paired
+  // with a call to `UnsafeArenaAddAllocatedMessage`.
+  Message* UnsafeArenaReleaseLast(Message* message,
+                                  const FieldDescriptor* field) const;
+
   // Swap the complete contents of two messages.
   void Swap(Message* message1, Message* message2) const;
 
@@ -514,6 +557,16 @@
   void SwapElements(Message* message, const FieldDescriptor* field, int index1,
                     int index2) const;
 
+  // Swap without internal safety and ownership checks. This method should only
+  // be used when the objects are on the same arena.
+  void UnsafeArenaSwap(Message* lhs, Message* rhs) const;
+
+  // SwapFields without internal safety and ownership checks. This method should
+  // only be used when the objects are on the same arena.
+  void UnsafeArenaSwapFields(
+      Message* lhs, Message* rhs,
+      const std::vector<const FieldDescriptor*>& fields) const;
+
   // List all fields of the message which are currently set, except for unknown
   // fields, but including extension known to the parser (i.e. compiled in).
   // Singular fields will only be listed if HasField(field) would return true
@@ -529,10 +582,12 @@
   // These get the value of a non-repeated field.  They return the default
   // value for fields that aren't set.
 
-  int32 GetInt32(const Message& message, const FieldDescriptor* field) const;
-  int64 GetInt64(const Message& message, const FieldDescriptor* field) const;
-  uint32 GetUInt32(const Message& message, const FieldDescriptor* field) const;
-  uint64 GetUInt64(const Message& message, const FieldDescriptor* field) const;
+  int32_t GetInt32(const Message& message, const FieldDescriptor* field) const;
+  int64_t GetInt64(const Message& message, const FieldDescriptor* field) const;
+  uint32_t GetUInt32(const Message& message,
+                     const FieldDescriptor* field) const;
+  uint64_t GetUInt64(const Message& message,
+                     const FieldDescriptor* field) const;
   float GetFloat(const Message& message, const FieldDescriptor* field) const;
   double GetDouble(const Message& message, const FieldDescriptor* field) const;
   bool GetBool(const Message& message, const FieldDescriptor* field) const;
@@ -577,13 +632,13 @@
   // These mutate the value of a non-repeated field.
 
   void SetInt32(Message* message, const FieldDescriptor* field,
-                int32 value) const;
+                int32_t value) const;
   void SetInt64(Message* message, const FieldDescriptor* field,
-                int64 value) const;
+                int64_t value) const;
   void SetUInt32(Message* message, const FieldDescriptor* field,
-                 uint32 value) const;
+                 uint32_t value) const;
   void SetUInt64(Message* message, const FieldDescriptor* field,
-                 uint64 value) const;
+                 uint64_t value) const;
   void SetFloat(Message* message, const FieldDescriptor* field,
                 float value) const;
   void SetDouble(Message* message, const FieldDescriptor* field,
@@ -652,14 +707,14 @@
   // Repeated field getters ------------------------------------------
   // These get the value of one element of a repeated field.
 
-  int32 GetRepeatedInt32(const Message& message, const FieldDescriptor* field,
-                         int index) const;
-  int64 GetRepeatedInt64(const Message& message, const FieldDescriptor* field,
-                         int index) const;
-  uint32 GetRepeatedUInt32(const Message& message, const FieldDescriptor* field,
+  int32_t GetRepeatedInt32(const Message& message, const FieldDescriptor* field,
                            int index) const;
-  uint64 GetRepeatedUInt64(const Message& message, const FieldDescriptor* field,
+  int64_t GetRepeatedInt64(const Message& message, const FieldDescriptor* field,
                            int index) const;
+  uint32_t GetRepeatedUInt32(const Message& message,
+                             const FieldDescriptor* field, int index) const;
+  uint64_t GetRepeatedUInt64(const Message& message,
+                             const FieldDescriptor* field, int index) const;
   float GetRepeatedFloat(const Message& message, const FieldDescriptor* field,
                          int index) const;
   double GetRepeatedDouble(const Message& message, const FieldDescriptor* field,
@@ -693,13 +748,13 @@
   // These mutate the value of one element of a repeated field.
 
   void SetRepeatedInt32(Message* message, const FieldDescriptor* field,
-                        int index, int32 value) const;
+                        int index, int32_t value) const;
   void SetRepeatedInt64(Message* message, const FieldDescriptor* field,
-                        int index, int64 value) const;
+                        int index, int64_t value) const;
   void SetRepeatedUInt32(Message* message, const FieldDescriptor* field,
-                         int index, uint32 value) const;
+                         int index, uint32_t value) const;
   void SetRepeatedUInt64(Message* message, const FieldDescriptor* field,
-                         int index, uint64 value) const;
+                         int index, uint64_t value) const;
   void SetRepeatedFloat(Message* message, const FieldDescriptor* field,
                         int index, float value) const;
   void SetRepeatedDouble(Message* message, const FieldDescriptor* field,
@@ -730,13 +785,13 @@
   // These add an element to a repeated field.
 
   void AddInt32(Message* message, const FieldDescriptor* field,
-                int32 value) const;
+                int32_t value) const;
   void AddInt64(Message* message, const FieldDescriptor* field,
-                int64 value) const;
+                int64_t value) const;
   void AddUInt32(Message* message, const FieldDescriptor* field,
-                 uint32 value) const;
+                 uint32_t value) const;
   void AddUInt64(Message* message, const FieldDescriptor* field,
-                 uint64 value) const;
+                 uint64_t value) const;
   void AddFloat(Message* message, const FieldDescriptor* field,
                 float value) const;
   void AddDouble(Message* message, const FieldDescriptor* field,
@@ -765,6 +820,13 @@
   void AddAllocatedMessage(Message* message, const FieldDescriptor* field,
                            Message* new_entry) const;
 
+  // Similar to AddAllocatedMessage() without internal safety and ownership
+  // checks. This method should only be used when the objects are on the same
+  // arena or paired with a call to `UnsafeArenaReleaseLast`.
+  void UnsafeArenaAddAllocatedMessage(Message* message,
+                                      const FieldDescriptor* field,
+                                      Message* new_entry) const;
+
 
   // Get a RepeatedFieldRef object that can be used to read the underlying
   // repeated field. The type parameter T must be set according to the
@@ -772,14 +834,14 @@
   // to acceptable T.
   //
   //   field->cpp_type()      T
-  //   CPPTYPE_INT32        int32
-  //   CPPTYPE_UINT32       uint32
-  //   CPPTYPE_INT64        int64
-  //   CPPTYPE_UINT64       uint64
+  //   CPPTYPE_INT32        int32_t
+  //   CPPTYPE_UINT32       uint32_t
+  //   CPPTYPE_INT64        int64_t
+  //   CPPTYPE_UINT64       uint64_t
   //   CPPTYPE_DOUBLE       double
   //   CPPTYPE_FLOAT        float
   //   CPPTYPE_BOOL         bool
-  //   CPPTYPE_ENUM         generated enum type or int32
+  //   CPPTYPE_ENUM         generated enum type or int32_t
   //   CPPTYPE_STRING       std::string
   //   CPPTYPE_MESSAGE      generated message type or google::protobuf::Message
   //
@@ -1010,6 +1072,7 @@
   friend class ::PROTOBUF_NAMESPACE_ID::MessageLayoutInspector;
   friend class ::PROTOBUF_NAMESPACE_ID::AssignDescriptorsHelper;
   friend class DynamicMessageFactory;
+  friend class DynamicMessageReflectionHelper;
   friend class GeneratedMessageReflectionTestHelper;
   friend class python::MapReflectionFriend;
   friend class python::MessageReflectionFriend;
@@ -1101,11 +1164,11 @@
 
   const Message* GetDefaultMessageInstance(const FieldDescriptor* field) const;
 
-  inline const uint32* GetHasBits(const Message& message) const;
-  inline uint32* MutableHasBits(Message* message) const;
-  inline uint32 GetOneofCase(const Message& message,
-                             const OneofDescriptor* oneof_descriptor) const;
-  inline uint32* MutableOneofCase(
+  inline const uint32_t* GetHasBits(const Message& message) const;
+  inline uint32_t* MutableHasBits(Message* message) const;
+  inline uint32_t GetOneofCase(const Message& message,
+                               const OneofDescriptor* oneof_descriptor) const;
+  inline uint32_t* MutableOneofCase(
       Message* message, const OneofDescriptor* oneof_descriptor) const;
   inline bool HasExtensionSet(const Message& /* message */) const {
     return schema_.HasExtensionSet();
@@ -1118,6 +1181,8 @@
 
   internal::InternalMetadata* MutableInternalMetadata(Message* message) const;
 
+  inline bool IsInlined(const FieldDescriptor* field) const;
+
   inline bool HasBit(const Message& message,
                      const FieldDescriptor* field) const;
   inline void SetBit(Message* message, const FieldDescriptor* field) const;
@@ -1125,6 +1190,12 @@
   inline void SwapBit(Message* message1, Message* message2,
                       const FieldDescriptor* field) const;
 
+  inline const uint32_t* GetInlinedStringDonatedArray(
+      const Message& message) const;
+  inline uint32_t* MutableInlinedStringDonatedArray(Message* message) const;
+  inline bool IsInlinedStringDonated(const Message& message,
+                                     const FieldDescriptor* field) const;
+
   // Shallow-swap fields listed in fields vector of two messages. It is the
   // caller's responsibility to make sure shallow swap is safe.
   void UnsafeShallowSwapFields(
@@ -1144,14 +1215,10 @@
   void SwapFieldsImpl(Message* message1, Message* message2,
                       const std::vector<const FieldDescriptor*>& fields) const;
 
-  void SwapOneofField(Message* message1, Message* message2,
+  template <bool unsafe_shallow_swap>
+  void SwapOneofField(Message* lhs, Message* rhs,
                       const OneofDescriptor* oneof_descriptor) const;
 
-  // Unsafe but shallow version of SwapOneofField.
-  void UnsafeShallowSwapOneofField(
-      Message* message1, Message* message2,
-      const OneofDescriptor* oneof_descriptor) const;
-
   inline bool HasOneofField(const Message& message,
                             const FieldDescriptor* field) const;
   inline void SetOneofCase(Message* message,
@@ -1294,10 +1361,10 @@
   Reflection::MutableRepeatedFieldInternal<TYPE>(                  \
       Message * message, const FieldDescriptor* field) const;
 
-DECLARE_GET_REPEATED_FIELD(int32)
-DECLARE_GET_REPEATED_FIELD(int64)
-DECLARE_GET_REPEATED_FIELD(uint32)
-DECLARE_GET_REPEATED_FIELD(uint64)
+DECLARE_GET_REPEATED_FIELD(int32_t)
+DECLARE_GET_REPEATED_FIELD(int64_t)
+DECLARE_GET_REPEATED_FIELD(uint32_t)
+DECLARE_GET_REPEATED_FIELD(uint64_t)
 DECLARE_GET_REPEATED_FIELD(float)
 DECLARE_GET_REPEATED_FIELD(double)
 DECLARE_GET_REPEATED_FIELD(bool)
@@ -1422,6 +1489,28 @@
 const Type& Reflection::DefaultRaw(const FieldDescriptor* field) const {
   return *reinterpret_cast<const Type*>(schema_.GetFieldDefault(field));
 }
+
+uint32_t Reflection::GetOneofCase(
+    const Message& message, const OneofDescriptor* oneof_descriptor) const {
+  GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
+  return internal::GetConstRefAtOffset<uint32_t>(
+      message, schema_.GetOneofCaseOffset(oneof_descriptor));
+}
+
+bool Reflection::HasOneofField(const Message& message,
+                               const FieldDescriptor* field) const {
+  return (GetOneofCase(message, field->containing_oneof()) ==
+          static_cast<uint32_t>(field->number()));
+}
+
+template <typename Type>
+const Type& Reflection::GetRaw(const Message& message,
+                               const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!schema_.InRealOneof(field) || HasOneofField(message, field))
+      << "Field = " << field->full_name();
+  return internal::GetConstRefAtOffset<Type>(message,
+                                             schema_.GetFieldOffset(field));
+}
 }  // namespace protobuf
 }  // namespace google
 
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index f137675..3dea09e 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -336,15 +336,15 @@
 
 // ===================================================================
 
-inline uint8* SerializeToArrayImpl(const MessageLite& msg, uint8* target,
-                                   int size) {
+inline uint8_t* SerializeToArrayImpl(const MessageLite& msg, uint8_t* target,
+                                     int size) {
   constexpr bool debug = false;
   if (debug) {
     // Force serialization to a stream with a block size of 1, which forces
     // all writes to the stream to cross buffers triggering all fallback paths
     // in the unittests when serializing to string / array.
     io::ArrayOutputStream stream(target, size, 1);
-    uint8* ptr;
+    uint8_t* ptr;
     io::EpsCopyOutputStream out(
         &stream, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
         &ptr);
@@ -362,7 +362,7 @@
   }
 }
 
-uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
+uint8_t* MessageLite::SerializeWithCachedSizesToArray(uint8_t* target) const {
   // We only optimize this when using optimize_for = SPEED.  In other cases
   // we just use the CodedOutputStream path.
   return SerializeToArrayImpl(*this, target, GetCachedSize());
@@ -389,7 +389,7 @@
   }
   int final_byte_count = output->ByteCount();
 
-  if (final_byte_count - original_byte_count != static_cast<int64>(size)) {
+  if (final_byte_count - original_byte_count != static_cast<int64_t>(size)) {
     ByteSizeConsistencyError(size, ByteSizeLong(),
                              final_byte_count - original_byte_count, *this);
   }
@@ -412,7 +412,7 @@
     return false;
   }
 
-  uint8* target;
+  uint8_t* target;
   io::EpsCopyOutputStream stream(
       output, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
       &target);
@@ -459,9 +459,9 @@
     return false;
   }
 
-  STLStringResizeUninitialized(output, old_size + byte_size);
-  uint8* start =
-      reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size);
+  STLStringResizeUninitializedAmortized(output, old_size + byte_size);
+  uint8_t* start =
+      reinterpret_cast<uint8_t*>(io::mutable_string_data(output) + old_size);
   SerializeToArrayImpl(*this, start, byte_size);
   return true;
 }
@@ -488,8 +488,8 @@
                << " exceeded maximum protobuf size of 2GB: " << byte_size;
     return false;
   }
-  if (size < static_cast<int64>(byte_size)) return false;
-  uint8* start = reinterpret_cast<uint8*>(data);
+  if (size < static_cast<int64_t>(byte_size)) return false;
+  uint8_t* start = reinterpret_cast<uint8_t*>(data);
   SerializeToArrayImpl(*this, start, byte_size);
   return true;
 }
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index f82bd0c..d813850 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -158,7 +158,7 @@
   // Prefer c++14 aligned_storage, but for compatibility this will do.
   union AlignedUnion {
     alignas(T) char space[sizeof(T)];
-    int64 align_to_int64;
+    int64_t align_to_int64;
     void* align_to_ptr;
   } union_;
 };
@@ -449,7 +449,7 @@
   // must point at a byte array of at least ByteSize() bytes.  Whether to use
   // deterministic serialization, e.g., maps in sorted order, is determined by
   // CodedOutputStream::IsDefaultSerializationDeterministic().
-  uint8* SerializeWithCachedSizesToArray(uint8* target) const;
+  uint8_t* SerializeWithCachedSizesToArray(uint8_t* target) const;
 
   // Returns the result of the last call to ByteSize().  An embedded message's
   // size is needed both to serialize it (because embedded messages are
@@ -507,9 +507,9 @@
   bool ParseFrom(const T& input);
 
   // Fast path when conditions match (ie. non-deterministic)
-  //  uint8* _InternalSerialize(uint8* ptr) const;
-  virtual uint8* _InternalSerialize(uint8* ptr,
-                                    io::EpsCopyOutputStream* stream) const = 0;
+  //  uint8_t* _InternalSerialize(uint8_t* ptr) const;
+  virtual uint8_t* _InternalSerialize(
+      uint8_t* ptr, io::EpsCopyOutputStream* stream) const = 0;
 
   // Identical to IsInitialized() except that it logs an error message.
   bool IsInitializedWithErrors() const {
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
index 1bf5ef8..354d748 100644
--- a/src/google/protobuf/parse_context.cc
+++ b/src/google/protobuf/parse_context.cc
@@ -55,7 +55,7 @@
   auto ptr = begin + overrun;
   auto end = begin + kSlopBytes;
   while (ptr < end) {
-    uint32 tag;
+    uint32_t tag;
     ptr = ReadTag(ptr, &tag);
     if (ptr == nullptr || ptr > end) return false;
     // ending on 0 tag is allowed and is the major reason for the necessity of
@@ -63,7 +63,7 @@
     if (tag == 0) return true;
     switch (tag & 7) {
       case 0: {  // Varint
-        uint64 val;
+        uint64_t val;
         ptr = VarintParse(ptr, &val);
         if (ptr == nullptr) return false;
         break;
@@ -73,7 +73,7 @@
         break;
       }
       case 2: {  // len delim
-        int32 size = ReadSize(&ptr);
+        int32_t size = ReadSize(&ptr);
         if (ptr == nullptr || size > end - ptr) return false;
         ptr += size;
         break;
@@ -240,11 +240,11 @@
 void byteswap<1>(void* p) {}
 template <>
 void byteswap<4>(void* p) {
-  *static_cast<uint32*>(p) = bswap_32(*static_cast<uint32*>(p));
+  *static_cast<uint32_t*>(p) = bswap_32(*static_cast<uint32_t*>(p));
 }
 template <>
 void byteswap<8>(void* p) {
-  *static_cast<uint64*>(p) = bswap_64(*static_cast<uint64*>(p));
+  *static_cast<uint64_t*>(p) = bswap_64(*static_cast<uint64_t*>(p));
 }
 
 const char* EpsCopyInputStream::InitFrom(io::ZeroCopyInputStream* zcis) {
@@ -296,29 +296,30 @@
   return ParseMessage(reinterpret_cast<MessageLite*>(msg), ptr);
 }
 
-inline void WriteVarint(uint64 val, std::string* s) {
+inline void WriteVarint(uint64_t val, std::string* s) {
   while (val >= 128) {
-    uint8 c = val | 0x80;
+    uint8_t c = val | 0x80;
     s->push_back(c);
     val >>= 7;
   }
   s->push_back(val);
 }
 
-void WriteVarint(uint32 num, uint64 val, std::string* s) {
+void WriteVarint(uint32_t num, uint64_t val, std::string* s) {
   WriteVarint(num << 3, s);
   WriteVarint(val, s);
 }
 
-void WriteLengthDelimited(uint32 num, StringPiece val, std::string* s) {
+void WriteLengthDelimited(uint32_t num, StringPiece val, std::string* s) {
   WriteVarint((num << 3) + 2, s);
   WriteVarint(val.size(), s);
   s->append(val.data(), val.size());
 }
 
-std::pair<const char*, uint32> VarintParseSlow32(const char* p, uint32 res) {
+std::pair<const char*, uint32_t> VarintParseSlow32(const char* p,
+                                                   uint32_t res) {
   for (std::uint32_t i = 2; i < 5; i++) {
-    uint32 byte = static_cast<uint8>(p[i]);
+    uint32_t byte = static_cast<uint8_t>(p[i]);
     res += (byte - 1) << (7 * i);
     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
       return {p + i + 1, res};
@@ -326,7 +327,7 @@
   }
   // Accept >5 bytes
   for (std::uint32_t i = 5; i < 10; i++) {
-    uint32 byte = static_cast<uint8>(p[i]);
+    uint32_t byte = static_cast<uint8_t>(p[i]);
     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
       return {p + i + 1, res};
     }
@@ -334,10 +335,11 @@
   return {nullptr, 0};
 }
 
-std::pair<const char*, uint64> VarintParseSlow64(const char* p, uint32 res32) {
-  uint64 res = res32;
+std::pair<const char*, uint64_t> VarintParseSlow64(const char* p,
+                                                   uint32_t res32) {
+  uint64_t res = res32;
   for (std::uint32_t i = 2; i < 10; i++) {
-    uint64 byte = static_cast<uint8>(p[i]);
+    uint64_t byte = static_cast<uint8_t>(p[i]);
     res += (byte - 1) << (7 * i);
     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
       return {p + i + 1, res};
@@ -346,9 +348,9 @@
   return {nullptr, 0};
 }
 
-std::pair<const char*, uint32> ReadTagFallback(const char* p, uint32 res) {
+std::pair<const char*, uint32_t> ReadTagFallback(const char* p, uint32_t res) {
   for (std::uint32_t i = 2; i < 5; i++) {
-    uint32 byte = static_cast<uint8>(p[i]);
+    uint32_t byte = static_cast<uint8_t>(p[i]);
     res += (byte - 1) << (7 * i);
     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
       return {p + i + 1, res};
@@ -357,15 +359,15 @@
   return {nullptr, 0};
 }
 
-std::pair<const char*, int32> ReadSizeFallback(const char* p, uint32 res) {
+std::pair<const char*, int32_t> ReadSizeFallback(const char* p, uint32_t res) {
   for (std::uint32_t i = 1; i < 4; i++) {
-    uint32 byte = static_cast<uint8>(p[i]);
+    uint32_t byte = static_cast<uint8_t>(p[i]);
     res += (byte - 1) << (7 * i);
     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
       return {p + i + 1, res};
     }
   }
-  std::uint32_t byte = static_cast<uint8>(p[4]);
+  std::uint32_t byte = static_cast<uint8_t>(p[4]);
   if (PROTOBUF_PREDICT_FALSE(byte >= 8)) return {nullptr, 0};  // size >= 2gb
   res += (byte - 1) << 28;
   // Protect against sign integer overflow in PushLimit. Limits are relative
@@ -406,7 +408,7 @@
 
 template <typename T, bool sign>
 const char* VarintParser(void* object, const char* ptr, ParseContext* ctx) {
-  return ctx->ReadPackedVarint(ptr, [object](uint64 varint) {
+  return ctx->ReadPackedVarint(ptr, [object](uint64_t varint) {
     T val;
     if (sign) {
       if (sizeof(T) == 8) {
@@ -423,27 +425,27 @@
 
 const char* PackedInt32Parser(void* object, const char* ptr,
                               ParseContext* ctx) {
-  return VarintParser<int32, false>(object, ptr, ctx);
+  return VarintParser<int32_t, false>(object, ptr, ctx);
 }
 const char* PackedUInt32Parser(void* object, const char* ptr,
                                ParseContext* ctx) {
-  return VarintParser<uint32, false>(object, ptr, ctx);
+  return VarintParser<uint32_t, false>(object, ptr, ctx);
 }
 const char* PackedInt64Parser(void* object, const char* ptr,
                               ParseContext* ctx) {
-  return VarintParser<int64, false>(object, ptr, ctx);
+  return VarintParser<int64_t, false>(object, ptr, ctx);
 }
 const char* PackedUInt64Parser(void* object, const char* ptr,
                                ParseContext* ctx) {
-  return VarintParser<uint64, false>(object, ptr, ctx);
+  return VarintParser<uint64_t, false>(object, ptr, ctx);
 }
 const char* PackedSInt32Parser(void* object, const char* ptr,
                                ParseContext* ctx) {
-  return VarintParser<int32, true>(object, ptr, ctx);
+  return VarintParser<int32_t, true>(object, ptr, ctx);
 }
 const char* PackedSInt64Parser(void* object, const char* ptr,
                                ParseContext* ctx) {
-  return VarintParser<int64, true>(object, ptr, ctx);
+  return VarintParser<int64_t, true>(object, ptr, ctx);
 }
 
 const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx) {
@@ -464,19 +466,19 @@
 
 const char* PackedFixed32Parser(void* object, const char* ptr,
                                 ParseContext* ctx) {
-  return FixedParser<uint32>(object, ptr, ctx);
+  return FixedParser<uint32_t>(object, ptr, ctx);
 }
 const char* PackedSFixed32Parser(void* object, const char* ptr,
                                  ParseContext* ctx) {
-  return FixedParser<int32>(object, ptr, ctx);
+  return FixedParser<int32_t>(object, ptr, ctx);
 }
 const char* PackedFixed64Parser(void* object, const char* ptr,
                                 ParseContext* ctx) {
-  return FixedParser<uint64>(object, ptr, ctx);
+  return FixedParser<uint64_t>(object, ptr, ctx);
 }
 const char* PackedSFixed64Parser(void* object, const char* ptr,
                                  ParseContext* ctx) {
-  return FixedParser<int64>(object, ptr, ctx);
+  return FixedParser<int64_t>(object, ptr, ctx);
 }
 const char* PackedFloatParser(void* object, const char* ptr,
                               ParseContext* ctx) {
@@ -492,20 +494,20 @@
   explicit UnknownFieldLiteParserHelper(std::string* unknown)
       : unknown_(unknown) {}
 
-  void AddVarint(uint32 num, uint64 value) {
+  void AddVarint(uint32_t num, uint64_t value) {
     if (unknown_ == nullptr) return;
     WriteVarint(num * 8, unknown_);
     WriteVarint(value, unknown_);
   }
-  void AddFixed64(uint32 num, uint64 value) {
+  void AddFixed64(uint32_t num, uint64_t value) {
     if (unknown_ == nullptr) return;
     WriteVarint(num * 8 + 1, unknown_);
     char buffer[8];
     io::CodedOutputStream::WriteLittleEndian64ToArray(
-        value, reinterpret_cast<uint8*>(buffer));
+        value, reinterpret_cast<uint8_t*>(buffer));
     unknown_->append(buffer, 8);
   }
-  const char* ParseLengthDelimited(uint32 num, const char* ptr,
+  const char* ParseLengthDelimited(uint32_t num, const char* ptr,
                                    ParseContext* ctx) {
     int size = ReadSize(&ptr);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
@@ -514,19 +516,19 @@
     WriteVarint(size, unknown_);
     return ctx->AppendString(ptr, size, unknown_);
   }
-  const char* ParseGroup(uint32 num, const char* ptr, ParseContext* ctx) {
+  const char* ParseGroup(uint32_t num, const char* ptr, ParseContext* ctx) {
     if (unknown_) WriteVarint(num * 8 + 3, unknown_);
     ptr = ctx->ParseGroup(this, ptr, num * 8 + 3);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     if (unknown_) WriteVarint(num * 8 + 4, unknown_);
     return ptr;
   }
-  void AddFixed32(uint32 num, uint32 value) {
+  void AddFixed32(uint32_t num, uint32_t value) {
     if (unknown_ == nullptr) return;
     WriteVarint(num * 8 + 5, unknown_);
     char buffer[4];
     io::CodedOutputStream::WriteLittleEndian32ToArray(
-        value, reinterpret_cast<uint8*>(buffer));
+        value, reinterpret_cast<uint8_t*>(buffer));
     unknown_->append(buffer, 4);
   }
 
@@ -544,8 +546,8 @@
   return WireFormatParser(field_parser, ptr, ctx);
 }
 
-const char* UnknownFieldParse(uint32 tag, std::string* unknown, const char* ptr,
-                              ParseContext* ctx) {
+const char* UnknownFieldParse(uint32_t tag, std::string* unknown,
+                              const char* ptr, ParseContext* ctx) {
   UnknownFieldLiteParserHelper field_parser(unknown);
   return FieldParser(tag, field_parser, ptr, ctx);
 }
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
index d858191..c5d1ab9 100644
--- a/src/google/protobuf/parse_context.h
+++ b/src/google/protobuf/parse_context.h
@@ -40,6 +40,7 @@
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/inlined_string_field.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/port.h>
 #include <google/protobuf/repeated_field.h>
@@ -59,12 +60,12 @@
 namespace internal {
 
 // Template code below needs to know about the existence of these functions.
-PROTOBUF_EXPORT void WriteVarint(uint32 num, uint64 val, std::string* s);
-PROTOBUF_EXPORT void WriteLengthDelimited(uint32 num, StringPiece val,
+PROTOBUF_EXPORT void WriteVarint(uint32_t num, uint64_t val, std::string* s);
+PROTOBUF_EXPORT void WriteLengthDelimited(uint32_t num, StringPiece val,
                                           std::string* s);
 // Inline because it is just forwarding to s->WriteVarint
-inline void WriteVarint(uint32 num, uint64 val, UnknownFieldSet* s);
-inline void WriteLengthDelimited(uint32 num, StringPiece val,
+inline void WriteVarint(uint32_t num, uint64_t val, UnknownFieldSet* s);
+inline void WriteLengthDelimited(uint32_t num, StringPiece val,
                                  UnknownFieldSet* s);
 
 
@@ -184,15 +185,15 @@
   PROTOBUF_MUST_USE_RESULT const char* ReadPackedVarint(const char* ptr,
                                                         Add add);
 
-  uint32 LastTag() const { return last_tag_minus_1_ + 1; }
-  bool ConsumeEndGroup(uint32 start_tag) {
+  uint32_t LastTag() const { return last_tag_minus_1_ + 1; }
+  bool ConsumeEndGroup(uint32_t start_tag) {
     bool res = last_tag_minus_1_ == start_tag;
     last_tag_minus_1_ = 0;
     return res;
   }
   bool EndedAtLimit() const { return last_tag_minus_1_ == 0; }
   bool EndedAtEndOfStream() const { return last_tag_minus_1_ == 1; }
-  void SetLastTag(uint32 tag) { last_tag_minus_1_ = tag - 1; }
+  void SetLastTag(uint32_t tag) { last_tag_minus_1_ = tag - 1; }
   void SetEndOfStream() { last_tag_minus_1_ = 1; }
   bool IsExceedingLimit(const char* ptr) {
     return ptr > limit_end_ &&
@@ -281,7 +282,7 @@
   // This var doesn't really belong in EpsCopyInputStream and should be part of
   // the ParseContext, but case 2 is most easily and optimally implemented in
   // DoneFallback.
-  uint32 last_tag_minus_1_ = 0;
+  uint32_t last_tag_minus_1_ = 0;
   int overall_limit_ = INT_MAX;  // Overall limit independent of pushed limits.
   // Pretty random large number that seems like a safe allocation on most
   // systems. TODO(gerbens) do we need to set this as build flag?
@@ -406,7 +407,7 @@
 
   template <typename T>
   PROTOBUF_MUST_USE_RESULT PROTOBUF_NDEBUG_INLINE const char* ParseGroup(
-      T* msg, const char* ptr, uint32 tag) {
+      T* msg, const char* ptr, uint32_t tag) {
     if (--depth_ < 0) return nullptr;
     group_depth_++;
     ptr = msg->_InternalParse(ptr, this);
@@ -440,7 +441,7 @@
   Data data_;
 };
 
-template <uint32 tag>
+template <uint32_t tag>
 bool ExpectTag(const char* ptr) {
   if (tag < 128) {
     return *ptr == static_cast<char>(tag);
@@ -456,13 +457,13 @@
 
 template <>
 struct EndianHelper<1> {
-  static uint8 Load(const void* p) { return *static_cast<const uint8*>(p); }
+  static uint8_t Load(const void* p) { return *static_cast<const uint8_t*>(p); }
 };
 
 template <>
 struct EndianHelper<2> {
-  static uint16 Load(const void* p) {
-    uint16 tmp;
+  static uint16_t Load(const void* p) {
+    uint16_t tmp;
     std::memcpy(&tmp, p, 2);
 #ifndef PROTOBUF_LITTLE_ENDIAN
     tmp = bswap_16(tmp);
@@ -473,8 +474,8 @@
 
 template <>
 struct EndianHelper<4> {
-  static uint32 Load(const void* p) {
-    uint32 tmp;
+  static uint32_t Load(const void* p) {
+    uint32_t tmp;
     std::memcpy(&tmp, p, 4);
 #ifndef PROTOBUF_LITTLE_ENDIAN
     tmp = bswap_32(tmp);
@@ -485,8 +486,8 @@
 
 template <>
 struct EndianHelper<8> {
-  static uint64 Load(const void* p) {
-    uint64 tmp;
+  static uint64_t Load(const void* p) {
+    uint64_t tmp;
     std::memcpy(&tmp, p, 8);
 #ifndef PROTOBUF_LITTLE_ENDIAN
     tmp = bswap_64(tmp);
@@ -504,17 +505,17 @@
 }
 
 PROTOBUF_EXPORT
-std::pair<const char*, uint32> VarintParseSlow32(const char* p, uint32 res);
+std::pair<const char*, uint32_t> VarintParseSlow32(const char* p, uint32_t res);
 PROTOBUF_EXPORT
-std::pair<const char*, uint64> VarintParseSlow64(const char* p, uint32 res);
+std::pair<const char*, uint64_t> VarintParseSlow64(const char* p, uint32_t res);
 
-inline const char* VarintParseSlow(const char* p, uint32 res, uint32* out) {
+inline const char* VarintParseSlow(const char* p, uint32_t res, uint32_t* out) {
   auto tmp = VarintParseSlow32(p, res);
   *out = tmp.second;
   return tmp.first;
 }
 
-inline const char* VarintParseSlow(const char* p, uint32 res, uint64* out) {
+inline const char* VarintParseSlow(const char* p, uint32_t res, uint64_t* out) {
   auto tmp = VarintParseSlow64(p, res);
   *out = tmp.second;
   return tmp.first;
@@ -522,13 +523,13 @@
 
 template <typename T>
 PROTOBUF_MUST_USE_RESULT const char* VarintParse(const char* p, T* out) {
-  auto ptr = reinterpret_cast<const uint8*>(p);
-  uint32 res = ptr[0];
+  auto ptr = reinterpret_cast<const uint8_t*>(p);
+  uint32_t res = ptr[0];
   if (!(res & 0x80)) {
     *out = res;
     return p + 1;
   }
-  uint32 byte = ptr[1];
+  uint32_t byte = ptr[1];
   res += (byte - 1) << 7;
   if (!(byte & 0x80)) {
     *out = res;
@@ -541,16 +542,17 @@
 // Caller must ensure its safe to call.
 
 PROTOBUF_EXPORT
-std::pair<const char*, uint32> ReadTagFallback(const char* p, uint32 res);
+std::pair<const char*, uint32_t> ReadTagFallback(const char* p, uint32_t res);
 
 // Same as ParseVarint but only accept 5 bytes at most.
-inline const char* ReadTag(const char* p, uint32* out, uint32 /*max_tag*/ = 0) {
-  uint32 res = static_cast<uint8>(p[0]);
+inline const char* ReadTag(const char* p, uint32_t* out,
+                           uint32_t /*max_tag*/ = 0) {
+  uint32_t res = static_cast<uint8_t>(p[0]);
   if (res < 128) {
     *out = res;
     return p + 1;
   }
-  uint32 second = static_cast<uint8>(p[1]);
+  uint32_t second = static_cast<uint8_t>(p[1]);
   res += (second - 1) << 7;
   if (second < 128) {
     *out = res;
@@ -571,8 +573,8 @@
 // adc [rsi], 1
 // add eax, eax
 // and eax, edi
-inline uint32 DecodeTwoBytes(const char** ptr) {
-  uint32 value = UnalignedLoad<uint16>(*ptr);
+inline uint32_t DecodeTwoBytes(const char** ptr) {
+  uint32_t value = UnalignedLoad<uint16_t>(*ptr);
   // Sign extend the low byte continuation bit
   uint32_t x = static_cast<int8_t>(value);
   // This add is an amazing operation, it cancels the low byte continuation bit
@@ -586,11 +588,11 @@
 }
 
 // More efficient varint parsing for big varints
-inline const char* ParseBigVarint(const char* p, uint64* out) {
+inline const char* ParseBigVarint(const char* p, uint64_t* out) {
   auto pnew = p;
   auto tmp = DecodeTwoBytes(&pnew);
-  uint64 res = tmp >> 1;
-  if (PROTOBUF_PREDICT_TRUE(std::int16_t(tmp) >= 0)) {
+  uint64_t res = tmp >> 1;
+  if (PROTOBUF_PREDICT_TRUE(static_cast<std::int16_t>(tmp) >= 0)) {
     *out = res;
     return pnew;
   }
@@ -598,7 +600,7 @@
     pnew = p + 2 * i;
     tmp = DecodeTwoBytes(&pnew);
     res += (static_cast<std::uint64_t>(tmp) - 2) << (14 * i - 1);
-    if (PROTOBUF_PREDICT_TRUE(std::int16_t(tmp) >= 0)) {
+    if (PROTOBUF_PREDICT_TRUE(static_cast<std::int16_t>(tmp) >= 0)) {
       *out = res;
       return pnew;
     }
@@ -607,13 +609,13 @@
 }
 
 PROTOBUF_EXPORT
-std::pair<const char*, int32> ReadSizeFallback(const char* p, uint32 first);
+std::pair<const char*, int32_t> ReadSizeFallback(const char* p, uint32_t first);
 // Used for tags, could read up to 5 bytes which must be available. Additionally
-// it makes sure the unsigned value fits a int32, otherwise returns nullptr.
+// it makes sure the unsigned value fits a int32_t, otherwise returns nullptr.
 // Caller must ensure its safe to call.
-inline uint32 ReadSize(const char** pp) {
+inline uint32_t ReadSize(const char** pp) {
   auto p = *pp;
-  uint32 res = static_cast<uint8>(p[0]);
+  uint32_t res = static_cast<uint8_t>(p[0]);
   if (res < 128) {
     *pp = p + 1;
     return res;
@@ -628,28 +630,28 @@
 // function composition. We rely on the compiler to inline this.
 // Also in debug compiles having local scoped variables tend to generated
 // stack frames that scale as O(num fields).
-inline uint64 ReadVarint64(const char** p) {
-  uint64 tmp;
+inline uint64_t ReadVarint64(const char** p) {
+  uint64_t tmp;
   *p = VarintParse(*p, &tmp);
   return tmp;
 }
 
-inline uint32 ReadVarint32(const char** p) {
-  uint32 tmp;
+inline uint32_t ReadVarint32(const char** p) {
+  uint32_t tmp;
   *p = VarintParse(*p, &tmp);
   return tmp;
 }
 
-inline int64 ReadVarintZigZag64(const char** p) {
-  uint64 tmp;
+inline int64_t ReadVarintZigZag64(const char** p) {
+  uint64_t tmp;
   *p = VarintParse(*p, &tmp);
   return WireFormatLite::ZigZagDecode64(tmp);
 }
 
-inline int32 ReadVarintZigZag32(const char** p) {
-  uint64 tmp;
+inline int32_t ReadVarintZigZag32(const char** p) {
+  uint64_t tmp;
   *p = VarintParse(*p, &tmp);
-  return WireFormatLite::ZigZagDecode32(static_cast<uint32>(tmp));
+  return WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
 }
 
 template <typename T>
@@ -716,7 +718,7 @@
 template <typename Add>
 const char* ReadPackedVarintArray(const char* ptr, const char* end, Add add) {
   while (ptr < end) {
-    uint64 varint;
+    uint64_t varint;
     ptr = VarintParse(ptr, &varint);
     if (ptr == nullptr) return nullptr;
     add(varint);
@@ -786,22 +788,22 @@
   GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, nullptr)
 
 template <typename T>
-PROTOBUF_MUST_USE_RESULT const char* FieldParser(uint64 tag, T& field_parser,
+PROTOBUF_MUST_USE_RESULT const char* FieldParser(uint64_t tag, T& field_parser,
                                                  const char* ptr,
                                                  ParseContext* ctx) {
-  uint32 number = tag >> 3;
+  uint32_t number = tag >> 3;
   GOOGLE_PROTOBUF_PARSER_ASSERT(number != 0);
   using WireType = internal::WireFormatLite::WireType;
   switch (tag & 7) {
     case WireType::WIRETYPE_VARINT: {
-      uint64 value;
+      uint64_t value;
       ptr = VarintParse(ptr, &value);
       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       field_parser.AddVarint(number, value);
       break;
     }
     case WireType::WIRETYPE_FIXED64: {
-      uint64 value = UnalignedLoad<uint64>(ptr);
+      uint64_t value = UnalignedLoad<uint64_t>(ptr);
       ptr += 8;
       field_parser.AddFixed64(number, value);
       break;
@@ -821,7 +823,7 @@
       break;
     }
     case WireType::WIRETYPE_FIXED32: {
-      uint32 value = UnalignedLoad<uint32>(ptr);
+      uint32_t value = UnalignedLoad<uint32_t>(ptr);
       ptr += 4;
       field_parser.AddFixed32(number, value);
       break;
@@ -837,7 +839,7 @@
                                                       const char* ptr,
                                                       ParseContext* ctx) {
   while (!ctx->Done(&ptr)) {
-    uint32 tag;
+    uint32_t tag;
     ptr = ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
     if (tag == 0 || (tag & 7) == 4) {
@@ -874,7 +876,7 @@
     void* object, const char* ptr, ParseContext* ctx, bool (*is_valid)(int),
     InternalMetadata* metadata, int field_num) {
   return ctx->ReadPackedVarint(
-      ptr, [object, is_valid, metadata, field_num](uint64 val) {
+      ptr, [object, is_valid, metadata, field_num](uint64_t val) {
         if (is_valid(val)) {
           static_cast<RepeatedField<int>*>(object)->Add(val);
         } else {
@@ -889,7 +891,7 @@
     bool (*is_valid)(const void*, int), const void* data,
     InternalMetadata* metadata, int field_num) {
   return ctx->ReadPackedVarint(
-      ptr, [object, is_valid, data, metadata, field_num](uint64 val) {
+      ptr, [object, is_valid, data, metadata, field_num](uint64_t val) {
         if (is_valid(data, val)) {
           static_cast<RepeatedField<int>*>(object)->Add(val);
         } else {
@@ -920,7 +922,7 @@
 // useful in the generated code. It uses overload on std::string* vs
 // UnknownFieldSet* to make the generated code isomorphic between full and lite.
 PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* UnknownFieldParse(
-    uint32 tag, std::string* unknown, const char* ptr, ParseContext* ctx);
+    uint32_t tag, std::string* unknown, const char* ptr, ParseContext* ctx);
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index 82e98d9..4834d9d 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -52,6 +52,35 @@
 // GCC, and MSVC. Function-like macros are usable without an #ifdef guard.
 // Syntax macros (for example, attributes) are always defined, although
 // they may be empty.
+//
+// Some definitions rely on the NDEBUG macro and/or (in MSVC) _DEBUG:
+// - https://en.cppreference.com/w/c/error/assert
+// - https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros#microsoft-specific-predefined-macros
+//
+// References for predefined macros:
+// - Standard: https://en.cppreference.com/w/cpp/preprocessor/replace
+// - Clang: https://clang.llvm.org/docs/LanguageExtensions.html
+//          (see also GCC predefined macros)
+// - GCC: https://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html
+// - MSVC: https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+// - Interactive (Clang/GCC only): https://www.compiler-explorer.com/z/hc6jKd3sj
+//
+// References for attributes (and extension attributes):
+// - Standard: https://en.cppreference.com/w/cpp/language/attributes
+// - Clang: https://clang.llvm.org/docs/AttributeReference.html
+// - GCC: https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+//        (see Clang attribute docs as well)
+//
+// References for standard C++ language conformance (and minimum versions):
+// - Clang: https://clang.llvm.org/cxx_status.html
+// - GCC: https://gcc.gnu.org/projects/cxx-status.html
+// - MSVC: https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance
+//
+// Historical release notes (which can help to determine minimum versions):
+// - Clang: https://releases.llvm.org/
+// - GCC: https://gcc.gnu.org/releases.html
+// - MSVC: https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-history
+//         https://docs.microsoft.com/en-us/visualstudio/releasenotes/vs2017-relnotes-history
 
 // Portable fallbacks for C++20 feature test macros:
 // https://en.cppreference.com/w/cpp/feature_test
@@ -99,6 +128,23 @@
 #  define PROTOBUF_GNUC_MIN(x, y) 0
 #endif
 
+// Portable check for MSVC minimum version:
+// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+#if defined(_MSC_VER)
+#define PROTOBUF_MSC_VER_MIN(x) (_MSC_VER >= x)
+#else
+#define PROTOBUF_MSC_VER_MIN(x) 0
+#endif
+
+// Portable check for minimum C++ language version:
+// https://en.cppreference.com/w/cpp/preprocessor/replace
+// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+#if !defined(_MSVC_LANG)
+#define PROTOBUF_CPLUSPLUS_MIN(x) (__cplusplus >= x)
+#else
+#define PROTOBUF_CPLUSPLUS_MIN(x) (_MSVC_LANG >= x)
+#endif
+
 // Future versions of protobuf will include breaking changes to some APIs.
 // This macro can be set to enable these API changes ahead of time, so that
 // user code can be updated before upgrading versions of protobuf.
@@ -397,8 +443,8 @@
 #error PROTOBUF_PREDICT_(TRUE|FALSE) was previously defined
 #endif
 #if PROTOBUF_GNUC_MIN(3, 0)
-# define PROTOBUF_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
-# define PROTOBUF_PREDICT_FALSE(x) (__builtin_expect((x), 0))
+# define PROTOBUF_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
+# define PROTOBUF_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
 #else
 # define PROTOBUF_PREDICT_TRUE(x) (x)
 # define PROTOBUF_PREDICT_FALSE(x) (x)
@@ -409,10 +455,6 @@
 #endif
 # define PROTOBUF_MUST_USE_RESULT
 
-#ifdef PROTOBUF_MUST_USE_EXTRACT_RESULT
-#error PROTOBUF_MUST_USE_EXTRACT_RESULT was previously defined
-#endif
-
 #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
 #error PROTOBUF_FORCE_COPY_IN_RELEASE was previously defined
 #endif
@@ -424,7 +466,9 @@
 #ifdef PROTOBUF_FALLTHROUGH_INTENDED
 #error PROTOBUF_FALLTHROUGH_INTENDED was previously defined
 #endif
-#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#if __has_cpp_attribute(fallthrough)
+#define PROTOBUF_FALLTHROUGH_INTENDED [[fallthrough]]
+#elif __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
 #define PROTOBUF_FALLTHROUGH_INTENDED [[clang::fallthrough]]
 #elif PROTOBUF_GNUC_MIN(7, 0)
 #define PROTOBUF_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
@@ -590,11 +634,42 @@
 #  define PROTOBUF_TSAN __SANITIZE_THREAD__
 #endif
 
+// Tail call table-driven parsing can be enabled by defining
+// PROTOBUF_EXPERIMENTAL_USE_TAIL_CALL_TABLE_PARSER at compilation time. Note
+// that this macro is for small-scale testing only, and is not supported.
+#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED
+#error PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED was previously declared
+#endif
+#if defined(PROTOBUF_EXPERIMENTAL_USE_TAIL_CALL_TABLE_PARSER)
+#define PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED 1
+// Selectively use static member functions instead of templates:
+#ifndef PROTOBUF_TC_STATIC_PARSE_SINGULAR1
+#  define PROTOBUF_TC_STATIC_PARSE_SINGULAR1 1
+#endif
+#ifndef PROTOBUF_TC_STATIC_PARSE_SINGULAR2
+#  define PROTOBUF_TC_STATIC_PARSE_SINGULAR2 0
+#endif
+#ifndef PROTOBUF_TC_STATIC_PARSE_REPEATED1
+#  define PROTOBUF_TC_STATIC_PARSE_REPEATED1 0
+#endif
+#ifndef PROTOBUF_TC_STATIC_PARSE_REPEATED2
+#  define PROTOBUF_TC_STATIC_PARSE_REPEATED2 0
+#endif
+#endif
+
+#define PROTOBUF_TC_PARAM_DECL                                 \
+  ::google::protobuf::MessageLite *msg, const char *ptr,                 \
+      ::google::protobuf::internal::ParseContext *ctx,                   \
+      const ::google::protobuf::internal::TailCallParseTableBase *table, \
+      uint64_t hasbits, ::google::protobuf::internal::TcFieldData data
+
 #ifdef PROTOBUF_UNUSED
 #error PROTOBUF_UNUSED was previously defined
 #endif
-#if __has_cpp_attribute(unused) || \
-    (PROTOBUF_GNUC_MIN(3, 0) && !defined(__clang__))
+#if __has_cpp_attribute(maybe_unused) || \
+    (PROTOBUF_MSC_VER_MIN(1911) && PROTOBUF_CPLUSPLUS_MIN(201703L))
+#define PROTOBUF_UNUSED [[maybe_unused]]
+#elif __has_attribute(unused) || PROTOBUF_GNUC_MIN(3, 0)
 #define PROTOBUF_UNUSED __attribute__((__unused__))
 #else
 #define PROTOBUF_UNUSED
@@ -706,4 +781,3 @@
 #  undef __has_builtin
 #  undef PROTOBUF_has_builtin_DEFINED_
 #endif
-#undef PROTOBUF_GNUC_MIN
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index 4e956d4..f038341 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -34,6 +34,9 @@
 #ifndef PROTOBUF_NAMESPACE
 #error "port_undef.inc must be included after port_def.inc"
 #endif
+#undef PROTOBUF_GNUC_MIN
+#undef PROTOBUF_MSC_VER_MIN
+#undef PROTOBUF_CPLUSPLUS_MIN
 #undef PROTOBUF_NAMESPACE
 #undef PROTOBUF_NAMESPACE_ID
 #undef PROTOBUF_ALWAYS_INLINE
@@ -61,7 +64,6 @@
 #undef PROTOBUF_EXPORT
 #undef PROTOC_EXPORT
 #undef PROTOBUF_MUST_USE_RESULT
-#undef PROTOBUF_MUST_USE_EXTRACT_RESULT
 #undef PROTOBUF_FORCE_COPY_IN_RELEASE
 #undef PROTOBUF_FORCE_COPY_IN_SWAP
 #undef PROTOBUF_NAMESPACE_OPEN
@@ -82,6 +84,12 @@
 #undef PROTOBUF_ASAN
 #undef PROTOBUF_MSAN
 #undef PROTOBUF_TSAN
+#undef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED
+#undef PROTOBUF_TC_STATIC_PARSE_SINGULAR1
+#undef PROTOBUF_TC_STATIC_PARSE_SINGULAR2
+#undef PROTOBUF_TC_STATIC_PARSE_REPEATED1
+#undef PROTOBUF_TC_STATIC_PARSE_REPEATED2
+#undef PROTOBUF_TC_PARAM_DECL
 #undef PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED
 #undef PROTOBUF_LOCKS_EXCLUDED
 #undef PROTOBUF_NO_THREAD_SAFETY_ANALYSIS
diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h
index bb41fba..00be9c0 100644
--- a/src/google/protobuf/reflection.h
+++ b/src/google/protobuf/reflection.h
@@ -282,19 +282,19 @@
 // cpp_type to the type that should be used in this interface:
 //
 //   field->cpp_type()      T                Actual type of void*
-//   CPPTYPE_INT32        int32                   int32
-//   CPPTYPE_UINT32       uint32                  uint32
-//   CPPTYPE_INT64        int64                   int64
-//   CPPTYPE_UINT64       uint64                  uint64
+//   CPPTYPE_INT32        int32_t                 int32_t
+//   CPPTYPE_UINT32       uint32_t                uint32_t
+//   CPPTYPE_INT64        int64_t                 int64_t
+//   CPPTYPE_UINT64       uint64_t                uint64_t
 //   CPPTYPE_DOUBLE       double                  double
 //   CPPTYPE_FLOAT        float                   float
 //   CPPTYPE_BOOL         bool                    bool
-//   CPPTYPE_ENUM         generated enum type     int32
+//   CPPTYPE_ENUM         generated enum type     int32_t
 //   CPPTYPE_STRING       string                  std::string
 //   CPPTYPE_MESSAGE      generated message type  google::protobuf::Message
 //                        or google::protobuf::Message
 //
-// Note that for enums we use int32 in the interface.
+// Note that for enums we use int32_t in the interface.
 //
 // You can map from T to the actual type using RefTypeTraits:
 //   typedef RefTypeTraits<T>::AccessorValueType ActualType;
@@ -362,7 +362,7 @@
     // be ActualType. Here we have a ValueType object and want a ActualType
     // pointer. We can't cast a ValueType pointer to an ActualType pointer
     // directly because their type might be different (for enums ValueType
-    // may be a generated enum type while ActualType is int32). To be safe
+    // may be a generated enum type while ActualType is int32_t). To be safe
     // we make a copy to get a temporary ActualType object and use it.
     ActualType tmp = static_cast<ActualType>(value);
     Set(data, index, static_cast<const Value*>(&tmp));
@@ -376,7 +376,7 @@
     // be ActualType. Here we have a ValueType object and want a ActualType
     // pointer. We can't cast a ValueType pointer to an ActualType pointer
     // directly because their type might be different (for enums ValueType
-    // may be a generated enum type while ActualType is int32). To be safe
+    // may be a generated enum type while ActualType is int32_t). To be safe
     // we make a copy to get a temporary ActualType object and use it.
     ActualType tmp = static_cast<ActualType>(value);
     Add(data, static_cast<const Value*>(&tmp));
@@ -485,10 +485,10 @@
     static const FieldDescriptor::CppType cpp_type = \
         FieldDescriptor::CPPTYPE_##TYPE;             \
   };
-DEFINE_PRIMITIVE(INT32, int32)
-DEFINE_PRIMITIVE(UINT32, uint32)
-DEFINE_PRIMITIVE(INT64, int64)
-DEFINE_PRIMITIVE(UINT64, uint64)
+DEFINE_PRIMITIVE(INT32, int32_t)
+DEFINE_PRIMITIVE(UINT32, uint32_t)
+DEFINE_PRIMITIVE(INT64, int64_t)
+DEFINE_PRIMITIVE(UINT64, uint64_t)
 DEFINE_PRIMITIVE(FLOAT, float)
 DEFINE_PRIMITIVE(DOUBLE, double)
 DEFINE_PRIMITIVE(BOOL, bool)
@@ -512,10 +512,10 @@
     T, typename std::enable_if<is_proto_enum<T>::value>::type> {
   typedef RepeatedFieldRefIterator<T> iterator;
   typedef RepeatedFieldAccessor AccessorType;
-  // We use int32 for repeated enums in RepeatedFieldAccessor.
-  typedef int32 AccessorValueType;
+  // We use int32_t for repeated enums in RepeatedFieldAccessor.
+  typedef int32_t AccessorValueType;
   typedef T IteratorValueType;
-  typedef int32* IteratorPointerType;
+  typedef int32_t* IteratorPointerType;
   static constexpr FieldDescriptor::CppType cpp_type =
       FieldDescriptor::CPPTYPE_ENUM;
   static const Descriptor* GetMessageFieldDescriptor() { return NULL; }
diff --git a/src/google/protobuf/reflection_tester.cc b/src/google/protobuf/reflection_tester.cc
new file mode 100644
index 0000000..77601a7
--- /dev/null
+++ b/src/google/protobuf/reflection_tester.cc
@@ -0,0 +1,1673 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/reflection_tester.h>
+
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/message.h>
+#include <gtest/gtest.h>
+
+// Must include last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+MapReflectionTester::MapReflectionTester(const Descriptor* base_descriptor)
+    : base_descriptor_(base_descriptor) {
+  const DescriptorPool* pool = base_descriptor->file()->pool();
+  std::string package = base_descriptor->file()->package();
+
+  map_enum_foo_ = pool->FindEnumValueByName(package + ".MAP_ENUM_FOO");
+  map_enum_bar_ = pool->FindEnumValueByName(package + ".MAP_ENUM_BAR");
+  map_enum_baz_ = pool->FindEnumValueByName(package + ".MAP_ENUM_BAZ");
+
+  foreign_c_ = pool->FindFieldByName(package + ".ForeignMessage.c");
+  map_int32_int32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32Int32Entry.key");
+  map_int32_int32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32Int32Entry.value");
+  map_int64_int64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt64Int64Entry.key");
+  map_int64_int64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt64Int64Entry.value");
+  map_uint32_uint32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint32Uint32Entry.key");
+  map_uint32_uint32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint32Uint32Entry.value");
+  map_uint64_uint64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint64Uint64Entry.key");
+  map_uint64_uint64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint64Uint64Entry.value");
+  map_sint32_sint32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint32Sint32Entry.key");
+  map_sint32_sint32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint32Sint32Entry.value");
+  map_sint64_sint64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint64Sint64Entry.key");
+  map_sint64_sint64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint64Sint64Entry.value");
+  map_fixed32_fixed32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed32Fixed32Entry.key");
+  map_fixed32_fixed32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed32Fixed32Entry.value");
+  map_fixed64_fixed64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed64Fixed64Entry.key");
+  map_fixed64_fixed64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed64Fixed64Entry.value");
+  map_sfixed32_sfixed32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSfixed32Sfixed32Entry.key");
+  map_sfixed32_sfixed32_val_ = pool->FindFieldByName(
+      package + ".TestMap.MapSfixed32Sfixed32Entry.value");
+  map_sfixed64_sfixed64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSfixed64Sfixed64Entry.key");
+  map_sfixed64_sfixed64_val_ = pool->FindFieldByName(
+      package + ".TestMap.MapSfixed64Sfixed64Entry.value");
+  map_int32_float_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32FloatEntry.key");
+  map_int32_float_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32FloatEntry.value");
+  map_int32_double_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32DoubleEntry.key");
+  map_int32_double_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32DoubleEntry.value");
+  map_bool_bool_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapBoolBoolEntry.key");
+  map_bool_bool_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapBoolBoolEntry.value");
+  map_string_string_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapStringStringEntry.key");
+  map_string_string_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapStringStringEntry.value");
+  map_int32_bytes_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32BytesEntry.key");
+  map_int32_bytes_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32BytesEntry.value");
+  map_int32_enum_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32EnumEntry.key");
+  map_int32_enum_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32EnumEntry.value");
+  map_int32_foreign_message_key_ = pool->FindFieldByName(
+      package + ".TestMap.MapInt32ForeignMessageEntry.key");
+  map_int32_foreign_message_val_ = pool->FindFieldByName(
+      package + ".TestMap.MapInt32ForeignMessageEntry.value");
+
+  EXPECT_FALSE(map_enum_foo_ == nullptr);
+  EXPECT_FALSE(map_enum_bar_ == nullptr);
+  EXPECT_FALSE(map_enum_baz_ == nullptr);
+  EXPECT_FALSE(map_int32_int32_key_ == nullptr);
+  EXPECT_FALSE(map_int32_int32_val_ == nullptr);
+  EXPECT_FALSE(map_int64_int64_key_ == nullptr);
+  EXPECT_FALSE(map_int64_int64_val_ == nullptr);
+  EXPECT_FALSE(map_uint32_uint32_key_ == nullptr);
+  EXPECT_FALSE(map_uint32_uint32_val_ == nullptr);
+  EXPECT_FALSE(map_uint64_uint64_key_ == nullptr);
+  EXPECT_FALSE(map_uint64_uint64_val_ == nullptr);
+  EXPECT_FALSE(map_sint32_sint32_key_ == nullptr);
+  EXPECT_FALSE(map_sint32_sint32_val_ == nullptr);
+  EXPECT_FALSE(map_sint64_sint64_key_ == nullptr);
+  EXPECT_FALSE(map_sint64_sint64_val_ == nullptr);
+  EXPECT_FALSE(map_fixed32_fixed32_key_ == nullptr);
+  EXPECT_FALSE(map_fixed32_fixed32_val_ == nullptr);
+  EXPECT_FALSE(map_fixed64_fixed64_key_ == nullptr);
+  EXPECT_FALSE(map_fixed64_fixed64_val_ == nullptr);
+  EXPECT_FALSE(map_sfixed32_sfixed32_key_ == nullptr);
+  EXPECT_FALSE(map_sfixed32_sfixed32_val_ == nullptr);
+  EXPECT_FALSE(map_sfixed64_sfixed64_key_ == nullptr);
+  EXPECT_FALSE(map_sfixed64_sfixed64_val_ == nullptr);
+  EXPECT_FALSE(map_int32_float_key_ == nullptr);
+  EXPECT_FALSE(map_int32_float_val_ == nullptr);
+  EXPECT_FALSE(map_int32_double_key_ == nullptr);
+  EXPECT_FALSE(map_int32_double_val_ == nullptr);
+  EXPECT_FALSE(map_bool_bool_key_ == nullptr);
+  EXPECT_FALSE(map_bool_bool_val_ == nullptr);
+  EXPECT_FALSE(map_string_string_key_ == nullptr);
+  EXPECT_FALSE(map_string_string_val_ == nullptr);
+  EXPECT_FALSE(map_int32_bytes_key_ == nullptr);
+  EXPECT_FALSE(map_int32_bytes_val_ == nullptr);
+  EXPECT_FALSE(map_int32_enum_key_ == nullptr);
+  EXPECT_FALSE(map_int32_enum_val_ == nullptr);
+  EXPECT_FALSE(map_int32_foreign_message_key_ == nullptr);
+  EXPECT_FALSE(map_int32_foreign_message_val_ == nullptr);
+
+  std::vector<const FieldDescriptor*> all_map_descriptors = {
+      map_int32_int32_key_,
+      map_int32_int32_val_,
+      map_int64_int64_key_,
+      map_int64_int64_val_,
+      map_uint32_uint32_key_,
+      map_uint32_uint32_val_,
+      map_uint64_uint64_key_,
+      map_uint64_uint64_val_,
+      map_sint32_sint32_key_,
+      map_sint32_sint32_val_,
+      map_sint64_sint64_key_,
+      map_sint64_sint64_val_,
+      map_fixed32_fixed32_key_,
+      map_fixed32_fixed32_val_,
+      map_fixed64_fixed64_key_,
+      map_fixed64_fixed64_val_,
+      map_sfixed32_sfixed32_key_,
+      map_sfixed32_sfixed32_val_,
+      map_sfixed64_sfixed64_key_,
+      map_sfixed64_sfixed64_val_,
+      map_int32_float_key_,
+      map_int32_float_val_,
+      map_int32_double_key_,
+      map_int32_double_val_,
+      map_bool_bool_key_,
+      map_bool_bool_val_,
+      map_string_string_key_,
+      map_string_string_val_,
+      map_int32_bytes_key_,
+      map_int32_bytes_val_,
+      map_int32_enum_key_,
+      map_int32_enum_val_,
+      map_int32_foreign_message_key_,
+      map_int32_foreign_message_val_};
+  for (const FieldDescriptor* fdesc : all_map_descriptors) {
+    GOOGLE_CHECK(fdesc->containing_type() != nullptr) << fdesc->name();
+    if (fdesc->name() == "key") {
+      EXPECT_EQ(fdesc->containing_type()->map_key(), fdesc);
+    } else {
+      EXPECT_EQ(fdesc->name(), "value");
+      EXPECT_EQ(fdesc->containing_type()->map_value(), fdesc);
+    }
+  }
+}
+
+// Shorthand to get a FieldDescriptor for a field of unittest::TestMap.
+const FieldDescriptor* MapReflectionTester::F(const std::string& name) {
+  const FieldDescriptor* result = nullptr;
+  result = base_descriptor_->FindFieldByName(name);
+  GOOGLE_CHECK(result != nullptr);
+  return result;
+}
+
+void MapReflectionTester::SetMapFieldsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message = nullptr;
+  Message* sub_foreign_message = nullptr;
+
+  // Add first element.
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 0);
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 0);
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
+                                         0);
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
+                                         0);
+
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
+                                         0);
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
+                                         0);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_key_, 0);
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_key_, 0);
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 0);
+  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
+                                         0.0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 0);
+  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
+                                          0.0);
+
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, false);
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, false);
+
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
+                                          "0");
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
+                                          "0");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 0);
+  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
+                                          "0");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 0);
+  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
+                                        map_enum_bar_);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_int32_foreign_message_key_, 0);
+  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
+      sub_message, map_int32_foreign_message_val_, nullptr);
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 0);
+
+  // Add second element
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 1);
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 1);
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
+                                         1);
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
+                                         1);
+
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
+                                         1);
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
+                                         1);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_key_, 1);
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_key_, 1);
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 1);
+  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
+                                         1.0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 1);
+  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
+                                          1.0);
+
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, true);
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, true);
+
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
+                                          "1");
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
+                                          "1");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 1);
+  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
+                                          "1");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 1);
+  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
+                                        map_enum_baz_);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_int32_foreign_message_key_, 1);
+  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
+      sub_message, map_int32_foreign_message_val_, nullptr);
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 1);
+}
+
+void MapReflectionTester::SetMapFieldsViaMapReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  Message* sub_foreign_message = nullptr;
+  MapValueRef map_val;
+  MapValueConstRef map_val_const;
+
+  // Add first element.
+  MapKey map_key;
+  map_key.SetInt32Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_int32"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                 map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int64_int64"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                 map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetUInt32Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_uint32_uint32"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint32_uint32"), map_key, &map_val));
+  map_val.SetUInt32Value(0);
+
+  map_key.SetUInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint64_uint64"), map_key, &map_val));
+  map_val.SetUInt64Value(0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sint32_sint32"), map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sint64_sint64"), map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetUInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_fixed32_fixed32"), map_key, &map_val));
+  map_val.SetUInt32Value(0);
+
+  map_key.SetUInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_fixed64_fixed64"), map_key, &map_val));
+  map_val.SetUInt64Value(0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed32_sfixed32"), map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed64_sfixed64"), map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_float"),
+                                                 map_key, &map_val));
+  map_val.SetFloatValue(0.0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_double"),
+                                                 map_key, &map_val));
+  map_val.SetDoubleValue(0.0);
+
+  map_key.SetBoolValue(false);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_bool_bool"), map_key,
+                                          &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_bool_bool"),
+                                                 map_key, &map_val));
+  map_val.SetBoolValue(false);
+
+  map_key.SetStringValue("0");
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_string_string"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_string_string"), map_key, &map_val));
+  map_val.SetStringValue("0");
+
+  map_key.SetInt32Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_bytes"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"),
+                                                 map_key, &map_val));
+  map_val.SetStringValue("0");
+
+  map_key.SetInt32Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_enum"),
+                                          map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_enum"),
+                                                 map_key, &map_val));
+  map_val.SetEnumValue(map_enum_bar_->number());
+
+  map_key.SetInt32Value(0);
+  EXPECT_FALSE(reflection->LookupMapValue(
+      *message, F("map_int32_foreign_message"), map_key, &map_val_const));
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 0);
+
+  // Add second element
+  map_key.SetInt32Value(1);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                 map_key, &map_val));
+  map_val.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                  map_key, &map_val));
+
+  map_key.SetInt64Value(1);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                 map_key, &map_val));
+  map_val.SetInt64Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                  map_key, &map_val));
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_uint32_uint32"), map_key,
+                                     &map_val);
+  map_val.SetUInt32Value(1);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(1);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
+                                     &map_val);
+  map_val.SetInt32Value(1);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
+                                     &map_val);
+  map_val.SetInt64Value(1);
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
+                                     &map_val);
+  map_val.SetUInt32Value(1);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(1);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
+                                     map_key, &map_val);
+  map_val.SetInt32Value(1);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
+                                     map_key, &map_val);
+  map_val.SetInt64Value(1);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
+                                     &map_val);
+  map_val.SetFloatValue(1.0);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
+                                     &map_val);
+  map_val.SetDoubleValue(1.0);
+
+  map_key.SetBoolValue(true);
+  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
+                                     &map_val);
+  map_val.SetBoolValue(true);
+
+  map_key.SetStringValue("1");
+  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("1");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("1");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
+                                     &map_val);
+  map_val.SetEnumValue(map_enum_baz_->number());
+
+  map_key.SetInt32Value(1);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 1);
+}
+
+void MapReflectionTester::GetMapValueViaMapReflection(
+    Message* message, const std::string& field_name, const MapKey& map_key,
+    MapValueRef* map_val) {
+  const Reflection* reflection = message->GetReflection();
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F(field_name),
+                                                  map_key, map_val));
+}
+
+Message* MapReflectionTester::GetMapEntryViaReflection(
+    Message* message, const std::string& field_name, int index) {
+  const Reflection* reflection = message->GetReflection();
+  return reflection->MutableRepeatedMessage(message, F(field_name), index);
+}
+
+MapIterator MapReflectionTester::MapBegin(Message* message,
+                                          const std::string& field_name) {
+  const Reflection* reflection = message->GetReflection();
+  return reflection->MapBegin(message, F(field_name));
+}
+
+MapIterator MapReflectionTester::MapEnd(Message* message,
+                                        const std::string& field_name) {
+  const Reflection* reflection = message->GetReflection();
+  return reflection->MapEnd(message, F(field_name));
+}
+
+int MapReflectionTester::MapSize(const Message& message,
+                                 const std::string& field_name) {
+  const Reflection* reflection = message.GetReflection();
+  return reflection->MapSize(message, F(field_name));
+}
+
+void MapReflectionTester::ClearMapFieldsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  reflection->ClearField(message, F("map_int32_int32"));
+  reflection->ClearField(message, F("map_int64_int64"));
+  reflection->ClearField(message, F("map_uint32_uint32"));
+  reflection->ClearField(message, F("map_uint64_uint64"));
+  reflection->ClearField(message, F("map_sint32_sint32"));
+  reflection->ClearField(message, F("map_sint64_sint64"));
+  reflection->ClearField(message, F("map_fixed32_fixed32"));
+  reflection->ClearField(message, F("map_fixed64_fixed64"));
+  reflection->ClearField(message, F("map_sfixed32_sfixed32"));
+  reflection->ClearField(message, F("map_sfixed64_sfixed64"));
+  reflection->ClearField(message, F("map_int32_float"));
+  reflection->ClearField(message, F("map_int32_double"));
+  reflection->ClearField(message, F("map_bool_bool"));
+  reflection->ClearField(message, F("map_string_string"));
+  reflection->ClearField(message, F("map_int32_bytes"));
+  reflection->ClearField(message, F("map_int32_enum"));
+  reflection->ClearField(message, F("map_int32_foreign_message"));
+}
+
+void MapReflectionTester::ModifyMapFieldsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  MapValueRef map_val;
+  Message* sub_foreign_message;
+
+  // Modify the second element
+  MapKey map_key;
+  map_key.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                  map_key, &map_val));
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                  map_key, &map_val));
+  map_val.SetInt64Value(2);
+
+  map_key.SetUInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint32_uint32"), map_key, &map_val));
+  map_val.SetUInt32Value(2);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
+                                     &map_val);
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
+                                     &map_val);
+  map_val.SetInt64Value(2);
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
+                                     &map_val);
+  map_val.SetUInt32Value(2);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
+                                     map_key, &map_val);
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
+                                     map_key, &map_val);
+  map_val.SetInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
+                                     &map_val);
+  map_val.SetFloatValue(2.0);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
+                                     &map_val);
+  map_val.SetDoubleValue(2.0);
+
+  map_key.SetBoolValue(true);
+  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
+                                     &map_val);
+  map_val.SetBoolValue(false);
+
+  map_key.SetStringValue("1");
+  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("2");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("2");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
+                                     &map_val);
+  map_val.SetEnumValue(map_enum_foo_->number());
+
+  map_key.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 2);
+}
+
+void MapReflectionTester::RemoveLastMapsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    reflection->RemoveLast(message, field);
+  }
+}
+
+void MapReflectionTester::ReleaseLastMapsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+    Message* released = reflection->ReleaseLast(message, field);
+    ASSERT_TRUE(released != nullptr)
+        << "ReleaseLast returned nullptr for: " << field->name();
+    delete released;
+  }
+}
+
+void MapReflectionTester::SwapMapsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    reflection->SwapElements(message, field, 0, 1);
+  }
+}
+
+void MapReflectionTester::MutableUnknownFieldsOfMapFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message = nullptr;
+
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+}
+
+void MapReflectionTester::ExpectMapFieldsSetViaReflection(
+    const Message& message) {
+  std::string scratch;
+  const Reflection* reflection = message.GetReflection();
+  const Message* sub_message;
+  MapKey map_key;
+  MapValueConstRef map_value_const_ref;
+
+  // -----------------------------------------------------------------
+
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_int32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int64_int64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint32_uint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint64_uint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint32_sint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint64_sint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed32_fixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed64_fixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_float")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_double")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_bool_bool")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_string_string")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_bytes")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_enum")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_foreign_message")));
+
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_int32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_int32_key_);
+        int32_t val = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_int32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_TRUE(
+            reflection->ContainsMapKey(message, F("map_int32_int32"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_int32"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int64_t, int64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int64_int64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i);
+        int64_t key = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_int64_int64_key_);
+        int64_t val = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_int64_int64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt64Value(i);
+        EXPECT_TRUE(
+            reflection->ContainsMapKey(message, F("map_int64_int64"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int64_int64"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<uint32_t, uint32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_uint32_uint32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i);
+        uint32_t key = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_uint32_uint32_key_);
+        uint32_t val = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_uint32_uint32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetUInt32Value(i);
+        EXPECT_TRUE(reflection->ContainsMapKey(message, F("map_uint32_uint32"),
+                                               map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint32_uint32"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetUInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<uint64_t, uint64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_uint64_uint64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i);
+        uint64_t key = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_uint64_uint64_key_);
+        uint64_t val = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_uint64_uint64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetUInt64Value(i);
+        EXPECT_TRUE(reflection->ContainsMapKey(message, F("map_uint64_uint64"),
+                                               map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint64_uint64"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetUInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_sint32_sint32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sint32_sint32_key_);
+        int32_t val = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sint32_sint32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_sint32_sint32"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint32_sint32"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int64_t, int64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_sint64_sint64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i);
+        int64_t key = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sint64_sint64_key_);
+        int64_t val = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sint64_sint64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt64Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_sint64_sint64"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint64_sint64"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<uint32_t, uint32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_fixed32_fixed32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_fixed32_fixed32"), i);
+        uint32_t key = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_fixed32_fixed32_key_);
+        uint32_t val = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_fixed32_fixed32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetUInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_fixed32_fixed32"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(
+            message, F("map_fixed32_fixed32"), map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetUInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<uint64_t, uint64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_fixed64_fixed64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_fixed64_fixed64"), i);
+        uint64_t key = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_fixed64_fixed64_key_);
+        uint64_t val = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_fixed64_fixed64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetUInt64Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_fixed64_fixed64"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(
+            message, F("map_fixed64_fixed64"), map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetUInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(
+              message, F("map_sfixed32_sfixed32"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_sfixed32_sfixed32"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sfixed32_sfixed32_key_);
+        int32_t val = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sfixed32_sfixed32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_sfixed32_sfixed32"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message,
+                                               F("map_sfixed32_sfixed32"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int64_t, int64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(
+              message, F("map_sfixed64_sfixed64"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_sfixed64_sfixed64"), i);
+        int64_t key = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sfixed64_sfixed64_key_);
+        int64_t val = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sfixed64_sfixed64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt64Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_sfixed64_sfixed64"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message,
+                                               F("map_sfixed64_sfixed64"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, float> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_float"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_float"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_float_key_);
+        float val = sub_message->GetReflection()->GetFloat(
+            *sub_message, map_int32_float_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_int32_float"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_float"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetFloatValue(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, double> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_double"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_double"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_double_key_);
+        double val = sub_message->GetReflection()->GetDouble(
+            *sub_message, map_int32_double_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_int32_double"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_double"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetDoubleValue(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<bool, bool> map;
+    map[false] = false;
+    map[true] = true;
+    std::vector<bool> keys = {false, true};
+    std::vector<bool> vals = {false, true};
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_bool_bool"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i);
+        bool key = sub_message->GetReflection()->GetBool(*sub_message,
+                                                         map_bool_bool_key_);
+        bool val = sub_message->GetReflection()->GetBool(*sub_message,
+                                                         map_bool_bool_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetBoolValue(keys[i]);
+        EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_bool_bool"),
+                                                   map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_bool_bool"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetBoolValue(), vals[i]);
+      }
+    }
+  }
+  {
+    std::map<std::string, std::string> map;
+    map["0"] = "0";
+    map["1"] = "1";
+    std::vector<std::string> keys = {"0", "1"};
+    std::vector<std::string> vals = {"0", "1"};
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_string_string"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_string_string"), i);
+        std::string key = sub_message->GetReflection()->GetString(
+            *sub_message, map_string_string_key_);
+        std::string val = sub_message->GetReflection()->GetString(
+            *sub_message, map_string_string_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetStringValue(keys[i]);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_string_string"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_string_string"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetStringValue(), vals[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, std::string> map;
+    map[0] = "0";
+    map[1] = "1";
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_bytes"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_bytes_key_);
+        std::string val = sub_message->GetReflection()->GetString(
+            *sub_message, map_int32_bytes_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_int32_bytes"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_bytes"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetStringValue(), map[i]);
+      }
+    }
+  }
+  {
+    std::map<int32_t, const EnumValueDescriptor*> map;
+    map[0] = map_enum_bar_;
+    map[1] = map_enum_baz_;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(message,
+                                                     F("map_int32_enum"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_enum"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_enum_key_);
+        const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum(
+            *sub_message, map_int32_enum_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_enum"),
+                                                   map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_enum"),
+                                               map_key, &map_value_const_ref));
+        EXPECT_EQ(map_value_const_ref.GetEnumValue(), map[i]->number());
+      }
+    }
+  }
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      const internal::MapFieldBase& map_field =
+          reflection->GetRaw<internal::MapFieldBase>(
+              message, F("map_int32_foreign_message"));
+      if (map_field.IsRepeatedFieldValid()) {
+        // Check with RepeatedField Reflection
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_int32_foreign_message"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_foreign_message_key_);
+        const Message& foreign_message =
+            sub_message->GetReflection()->GetMessage(
+                *sub_message, map_int32_foreign_message_val_);
+        int32_t val = foreign_message.GetReflection()->GetInt32(foreign_message,
+                                                                foreign_c_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        // Check with Map Reflection
+        map_key.SetInt32Value(i);
+        EXPECT_EQ(true, reflection->ContainsMapKey(
+                            message, F("map_int32_foreign_message"), map_key));
+        EXPECT_TRUE(reflection->LookupMapValue(message,
+                                               F("map_int32_foreign_message"),
+                                               map_key, &map_value_const_ref));
+        const Message& foreign_message = map_value_const_ref.GetMessageValue();
+        EXPECT_EQ(foreign_message.GetReflection()->GetInt32(foreign_message,
+                                                            foreign_c_),
+                  map[i]);
+      }
+    }
+  }
+}
+
+void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator(
+    Message* message) {
+  std::string scratch;
+  std::string serialized;
+  const Reflection* reflection = message->GetReflection();
+
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_int32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int64_int64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint32_uint32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint64_uint64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint32_sint32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint64_sint64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed32_fixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed64_fixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed32_sfixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed64_sfixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_float")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_double")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_bool_bool")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_string_string")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_bytes")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_enum")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_foreign_message")));
+
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    int size = 0;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_int32"));
+         iter != reflection->MapEnd(message, F("map_int32_int32"));
+         ++iter, ++size) {
+      // Check const methods do not invalidate map.
+      message->DebugString();
+      message->ShortDebugString();
+      message->SerializeToString(&serialized);
+      message->SpaceUsedLong();
+      message->ByteSizeLong();
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+    EXPECT_EQ(size, 2);
+  }
+  {
+    std::map<int64_t, int64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int64_int64"));
+         iter != reflection->MapEnd(message, F("map_int64_int64")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
+                iter.GetValueRef().GetInt64Value());
+    }
+  }
+  {
+    std::map<uint32_t, uint32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_uint32_uint32"));
+         iter != reflection->MapEnd(message, F("map_uint32_uint32")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
+                iter.GetValueRef().GetUInt32Value());
+    }
+  }
+  {
+    std::map<uint64_t, uint64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_uint64_uint64"));
+         iter != reflection->MapEnd(message, F("map_uint64_uint64")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
+                iter.GetValueRef().GetUInt64Value());
+    }
+  }
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_sint32_sint32"));
+         iter != reflection->MapEnd(message, F("map_sint32_sint32")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+  }
+  {
+    std::map<int64_t, int64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_sint64_sint64"));
+         iter != reflection->MapEnd(message, F("map_sint64_sint64")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
+                iter.GetValueRef().GetInt64Value());
+    }
+  }
+  {
+    std::map<uint32_t, uint32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_fixed32_fixed32"));
+         iter != reflection->MapEnd(message, F("map_fixed32_fixed32"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
+                iter.GetValueRef().GetUInt32Value());
+    }
+  }
+  {
+    std::map<uint64_t, uint64_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_fixed64_fixed64"));
+         iter != reflection->MapEnd(message, F("map_fixed64_fixed64"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
+                iter.GetValueRef().GetUInt64Value());
+    }
+  }
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_sfixed32_sfixed32"));
+         iter != reflection->MapEnd(message, F("map_sfixed32_sfixed32"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+  }
+  {
+    std::map<int32_t, float> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_float"));
+         iter != reflection->MapEnd(message, F("map_int32_float")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetFloatValue());
+    }
+  }
+  {
+    std::map<int32_t, double> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_int32_double"));
+         iter != reflection->MapEnd(message, F("map_int32_double")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetDoubleValue());
+    }
+  }
+  {
+    std::map<bool, bool> map;
+    map[false] = false;
+    map[true] = true;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_bool_bool"));
+         iter != reflection->MapEnd(message, F("map_bool_bool")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetBoolValue()],
+                iter.GetValueRef().GetBoolValue());
+    }
+  }
+  {
+    std::map<std::string, std::string> map;
+    map["0"] = "0";
+    map["1"] = "1";
+    int size = 0;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_string_string"));
+         iter != reflection->MapEnd(message, F("map_string_string"));
+         ++iter, ++size) {
+      // Check const methods do not invalidate map.
+      message->DebugString();
+      message->ShortDebugString();
+      message->SerializeToString(&serialized);
+      message->SpaceUsedLong();
+      message->ByteSizeLong();
+      EXPECT_EQ(map[iter.GetKey().GetStringValue()],
+                iter.GetValueRef().GetStringValue());
+    }
+    EXPECT_EQ(size, 2);
+  }
+  {
+    std::map<int32_t, std::string> map;
+    map[0] = "0";
+    map[1] = "1";
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_bytes"));
+         iter != reflection->MapEnd(message, F("map_int32_bytes")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetStringValue());
+    }
+  }
+  {
+    std::map<int32_t, const EnumValueDescriptor*> map;
+    map[0] = map_enum_bar_;
+    map[1] = map_enum_baz_;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_enum"));
+         iter != reflection->MapEnd(message, F("map_int32_enum")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()]->number(),
+                iter.GetValueRef().GetEnumValue());
+    }
+  }
+  {
+    std::map<int32_t, int32_t> map;
+    map[0] = 0;
+    map[1] = 1;
+    int size = 0;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_int32_foreign_message"));
+         iter != reflection->MapEnd(message, F("map_int32_foreign_message"));
+         ++iter, ++size) {
+      // Check const methods do not invalidate map.
+      message->DebugString();
+      message->ShortDebugString();
+      message->SerializeToString(&serialized);
+      message->SpaceUsedLong();
+      message->ByteSizeLong();
+      const Message& sub_message = iter.GetValueRef().GetMessageValue();
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                sub_message.GetReflection()->GetInt32(sub_message, foreign_c_));
+    }
+    EXPECT_EQ(size, 2);
+  }
+}
+
+void MapReflectionTester::ExpectClearViaReflection(const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+  // Map fields are empty.
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_int32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int64_int64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint32_uint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint64_uint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint32_sint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint64_sint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed32_fixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed64_fixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_float")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_double")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_bool_bool")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_string_string")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_bytes")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_enum")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message")));
+  EXPECT_TRUE(reflection->GetMapData(message, F("map_int32_foreign_message"))
+                  ->IsMapValid());
+}
+
+void MapReflectionTester::ExpectClearViaReflectionIterator(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_int32")) ==
+              reflection->MapEnd(message, F("map_int32_int32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int64_int64")) ==
+              reflection->MapEnd(message, F("map_int64_int64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint32_uint32")) ==
+              reflection->MapEnd(message, F("map_uint32_uint32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint64_uint64")) ==
+              reflection->MapEnd(message, F("map_uint64_uint64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint32_sint32")) ==
+              reflection->MapEnd(message, F("map_sint32_sint32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint64_sint64")) ==
+              reflection->MapEnd(message, F("map_sint64_sint64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed32_fixed32")) ==
+              reflection->MapEnd(message, F("map_fixed32_fixed32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed64_fixed64")) ==
+              reflection->MapEnd(message, F("map_fixed64_fixed64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed32_sfixed32")) ==
+              reflection->MapEnd(message, F("map_sfixed32_sfixed32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed64_sfixed64")) ==
+              reflection->MapEnd(message, F("map_sfixed64_sfixed64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_float")) ==
+              reflection->MapEnd(message, F("map_int32_float")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_double")) ==
+              reflection->MapEnd(message, F("map_int32_double")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_bool_bool")) ==
+              reflection->MapEnd(message, F("map_bool_bool")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_string_string")) ==
+              reflection->MapEnd(message, F("map_string_string")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_bytes")) ==
+              reflection->MapEnd(message, F("map_int32_bytes")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_enum")) ==
+              reflection->MapEnd(message, F("map_int32_enum")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_foreign_message")) ==
+              reflection->MapEnd(message, F("map_int32_foreign_message")));
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/reflection_tester.h b/src/google/protobuf/reflection_tester.h
new file mode 100644
index 0000000..3a2dc81
--- /dev/null
+++ b/src/google/protobuf/reflection_tester.h
@@ -0,0 +1,122 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_REFLECTION_TESTER_H__
+#define GOOGLE_PROTOBUF_REFLECTION_TESTER_H__
+
+#include <google/protobuf/message.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+// Provides APIs to test protocol buffers reflectively.
+class MapReflectionTester {
+ public:
+  // base_descriptor must be a descriptor for TestMap, which is used for
+  // MapReflectionTester to fetch the FieldDescriptors needed to use the
+  // reflection interface.
+  explicit MapReflectionTester(const Descriptor* base_descriptor);
+
+  void SetMapFieldsViaReflection(Message* message);
+  void SetMapFieldsViaMapReflection(Message* message);
+  void ClearMapFieldsViaReflection(Message* message);
+  void ModifyMapFieldsViaReflection(Message* message);
+  void RemoveLastMapsViaReflection(Message* message);
+  void ReleaseLastMapsViaReflection(Message* message);
+  void SwapMapsViaReflection(Message* message);
+  void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message);
+  void ExpectMapFieldsSetViaReflection(const Message& message);
+  void ExpectMapFieldsSetViaReflectionIterator(Message* message);
+  void ExpectClearViaReflection(const Message& message);
+  void ExpectClearViaReflectionIterator(Message* message);
+  void GetMapValueViaMapReflection(Message* message,
+                                   const std::string& field_name,
+                                   const MapKey& map_key, MapValueRef* map_val);
+  Message* GetMapEntryViaReflection(Message* message,
+                                    const std::string& field_name, int index);
+  MapIterator MapBegin(Message* message, const std::string& field_name);
+  MapIterator MapEnd(Message* message, const std::string& field_name);
+  int MapSize(const Message& message, const std::string& field_name);
+
+ private:
+  const FieldDescriptor* F(const std::string& name);
+
+  const Descriptor* base_descriptor_;
+
+  const EnumValueDescriptor* map_enum_bar_;
+  const EnumValueDescriptor* map_enum_baz_;
+  const EnumValueDescriptor* map_enum_foo_;
+
+  const FieldDescriptor* foreign_c_;
+  const FieldDescriptor* map_int32_int32_key_;
+  const FieldDescriptor* map_int32_int32_val_;
+  const FieldDescriptor* map_int64_int64_key_;
+  const FieldDescriptor* map_int64_int64_val_;
+  const FieldDescriptor* map_uint32_uint32_key_;
+  const FieldDescriptor* map_uint32_uint32_val_;
+  const FieldDescriptor* map_uint64_uint64_key_;
+  const FieldDescriptor* map_uint64_uint64_val_;
+  const FieldDescriptor* map_sint32_sint32_key_;
+  const FieldDescriptor* map_sint32_sint32_val_;
+  const FieldDescriptor* map_sint64_sint64_key_;
+  const FieldDescriptor* map_sint64_sint64_val_;
+  const FieldDescriptor* map_fixed32_fixed32_key_;
+  const FieldDescriptor* map_fixed32_fixed32_val_;
+  const FieldDescriptor* map_fixed64_fixed64_key_;
+  const FieldDescriptor* map_fixed64_fixed64_val_;
+  const FieldDescriptor* map_sfixed32_sfixed32_key_;
+  const FieldDescriptor* map_sfixed32_sfixed32_val_;
+  const FieldDescriptor* map_sfixed64_sfixed64_key_;
+  const FieldDescriptor* map_sfixed64_sfixed64_val_;
+  const FieldDescriptor* map_int32_float_key_;
+  const FieldDescriptor* map_int32_float_val_;
+  const FieldDescriptor* map_int32_double_key_;
+  const FieldDescriptor* map_int32_double_val_;
+  const FieldDescriptor* map_bool_bool_key_;
+  const FieldDescriptor* map_bool_bool_val_;
+  const FieldDescriptor* map_string_string_key_;
+  const FieldDescriptor* map_string_string_val_;
+  const FieldDescriptor* map_int32_bytes_key_;
+  const FieldDescriptor* map_int32_bytes_val_;
+  const FieldDescriptor* map_int32_enum_key_;
+  const FieldDescriptor* map_int32_enum_val_;
+  const FieldDescriptor* map_int32_foreign_message_key_;
+  const FieldDescriptor* map_int32_foreign_message_val_;
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REFLECTION_TESTER_H__
diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc
index addd26ce..501575b 100644
--- a/src/google/protobuf/repeated_field.cc
+++ b/src/google/protobuf/repeated_field.cc
@@ -58,10 +58,10 @@
   Arena* arena = GetArena();
   new_size = std::max(internal::kRepeatedFieldLowerClampLimit,
                       std::max(total_size_ * 2, new_size));
-  GOOGLE_CHECK_LE(
-      static_cast<int64>(new_size),
-      static_cast<int64>((std::numeric_limits<size_t>::max() - kRepHeaderSize) /
-                         sizeof(old_rep->elements[0])))
+  GOOGLE_CHECK_LE(static_cast<int64_t>(new_size),
+           static_cast<int64_t>(
+               (std::numeric_limits<size_t>::max() - kRepHeaderSize) /
+               sizeof(old_rep->elements[0])))
       << "Requested size is too large to fit into size_t.";
   size_t bytes = kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size;
   if (arena == NULL) {
@@ -135,10 +135,10 @@
 
 
 template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<bool>;
-template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<int32>;
-template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<uint32>;
-template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<int64>;
-template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<uint64>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<int32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<uint32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<int64_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<uint64_t>;
 template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<float>;
 template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<double>;
 template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedPtrField<std::string>;
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index c8fe933..0541008 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -144,15 +144,15 @@
                                       q + sizeof(reg_type));                 \
   }
 
-PROTO_MEMSWAP_DEF_SIZE(uint8, 2)
-PROTO_MEMSWAP_DEF_SIZE(uint16, 4)
-PROTO_MEMSWAP_DEF_SIZE(uint32, 8)
+PROTO_MEMSWAP_DEF_SIZE(uint8_t, 2)
+PROTO_MEMSWAP_DEF_SIZE(uint16_t, 4)
+PROTO_MEMSWAP_DEF_SIZE(uint32_t, 8)
 
 #ifdef __SIZEOF_INT128__
-PROTO_MEMSWAP_DEF_SIZE(uint64, 16)
+PROTO_MEMSWAP_DEF_SIZE(uint64_t, 16)
 PROTO_MEMSWAP_DEF_SIZE(__uint128_t, (1u << 31))
 #else
-PROTO_MEMSWAP_DEF_SIZE(uint64, (1u << 31))
+PROTO_MEMSWAP_DEF_SIZE(uint64_t, (1u << 31))
 #endif
 
 #undef PROTO_MEMSWAP_DEF_SIZE
@@ -1089,18 +1089,18 @@
   // It is also useful in legacy code that uses temporary ownership to avoid
   // copies. Example:
   //   RepeatedPtrField<T> temp_field;
-  //   temp_field.AddAllocated(new T);
+  //   temp_field.UnsafeArenaAddAllocated(new T);
   //   ... // Do something with temp_field
-  //   temp_field.ExtractSubrange(0, temp_field.size(), nullptr);
+  //   temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr);
   // If you put temp_field on the arena this fails, because the ownership
   // transfers to the arena at the "AddAllocated" call and is not released
   // anymore causing a double delete. UnsafeArenaAddAllocated prevents this.
   void UnsafeArenaAddAllocated(Element* value);
 
-  // Remove the last element and return it.  Works only when operating on an
-  // arena. The returned pointer is to the original object in the arena, hence
-  // has the arena's lifetime.
-  // Requires:  current_size_ > 0
+  // Remove the last element and return it.  Unlike ReleaseLast, the returned
+  // pointer is always to the original object.  This may be in an arena, and
+  // therefore have the arena's lifetime.
+  // Requires: current_size_ > 0
   Element* UnsafeArenaReleaseLast();
 
   // Extract elements with indices in the range "[start .. start+num-1]".
@@ -1120,10 +1120,10 @@
   // UnsafeArenaExtractSubrange().
   void ExtractSubrange(int start, int num, Element** elements);
 
-  // Identical to ExtractSubrange() described above, except that when this
-  // repeated field is on an arena, no object copies are performed. Instead, the
-  // raw object pointers are returned. Thus, if on an arena, the returned
-  // objects must not be freed, because they will not be heap-allocated objects.
+  // Identical to ExtractSubrange() described above, except that no object
+  // copies are ever performed. Instead, the raw object pointers are returned.
+  // Thus, if on an arena, the returned objects must not be freed, because they
+  // will not be heap-allocated objects.
   void UnsafeArenaExtractSubrange(int start, int num, Element** elements);
 
   // When elements are removed by calls to RemoveLast() or Clear(), they
@@ -1362,7 +1362,7 @@
 
 template <typename Element>
 inline void RepeatedField<Element>::Add(const Element& value) {
-  uint32 size = current_size_;
+  uint32_t size = current_size_;
   if (static_cast<int>(size) == total_size_) {
     // value could reference an element of the array. Reserving new space will
     // invalidate the reference. So we must make a copy first.
@@ -1377,7 +1377,7 @@
 
 template <typename Element>
 inline Element* RepeatedField<Element>::Add() {
-  uint32 size = current_size_;
+  uint32_t size = current_size_;
   if (static_cast<int>(size) == total_size_) Reserve(total_size_ + 1);
   auto ptr = &elements()[size];
   current_size_ = size + 1;
@@ -1624,7 +1624,7 @@
   // this, since Element is supposed to be POD, but a previous version of this
   // code allocated storage with "new Element[size]" and some code uses
   // RepeatedField with non-POD types, relying on constructor invocation. If
-  // Element has a trivial constructor (e.g., int32), gcc (tested with -O2)
+  // Element has a trivial constructor (e.g., int32_t), gcc (tested with -O2)
   // completely removes this loop because the loop body is empty, so this has no
   // effect unless its side-effects are required for correctness.
   // Note that we do this before MoveArray() below because Element's copy
@@ -1978,9 +1978,7 @@
     // Pass value_arena and my_arena to avoid duplicate virtual call (value) or
     // load (mine).
     typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) {
-#ifdef PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
   GOOGLE_DCHECK(value_arena == nullptr || value_arena == my_arena);
-#endif  // PROTOBUF_INTERNAL_USE_MUST_USE_RESULT
   // Ensure that either the value is in the same arena, or if not, we do the
   // appropriate thing: Own() it (if it's on heap and we're in an arena) or copy
   // it to our arena/heap (otherwise).
@@ -2285,11 +2283,9 @@
 
   if (num == 0) return;
 
-#ifdef PROTOBUF_MUST_USE_EXTRACT_RESULT
   GOOGLE_DCHECK_NE(elements, nullptr)
       << "Releasing elements without transferring ownership is an unsafe "
          "operation.  Use UnsafeArenaExtractSubrange.";
-#endif
   if (elements == nullptr) {
     CloseGap(start, num);
     return;
@@ -2906,9 +2902,9 @@
 // This is slightly faster if that matters. It is also useful in legacy code
 // that uses temporary ownership to avoid copies. Example:
 //   RepeatedPtrField<T> temp_field;
-//   temp_field.AddAllocated(new T);
+//   temp_field.UnsafeArenaAddAllocated(new T);
 //   ... // Do something with temp_field
-//   temp_field.ExtractSubrange(0, temp_field.size(), nullptr);
+//   temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr);
 // If you put temp_field on the arena this fails, because the ownership
 // transfers to the arena at the "AddAllocated" call and is not released anymore
 // causing a double delete. Using UnsafeArenaAddAllocated prevents this.
@@ -2922,10 +2918,10 @@
 
 // Extern declarations of common instantiations to reduce library bloat.
 extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<bool>;
-extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<int32>;
-extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<uint32>;
-extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<int64>;
-extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<uint64>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<int32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<uint32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<int64_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<uint64_t>;
 extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<float>;
 extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<double>;
 extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
index 46b9e6d..429a63a 100644
--- a/src/google/protobuf/repeated_field_unittest.cc
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -1128,14 +1128,13 @@
 
   EXPECT_EQ(field.Add(),
             original);  // Should return same string for reuse.
-
-  EXPECT_EQ(field.ReleaseLast(), original);  // We take ownership.
+  EXPECT_EQ(field.UnsafeArenaReleaseLast(), original);  // We take ownership.
   EXPECT_EQ(field.ClearedCount(), 0);
 
   EXPECT_NE(field.Add(), original);  // Should NOT return the same string.
   EXPECT_EQ(field.ClearedCount(), 0);
 
-  field.AddAllocated(original);  // Give ownership back.
+  field.UnsafeArenaAddAllocated(original);  // Give ownership back.
   EXPECT_EQ(field.ClearedCount(), 0);
   EXPECT_EQ(field.Mutable(1), original);
 
@@ -1514,7 +1513,9 @@
           std::vector<std::string*> subject;
 
           // Create an array with "sz" elements and "extra" cleared elements.
-          RepeatedPtrField<std::string> field;
+          // Use an arena to avoid copies from debug-build stability checks.
+          Arena arena;
+          RepeatedPtrField<std::string> field(&arena);
           for (int i = 0; i < sz + extra; ++i) {
             subject.push_back(new std::string());
             field.AddAllocated(subject[i]);
@@ -1534,7 +1535,7 @@
 
           // Were the removed elements extracted into the catcher array?
           for (int i = 0; i < num; ++i)
-            EXPECT_EQ(catcher[i], subject[start + i]);
+            EXPECT_EQ(*catcher[i], *subject[start + i]);
           EXPECT_EQ(NULL, catcher[num]);
 
           // Does the resulting array contain the right values?
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index 1181ba8..14620c3 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -40,10 +40,11 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::SourceContext, file_name_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::SourceContext)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::SourceContext)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -148,28 +149,29 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.SourceContext.file_name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -212,13 +214,7 @@
         this->_internal_file_name());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData SourceContext::_class_data_ = {
@@ -227,8 +223,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceContext::GetClassData() const { return &_class_data_; }
 
-void SourceContext::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void SourceContext::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<SourceContext *>(to)->MergeFrom(
       static_cast<const SourceContext &>(from));
 }
@@ -259,11 +255,13 @@
 
 void SourceContext::InternalSwap(SourceContext* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &file_name_, GetArenaForAllocation(),
-      &other->file_name_, other->GetArenaForAllocation()
+      &file_name_, lhs_arena,
+      &other->file_name_, rhs_arena
   );
 }
 
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index 8e49a7b..26e665b 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -142,7 +142,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const SourceContext& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/string_member_robber.h b/src/google/protobuf/string_member_robber.h
new file mode 100644
index 0000000..a4c1051
--- /dev/null
+++ b/src/google/protobuf/string_member_robber.h
@@ -0,0 +1,38 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_STRING_MEMBER_ROBBER_H__
+#define GOOGLE_PROTOBUF_STRING_MEMBER_ROBBER_H__
+
+#include <string>
+#include <type_traits>
+
+
+#endif  // GOOGLE_PROTOBUF_STRING_MEMBER_ROBBER_H__
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index a561d2b..766d99e 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -75,6 +75,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, key_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, value_),
   0,
@@ -84,12 +85,14 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Struct, fields_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Value, _internal_metadata_),
   ~0u,  // no _extensions_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Value, _oneof_case_[0]),
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag,
   ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag,
   ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag,
@@ -102,13 +105,14 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::ListValue, values_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, 7, sizeof(PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse)},
-  { 9, -1, sizeof(PROTOBUF_NAMESPACE_ID::Struct)},
-  { 15, -1, sizeof(PROTOBUF_NAMESPACE_ID::Value)},
-  { 27, -1, sizeof(PROTOBUF_NAMESPACE_ID::ListValue)},
+  { 0, 8, -1, sizeof(PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse)},
+  { 10, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Struct)},
+  { 17, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Value)},
+  { 30, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::ListValue)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -255,28 +259,29 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -353,13 +358,7 @@
     total_size += Struct_FieldsEntry_DoNotUse::Funcs::ByteSizeLong(it->first, it->second);
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Struct::_class_data_ = {
@@ -368,8 +367,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Struct::GetClassData() const { return &_class_data_; }
 
-void Struct::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Struct::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Struct *>(to)->MergeFrom(
       static_cast<const Struct &>(from));
 }
@@ -588,14 +587,16 @@
           ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
           _internal_set_null_value(static_cast<PROTOBUF_NAMESPACE_ID::NullValue>(val));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // double number_value = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 17)) {
           _internal_set_number_value(::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<double>(ptr));
           ptr += sizeof(double);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // string string_value = 3;
       case 3:
@@ -604,49 +605,53 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Value.string_value"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // bool bool_value = 4;
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 32)) {
           _internal_set_bool_value(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.Struct struct_value = 5;
       case 5:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 42)) {
           ptr = ctx->ParseMessage(_internal_mutable_struct_value(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.ListValue list_value = 6;
       case 6:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 50)) {
           ptr = ctx->ParseMessage(_internal_mutable_list_value(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -759,13 +764,7 @@
       break;
     }
   }
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Value::_class_data_ = {
@@ -774,8 +773,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Value::GetClassData() const { return &_class_data_; }
 
-void Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Value *>(to)->MergeFrom(
       static_cast<const Value &>(from));
 }
@@ -916,28 +915,29 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -978,13 +978,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ListValue::_class_data_ = {
@@ -993,8 +987,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ListValue::GetClassData() const { return &_class_data_; }
 
-void ListValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void ListValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<ListValue *>(to)->MergeFrom(
       static_cast<const ListValue &>(from));
 }
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index a9c3eba..2d364f9 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -207,7 +207,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Struct& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -369,7 +369,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Value& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -619,7 +619,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const ListValue& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/stubs/stl_util.h b/src/google/protobuf/stubs/stl_util.h
index d01f9ec..3bc1dbf 100644
--- a/src/google/protobuf/stubs/stl_util.h
+++ b/src/google/protobuf/stubs/stl_util.h
@@ -35,6 +35,8 @@
 
 #include <google/protobuf/stubs/common.h>
 
+#include <algorithm>
+
 namespace google {
 namespace protobuf {
 
@@ -48,6 +50,18 @@
   s->resize(new_size);
 }
 
+// As above, but we make sure to follow amortized growth in which we always
+// increase the capacity by at least a constant factor >1.
+inline void STLStringResizeUninitializedAmortized(std::string* s,
+                                                  size_t new_size) {
+  const size_t cap = s->capacity();
+  if (new_size > cap) {
+    // Make sure to always grow by at least a factor of 2x.
+    s->reserve(std::max(new_size, 2 * cap));
+  }
+  STLStringResizeUninitialized(s, new_size);
+}
+
 // Return a mutable char* pointing to a string's internal buffer,
 // which may not be null-terminated. Writing through this pointer will
 // modify the string.
diff --git a/src/google/protobuf/test_messages_proto2.proto b/src/google/protobuf/test_messages_proto2.proto
index 1d0c33f..d064fbb 100644
--- a/src/google/protobuf/test_messages_proto2.proto
+++ b/src/google/protobuf/test_messages_proto2.proto
@@ -264,3 +264,13 @@
   optional bool optional_bool = 1006;
   repeated int32 repeated_int32 = 1011;
 }
+
+message NullHypothesisProto2 {
+}
+
+message EnumOnlyProto2 {
+  enum Bool {
+    kFalse = 0;
+    kTrue = 1;
+  }
+}
diff --git a/src/google/protobuf/test_messages_proto3.proto b/src/google/protobuf/test_messages_proto3.proto
index 4e409dc..278ee4f 100644
--- a/src/google/protobuf/test_messages_proto3.proto
+++ b/src/google/protobuf/test_messages_proto3.proto
@@ -277,3 +277,13 @@
   FOREIGN_BAR = 1;
   FOREIGN_BAZ = 2;
 }
+
+message NullHypothesisProto3 {
+}
+
+message EnumOnlyProto3 {
+  enum Bool {
+    kFalse = 0;
+    kTrue = 1;
+  }
+}
diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h
index 819f6d8..3ec3aa7 100644
--- a/src/google/protobuf/test_util.h
+++ b/src/google/protobuf/test_util.h
@@ -1204,7 +1204,6 @@
       "optional_import_message",
   };
   for (int i = 0; i < GOOGLE_ARRAYSIZE(fields); i++) {
-    const Message& sub_message = reflection->GetMessage(*message, F(fields[i]));
     Message* released = reflection->ReleaseMessage(message, F(fields[i]));
     switch (expected_release_state) {
       case IS_NULL:
@@ -1212,12 +1211,6 @@
         break;
       case NOT_NULL:
         EXPECT_TRUE(released != nullptr);
-        if (Arena::InternalHelper<Message>::GetArenaForAllocation(message) ==
-            nullptr) {
-          // released message must be same as sub_message if source message is
-          // not on arena.
-          EXPECT_EQ(&sub_message, released);
-        }
         break;
       case CAN_BE_NULL:
         break;
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 449a5a6..13bf91c 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -129,8 +129,8 @@
 // ===========================================================================
 // Implementation of the parse information tree class.
 void TextFormat::ParseInfoTree::RecordLocation(
-    const FieldDescriptor* field, TextFormat::ParseLocation location) {
-  locations_[field].push_back(location);
+    const FieldDescriptor* field, TextFormat::ParseLocationRange range) {
+  locations_[field].push_back(range);
 }
 
 TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::CreateNested(
@@ -155,17 +155,18 @@
   }
 }
 
-TextFormat::ParseLocation TextFormat::ParseInfoTree::GetLocation(
+TextFormat::ParseLocationRange TextFormat::ParseInfoTree::GetLocationRange(
     const FieldDescriptor* field, int index) const {
   CheckFieldIndex(field, index);
   if (index == -1) {
     index = 0;
   }
 
-  const std::vector<TextFormat::ParseLocation>* locations =
+  const std::vector<TextFormat::ParseLocationRange>* locations =
       FindOrNull(locations_, field);
-  if (locations == nullptr || index >= static_cast<int64>(locations->size())) {
-    return TextFormat::ParseLocation();
+  if (locations == nullptr ||
+      index >= static_cast<int64_t>(locations->size())) {
+    return TextFormat::ParseLocationRange();
   }
 
   return (*locations)[index];
@@ -179,7 +180,7 @@
   }
 
   auto it = nested_.find(field);
-  if (it == nested_.end() || index >= static_cast<int64>(it->second.size())) {
+  if (it == nested_.end() || index >= static_cast<int64_t>(it->second.size())) {
     return nullptr;
   }
 
@@ -458,7 +459,7 @@
     } else {
       DO(ConsumeIdentifier(&field_name));
 
-      int32 field_number;
+      int32_t field_number;
       if (allow_field_number_ && safe_strto32(field_name, &field_number)) {
         if (descriptor->IsExtensionNumber(field_number)) {
           field = finder_
@@ -610,8 +611,12 @@
     // If a parse info tree exists, add the location for the parsed
     // field.
     if (parse_info_tree_ != nullptr) {
+      int end_line = tokenizer_.previous().line;
+      int end_column = tokenizer_.previous().end_column;
+
       RecordLocation(parse_info_tree_, field,
-                     ParseLocation(start_line, start_column));
+                     ParseLocationRange(ParseLocation(start_line, start_column),
+                                        ParseLocation(end_line, end_column)));
     }
 
     return true;
@@ -716,28 +721,28 @@
 
     switch (field->cpp_type()) {
       case FieldDescriptor::CPPTYPE_INT32: {
-        int64 value;
+        int64_t value;
         DO(ConsumeSignedInteger(&value, kint32max));
-        SET_FIELD(Int32, static_cast<int32>(value));
+        SET_FIELD(Int32, static_cast<int32_t>(value));
         break;
       }
 
       case FieldDescriptor::CPPTYPE_UINT32: {
-        uint64 value;
+        uint64_t value;
         DO(ConsumeUnsignedInteger(&value, kuint32max));
-        SET_FIELD(UInt32, static_cast<uint32>(value));
+        SET_FIELD(UInt32, static_cast<uint32_t>(value));
         break;
       }
 
       case FieldDescriptor::CPPTYPE_INT64: {
-        int64 value;
+        int64_t value;
         DO(ConsumeSignedInteger(&value, kint64max));
         SET_FIELD(Int64, value);
         break;
       }
 
       case FieldDescriptor::CPPTYPE_UINT64: {
-        uint64 value;
+        uint64_t value;
         DO(ConsumeUnsignedInteger(&value, kuint64max));
         SET_FIELD(UInt64, value);
         break;
@@ -766,7 +771,7 @@
 
       case FieldDescriptor::CPPTYPE_BOOL: {
         if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
-          uint64 value;
+          uint64_t value;
           DO(ConsumeUnsignedInteger(&value, 1));
           SET_FIELD(Bool, value);
         } else {
@@ -787,7 +792,7 @@
 
       case FieldDescriptor::CPPTYPE_ENUM: {
         std::string value;
-        int64 int_value = kint64max;
+        int64_t int_value = kint64max;
         const EnumDescriptor* enum_type = field->enum_type();
         const EnumValueDescriptor* enum_value = nullptr;
 
@@ -996,9 +1001,9 @@
     return true;
   }
 
-  // Consumes a uint64 and saves its value in the value parameter.
+  // Consumes a uint64_t and saves its value in the value parameter.
   // Returns false if the token is not of type INTEGER.
-  bool ConsumeUnsignedInteger(uint64* value, uint64 max_value) {
+  bool ConsumeUnsignedInteger(uint64_t* value, uint64_t max_value) {
     if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
       ReportError("Expected integer, got: " + tokenizer_.current().text);
       return false;
@@ -1014,12 +1019,12 @@
     return true;
   }
 
-  // Consumes an int64 and saves its value in the value parameter.
+  // Consumes an int64_t and saves its value in the value parameter.
   // Note that since the tokenizer does not support negative numbers,
   // we actually may consume an additional token (for the minus sign) in this
   // method. Returns false if the token is not an integer
   // (signed or otherwise).
-  bool ConsumeSignedInteger(int64* value, uint64 max_value) {
+  bool ConsumeSignedInteger(int64_t* value, uint64_t max_value) {
     bool negative = false;
 
     if (TryConsume("-")) {
@@ -1029,18 +1034,18 @@
       ++max_value;
     }
 
-    uint64 unsigned_value;
+    uint64_t unsigned_value;
 
     DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
 
     if (negative) {
-      if ((static_cast<uint64>(kint64max) + 1) == unsigned_value) {
+      if ((static_cast<uint64_t>(kint64max) + 1) == unsigned_value) {
         *value = kint64min;
       } else {
-        *value = -static_cast<int64>(unsigned_value);
+        *value = -static_cast<int64_t>(unsigned_value);
       }
     } else {
-      *value = static_cast<int64>(unsigned_value);
+      *value = static_cast<int64_t>(unsigned_value);
     }
 
     return true;
@@ -1048,7 +1053,7 @@
 
   // Consumes a double and saves its value in the value parameter.
   // Accepts decimal numbers only, rejects hex or oct numbers.
-  bool ConsumeUnsignedDecimalAsDouble(double* value, uint64 max_value) {
+  bool ConsumeUnsignedDecimalAsDouble(double* value, uint64_t max_value) {
     if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
       ReportError("Expected integer, got: " + tokenizer_.current().text);
       return false;
@@ -1060,7 +1065,7 @@
       return false;
     }
 
-    uint64 uint64_value;
+    uint64_t uint64_value;
     if (io::Tokenizer::ParseInteger(text, max_value, &uint64_value)) {
       *value = static_cast<double>(uint64_value);
     } else {
@@ -1352,7 +1357,7 @@
       if (failed_) return;
     }
 
-    while (static_cast<int64>(size) > buffer_size_) {
+    while (static_cast<int64_t>(size) > buffer_size_) {
       // Data exceeds space in the buffer.  Copy what we can and request a
       // new buffer.
       if (buffer_size_ > 0) {
@@ -1509,8 +1514,9 @@
   if (input.size() > INT_MAX) {
     error_collector->AddError(
         -1, 0,
-        StrCat("Input size too large: ", static_cast<int64>(input.size()),
-                     " bytes", " > ", INT_MAX, " bytes."));
+        StrCat(
+            "Input size too large: ", static_cast<int64_t>(input.size()),
+            " bytes", " > ", INT_MAX, " bytes."));
     return false;
   }
   return true;
@@ -1661,16 +1667,16 @@
 std::string TextFormat::FieldValuePrinter::PrintBool(bool val) const {
   FORWARD_IMPL(PrintBool, val);
 }
-std::string TextFormat::FieldValuePrinter::PrintInt32(int32 val) const {
+std::string TextFormat::FieldValuePrinter::PrintInt32(int32_t val) const {
   FORWARD_IMPL(PrintInt32, val);
 }
-std::string TextFormat::FieldValuePrinter::PrintUInt32(uint32 val) const {
+std::string TextFormat::FieldValuePrinter::PrintUInt32(uint32_t val) const {
   FORWARD_IMPL(PrintUInt32, val);
 }
-std::string TextFormat::FieldValuePrinter::PrintInt64(int64 val) const {
+std::string TextFormat::FieldValuePrinter::PrintInt64(int64_t val) const {
   FORWARD_IMPL(PrintInt64, val);
 }
-std::string TextFormat::FieldValuePrinter::PrintUInt64(uint64 val) const {
+std::string TextFormat::FieldValuePrinter::PrintUInt64(uint64_t val) const {
   FORWARD_IMPL(PrintUInt64, val);
 }
 std::string TextFormat::FieldValuePrinter::PrintFloat(float val) const {
@@ -1688,7 +1694,7 @@
   return PrintString(val);
 }
 std::string TextFormat::FieldValuePrinter::PrintEnum(
-    int32 val, const std::string& name) const {
+    int32_t val, const std::string& name) const {
   FORWARD_IMPL(PrintEnum, val, name);
 }
 std::string TextFormat::FieldValuePrinter::PrintFieldName(
@@ -1721,19 +1727,19 @@
   }
 }
 void TextFormat::FastFieldValuePrinter::PrintInt32(
-    int32 val, BaseTextGenerator* generator) const {
+    int32_t val, BaseTextGenerator* generator) const {
   generator->PrintString(StrCat(val));
 }
 void TextFormat::FastFieldValuePrinter::PrintUInt32(
-    uint32 val, BaseTextGenerator* generator) const {
+    uint32_t val, BaseTextGenerator* generator) const {
   generator->PrintString(StrCat(val));
 }
 void TextFormat::FastFieldValuePrinter::PrintInt64(
-    int64 val, BaseTextGenerator* generator) const {
+    int64_t val, BaseTextGenerator* generator) const {
   generator->PrintString(StrCat(val));
 }
 void TextFormat::FastFieldValuePrinter::PrintUInt64(
-    uint64 val, BaseTextGenerator* generator) const {
+    uint64_t val, BaseTextGenerator* generator) const {
   generator->PrintString(StrCat(val));
 }
 void TextFormat::FastFieldValuePrinter::PrintFloat(
@@ -1745,7 +1751,7 @@
   generator->PrintString(!std::isnan(val) ? SimpleDtoa(val) : "nan");
 }
 void TextFormat::FastFieldValuePrinter::PrintEnum(
-    int32 val, const std::string& name, BaseTextGenerator* generator) const {
+    int32_t val, const std::string& name, BaseTextGenerator* generator) const {
   generator->PrintString(name);
 }
 
@@ -1820,19 +1826,19 @@
                  TextFormat::BaseTextGenerator* generator) const override {
     generator->PrintString(delegate_->PrintBool(val));
   }
-  void PrintInt32(int32 val,
+  void PrintInt32(int32_t val,
                   TextFormat::BaseTextGenerator* generator) const override {
     generator->PrintString(delegate_->PrintInt32(val));
   }
-  void PrintUInt32(uint32 val,
+  void PrintUInt32(uint32_t val,
                    TextFormat::BaseTextGenerator* generator) const override {
     generator->PrintString(delegate_->PrintUInt32(val));
   }
-  void PrintInt64(int64 val,
+  void PrintInt64(int64_t val,
                   TextFormat::BaseTextGenerator* generator) const override {
     generator->PrintString(delegate_->PrintInt64(val));
   }
-  void PrintUInt64(uint64 val,
+  void PrintUInt64(uint64_t val,
                    TextFormat::BaseTextGenerator* generator) const override {
     generator->PrintString(delegate_->PrintUInt64(val));
   }
@@ -1852,7 +1858,7 @@
                   TextFormat::BaseTextGenerator* generator) const override {
     generator->PrintString(delegate_->PrintBytes(val));
   }
-  void PrintEnum(int32 val, const std::string& name,
+  void PrintEnum(int32_t val, const std::string& name,
                  TextFormat::BaseTextGenerator* generator) const override {
     generator->PrintString(delegate_->PrintEnum(val, name));
   }
@@ -2155,23 +2161,23 @@
         return first < second;
       }
       case FieldDescriptor::CPPTYPE_INT32: {
-        int32 first = reflection->GetInt32(*a, field_);
-        int32 second = reflection->GetInt32(*b, field_);
+        int32_t first = reflection->GetInt32(*a, field_);
+        int32_t second = reflection->GetInt32(*b, field_);
         return first < second;
       }
       case FieldDescriptor::CPPTYPE_INT64: {
-        int64 first = reflection->GetInt64(*a, field_);
-        int64 second = reflection->GetInt64(*b, field_);
+        int64_t first = reflection->GetInt64(*a, field_);
+        int64_t second = reflection->GetInt64(*b, field_);
         return first < second;
       }
       case FieldDescriptor::CPPTYPE_UINT32: {
-        uint32 first = reflection->GetUInt32(*a, field_);
-        uint32 second = reflection->GetUInt32(*b, field_);
+        uint32_t first = reflection->GetUInt32(*a, field_);
+        uint32_t second = reflection->GetUInt32(*b, field_);
         return first < second;
       }
       case FieldDescriptor::CPPTYPE_UINT64: {
-        uint64 first = reflection->GetUInt64(*a, field_);
-        uint64 second = reflection->GetUInt64(*b, field_);
+        uint64_t first = reflection->GetUInt64(*a, field_);
+        uint64_t second = reflection->GetUInt64(*b, field_);
         return first < second;
       }
       case FieldDescriptor::CPPTYPE_STRING: {
@@ -2585,7 +2591,7 @@
         // budget when we attempt to parse the data. UnknownFieldSet parsing is
         // recursive because of groups.
         io::CodedInputStream input_stream(
-            reinterpret_cast<const uint8*>(value.data()), value.size());
+            reinterpret_cast<const uint8_t*>(value.data()), value.size());
         input_stream.SetRecursionLimit(recursion_budget);
         UnknownFieldSet embedded_unknown_fields;
         if (!value.empty() && recursion_budget > 0 &&
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index ce4d1f4..4831de6 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -126,17 +126,17 @@
     FastFieldValuePrinter();
     virtual ~FastFieldValuePrinter();
     virtual void PrintBool(bool val, BaseTextGenerator* generator) const;
-    virtual void PrintInt32(int32 val, BaseTextGenerator* generator) const;
-    virtual void PrintUInt32(uint32 val, BaseTextGenerator* generator) const;
-    virtual void PrintInt64(int64 val, BaseTextGenerator* generator) const;
-    virtual void PrintUInt64(uint64 val, BaseTextGenerator* generator) const;
+    virtual void PrintInt32(int32_t val, BaseTextGenerator* generator) const;
+    virtual void PrintUInt32(uint32_t val, BaseTextGenerator* generator) const;
+    virtual void PrintInt64(int64_t val, BaseTextGenerator* generator) const;
+    virtual void PrintUInt64(uint64_t val, BaseTextGenerator* generator) const;
     virtual void PrintFloat(float val, BaseTextGenerator* generator) const;
     virtual void PrintDouble(double val, BaseTextGenerator* generator) const;
     virtual void PrintString(const std::string& val,
                              BaseTextGenerator* generator) const;
     virtual void PrintBytes(const std::string& val,
                             BaseTextGenerator* generator) const;
-    virtual void PrintEnum(int32 val, const std::string& name,
+    virtual void PrintEnum(int32_t val, const std::string& name,
                            BaseTextGenerator* generator) const;
     virtual void PrintFieldName(const Message& message, int field_index,
                                 int field_count, const Reflection* reflection,
@@ -171,15 +171,15 @@
     FieldValuePrinter();
     virtual ~FieldValuePrinter();
     virtual std::string PrintBool(bool val) const;
-    virtual std::string PrintInt32(int32 val) const;
-    virtual std::string PrintUInt32(uint32 val) const;
-    virtual std::string PrintInt64(int64 val) const;
-    virtual std::string PrintUInt64(uint64 val) const;
+    virtual std::string PrintInt32(int32_t val) const;
+    virtual std::string PrintUInt32(uint32_t val) const;
+    virtual std::string PrintInt64(int64_t val) const;
+    virtual std::string PrintUInt64(uint64_t val) const;
     virtual std::string PrintFloat(float val) const;
     virtual std::string PrintDouble(double val) const;
     virtual std::string PrintString(const std::string& val) const;
     virtual std::string PrintBytes(const std::string& val) const;
-    virtual std::string PrintEnum(int32 val, const std::string& name) const;
+    virtual std::string PrintEnum(int32_t val, const std::string& name) const;
     virtual std::string PrintFieldName(const Message& message,
                                        const Reflection* reflection,
                                        const FieldDescriptor* field) const;
@@ -341,7 +341,7 @@
     // property of TextFormat::Printer.  That is, from the printed message, we
     // cannot fully recover the original string field any more.
     void SetTruncateStringFieldLongerThan(
-        const int64 truncate_string_field_longer_than) {
+        const int64_t truncate_string_field_longer_than) {
       truncate_string_field_longer_than_ = truncate_string_field_longer_than;
     }
 
@@ -431,7 +431,7 @@
     bool hide_unknown_fields_;
     bool print_message_fields_in_index_order_;
     bool expand_any_;
-    int64 truncate_string_field_longer_than_;
+    int64_t truncate_string_field_longer_than_;
 
     std::unique_ptr<const FastFieldValuePrinter> default_field_value_printer_;
     typedef std::map<const FieldDescriptor*,
@@ -488,6 +488,16 @@
         : line(line_param), column(column_param) {}
   };
 
+  // A range of locations in the parsed text, including `start` and excluding
+  // `end`.
+  struct ParseLocationRange {
+    ParseLocation start;
+    ParseLocation end;
+    ParseLocationRange() : start(), end() {}
+    ParseLocationRange(ParseLocation start_param, ParseLocation end_param)
+        : start(start_param), end(end_param) {}
+  };
+
   // Data structure which is populated with the locations of each field
   // value parsed from the text.
   class PROTOBUF_EXPORT ParseInfoTree {
@@ -496,10 +506,18 @@
     ParseInfoTree(const ParseInfoTree&) = delete;
     ParseInfoTree& operator=(const ParseInfoTree&) = delete;
 
-    // Returns the parse location for index-th value of the field in the parsed
-    // text. If none exists, returns a location with line = -1. Index should be
-    // -1 for not-repeated fields.
-    ParseLocation GetLocation(const FieldDescriptor* field, int index) const;
+    // Returns the parse location range for index-th value of the field in
+    // the parsed text. If none exists, returns a location with start and end
+    // line -1. Index should be -1 for not-repeated fields.
+    ParseLocationRange GetLocationRange(const FieldDescriptor* field,
+                                        int index) const;
+
+    // Returns the starting parse location for index-th value of the field in
+    // the parsed text. If none exists, returns a location with line = -1. Index
+    // should be -1 for not-repeated fields.
+    ParseLocation GetLocation(const FieldDescriptor* field, int index) const {
+      return GetLocationRange(field, index).start;
+    }
 
     // Returns the parse info tree for the given field, which must be a message
     // type. The nested information tree is owned by the root tree and will be
@@ -511,14 +529,14 @@
     // Allow the text format parser to record information into the tree.
     friend class TextFormat;
 
-    // Records the starting location of a single value for a field.
-    void RecordLocation(const FieldDescriptor* field, ParseLocation location);
+    // Records the starting and ending locations of a single value for a field.
+    void RecordLocation(const FieldDescriptor* field, ParseLocationRange range);
 
     // Create and records a nested tree for a nested message field.
     ParseInfoTree* CreateNested(const FieldDescriptor* field);
 
     // Defines the map from the index-th field descriptor to its parse location.
-    typedef std::map<const FieldDescriptor*, std::vector<ParseLocation> >
+    typedef std::map<const FieldDescriptor*, std::vector<ParseLocationRange>>
         LocationMap;
 
     // Defines the map from the index-th field descriptor to the nested parse
@@ -635,7 +653,7 @@
   // helpers for ParserImpl to call methods of ParseInfoTree.
   static inline void RecordLocation(ParseInfoTree* info_tree,
                                     const FieldDescriptor* field,
-                                    ParseLocation location);
+                                    ParseLocationRange location);
   static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree,
                                             const FieldDescriptor* field);
 
@@ -644,7 +662,7 @@
 
 inline void TextFormat::RecordLocation(ParseInfoTree* info_tree,
                                        const FieldDescriptor* field,
-                                       ParseLocation location) {
+                                       ParseLocationRange location) {
   info_tree->RecordLocation(field, location);
 }
 
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index cedc928..f8848c4 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -1407,12 +1407,18 @@
   }
 
   void ExpectLocation(TextFormat::ParseInfoTree* tree, const Descriptor* d,
-                      const std::string& field_name, int index, int line,
-                      int column) {
-    TextFormat::ParseLocation location =
+                      const std::string& field_name, int index, int start_line,
+                      int start_column, int end_line, int end_column) {
+    TextFormat::ParseLocationRange range =
+        tree->GetLocationRange(d->FindFieldByName(field_name), index);
+    EXPECT_EQ(start_line, range.start.line);
+    EXPECT_EQ(start_column, range.start.column);
+    EXPECT_EQ(end_line, range.end.line);
+    EXPECT_EQ(end_column, range.end.column);
+    TextFormat::ParseLocation start_location =
         tree->GetLocation(d->FindFieldByName(field_name), index);
-    EXPECT_EQ(line, location.line);
-    EXPECT_EQ(column, location.column);
+    EXPECT_EQ(start_line, start_location.line);
+    EXPECT_EQ(start_column, start_location.column);
   }
 
   // An error collector which simply concatenates all its errors into a big
@@ -1462,22 +1468,22 @@
   ExpectSuccessAndTree(stringData, message.get(), &tree);
 
   // Verify that the tree has the correct positions.
-  ExpectLocation(&tree, d, "optional_int32", -1, 0, 0);
-  ExpectLocation(&tree, d, "optional_int64", -1, 1, 0);
-  ExpectLocation(&tree, d, "optional_double", -1, 2, 2);
+  ExpectLocation(&tree, d, "optional_int32", -1, 0, 0, 0, 17);
+  ExpectLocation(&tree, d, "optional_int64", -1, 1, 0, 1, 17);
+  ExpectLocation(&tree, d, "optional_double", -1, 2, 2, 2, 22);
 
-  ExpectLocation(&tree, d, "repeated_int32", 0, 3, 0);
-  ExpectLocation(&tree, d, "repeated_int32", 1, 4, 0);
+  ExpectLocation(&tree, d, "repeated_int32", 0, 3, 0, 3, 17);
+  ExpectLocation(&tree, d, "repeated_int32", 1, 4, 0, 4, 18);
 
-  ExpectLocation(&tree, d, "optional_nested_message", -1, 5, 0);
-  ExpectLocation(&tree, d, "repeated_nested_message", 0, 8, 0);
-  ExpectLocation(&tree, d, "repeated_nested_message", 1, 11, 0);
+  ExpectLocation(&tree, d, "optional_nested_message", -1, 5, 0, 7, 1);
+  ExpectLocation(&tree, d, "repeated_nested_message", 0, 8, 0, 10, 1);
+  ExpectLocation(&tree, d, "repeated_nested_message", 1, 11, 0, 13, 1);
 
-  // Check for fields not set. For an invalid field, the location returned
-  // should be -1, -1.
-  ExpectLocation(&tree, d, "repeated_int64", 0, -1, -1);
-  ExpectLocation(&tree, d, "repeated_int32", 6, -1, -1);
-  ExpectLocation(&tree, d, "some_unknown_field", -1, -1, -1);
+  // Check for fields not set. For an invalid field, the start and end locations
+  // returned should be -1, -1.
+  ExpectLocation(&tree, d, "repeated_int64", 0, -1, -1, -1, -1);
+  ExpectLocation(&tree, d, "repeated_int32", 6, -1, -1, -1, -1);
+  ExpectLocation(&tree, d, "some_unknown_field", -1, -1, -1, -1, -1);
 
   // Verify inside the nested message.
   const FieldDescriptor* nested_field =
@@ -1485,15 +1491,18 @@
 
   TextFormat::ParseInfoTree* nested_tree =
       tree.GetTreeForNested(nested_field, -1);
-  ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 6, 2);
+  ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 6, 2, 6,
+                 8);
 
   // Verify inside another nested message.
   nested_field = d->FindFieldByName("repeated_nested_message");
   nested_tree = tree.GetTreeForNested(nested_field, 0);
-  ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 9, 2);
+  ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 9, 2, 9,
+                 8);
 
   nested_tree = tree.GetTreeForNested(nested_field, 1);
-  ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 12, 2);
+  ExpectLocation(nested_tree, nested_field->message_type(), "bb", -1, 12, 2, 12,
+                 8);
 
   // Verify a NULL tree for an unknown nested field.
   TextFormat::ParseInfoTree* unknown_nested_tree =
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index c74a973..43954d9 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -41,11 +41,12 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Timestamp, seconds_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Timestamp, nanos_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::Timestamp)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Timestamp)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -150,35 +151,37 @@
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) {
           seconds_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // int32 nanos = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 16)) {
           nanos_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -218,25 +221,15 @@
 
   // int64 seconds = 1;
   if (this->_internal_seconds() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64Size(
-        this->_internal_seconds());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
   }
 
   // int32 nanos = 2;
   if (this->_internal_nanos() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-        this->_internal_nanos());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Timestamp::_class_data_ = {
@@ -245,8 +238,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Timestamp::GetClassData() const { return &_class_data_; }
 
-void Timestamp::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Timestamp::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Timestamp *>(to)->MergeFrom(
       static_cast<const Timestamp &>(from));
 }
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 8ea03e2..3efba58 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -142,7 +142,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Timestamp& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index 1de2532..c892956 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -113,6 +113,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Type, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Type, fields_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Type, oneofs_),
@@ -124,6 +125,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Field, kind_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Field, cardinality_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Field, number_),
@@ -139,6 +141,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Enum, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Enum, enumvalue_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Enum, options_),
@@ -149,6 +152,7 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumValue, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumValue, number_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::EnumValue, options_),
@@ -157,15 +161,16 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Option, name_),
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Option, value_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::Type)},
-  { 11, -1, sizeof(PROTOBUF_NAMESPACE_ID::Field)},
-  { 26, -1, sizeof(PROTOBUF_NAMESPACE_ID::Enum)},
-  { 36, -1, sizeof(PROTOBUF_NAMESPACE_ID::EnumValue)},
-  { 44, -1, sizeof(PROTOBUF_NAMESPACE_ID::Option)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Type)},
+  { 12, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Field)},
+  { 28, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Enum)},
+  { 39, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::EnumValue)},
+  { 48, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Option)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -442,7 +447,8 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Type.name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.Field fields = 2;
       case 2:
@@ -454,7 +460,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated string oneofs = 3;
       case 3:
@@ -468,7 +475,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.Option options = 4;
       case 4:
@@ -480,14 +488,16 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.SourceContext source_context = 5;
       case 5:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 42)) {
           ptr = ctx->ParseMessage(_internal_mutable_source_context(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.Syntax syntax = 6;
       case 6:
@@ -495,28 +505,29 @@
           ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
           _internal_set_syntax(static_cast<PROTOBUF_NAMESPACE_ID::Syntax>(val));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -635,13 +646,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_syntax());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Type::_class_data_ = {
@@ -650,8 +655,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Type::GetClassData() const { return &_class_data_; }
 
-void Type::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Type::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Type *>(to)->MergeFrom(
       static_cast<const Type &>(from));
 }
@@ -691,14 +696,16 @@
 
 void Type::InternalSwap(Type* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   fields_.InternalSwap(&other->fields_);
   oneofs_.InternalSwap(&other->oneofs_);
   options_.InternalSwap(&other->options_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(Type, syntax_)
@@ -825,7 +832,8 @@
           ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
           _internal_set_kind(static_cast<PROTOBUF_NAMESPACE_ID::Field_Kind>(val));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.Field.Cardinality cardinality = 2;
       case 2:
@@ -833,14 +841,16 @@
           ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
           _internal_set_cardinality(static_cast<PROTOBUF_NAMESPACE_ID::Field_Cardinality>(val));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // int32 number = 3;
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 24)) {
           number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // string name = 4;
       case 4:
@@ -849,7 +859,8 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Field.name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // string type_url = 6;
       case 6:
@@ -858,21 +869,24 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Field.type_url"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // int32 oneof_index = 7;
       case 7:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 56)) {
           oneof_index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // bool packed = 8;
       case 8:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 64)) {
           packed_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.Option options = 9;
       case 9:
@@ -884,7 +898,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<74>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // string json_name = 10;
       case 10:
@@ -893,7 +908,8 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Field.json_name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // string default_value = 11;
       case 11:
@@ -902,28 +918,29 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Field.default_value"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1078,16 +1095,12 @@
 
   // int32 number = 3;
   if (this->_internal_number() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-        this->_internal_number());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_number());
   }
 
   // int32 oneof_index = 7;
   if (this->_internal_oneof_index() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-        this->_internal_oneof_index());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
   }
 
   // bool packed = 8;
@@ -1095,13 +1108,7 @@
     total_size += 1 + 1;
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Field::_class_data_ = {
@@ -1110,8 +1117,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Field::GetClassData() const { return &_class_data_; }
 
-void Field::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Field::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Field *>(to)->MergeFrom(
       static_cast<const Field &>(from));
 }
@@ -1167,27 +1174,29 @@
 
 void Field::InternalSwap(Field* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   options_.InternalSwap(&other->options_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &type_url_, GetArenaForAllocation(),
-      &other->type_url_, other->GetArenaForAllocation()
+      &type_url_, lhs_arena,
+      &other->type_url_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &json_name_, GetArenaForAllocation(),
-      &other->json_name_, other->GetArenaForAllocation()
+      &json_name_, lhs_arena,
+      &other->json_name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &default_value_, GetArenaForAllocation(),
-      &other->default_value_, other->GetArenaForAllocation()
+      &default_value_, lhs_arena,
+      &other->default_value_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(Field, packed_)
@@ -1311,7 +1320,8 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Enum.name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.EnumValue enumvalue = 2;
       case 2:
@@ -1323,7 +1333,8 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.Option options = 3;
       case 3:
@@ -1335,14 +1346,16 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.SourceContext source_context = 4;
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 34)) {
           ptr = ctx->ParseMessage(_internal_mutable_source_context(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.Syntax syntax = 5;
       case 5:
@@ -1350,28 +1363,29 @@
           ::PROTOBUF_NAMESPACE_ID::uint64 val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
           _internal_set_syntax(static_cast<PROTOBUF_NAMESPACE_ID::Syntax>(val));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1472,13 +1486,7 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_syntax());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Enum::_class_data_ = {
@@ -1487,8 +1495,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Enum::GetClassData() const { return &_class_data_; }
 
-void Enum::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Enum::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Enum *>(to)->MergeFrom(
       static_cast<const Enum &>(from));
 }
@@ -1527,13 +1535,15 @@
 
 void Enum::InternalSwap(Enum* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   enumvalue_.InternalSwap(&other->enumvalue_);
   options_.InternalSwap(&other->options_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
       PROTOBUF_FIELD_OFFSET(Enum, syntax_)
@@ -1630,14 +1640,16 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.EnumValue.name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // int32 number = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 16)) {
           number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // repeated .google.protobuf.Option options = 3;
       case 3:
@@ -1649,28 +1661,29 @@
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1736,18 +1749,10 @@
 
   // int32 number = 2;
   if (this->_internal_number() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-        this->_internal_number());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_number());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumValue::_class_data_ = {
@@ -1756,8 +1761,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValue::GetClassData() const { return &_class_data_; }
 
-void EnumValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void EnumValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<EnumValue *>(to)->MergeFrom(
       static_cast<const EnumValue &>(from));
 }
@@ -1792,12 +1797,14 @@
 
 void EnumValue::InternalSwap(EnumValue* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   options_.InternalSwap(&other->options_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   swap(number_, other->number_);
 }
@@ -1905,35 +1912,37 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Option.name"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
       // .google.protobuf.Any value = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) {
           ptr = ctx->ParseMessage(_internal_mutable_value(), ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1991,13 +2000,7 @@
         *value_);
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Option::_class_data_ = {
@@ -2006,8 +2009,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Option::GetClassData() const { return &_class_data_; }
 
-void Option::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Option::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Option *>(to)->MergeFrom(
       static_cast<const Option &>(from));
 }
@@ -2041,11 +2044,13 @@
 
 void Option::InternalSwap(Option* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &name_, GetArenaForAllocation(),
-      &other->name_, other->GetArenaForAllocation()
+      &name_, lhs_arena,
+      &other->name_, rhs_arena
   );
   swap(value_, other->value_);
 }
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index 1ec987c..ca45f0f 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -255,7 +255,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Type& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -496,7 +496,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Field& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -861,7 +861,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Enum& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -1076,7 +1076,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const EnumValue& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -1251,7 +1251,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Option& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index 0925165..7dda924 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -972,6 +972,7 @@
   optional int32 _field_name4 = 4;
   optional int32 FIELD_NAME5 = 5;
   optional int32 field_name6 = 6 [json_name = "@type"];
+  optional int32 fieldname7 = 7;
 }
 
 message TestHugeFieldNumbers {
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 1e81116..0d9bf62 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -132,7 +132,7 @@
   return sizeof(*this) + SpaceUsedExcludingSelf();
 }
 
-void UnknownFieldSet::AddVarint(int number, uint64 value) {
+void UnknownFieldSet::AddVarint(int number, uint64_t value) {
   UnknownField field;
   field.number_ = number;
   field.SetType(UnknownField::TYPE_VARINT);
@@ -140,7 +140,7 @@
   fields_.push_back(field);
 }
 
-void UnknownFieldSet::AddFixed32(int number, uint32 value) {
+void UnknownFieldSet::AddFixed32(int number, uint32_t value) {
   UnknownField field;
   field.number_ = number;
   field.SetType(UnknownField::TYPE_FIXED32);
@@ -148,7 +148,7 @@
   fields_.push_back(field);
 }
 
-void UnknownFieldSet::AddFixed64(int number, uint64 value) {
+void UnknownFieldSet::AddFixed64(int number, uint64_t value) {
   UnknownField field;
   field.number_ = number;
   field.SetType(UnknownField::TYPE_FIXED64);
@@ -269,8 +269,8 @@
 }
 
 
-uint8* UnknownField::InternalSerializeLengthDelimitedNoTag(
-    uint8* target, io::EpsCopyOutputStream* stream) const {
+uint8_t* UnknownField::InternalSerializeLengthDelimitedNoTag(
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
   GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
   const std::string& data = *data_.length_delimited_.string_value;
   target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target);
@@ -285,22 +285,24 @@
   explicit UnknownFieldParserHelper(UnknownFieldSet* unknown)
       : unknown_(unknown) {}
 
-  void AddVarint(uint32 num, uint64 value) { unknown_->AddVarint(num, value); }
-  void AddFixed64(uint32 num, uint64 value) {
+  void AddVarint(uint32_t num, uint64_t value) {
+    unknown_->AddVarint(num, value);
+  }
+  void AddFixed64(uint32_t num, uint64_t value) {
     unknown_->AddFixed64(num, value);
   }
-  const char* ParseLengthDelimited(uint32 num, const char* ptr,
+  const char* ParseLengthDelimited(uint32_t num, const char* ptr,
                                    ParseContext* ctx) {
     std::string* s = unknown_->AddLengthDelimited(num);
     int size = ReadSize(&ptr);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     return ctx->ReadString(ptr, size, s);
   }
-  const char* ParseGroup(uint32 num, const char* ptr, ParseContext* ctx) {
+  const char* ParseGroup(uint32_t num, const char* ptr, ParseContext* ctx) {
     UnknownFieldParserHelper child(unknown_->AddGroup(num));
     return ctx->ParseGroup(&child, ptr, num * 8 + 3);
   }
-  void AddFixed32(uint32 num, uint32 value) {
+  void AddFixed32(uint32_t num, uint32_t value) {
     unknown_->AddFixed32(num, value);
   }
 
@@ -318,7 +320,7 @@
   return WireFormatParser(field_parser, ptr, ctx);
 }
 
-const char* UnknownFieldParse(uint64 tag, UnknownFieldSet* unknown,
+const char* UnknownFieldParse(uint64_t tag, UnknownFieldSet* unknown,
                               const char* ptr, ParseContext* ctx) {
   UnknownFieldParserHelper field_parser(unknown);
   return FieldParser(tag, field_parser, ptr, ctx);
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index ab3633d..c5ca06b 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -136,9 +136,9 @@
 
   // Adding fields ---------------------------------------------------
 
-  void AddVarint(int number, uint64 value);
-  void AddFixed32(int number, uint32 value);
-  void AddFixed64(int number, uint64 value);
+  void AddVarint(int number, uint64_t value);
+  void AddFixed32(int number, uint32_t value);
+  void AddFixed64(int number, uint64_t value);
   void AddLengthDelimited(int number, const std::string& value);
   std::string* AddLengthDelimited(int number);
   UnknownFieldSet* AddGroup(int number);
@@ -209,10 +209,10 @@
 
 namespace internal {
 
-inline void WriteVarint(uint32 num, uint64 val, UnknownFieldSet* unknown) {
+inline void WriteVarint(uint32_t num, uint64_t val, UnknownFieldSet* unknown) {
   unknown->AddVarint(num, val);
 }
-inline void WriteLengthDelimited(uint32 num, StringPiece val,
+inline void WriteLengthDelimited(uint32_t num, StringPiece val,
                                  UnknownFieldSet* unknown) {
   unknown->AddLengthDelimited(num)->assign(val.data(), val.size());
 }
@@ -221,7 +221,7 @@
 const char* UnknownGroupParse(UnknownFieldSet* unknown, const char* ptr,
                               ParseContext* ctx);
 PROTOBUF_EXPORT
-const char* UnknownFieldParse(uint64 tag, UnknownFieldSet* unknown,
+const char* UnknownFieldParse(uint64_t tag, UnknownFieldSet* unknown,
                               const char* ptr, ParseContext* ctx);
 
 }  // namespace internal
@@ -246,15 +246,15 @@
   // Accessors -------------------------------------------------------
   // Each method works only for UnknownFields of the corresponding type.
 
-  inline uint64 varint() const;
-  inline uint32 fixed32() const;
-  inline uint64 fixed64() const;
+  inline uint64_t varint() const;
+  inline uint32_t fixed32() const;
+  inline uint64_t fixed64() const;
   inline const std::string& length_delimited() const;
   inline const UnknownFieldSet& group() const;
 
-  inline void set_varint(uint64 value);
-  inline void set_fixed32(uint32 value);
-  inline void set_fixed64(uint64 value);
+  inline void set_varint(uint64_t value);
+  inline void set_fixed32(uint32_t value);
+  inline void set_fixed64(uint64_t value);
   inline void set_length_delimited(const std::string& value);
   inline std::string* mutable_length_delimited();
   inline UnknownFieldSet* mutable_group();
@@ -269,8 +269,8 @@
   }
 
   inline size_t GetLengthDelimitedSize() const;
-  uint8* InternalSerializeLengthDelimitedNoTag(
-      uint8* target, io::EpsCopyOutputStream* stream) const;
+  uint8_t* InternalSerializeLengthDelimitedNoTag(
+      uint8_t* target, io::EpsCopyOutputStream* stream) const;
 
 
   // If this UnknownField contains a pointer, delete it.
@@ -287,12 +287,12 @@
     std::string* string_value;
   };
 
-  uint32 number_;
-  uint32 type_;
+  uint32_t number_;
+  uint32_t type_;
   union {
-    uint64 varint_;
-    uint32 fixed32_;
-    uint64 fixed64_;
+    uint64_t varint_;
+    uint32_t fixed32_;
+    uint64_t fixed64_;
     mutable union LengthDelimited length_delimited_;
     UnknownFieldSet* group_;
   } data_;
@@ -342,15 +342,15 @@
   return static_cast<Type>(type_);
 }
 
-inline uint64 UnknownField::varint() const {
+inline uint64_t UnknownField::varint() const {
   assert(type() == TYPE_VARINT);
   return data_.varint_;
 }
-inline uint32 UnknownField::fixed32() const {
+inline uint32_t UnknownField::fixed32() const {
   assert(type() == TYPE_FIXED32);
   return data_.fixed32_;
 }
-inline uint64 UnknownField::fixed64() const {
+inline uint64_t UnknownField::fixed64() const {
   assert(type() == TYPE_FIXED64);
   return data_.fixed64_;
 }
@@ -363,15 +363,15 @@
   return *data_.group_;
 }
 
-inline void UnknownField::set_varint(uint64 value) {
+inline void UnknownField::set_varint(uint64_t value) {
   assert(type() == TYPE_VARINT);
   data_.varint_ = value;
 }
-inline void UnknownField::set_fixed32(uint32 value) {
+inline void UnknownField::set_fixed32(uint32_t value) {
   assert(type() == TYPE_FIXED32);
   data_.fixed32_ = value;
 }
-inline void UnknownField::set_fixed64(uint64 value) {
+inline void UnknownField::set_fixed64(uint64_t value) {
   assert(type() == TYPE_FIXED64);
   data_.fixed64_ = value;
 }
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index 88e01df..6d7f2f9 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -204,6 +204,28 @@
   }
 }
 
+void AddSpecificIndex(
+    google::protobuf::util::MessageDifferencer::SpecificField* specific_field,
+    const Message& message, const FieldDescriptor* field, int index) {
+  if (field->is_map()) {
+    const Reflection* reflection = message.GetReflection();
+    specific_field->map_entry1 =
+        &reflection->GetRepeatedMessage(message, field, index);
+  }
+  specific_field->index = index;
+}
+
+void AddSpecificNewIndex(
+    google::protobuf::util::MessageDifferencer::SpecificField* specific_field,
+    const Message& message, const FieldDescriptor* field, int index) {
+  if (field->is_map()) {
+    const Reflection* reflection = message.GetReflection();
+    specific_field->map_entry2 =
+        &reflection->GetRepeatedMessage(message, field, index);
+  }
+  specific_field->new_index = index;
+}
+
 MessageDifferencer::MapEntryKeyComparator::MapEntryKeyComparator(
     MessageDifferencer* message_differencer)
     : message_differencer_(message_differencer) {}
@@ -759,7 +781,11 @@
         for (int i = 0; i < count; ++i) {
           SpecificField specific_field;
           specific_field.field = field1;
-          specific_field.index = field1->is_repeated() ? i : -1;
+          if (field1->is_repeated()) {
+            AddSpecificIndex(&specific_field, message1, field1, i);
+          } else {
+            specific_field.index = -1;
+          }
 
           parent_fields->push_back(specific_field);
           reporter_->ReportDeleted(message1, message2, *parent_fields);
@@ -799,8 +825,13 @@
         for (int i = 0; i < count; ++i) {
           SpecificField specific_field;
           specific_field.field = field2;
-          specific_field.index = field2->is_repeated() ? i : -1;
-          specific_field.new_index = specific_field.index;
+          if (field2->is_repeated()) {
+            specific_field.index = i;
+            AddSpecificNewIndex(&specific_field, message2, field2, i);
+          } else {
+            specific_field.index = -1;
+            specific_field.new_index = -1;
+          }
 
           parent_fields->push_back(specific_field);
           reporter_->ReportAdded(message1, message2, *parent_fields);
@@ -904,6 +935,10 @@
         reflection2->GetRepeatedMessage(*message2, repeated_field, index2);
     SpecificField specific_field;
     specific_field.field = repeated_field;
+    if (repeated_field->is_map()) {
+      specific_field.map_entry1 = &m1;
+      specific_field.map_entry2 = &m2;
+    }
     specific_field.index = index1;
     specific_field.new_index = index2;
     current_parent_fields.push_back(specific_field);
@@ -1116,7 +1151,7 @@
     if (!simple_list && match_list1[i] == -1) {
       if (smart_list) {
         if (reporter_ == nullptr) return false;
-        specific_field.index = i;
+        AddSpecificIndex(&specific_field, message1, repeated_field, i);
         parent_fields->push_back(specific_field);
         reporter_->ReportDeleted(message1, message2, *parent_fields);
         parent_fields->pop_back();
@@ -1131,7 +1166,7 @@
         GOOGLE_CHECK_LE(0, j);
         if (reporter_ == nullptr) return false;
         specific_field.index = j;
-        specific_field.new_index = j;
+        AddSpecificNewIndex(&specific_field, message2, repeated_field, j);
         parent_fields->push_back(specific_field);
         reporter_->ReportAdded(message1, message2, *parent_fields);
         parent_fields->pop_back();
@@ -1140,11 +1175,12 @@
         match_list2[j] = -2;
       }
     }
-    specific_field.index = i;
+    AddSpecificIndex(&specific_field, message1, repeated_field, i);
     if (simple_list) {
-      specific_field.new_index = i;
+      AddSpecificNewIndex(&specific_field, message2, repeated_field, i);
     } else {
-      specific_field.new_index = match_list1[i];
+      AddSpecificNewIndex(&specific_field, message2, repeated_field,
+                          match_list1[i]);
       next_unmatched_index = match_list1[i] + 1;
     }
 
@@ -1184,7 +1220,7 @@
 
     if (reporter_ == NULL) continue;
     specific_field.index = i;
-    specific_field.new_index = i;
+    AddSpecificNewIndex(&specific_field, message2, repeated_field, i);
     parent_fields->push_back(specific_field);
     reporter_->ReportAdded(message1, message2, *parent_fields);
     parent_fields->pop_back();
@@ -1194,7 +1230,7 @@
     if (!simple_list && match_list1[i] != -1) continue;
     if (simple_list && i < count2) continue;
     assert(reporter_ != NULL);
-    specific_field.index = i;
+    AddSpecificIndex(&specific_field, message1, repeated_field, i);
     parent_fields->push_back(specific_field);
     reporter_->ReportDeleted(message1, message2, *parent_fields);
     parent_fields->pop_back();
@@ -1239,8 +1275,8 @@
       // Append currently compared field to the end of parent_fields.
       SpecificField specific_field;
       specific_field.field = field;
-      specific_field.index = index1;
-      specific_field.new_index = index2;
+      AddSpecificIndex(&specific_field, message1, field, index1);
+      AddSpecificNewIndex(&specific_field, message2, field, index2);
       parent_fields->push_back(specific_field);
       const bool compare_result = Compare(m1, m2, parent_fields);
       parent_fields->pop_back();
@@ -1377,7 +1413,7 @@
       any.GetDescriptor()->file()->pool()->FindMessageTypeByName(
           full_type_name);
   if (desc == NULL) {
-    GOOGLE_DLOG(ERROR) << "Proto type '" << full_type_name << "' not found";
+    GOOGLE_LOG(INFO) << "Proto type '" << full_type_name << "' not found";
     return false;
   }
 
@@ -1932,7 +1968,7 @@
       }
 
       if (specific_field.field->is_map()) {
-        PrintMapKey(field_path, left_side, specific_field, i);
+        PrintMapKey(left_side, specific_field);
         continue;
       }
     } else {
@@ -2038,66 +2074,21 @@
 }
 
 void MessageDifferencer::StreamReporter::PrintMapKey(
-    const std::vector<SpecificField>& field_path, bool left_side,
-    const SpecificField& specific_field, size_t target_field_index) {
+    bool left_side, const SpecificField& specific_field) {
   if (message1_ == nullptr || message2_ == nullptr) {
     GOOGLE_LOG(WARNING) << "PrintPath cannot log map keys; "
                     "use SetMessages to provide the messages "
                     "being compared prior to any processing.";
     return;
   }
-  auto get_target_message = [=](const SpecificField& specific_field,
-                                const Reflection* reflection,
-                                const Message* message) {
-    return &(
-        specific_field.field->is_repeated()
-            ? reflection->GetRepeatedMessage(
-                  *message, specific_field.field,
-                  left_side ? specific_field.index : specific_field.new_index)
-            : reflection->GetMessage(*message, specific_field.field));
-  };
 
-  std::unique_ptr<Message> deserialized_msg;  // used for protobuf.Any case
-  std::unique_ptr<DynamicMessageFactory> dynamic_message_factory;
-  const Message* found_message = left_side ? message1_ : message2_;
-  for (size_t j = 0; j <= target_field_index;
-       j++) {  // iterate until we find target field
-    if (specific_field.field->is_repeated()) {
-      int index = left_side ? specific_field.index : specific_field.new_index;
-      if (index < 0) {
-        // Filtered messages fall in this case
-        GOOGLE_LOG(WARNING) << "Invalid index " << index << " for map.\n";
-        found_message = nullptr;
-        break;
-      }
-    }
-    if (found_message->GetTypeName() == "google.protobuf.Any") {
-      if (!unpack_any_field_.UnpackAny(*found_message, &deserialized_msg)) {
-        GOOGLE_LOG(ERROR) << "Cannot print Any message map key due to "
-                      "unpacking error\n";
-        found_message = nullptr;
-        break;
-      }
-
-      found_message =
-          get_target_message(field_path[j], deserialized_msg->GetReflection(),
-                             deserialized_msg.get());
-
-    } else {
-      found_message = get_target_message(
-          field_path[j], found_message->GetReflection(), found_message);
-    }
-  }
-
+  const Message* found_message =
+      left_side ? specific_field.map_entry1 : specific_field.map_entry2;
   std::string key_string = "";
   if (found_message != nullptr) {
     // NB: the map key is always the first field
     const FieldDescriptor* fd = found_message->GetDescriptor()->field(0);
-    if (fd->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      key_string = found_message->GetReflection()
-                       ->GetMessage(*found_message, fd)
-                       .ShortDebugString();
-    } else if (fd->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+    if (fd->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
       // Not using PrintFieldValueToString for strings to avoid extra
       // characters
       key_string = found_message->GetReflection()->GetString(
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index 4cdb817..1ee6a38 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -194,6 +194,10 @@
     // has not moved, "new_index" will have the same value as "index".
     int new_index = -1;
 
+    // If "field" is a map field, point to the map entry.
+    const Message* map_entry1 = nullptr;
+    const Message* map_entry2 = nullptr;
+
     // For unknown fields, these are the pointers to the UnknownFieldSet
     // containing the unknown fields. In certain cases (e.g. proto1's
     // MessageSet, or nested groups of unknown fields), these may differ from
@@ -695,12 +699,10 @@
     // Just print a string
     void Print(const std::string& str);
 
-    // helper function for PrintPath that contains logic for printing maps
-    void PrintMapKey(const std::vector<SpecificField>& field_path,
-                     bool left_side, const SpecificField& specific_field,
-                     size_t target_field_index);
-
    private:
+    // helper function for PrintPath that contains logic for printing maps
+    void PrintMapKey(bool left_side, const SpecificField& specific_field);
+
     io::Printer* printer_;
     bool delete_printer_;
     bool report_modified_aggregates_;
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index c30b7ab..4b94f68 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -70,7 +70,7 @@
 // ===================================================================
 
 bool UnknownFieldSetFieldSkipper::SkipField(io::CodedInputStream* input,
-                                            uint32 tag) {
+                                            uint32_t tag) {
   return WireFormat::SkipField(input, tag, unknown_fields_);
 }
 
@@ -82,7 +82,7 @@
   unknown_fields_->AddVarint(field_number, value);
 }
 
-bool WireFormat::SkipField(io::CodedInputStream* input, uint32 tag,
+bool WireFormat::SkipField(io::CodedInputStream* input, uint32_t tag,
                            UnknownFieldSet* unknown_fields) {
   int number = WireFormatLite::GetTagFieldNumber(tag);
   // Field number 0 is illegal.
@@ -90,19 +90,19 @@
 
   switch (WireFormatLite::GetTagWireType(tag)) {
     case WireFormatLite::WIRETYPE_VARINT: {
-      uint64 value;
+      uint64_t value;
       if (!input->ReadVarint64(&value)) return false;
       if (unknown_fields != NULL) unknown_fields->AddVarint(number, value);
       return true;
     }
     case WireFormatLite::WIRETYPE_FIXED64: {
-      uint64 value;
+      uint64_t value;
       if (!input->ReadLittleEndian64(&value)) return false;
       if (unknown_fields != NULL) unknown_fields->AddFixed64(number, value);
       return true;
     }
     case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
-      uint32 length;
+      uint32_t length;
       if (!input->ReadVarint32(&length)) return false;
       if (unknown_fields == NULL) {
         if (!input->Skip(length)) return false;
@@ -134,7 +134,7 @@
       return false;
     }
     case WireFormatLite::WIRETYPE_FIXED32: {
-      uint32 value;
+      uint32_t value;
       if (!input->ReadLittleEndian32(&value)) return false;
       if (unknown_fields != NULL) unknown_fields->AddFixed32(number, value);
       return true;
@@ -148,7 +148,7 @@
 bool WireFormat::SkipMessage(io::CodedInputStream* input,
                              UnknownFieldSet* unknown_fields) {
   while (true) {
-    uint32 tag = input->ReadTag();
+    uint32_t tag = input->ReadTag();
     if (tag == 0) {
       // End of input.  This is a valid place to end, so return true.
       return true;
@@ -166,11 +166,11 @@
 }
 
 bool WireFormat::ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
-                                                uint32 field_number,
+                                                uint32_t field_number,
                                                 bool (*is_valid)(int),
                                                 UnknownFieldSet* unknown_fields,
                                                 RepeatedField<int>* values) {
-  uint32 length;
+  uint32_t length;
   if (!input->ReadVarint32(&length)) return false;
   io::CodedInputStream::Limit limit = input->PushLimit(length);
   while (input->BytesUntilLimit() > 0) {
@@ -189,8 +189,8 @@
   return true;
 }
 
-uint8* WireFormat::InternalSerializeUnknownFieldsToArray(
-    const UnknownFieldSet& unknown_fields, uint8* target,
+uint8_t* WireFormat::InternalSerializeUnknownFieldsToArray(
+    const UnknownFieldSet& unknown_fields, uint8_t* target,
     io::EpsCopyOutputStream* stream) {
   for (int i = 0; i < unknown_fields.field_count(); i++) {
     const UnknownField& field = unknown_fields.field(i);
@@ -227,8 +227,8 @@
   return target;
 }
 
-uint8* WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
-    const UnknownFieldSet& unknown_fields, uint8* target,
+uint8_t* WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
+    const UnknownFieldSet& unknown_fields, uint8_t* target,
     io::EpsCopyOutputStream* stream) {
   for (int i = 0; i < unknown_fields.field_count(); i++) {
     const UnknownField& field = unknown_fields.field(i);
@@ -278,12 +278,12 @@
       case UnknownField::TYPE_FIXED32:
         size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
             field.number(), WireFormatLite::WIRETYPE_FIXED32));
-        size += sizeof(int32);
+        size += sizeof(int32_t);
         break;
       case UnknownField::TYPE_FIXED64:
         size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
             field.number(), WireFormatLite::WIRETYPE_FIXED64));
-        size += sizeof(int64);
+        size += sizeof(int64_t);
         break;
       case UnknownField::TYPE_LENGTH_DELIMITED:
         size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
@@ -334,7 +334,7 @@
   const Reflection* message_reflection = message->GetReflection();
 
   while (true) {
-    uint32 tag = input->ReadTag();
+    uint32_t tag = input->ReadTag();
     if (tag == 0) {
       // End of input.  This is a valid place to end, so return true.
       return true;
@@ -380,15 +380,15 @@
 }
 
 bool WireFormat::SkipMessageSetField(io::CodedInputStream* input,
-                                     uint32 field_number,
+                                     uint32_t field_number,
                                      UnknownFieldSet* unknown_fields) {
-  uint32 length;
+  uint32_t length;
   if (!input->ReadVarint32(&length)) return false;
   return input->ReadString(unknown_fields->AddLengthDelimited(field_number),
                            length);
 }
 
-bool WireFormat::ParseAndMergeMessageSetField(uint32 field_number,
+bool WireFormat::ParseAndMergeMessageSetField(uint32_t field_number,
                                               const FieldDescriptor* field,
                                               Message* message,
                                               io::CodedInputStream* input) {
@@ -415,7 +415,7 @@
 }
 
 bool WireFormat::ParseAndMergeField(
-    uint32 tag,
+    uint32_t tag,
     const FieldDescriptor* field,  // May be NULL for unknown
     Message* message, io::CodedInputStream* input) {
   const Reflection* message_reflection = message->GetReflection();
@@ -441,7 +441,7 @@
     return SkipField(input, tag,
                      message_reflection->MutableUnknownFields(message));
   } else if (value_format == PACKED_FORMAT) {
-    uint32 length;
+    uint32_t length;
     if (!input->ReadVarint32(&length)) return false;
     io::CodedInputStream::Limit limit = input->PushLimit(length);
 
@@ -459,17 +459,17 @@
     break;                                                                     \
   }
 
-      HANDLE_PACKED_TYPE(INT32, int32, Int32)
-      HANDLE_PACKED_TYPE(INT64, int64, Int64)
-      HANDLE_PACKED_TYPE(SINT32, int32, Int32)
-      HANDLE_PACKED_TYPE(SINT64, int64, Int64)
-      HANDLE_PACKED_TYPE(UINT32, uint32, UInt32)
-      HANDLE_PACKED_TYPE(UINT64, uint64, UInt64)
+      HANDLE_PACKED_TYPE(INT32, int32_t, Int32)
+      HANDLE_PACKED_TYPE(INT64, int64_t, Int64)
+      HANDLE_PACKED_TYPE(SINT32, int32_t, Int32)
+      HANDLE_PACKED_TYPE(SINT64, int64_t, Int64)
+      HANDLE_PACKED_TYPE(UINT32, uint32_t, UInt32)
+      HANDLE_PACKED_TYPE(UINT64, uint64_t, UInt64)
 
-      HANDLE_PACKED_TYPE(FIXED32, uint32, UInt32)
-      HANDLE_PACKED_TYPE(FIXED64, uint64, UInt64)
-      HANDLE_PACKED_TYPE(SFIXED32, int32, Int32)
-      HANDLE_PACKED_TYPE(SFIXED64, int64, Int64)
+      HANDLE_PACKED_TYPE(FIXED32, uint32_t, UInt32)
+      HANDLE_PACKED_TYPE(FIXED64, uint64_t, UInt64)
+      HANDLE_PACKED_TYPE(SFIXED32, int32_t, Int32)
+      HANDLE_PACKED_TYPE(SFIXED64, int64_t, Int64)
 
       HANDLE_PACKED_TYPE(FLOAT, float, Float)
       HANDLE_PACKED_TYPE(DOUBLE, double, Double)
@@ -494,7 +494,7 @@
             } else {
               // The enum value is not one of the known values.  Add it to the
               // UnknownFieldSet.
-              int64 sign_extended_value = static_cast<int64>(value);
+              int64_t sign_extended_value = static_cast<int64_t>(value);
               message_reflection->MutableUnknownFields(message)->AddVarint(
                   WireFormatLite::GetTagFieldNumber(tag), sign_extended_value);
             }
@@ -532,17 +532,17 @@
     break;                                                                    \
   }
 
-      HANDLE_TYPE(INT32, int32, Int32)
-      HANDLE_TYPE(INT64, int64, Int64)
-      HANDLE_TYPE(SINT32, int32, Int32)
-      HANDLE_TYPE(SINT64, int64, Int64)
-      HANDLE_TYPE(UINT32, uint32, UInt32)
-      HANDLE_TYPE(UINT64, uint64, UInt64)
+      HANDLE_TYPE(INT32, int32_t, Int32)
+      HANDLE_TYPE(INT64, int64_t, Int64)
+      HANDLE_TYPE(SINT32, int32_t, Int32)
+      HANDLE_TYPE(SINT64, int64_t, Int64)
+      HANDLE_TYPE(UINT32, uint32_t, UInt32)
+      HANDLE_TYPE(UINT64, uint64_t, UInt64)
 
-      HANDLE_TYPE(FIXED32, uint32, UInt32)
-      HANDLE_TYPE(FIXED64, uint64, UInt64)
-      HANDLE_TYPE(SFIXED32, int32, Int32)
-      HANDLE_TYPE(SFIXED64, int64, Int64)
+      HANDLE_TYPE(FIXED32, uint32_t, UInt32)
+      HANDLE_TYPE(FIXED64, uint64_t, UInt64)
+      HANDLE_TYPE(SFIXED32, int32_t, Int32)
+      HANDLE_TYPE(SFIXED64, int64_t, Int64)
 
       HANDLE_TYPE(FLOAT, float, Float)
       HANDLE_TYPE(DOUBLE, double, Double)
@@ -641,7 +641,7 @@
       return ParseAndMergeMessageSetField(type_id, field, message, input);
     }
 
-    bool SkipField(uint32 tag, io::CodedInputStream* input) {
+    bool SkipField(uint32_t tag, io::CodedInputStream* input) {
       return WireFormat::SkipField(input, tag, NULL);
     }
 
@@ -658,14 +658,14 @@
     // Parse a MessageSetItem
     auto metadata = reflection->MutableInternalMetadata(msg);
     std::string payload;
-    uint32 type_id = 0;
+    uint32_t type_id = 0;
     bool payload_read = false;
     while (!ctx->Done(&ptr)) {
       // We use 64 bit tags in order to allow typeid's that span the whole
       // range of 32 bit numbers.
-      uint32 tag = static_cast<uint8>(*ptr++);
+      uint32_t tag = static_cast<uint8_t>(*ptr++);
       if (tag == WireFormatLite::kMessageSetTypeIdTag) {
-        uint64 tmp;
+        uint64_t tmp;
         ptr = ParseBigVarint(ptr, &tmp);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         type_id = tmp;
@@ -701,7 +701,7 @@
         continue;
       } else if (tag == WireFormatLite::kMessageSetMessageTag) {
         if (type_id == 0) {
-          int32 size = ReadSize(&ptr);
+          int32_t size = ReadSize(&ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
           ptr = ctx->ReadString(ptr, size, &payload);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
@@ -718,7 +718,7 @@
             }
           }
           ptr = WireFormat::_InternalParseAndMergeField(
-              msg, ptr, ctx, static_cast<uint64>(type_id) * 8 + 2, reflection,
+              msg, ptr, ctx, static_cast<uint64_t>(type_id) * 8 + 2, reflection,
               field);
           type_id = 0;
         }
@@ -740,7 +740,7 @@
 
   const char* ParseMessageSet(const char* ptr, internal::ParseContext* ctx) {
     while (!ctx->Done(&ptr)) {
-      uint32 tag;
+      uint32_t tag;
       ptr = ReadTag(ptr, &tag);
       if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
       if (tag == 0 || (tag & 7) == WireFormatLite::WIRETYPE_END_GROUP) {
@@ -786,7 +786,7 @@
     return message_set.ParseMessageSet(ptr, ctx);
   }
   while (!ctx->Done(&ptr)) {
-    uint32 tag;
+    uint32_t tag;
     ptr = ReadTag(ptr, &tag);
     if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
     if (tag == 0 || (tag & 7) == WireFormatLite::WIRETYPE_END_GROUP) {
@@ -815,7 +815,7 @@
 }
 
 const char* WireFormat::_InternalParseAndMergeField(
-    Message* msg, const char* ptr, internal::ParseContext* ctx, uint64 tag,
+    Message* msg, const char* ptr, internal::ParseContext* ctx, uint64_t tag,
     const Reflection* reflection, const FieldDescriptor* field) {
   if (field == nullptr) {
     // unknown field set parser takes 64bit tags, because message set type ids
@@ -836,17 +836,17 @@
     return ptr;                                                             \
   }
 
-        HANDLE_PACKED_TYPE(INT32, int32, Int32)
-        HANDLE_PACKED_TYPE(INT64, int64, Int64)
-        HANDLE_PACKED_TYPE(SINT32, int32, SInt32)
-        HANDLE_PACKED_TYPE(SINT64, int64, SInt64)
-        HANDLE_PACKED_TYPE(UINT32, uint32, UInt32)
-        HANDLE_PACKED_TYPE(UINT64, uint64, UInt64)
+        HANDLE_PACKED_TYPE(INT32, int32_t, Int32)
+        HANDLE_PACKED_TYPE(INT64, int64_t, Int64)
+        HANDLE_PACKED_TYPE(SINT32, int32_t, SInt32)
+        HANDLE_PACKED_TYPE(SINT64, int64_t, SInt64)
+        HANDLE_PACKED_TYPE(UINT32, uint32_t, UInt32)
+        HANDLE_PACKED_TYPE(UINT64, uint64_t, UInt64)
 
-        HANDLE_PACKED_TYPE(FIXED32, uint32, Fixed32)
-        HANDLE_PACKED_TYPE(FIXED64, uint64, Fixed64)
-        HANDLE_PACKED_TYPE(SFIXED32, int32, SFixed32)
-        HANDLE_PACKED_TYPE(SFIXED64, int64, SFixed64)
+        HANDLE_PACKED_TYPE(FIXED32, uint32_t, Fixed32)
+        HANDLE_PACKED_TYPE(FIXED64, uint64_t, Fixed64)
+        HANDLE_PACKED_TYPE(SFIXED32, int32_t, SFixed32)
+        HANDLE_PACKED_TYPE(SFIXED64, int64_t, SFixed64)
 
         HANDLE_PACKED_TYPE(FLOAT, float, Float)
         HANDLE_PACKED_TYPE(DOUBLE, double, Double)
@@ -863,7 +863,7 @@
             ptr = internal::PackedEnumParser(rep_enum, ptr, ctx);
           } else {
             return ctx->ReadPackedVarint(
-                ptr, [rep_enum, field, reflection, msg](uint64 val) {
+                ptr, [rep_enum, field, reflection, msg](uint64_t val) {
                   if (field->enum_type()->FindValueByNumber(val) != nullptr) {
                     rep_enum->Add(val);
                   } else {
@@ -906,14 +906,14 @@
     return ptr;                                           \
   }
 
-    HANDLE_TYPE(BOOL, uint64, Bool)
-    HANDLE_TYPE(INT32, uint32, Int32)
-    HANDLE_TYPE(INT64, uint64, Int64)
-    HANDLE_TYPE(UINT32, uint32, UInt32)
-    HANDLE_TYPE(UINT64, uint64, UInt64)
+    HANDLE_TYPE(BOOL, uint64_t, Bool)
+    HANDLE_TYPE(INT32, uint32_t, Int32)
+    HANDLE_TYPE(INT64, uint64_t, Int64)
+    HANDLE_TYPE(UINT32, uint32_t, UInt32)
+    HANDLE_TYPE(UINT64, uint64_t, UInt64)
 
     case FieldDescriptor::TYPE_SINT32: {
-      int32 value = ReadVarintZigZag32(&ptr);
+      int32_t value = ReadVarintZigZag32(&ptr);
       if (ptr == nullptr) return nullptr;
       if (field->is_repeated()) {
         reflection->AddInt32(msg, field, value);
@@ -923,7 +923,7 @@
       return ptr;
     }
     case FieldDescriptor::TYPE_SINT64: {
-      int64 value = ReadVarintZigZag64(&ptr);
+      int64_t value = ReadVarintZigZag64(&ptr);
       if (ptr == nullptr) return nullptr;
       if (field->is_repeated()) {
         reflection->AddInt64(msg, field, value);
@@ -946,10 +946,10 @@
     return ptr;                                           \
   }
 
-      HANDLE_TYPE(FIXED32, uint32, UInt32)
-      HANDLE_TYPE(FIXED64, uint64, UInt64)
-      HANDLE_TYPE(SFIXED32, int32, Int32)
-      HANDLE_TYPE(SFIXED64, int64, Int64)
+      HANDLE_TYPE(FIXED32, uint32_t, UInt32)
+      HANDLE_TYPE(FIXED64, uint64_t, UInt64)
+      HANDLE_TYPE(SFIXED32, int32_t, Int32)
+      HANDLE_TYPE(SFIXED64, int64_t, Int64)
 
       HANDLE_TYPE(FLOAT, float, Float)
       HANDLE_TYPE(DOUBLE, double, Double)
@@ -957,7 +957,7 @@
 #undef HANDLE_TYPE
 
     case FieldDescriptor::TYPE_ENUM: {
-      uint32 value;
+      uint32_t value;
       ptr = VarintParse(ptr, &value);
       if (ptr == nullptr) return nullptr;
       if (field->is_repeated()) {
@@ -1030,8 +1030,8 @@
 
 // ===================================================================
 
-uint8* WireFormat::_InternalSerialize(const Message& message, uint8* target,
-                                      io::EpsCopyOutputStream* stream) {
+uint8_t* WireFormat::_InternalSerialize(const Message& message, uint8_t* target,
+                                        io::EpsCopyOutputStream* stream) {
   const Descriptor* descriptor = message.GetDescriptor();
   const Reflection* message_reflection = message.GetReflection();
 
@@ -1059,9 +1059,9 @@
   }
 }
 
-uint8* SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
-                                      const MapKey& value, uint8* target,
-                                      io::EpsCopyOutputStream* stream) {
+uint8_t* SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
+                                        const MapKey& value, uint8_t* target,
+                                        io::EpsCopyOutputStream* stream) {
   target = stream->EnsureSpace(target);
   switch (field->type()) {
     case FieldDescriptor::TYPE_DOUBLE:
@@ -1096,9 +1096,9 @@
   return target;
 }
 
-static uint8* SerializeMapValueRefWithCachedSizes(
-    const FieldDescriptor* field, const MapValueConstRef& value, uint8* target,
-    io::EpsCopyOutputStream* stream) {
+static uint8_t* SerializeMapValueRefWithCachedSizes(
+    const FieldDescriptor* field, const MapValueConstRef& value,
+    uint8_t* target, io::EpsCopyOutputStream* stream) {
   target = stream->EnsureSpace(target);
   switch (field->type()) {
 #define CASE_TYPE(FieldType, CamelFieldType, CamelCppType)   \
@@ -1180,11 +1180,11 @@
   };
 };
 
-static uint8* InternalSerializeMapEntry(const FieldDescriptor* field,
-                                        const MapKey& key,
-                                        const MapValueConstRef& value,
-                                        uint8* target,
-                                        io::EpsCopyOutputStream* stream) {
+static uint8_t* InternalSerializeMapEntry(const FieldDescriptor* field,
+                                          const MapKey& key,
+                                          const MapValueConstRef& value,
+                                          uint8_t* target,
+                                          io::EpsCopyOutputStream* stream) {
   const FieldDescriptor* key_field = field->message_type()->field(0);
   const FieldDescriptor* value_field = field->message_type()->field(1);
 
@@ -1201,9 +1201,10 @@
   return target;
 }
 
-uint8* WireFormat::InternalSerializeField(const FieldDescriptor* field,
-                                          const Message& message, uint8* target,
-                                          io::EpsCopyOutputStream* stream) {
+uint8_t* WireFormat::InternalSerializeField(const FieldDescriptor* field,
+                                            const Message& message,
+                                            uint8_t* target,
+                                            io::EpsCopyOutputStream* stream) {
   const Reflection* message_reflection = message.GetReflection();
 
   if (field->is_extension() &&
@@ -1286,12 +1287,12 @@
     break;                                                                     \
   }
 
-      HANDLE_PRIMITIVE_TYPE(INT32, int32, Int32, Int32)
-      HANDLE_PRIMITIVE_TYPE(INT64, int64, Int64, Int64)
-      HANDLE_PRIMITIVE_TYPE(SINT32, int32, SInt32, Int32)
-      HANDLE_PRIMITIVE_TYPE(SINT64, int64, SInt64, Int64)
-      HANDLE_PRIMITIVE_TYPE(UINT32, uint32, UInt32, UInt32)
-      HANDLE_PRIMITIVE_TYPE(UINT64, uint64, UInt64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(INT32, int32_t, Int32, Int32)
+      HANDLE_PRIMITIVE_TYPE(INT64, int64_t, Int64, Int64)
+      HANDLE_PRIMITIVE_TYPE(SINT32, int32_t, SInt32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SINT64, int64_t, SInt64, Int64)
+      HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t, UInt32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t, UInt64, UInt64)
       HANDLE_PRIMITIVE_TYPE(ENUM, int, Enum, Enum)
 
 #undef HANDLE_PRIMITIVE_TYPE
@@ -1303,10 +1304,10 @@
     break;                                                                     \
   }
 
-      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32, Fixed32, UInt32)
-      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64, Fixed64, UInt64)
-      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32, SFixed32, Int32)
-      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64, SFixed64, Int64)
+      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32_t, Fixed32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64_t, Fixed64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32_t, SFixed32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64_t, SFixed64, Int64)
 
       HANDLE_PRIMITIVE_TYPE(FLOAT, float, Float, Float)
       HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)
@@ -1334,17 +1335,17 @@
     break;                                                                    \
   }
 
-      HANDLE_PRIMITIVE_TYPE(INT32, int32, Int32, Int32)
-      HANDLE_PRIMITIVE_TYPE(INT64, int64, Int64, Int64)
-      HANDLE_PRIMITIVE_TYPE(SINT32, int32, SInt32, Int32)
-      HANDLE_PRIMITIVE_TYPE(SINT64, int64, SInt64, Int64)
-      HANDLE_PRIMITIVE_TYPE(UINT32, uint32, UInt32, UInt32)
-      HANDLE_PRIMITIVE_TYPE(UINT64, uint64, UInt64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(INT32, int32_t, Int32, Int32)
+      HANDLE_PRIMITIVE_TYPE(INT64, int64_t, Int64, Int64)
+      HANDLE_PRIMITIVE_TYPE(SINT32, int32_t, SInt32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SINT64, int64_t, SInt64, Int64)
+      HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t, UInt32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t, UInt64, UInt64)
 
-      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32, Fixed32, UInt32)
-      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64, Fixed64, UInt64)
-      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32, SFixed32, Int32)
-      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64, SFixed64, Int64)
+      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32_t, Fixed32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64_t, Fixed64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32_t, SFixed32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64_t, SFixed64, Int64)
 
       HANDLE_PRIMITIVE_TYPE(FLOAT, float, Float, Float)
       HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)
@@ -1418,8 +1419,8 @@
   return target;
 }
 
-uint8* WireFormat::InternalSerializeMessageSetItem(
-    const FieldDescriptor* field, const Message& message, uint8* target,
+uint8_t* WireFormat::InternalSerializeMessageSetItem(
+    const FieldDescriptor* field, const Message& message, uint8_t* target,
     io::EpsCopyOutputStream* stream) {
   const Reflection* message_reflection = message.GetReflection();
 
diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h
index d4ffbdf..7ca217a 100644
--- a/src/google/protobuf/wire_format.h
+++ b/src/google/protobuf/wire_format.h
@@ -132,8 +132,8 @@
            "originally expected.  Perhaps it was modified by another thread "
            "during serialization?";
   }
-  static uint8* _InternalSerialize(const Message& message, uint8* target,
-                                   io::EpsCopyOutputStream* stream);
+  static uint8_t* _InternalSerialize(const Message& message, uint8_t* target,
+                                     io::EpsCopyOutputStream* stream);
 
   // Implements Message::ByteSize() via reflection.  WARNING:  The result
   // of this method is *not* cached anywhere.  However, all embedded messages
@@ -148,7 +148,7 @@
   // Skips a field value of the given WireType.  The input should start
   // positioned immediately after the tag.  If unknown_fields is non-NULL,
   // the contents of the field will be added to it.
-  static bool SkipField(io::CodedInputStream* input, uint32 tag,
+  static bool SkipField(io::CodedInputStream* input, uint32_t tag,
                         UnknownFieldSet* unknown_fields);
 
   // Reads and ignores a message from the input.  If unknown_fields is
@@ -160,7 +160,7 @@
   // for which is_valid(value) returns false are appended to
   // unknown_fields_stream.
   static bool ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
-                                             uint32 field_number,
+                                             uint32_t field_number,
                                              bool (*is_valid)(int),
                                              UnknownFieldSet* unknown_fields,
                                              RepeatedField<int>* values);
@@ -176,16 +176,16 @@
   // ComputeUnknownFieldsSize(unknown_fields).
   //
   // Returns a pointer past the last written byte.
-  static uint8* SerializeUnknownFieldsToArray(
-      const UnknownFieldSet& unknown_fields, uint8* target) {
+  static uint8_t* SerializeUnknownFieldsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target) {
     io::EpsCopyOutputStream stream(
         target, static_cast<int>(ComputeUnknownFieldsSize(unknown_fields)),
         io::CodedOutputStream::IsDefaultSerializationDeterministic());
     return InternalSerializeUnknownFieldsToArray(unknown_fields, target,
                                                  &stream);
   }
-  static uint8* InternalSerializeUnknownFieldsToArray(
-      const UnknownFieldSet& unknown_fields, uint8* target,
+  static uint8_t* InternalSerializeUnknownFieldsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target,
       io::EpsCopyOutputStream* stream);
 
   // Same thing except for messages that have the message_set_wire_format
@@ -200,10 +200,10 @@
   // ComputeUnknownMessageSetItemsSize(unknown_fields).
   //
   // Returns a pointer past the last written byte.
-  static uint8* SerializeUnknownMessageSetItemsToArray(
-      const UnknownFieldSet& unknown_fields, uint8* target);
-  static uint8* InternalSerializeUnknownMessageSetItemsToArray(
-      const UnknownFieldSet& unknown_fields, uint8* target,
+  static uint8_t* SerializeUnknownMessageSetItemsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target);
+  static uint8_t* InternalSerializeUnknownMessageSetItemsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target,
       io::EpsCopyOutputStream* stream);
 
   // Compute the size of the UnknownFieldSet on the wire.
@@ -219,12 +219,12 @@
   //
   // This is different from MakeTag(field->number(), field->type()) in the
   // case of packed repeated fields.
-  static uint32 MakeTag(const FieldDescriptor* field);
+  static uint32_t MakeTag(const FieldDescriptor* field);
 
   // Parse a single field.  The input should start out positioned immediately
   // after the tag.
   static bool ParseAndMergeField(
-      uint32 tag,
+      uint32_t tag,
       const FieldDescriptor* field,  // May be NULL for unknown
       Message* message, io::CodedInputStream* input);
 
@@ -235,9 +235,9 @@
     output->SetCur(InternalSerializeField(field, message, output->Cur(),
                                           output->EpsCopy()));
   }
-  static uint8* InternalSerializeField(
+  static uint8_t* InternalSerializeField(
       const FieldDescriptor* field,  // Cannot be NULL
-      const Message& message, uint8* target, io::EpsCopyOutputStream* stream);
+      const Message& message, uint8_t* target, io::EpsCopyOutputStream* stream);
 
   // Compute size of a single field.  If the field is a message type, this
   // will call ByteSize() for the embedded message, insuring that it caches
@@ -255,8 +255,8 @@
     output->SetCur(InternalSerializeMessageSetItem(
         field, message, output->Cur(), output->EpsCopy()));
   }
-  static uint8* InternalSerializeMessageSetItem(
-      const FieldDescriptor* field, const Message& message, uint8* target,
+  static uint8_t* InternalSerializeMessageSetItem(
+      const FieldDescriptor* field, const Message& message, uint8_t* target,
       io::EpsCopyOutputStream* stream);
   static size_t MessageSetItemByteSize(const FieldDescriptor* field,
                                        const Message& message);
@@ -287,18 +287,18 @@
   struct MessageSetParser;
   // Skip a MessageSet field.
   static bool SkipMessageSetField(io::CodedInputStream* input,
-                                  uint32 field_number,
+                                  uint32_t field_number,
                                   UnknownFieldSet* unknown_fields);
 
   // Parse a MessageSet field.
-  static bool ParseAndMergeMessageSetField(uint32 field_number,
+  static bool ParseAndMergeMessageSetField(uint32_t field_number,
                                            const FieldDescriptor* field,
                                            Message* message,
                                            io::CodedInputStream* input);
   // Parses the value from the wire that belongs to tag.
   static const char* _InternalParseAndMergeField(Message* msg, const char* ptr,
                                                  internal::ParseContext* ctx,
-                                                 uint64 tag,
+                                                 uint64_t tag,
                                                  const Reflection* reflection,
                                                  const FieldDescriptor* field);
 
@@ -313,7 +313,7 @@
   ~UnknownFieldSetFieldSkipper() override {}
 
   // implements FieldSkipper -----------------------------------------
-  bool SkipField(io::CodedInputStream* input, uint32 tag) override;
+  bool SkipField(io::CodedInputStream* input, uint32_t tag) override;
   bool SkipMessage(io::CodedInputStream* input) override;
   void SkipUnknownEnum(int field_number, int value) override;
 
@@ -340,7 +340,7 @@
       static_cast<WireFormatLite::FieldType>(implicit_cast<int>(type)));
 }
 
-inline uint32 WireFormat::MakeTag(const FieldDescriptor* field) {
+inline uint32_t WireFormat::MakeTag(const FieldDescriptor* field) {
   return WireFormatLite::MakeTag(field->number(), WireTypeForField(field));
 }
 
@@ -382,8 +382,8 @@
 }
 
 
-inline uint8* InternalSerializeUnknownMessageSetItemsToArray(
-    const UnknownFieldSet& unknown_fields, uint8* target,
+inline uint8_t* InternalSerializeUnknownMessageSetItemsToArray(
+    const UnknownFieldSet& unknown_fields, uint8_t* target,
     io::EpsCopyOutputStream* stream) {
   return WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
       unknown_fields, target, stream);
@@ -402,9 +402,9 @@
 size_t MapKeyDataOnlyByteSize(const FieldDescriptor* field,
                               const MapKey& value);
 
-uint8* SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
-                                      const MapKey& value, uint8* target,
-                                      io::EpsCopyOutputStream* stream);
+uint8_t* SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
+                                        const MapKey& value, uint8_t* target,
+                                        io::EpsCopyOutputStream* stream);
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index 7af7bf4..f61f4e5 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -120,22 +120,22 @@
         WireFormatLite::WIRETYPE_VARINT,            // TYPE_SINT64
 };
 
-bool WireFormatLite::SkipField(io::CodedInputStream* input, uint32 tag) {
+bool WireFormatLite::SkipField(io::CodedInputStream* input, uint32_t tag) {
   // Field number 0 is illegal.
   if (WireFormatLite::GetTagFieldNumber(tag) == 0) return false;
   switch (WireFormatLite::GetTagWireType(tag)) {
     case WireFormatLite::WIRETYPE_VARINT: {
-      uint64 value;
+      uint64_t value;
       if (!input->ReadVarint64(&value)) return false;
       return true;
     }
     case WireFormatLite::WIRETYPE_FIXED64: {
-      uint64 value;
+      uint64_t value;
       if (!input->ReadLittleEndian64(&value)) return false;
       return true;
     }
     case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
-      uint32 length;
+      uint32_t length;
       if (!input->ReadVarint32(&length)) return false;
       if (!input->Skip(length)) return false;
       return true;
@@ -156,7 +156,7 @@
       return false;
     }
     case WireFormatLite::WIRETYPE_FIXED32: {
-      uint32 value;
+      uint32_t value;
       if (!input->ReadLittleEndian32(&value)) return false;
       return true;
     }
@@ -166,27 +166,27 @@
   }
 }
 
-bool WireFormatLite::SkipField(io::CodedInputStream* input, uint32 tag,
+bool WireFormatLite::SkipField(io::CodedInputStream* input, uint32_t tag,
                                io::CodedOutputStream* output) {
   // Field number 0 is illegal.
   if (WireFormatLite::GetTagFieldNumber(tag) == 0) return false;
   switch (WireFormatLite::GetTagWireType(tag)) {
     case WireFormatLite::WIRETYPE_VARINT: {
-      uint64 value;
+      uint64_t value;
       if (!input->ReadVarint64(&value)) return false;
       output->WriteVarint32(tag);
       output->WriteVarint64(value);
       return true;
     }
     case WireFormatLite::WIRETYPE_FIXED64: {
-      uint64 value;
+      uint64_t value;
       if (!input->ReadLittleEndian64(&value)) return false;
       output->WriteVarint32(tag);
       output->WriteLittleEndian64(value);
       return true;
     }
     case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
-      uint32 length;
+      uint32_t length;
       if (!input->ReadVarint32(&length)) return false;
       output->WriteVarint32(tag);
       output->WriteVarint32(length);
@@ -213,7 +213,7 @@
       return false;
     }
     case WireFormatLite::WIRETYPE_FIXED32: {
-      uint32 value;
+      uint32_t value;
       if (!input->ReadLittleEndian32(&value)) return false;
       output->WriteVarint32(tag);
       output->WriteLittleEndian32(value);
@@ -227,7 +227,7 @@
 
 bool WireFormatLite::SkipMessage(io::CodedInputStream* input) {
   while (true) {
-    uint32 tag = input->ReadTag();
+    uint32_t tag = input->ReadTag();
     if (tag == 0) {
       // End of input.  This is a valid place to end, so return true.
       return true;
@@ -247,7 +247,7 @@
 bool WireFormatLite::SkipMessage(io::CodedInputStream* input,
                                  io::CodedOutputStream* output) {
   while (true) {
-    uint32 tag = input->ReadTag();
+    uint32_t tag = input->ReadTag();
     if (tag == 0) {
       // End of input.  This is a valid place to end, so return true.
       return true;
@@ -265,7 +265,7 @@
   }
 }
 
-bool FieldSkipper::SkipField(io::CodedInputStream* input, uint32 tag) {
+bool FieldSkipper::SkipField(io::CodedInputStream* input, uint32_t tag) {
   return WireFormatLite::SkipField(input, tag);
 }
 
@@ -278,7 +278,7 @@
 }
 
 bool CodedOutputStreamFieldSkipper::SkipField(io::CodedInputStream* input,
-                                              uint32 tag) {
+                                              uint32_t tag) {
   return WireFormatLite::SkipField(input, tag, unknown_fields_);
 }
 
@@ -295,7 +295,7 @@
 bool WireFormatLite::ReadPackedEnumPreserveUnknowns(
     io::CodedInputStream* input, int field_number, bool (*is_valid)(int),
     io::CodedOutputStream* unknown_fields_stream, RepeatedField<int>* values) {
-  uint32 length;
+  uint32_t length;
   if (!input->ReadVarint32(&length)) return false;
   io::CodedInputStream::Limit limit = input->PushLimit(length);
   while (input->BytesUntilLimit() > 0) {
@@ -306,8 +306,8 @@
     if (is_valid == NULL || is_valid(value)) {
       values->Add(value);
     } else {
-      uint32 tag = WireFormatLite::MakeTag(field_number,
-                                           WireFormatLite::WIRETYPE_VARINT);
+      uint32_t tag = WireFormatLite::MakeTag(field_number,
+                                             WireFormatLite::WIRETYPE_VARINT);
       unknown_fields_stream->WriteVarint32(tag);
       unknown_fields_stream->WriteVarint32(value);
     }
@@ -319,31 +319,31 @@
 #if !defined(PROTOBUF_LITTLE_ENDIAN)
 
 namespace {
-void EncodeFixedSizeValue(float v, uint8* dest) {
+void EncodeFixedSizeValue(float v, uint8_t* dest) {
   WireFormatLite::WriteFloatNoTagToArray(v, dest);
 }
 
-void EncodeFixedSizeValue(double v, uint8* dest) {
+void EncodeFixedSizeValue(double v, uint8_t* dest) {
   WireFormatLite::WriteDoubleNoTagToArray(v, dest);
 }
 
-void EncodeFixedSizeValue(uint32 v, uint8* dest) {
+void EncodeFixedSizeValue(uint32_t v, uint8_t* dest) {
   WireFormatLite::WriteFixed32NoTagToArray(v, dest);
 }
 
-void EncodeFixedSizeValue(uint64 v, uint8* dest) {
+void EncodeFixedSizeValue(uint64_t v, uint8_t* dest) {
   WireFormatLite::WriteFixed64NoTagToArray(v, dest);
 }
 
-void EncodeFixedSizeValue(int32 v, uint8* dest) {
+void EncodeFixedSizeValue(int32_t v, uint8_t* dest) {
   WireFormatLite::WriteSFixed32NoTagToArray(v, dest);
 }
 
-void EncodeFixedSizeValue(int64 v, uint8* dest) {
+void EncodeFixedSizeValue(int64_t v, uint8_t* dest) {
   WireFormatLite::WriteSFixed64NoTagToArray(v, dest);
 }
 
-void EncodeFixedSizeValue(bool v, uint8* dest) {
+void EncodeFixedSizeValue(bool v, uint8_t* dest) {
   WireFormatLite::WriteBoolNoTagToArray(v, dest);
 }
 }  // anonymous namespace
@@ -356,10 +356,10 @@
   output->WriteRaw(reinterpret_cast<const char*>(a), n * sizeof(a[0]));
 #else
   const int kAtATime = 128;
-  uint8 buf[sizeof(CType) * kAtATime];
+  uint8_t buf[sizeof(CType) * kAtATime];
   for (int i = 0; i < n; i += kAtATime) {
     int to_do = std::min(kAtATime, n - i);
-    uint8* ptr = buf;
+    uint8_t* ptr = buf;
     for (int j = 0; j < to_do; j++) {
       EncodeFixedSizeValue(a[i + j], ptr);
       ptr += sizeof(a[0]);
@@ -379,24 +379,24 @@
   WriteArray<double>(a, n, output);
 }
 
-void WireFormatLite::WriteFixed32Array(const uint32* a, int n,
+void WireFormatLite::WriteFixed32Array(const uint32_t* a, int n,
                                        io::CodedOutputStream* output) {
-  WriteArray<uint32>(a, n, output);
+  WriteArray<uint32_t>(a, n, output);
 }
 
-void WireFormatLite::WriteFixed64Array(const uint64* a, int n,
+void WireFormatLite::WriteFixed64Array(const uint64_t* a, int n,
                                        io::CodedOutputStream* output) {
-  WriteArray<uint64>(a, n, output);
+  WriteArray<uint64_t>(a, n, output);
 }
 
-void WireFormatLite::WriteSFixed32Array(const int32* a, int n,
+void WireFormatLite::WriteSFixed32Array(const int32_t* a, int n,
                                         io::CodedOutputStream* output) {
-  WriteArray<int32>(a, n, output);
+  WriteArray<int32_t>(a, n, output);
 }
 
-void WireFormatLite::WriteSFixed64Array(const int64* a, int n,
+void WireFormatLite::WriteSFixed64Array(const int64_t* a, int n,
                                         io::CodedOutputStream* output) {
-  WriteArray<int64>(a, n, output);
+  WriteArray<int64_t>(a, n, output);
 }
 
 void WireFormatLite::WriteBoolArray(const bool* a, int n,
@@ -404,52 +404,52 @@
   WriteArray<bool>(a, n, output);
 }
 
-void WireFormatLite::WriteInt32(int field_number, int32 value,
+void WireFormatLite::WriteInt32(int field_number, int32_t value,
                                 io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_VARINT, output);
   WriteInt32NoTag(value, output);
 }
-void WireFormatLite::WriteInt64(int field_number, int64 value,
+void WireFormatLite::WriteInt64(int field_number, int64_t value,
                                 io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_VARINT, output);
   WriteInt64NoTag(value, output);
 }
-void WireFormatLite::WriteUInt32(int field_number, uint32 value,
+void WireFormatLite::WriteUInt32(int field_number, uint32_t value,
                                  io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_VARINT, output);
   WriteUInt32NoTag(value, output);
 }
-void WireFormatLite::WriteUInt64(int field_number, uint64 value,
+void WireFormatLite::WriteUInt64(int field_number, uint64_t value,
                                  io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_VARINT, output);
   WriteUInt64NoTag(value, output);
 }
-void WireFormatLite::WriteSInt32(int field_number, int32 value,
+void WireFormatLite::WriteSInt32(int field_number, int32_t value,
                                  io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_VARINT, output);
   WriteSInt32NoTag(value, output);
 }
-void WireFormatLite::WriteSInt64(int field_number, int64 value,
+void WireFormatLite::WriteSInt64(int field_number, int64_t value,
                                  io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_VARINT, output);
   WriteSInt64NoTag(value, output);
 }
-void WireFormatLite::WriteFixed32(int field_number, uint32 value,
+void WireFormatLite::WriteFixed32(int field_number, uint32_t value,
                                   io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_FIXED32, output);
   WriteFixed32NoTag(value, output);
 }
-void WireFormatLite::WriteFixed64(int field_number, uint64 value,
+void WireFormatLite::WriteFixed64(int field_number, uint64_t value,
                                   io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_FIXED64, output);
   WriteFixed64NoTag(value, output);
 }
-void WireFormatLite::WriteSFixed32(int field_number, int32 value,
+void WireFormatLite::WriteSFixed32(int field_number, int32_t value,
                                    io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_FIXED32, output);
   WriteSFixed32NoTag(value, output);
 }
-void WireFormatLite::WriteSFixed64(int field_number, int64 value,
+void WireFormatLite::WriteSFixed64(int field_number, int64_t value,
                                    io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_FIXED64, output);
   WriteSFixed64NoTag(value, output);
@@ -551,7 +551,7 @@
     io::CodedInputStream* input, std::string* value);
 inline static bool ReadBytesToString(io::CodedInputStream* input,
                                      std::string* value) {
-  uint32 length;
+  uint32_t length;
   return input->ReadVarint32(&length) && input->ReadString(value, length);
 }
 
@@ -614,10 +614,10 @@
       "Cannot SignExtended unsigned types");
   static_assert(!(SignExtended && ZigZag),
                 "Cannot SignExtended and ZigZag on the same type");
-  uint32 sum = n;
-  uint32 msb_sum = 0;
+  uint32_t sum = n;
+  uint32_t msb_sum = 0;
   for (int i = 0; i < n; i++) {
-    uint32 x = data[i];
+    uint32_t x = data[i];
     if (ZigZag) {
       x = WireFormatLite::ZigZagEncode32(x);
     } else if (SignExtended) {
@@ -642,16 +642,16 @@
   // is_unsigned<T> => !ZigZag
   static_assert(!ZigZag || !std::is_unsigned<T>::value,
                 "Cannot ZigZag encode unsigned types");
-  uint64 sum = n;
+  uint64_t sum = n;
   for (int i = 0; i < n; i++) {
-    uint64 x = data[i];
+    uint64_t x = data[i];
     if (ZigZag) {
       x = WireFormatLite::ZigZagEncode64(x);
     }
     // First step is a binary search, we can't branch in sse so we use the
     // result of the compare to adjust sum and appropriately. This code is
     // written to make clang recognize the vectorization.
-    uint64 tmp = x >= (static_cast<uint64>(1) << 35) ? -1 : 0;
+    uint64_t tmp = x >= (static_cast<uint64_t>(1) << 35) ? -1 : 0;
     sum += 5 & tmp;
     x >>= 35 & tmp;
     if (x > 0x7F) sum++;
@@ -667,15 +667,15 @@
 // varint size routine for each element is faster.
 // Hence we enable it only for clang
 #if defined(__SSE__) && defined(__clang__)
-size_t WireFormatLite::Int32Size(const RepeatedField<int32>& value) {
+size_t WireFormatLite::Int32Size(const RepeatedField<int32_t>& value) {
   return VarintSize<false, true>(value.data(), value.size());
 }
 
-size_t WireFormatLite::UInt32Size(const RepeatedField<uint32>& value) {
+size_t WireFormatLite::UInt32Size(const RepeatedField<uint32_t>& value) {
   return VarintSize<false, false>(value.data(), value.size());
 }
 
-size_t WireFormatLite::SInt32Size(const RepeatedField<int32>& value) {
+size_t WireFormatLite::SInt32Size(const RepeatedField<int32_t>& value) {
   return VarintSize<true, false>(value.data(), value.size());
 }
 
@@ -686,7 +686,7 @@
 
 #else  // !(defined(__SSE4_1__) && defined(__clang__))
 
-size_t WireFormatLite::Int32Size(const RepeatedField<int32>& value) {
+size_t WireFormatLite::Int32Size(const RepeatedField<int32_t>& value) {
   size_t out = 0;
   const int n = value.size();
   for (int i = 0; i < n; i++) {
@@ -695,7 +695,7 @@
   return out;
 }
 
-size_t WireFormatLite::UInt32Size(const RepeatedField<uint32>& value) {
+size_t WireFormatLite::UInt32Size(const RepeatedField<uint32_t>& value) {
   size_t out = 0;
   const int n = value.size();
   for (int i = 0; i < n; i++) {
@@ -704,7 +704,7 @@
   return out;
 }
 
-size_t WireFormatLite::SInt32Size(const RepeatedField<int32>& value) {
+size_t WireFormatLite::SInt32Size(const RepeatedField<int32_t>& value) {
   size_t out = 0;
   const int n = value.size();
   for (int i = 0; i < n; i++) {
@@ -730,21 +730,21 @@
 // enable this.
 #define USE_SSE_FOR_64_BIT_INTEGER_ARRAYS 0
 #if USE_SSE_FOR_64_BIT_INTEGER_ARRAYS
-size_t WireFormatLite::Int64Size(const RepeatedField<int64>& value) {
+size_t WireFormatLite::Int64Size(const RepeatedField<int64_t>& value) {
   return VarintSize64<false>(value.data(), value.size());
 }
 
-size_t WireFormatLite::UInt64Size(const RepeatedField<uint64>& value) {
+size_t WireFormatLite::UInt64Size(const RepeatedField<uint64_t>& value) {
   return VarintSize64<false>(value.data(), value.size());
 }
 
-size_t WireFormatLite::SInt64Size(const RepeatedField<int64>& value) {
+size_t WireFormatLite::SInt64Size(const RepeatedField<int64_t>& value) {
   return VarintSize64<true>(value.data(), value.size());
 }
 
 #else
 
-size_t WireFormatLite::Int64Size(const RepeatedField<int64>& value) {
+size_t WireFormatLite::Int64Size(const RepeatedField<int64_t>& value) {
   size_t out = 0;
   const int n = value.size();
   for (int i = 0; i < n; i++) {
@@ -753,7 +753,7 @@
   return out;
 }
 
-size_t WireFormatLite::UInt64Size(const RepeatedField<uint64>& value) {
+size_t WireFormatLite::UInt64Size(const RepeatedField<uint64_t>& value) {
   size_t out = 0;
   const int n = value.size();
   for (int i = 0; i < n; i++) {
@@ -762,7 +762,7 @@
   return out;
 }
 
-size_t WireFormatLite::SInt64Size(const RepeatedField<int64>& value) {
+size_t WireFormatLite::SInt64Size(const RepeatedField<int64_t>& value) {
   size_t out = 0;
   const int n = value.size();
   for (int i = 0; i < n; i++) {
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index c1abaf1..83668e9 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -157,16 +157,16 @@
   // Number of bits in a tag which identify the wire type.
   static constexpr int kTagTypeBits = 3;
   // Mask for those bits.
-  static constexpr uint32 kTagTypeMask = (1 << kTagTypeBits) - 1;
+  static constexpr uint32_t kTagTypeMask = (1 << kTagTypeBits) - 1;
 
   // Helper functions for encoding and decoding tags.  (Inlined below and in
   // _inl.h)
   //
   // This is different from MakeTag(field->number(), field->type()) in the
   // case of packed repeated fields.
-  constexpr static uint32 MakeTag(int field_number, WireType type);
-  static WireType GetTagWireType(uint32 tag);
-  static int GetTagFieldNumber(uint32 tag);
+  constexpr static uint32_t MakeTag(int field_number, WireType type);
+  static WireType GetTagWireType(uint32_t tag);
+  static int GetTagFieldNumber(uint32_t tag);
 
   // Compute the byte size of a tag.  For groups, this includes both the start
   // and end tags.
@@ -177,12 +177,12 @@
   // positioned immediately after the tag.  Skipped values are simply
   // discarded, not recorded anywhere.  See WireFormat::SkipField() for a
   // version that records to an UnknownFieldSet.
-  static bool SkipField(io::CodedInputStream* input, uint32 tag);
+  static bool SkipField(io::CodedInputStream* input, uint32_t tag);
 
   // Skips a field value with the given tag.  The input should start
   // positioned immediately after the tag. Skipped values are recorded to a
   // CodedOutputStream.
-  static bool SkipField(io::CodedInputStream* input, uint32 tag,
+  static bool SkipField(io::CodedInputStream* input, uint32_t tag,
                         io::CodedOutputStream* output);
 
   // Reads and ignores a message from the input.  Skipped values are simply
@@ -200,7 +200,7 @@
   // as a switch case or a template input.  WireFormatLite::MakeTag() is more
   // type-safe, though, so prefer it if possible.
 #define GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(FIELD_NUMBER, TYPE) \
-  static_cast<uint32>((static_cast<uint32>(FIELD_NUMBER) << 3) | (TYPE))
+  static_cast<uint32_t>((static_cast<uint32_t>(FIELD_NUMBER) << 3) | (TYPE))
 
   // These are the tags for the old MessageSet format, which was defined as:
   //   message MessageSet {
@@ -227,10 +227,10 @@
   // Helper functions for converting between floats/doubles and IEEE-754
   // uint32s/uint64s so that they can be written.  (Assumes your platform
   // uses IEEE-754 floats.)
-  static uint32 EncodeFloat(float value);
-  static float DecodeFloat(uint32 value);
-  static uint64 EncodeDouble(double value);
-  static double DecodeDouble(uint64 value);
+  static uint32_t EncodeFloat(float value);
+  static float DecodeFloat(uint32_t value);
+  static uint64_t EncodeDouble(double value);
+  static double DecodeDouble(uint64_t value);
 
   // Helper functions for mapping signed integers to unsigned integers in
   // such a way that numbers with small magnitudes will encode to smaller
@@ -238,10 +238,10 @@
   // number and varint-encode it, it will always take 10 bytes, defeating
   // the purpose of varint.  So, for the "sint32" and "sint64" field types,
   // we ZigZag-encode the values.
-  static uint32 ZigZagEncode32(int32 n);
-  static int32 ZigZagDecode32(uint32 n);
-  static uint64 ZigZagEncode64(int64 n);
-  static int64 ZigZagDecode64(uint64 n);
+  static uint32_t ZigZagEncode32(int32_t n);
+  static int32_t ZigZagDecode32(uint32_t n);
+  static uint64_t ZigZagEncode64(int64_t n);
+  static int64_t ZigZagDecode64(uint64_t n);
 
   // =================================================================
   // Methods for reading/writing individual field.
@@ -261,13 +261,13 @@
   // protocol compiler.
   template <typename CType, enum FieldType DeclaredType>
   PROTOBUF_NDEBUG_INLINE static bool ReadRepeatedPrimitive(
-      int tag_size, uint32 tag, io::CodedInputStream* input,
+      int tag_size, uint32_t tag, io::CodedInputStream* input,
       RepeatedField<CType>* value);
 
   // Identical to ReadRepeatedPrimitive, except will not inline the
   // implementation.
   template <typename CType, enum FieldType DeclaredType>
-  static bool ReadRepeatedPrimitiveNoInline(int tag_size, uint32 tag,
+  static bool ReadRepeatedPrimitiveNoInline(int tag_size, uint32_t tag,
                                             io::CodedInputStream* input,
                                             RepeatedField<CType>* value);
 
@@ -277,8 +277,8 @@
   // This is only implemented for the types with fixed wire size, e.g.
   // float, double, and the (s)fixed* types.
   template <typename CType, enum FieldType DeclaredType>
-  PROTOBUF_NDEBUG_INLINE static const uint8* ReadPrimitiveFromArray(
-      const uint8* buffer, CType* value);
+  PROTOBUF_NDEBUG_INLINE static const uint8_t* ReadPrimitiveFromArray(
+      const uint8_t* buffer, CType* value);
 
   // Reads a primitive packed field.
   //
@@ -350,25 +350,25 @@
 
   // Write fields, without tags.
   PROTOBUF_NDEBUG_INLINE static void WriteInt32NoTag(
-      int32 value, io::CodedOutputStream* output);
+      int32_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteInt64NoTag(
-      int64 value, io::CodedOutputStream* output);
+      int64_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteUInt32NoTag(
-      uint32 value, io::CodedOutputStream* output);
+      uint32_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteUInt64NoTag(
-      uint64 value, io::CodedOutputStream* output);
+      uint64_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteSInt32NoTag(
-      int32 value, io::CodedOutputStream* output);
+      int32_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteSInt64NoTag(
-      int64 value, io::CodedOutputStream* output);
+      int64_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteFixed32NoTag(
-      uint32 value, io::CodedOutputStream* output);
+      uint32_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteFixed64NoTag(
-      uint64 value, io::CodedOutputStream* output);
+      uint64_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteSFixed32NoTag(
-      int32 value, io::CodedOutputStream* output);
+      int32_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteSFixed64NoTag(
-      int64 value, io::CodedOutputStream* output);
+      int64_t value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteFloatNoTag(
       float value, io::CodedOutputStream* output);
   PROTOBUF_NDEBUG_INLINE static void WriteDoubleNoTag(
@@ -383,37 +383,37 @@
                               io::CodedOutputStream* output);
   static void WriteDoubleArray(const double* a, int n,
                                io::CodedOutputStream* output);
-  static void WriteFixed32Array(const uint32* a, int n,
+  static void WriteFixed32Array(const uint32_t* a, int n,
                                 io::CodedOutputStream* output);
-  static void WriteFixed64Array(const uint64* a, int n,
+  static void WriteFixed64Array(const uint64_t* a, int n,
                                 io::CodedOutputStream* output);
-  static void WriteSFixed32Array(const int32* a, int n,
+  static void WriteSFixed32Array(const int32_t* a, int n,
                                  io::CodedOutputStream* output);
-  static void WriteSFixed64Array(const int64* a, int n,
+  static void WriteSFixed64Array(const int64_t* a, int n,
                                  io::CodedOutputStream* output);
   static void WriteBoolArray(const bool* a, int n,
                              io::CodedOutputStream* output);
 
   // Write fields, including tags.
-  static void WriteInt32(int field_number, int32 value,
+  static void WriteInt32(int field_number, int32_t value,
                          io::CodedOutputStream* output);
-  static void WriteInt64(int field_number, int64 value,
+  static void WriteInt64(int field_number, int64_t value,
                          io::CodedOutputStream* output);
-  static void WriteUInt32(int field_number, uint32 value,
+  static void WriteUInt32(int field_number, uint32_t value,
                           io::CodedOutputStream* output);
-  static void WriteUInt64(int field_number, uint64 value,
+  static void WriteUInt64(int field_number, uint64_t value,
                           io::CodedOutputStream* output);
-  static void WriteSInt32(int field_number, int32 value,
+  static void WriteSInt32(int field_number, int32_t value,
                           io::CodedOutputStream* output);
-  static void WriteSInt64(int field_number, int64 value,
+  static void WriteSInt64(int field_number, int64_t value,
                           io::CodedOutputStream* output);
-  static void WriteFixed32(int field_number, uint32 value,
+  static void WriteFixed32(int field_number, uint32_t value,
                            io::CodedOutputStream* output);
-  static void WriteFixed64(int field_number, uint64 value,
+  static void WriteFixed64(int field_number, uint64_t value,
                            io::CodedOutputStream* output);
-  static void WriteSFixed32(int field_number, int32 value,
+  static void WriteSFixed32(int field_number, int32_t value,
                             io::CodedOutputStream* output);
-  static void WriteSFixed64(int field_number, int64 value,
+  static void WriteSFixed64(int field_number, int64_t value,
                             io::CodedOutputStream* output);
   static void WriteFloat(int field_number, float value,
                          io::CodedOutputStream* output);
@@ -459,161 +459,161 @@
                                            io::CodedOutputStream* output);
 
   // Like above, but use only *ToArray methods of CodedOutputStream.
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteTagToArray(int field_number,
-                                                       WireType type,
-                                                       uint8* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteTagToArray(int field_number,
+                                                         WireType type,
+                                                         uint8_t* target);
 
   // Write fields, without tags.
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteInt32NoTagToArray(int32 value,
-                                                              uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteInt64NoTagToArray(int64 value,
-                                                              uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteUInt32NoTagToArray(uint32 value,
-                                                               uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteUInt64NoTagToArray(uint64 value,
-                                                               uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSInt32NoTagToArray(int32 value,
-                                                               uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSInt64NoTagToArray(int64 value,
-                                                               uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFixed32NoTagToArray(uint32 value,
-                                                                uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFixed64NoTagToArray(uint64 value,
-                                                                uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSFixed32NoTagToArray(int32 value,
-                                                                 uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSFixed64NoTagToArray(int64 value,
-                                                                 uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFloatNoTagToArray(float value,
-                                                              uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteDoubleNoTagToArray(double value,
-                                                               uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteBoolNoTagToArray(bool value,
-                                                             uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteEnumNoTagToArray(int value,
-                                                             uint8* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32NoTagToArray(
+      int32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64NoTagToArray(
+      int64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32NoTagToArray(
+      uint32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64NoTagToArray(
+      uint64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32NoTagToArray(
+      int32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64NoTagToArray(
+      int64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32NoTagToArray(
+      uint32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64NoTagToArray(
+      uint64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32NoTagToArray(
+      int32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64NoTagToArray(
+      int64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatNoTagToArray(
+      float value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleNoTagToArray(
+      double value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolNoTagToArray(bool value,
+                                                               uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumNoTagToArray(int value,
+                                                               uint8_t* target);
 
   // Write fields, without tags.  These require that value.size() > 0.
   template <typename T>
-  PROTOBUF_NDEBUG_INLINE static uint8* WritePrimitiveNoTagToArray(
-      const RepeatedField<T>& value, uint8* (*Writer)(T, uint8*),
-      uint8* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WritePrimitiveNoTagToArray(
+      const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+      uint8_t* target);
   template <typename T>
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFixedNoTagToArray(
-      const RepeatedField<T>& value, uint8* (*Writer)(T, uint8*),
-      uint8* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixedNoTagToArray(
+      const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+      uint8_t* target);
 
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteInt32NoTagToArray(
-      const RepeatedField<int32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteInt64NoTagToArray(
-      const RepeatedField<int64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteUInt32NoTagToArray(
-      const RepeatedField<uint32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteUInt64NoTagToArray(
-      const RepeatedField<uint64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSInt32NoTagToArray(
-      const RepeatedField<int32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSInt64NoTagToArray(
-      const RepeatedField<int64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFixed32NoTagToArray(
-      const RepeatedField<uint32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFixed64NoTagToArray(
-      const RepeatedField<uint64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSFixed32NoTagToArray(
-      const RepeatedField<int32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSFixed64NoTagToArray(
-      const RepeatedField<int64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFloatNoTagToArray(
-      const RepeatedField<float>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteDoubleNoTagToArray(
-      const RepeatedField<double>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteBoolNoTagToArray(
-      const RepeatedField<bool>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteEnumNoTagToArray(
-      const RepeatedField<int>& value, uint8* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32NoTagToArray(
+      const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64NoTagToArray(
+      const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32NoTagToArray(
+      const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64NoTagToArray(
+      const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32NoTagToArray(
+      const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64NoTagToArray(
+      const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32NoTagToArray(
+      const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64NoTagToArray(
+      const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32NoTagToArray(
+      const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64NoTagToArray(
+      const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatNoTagToArray(
+      const RepeatedField<float>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleNoTagToArray(
+      const RepeatedField<double>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolNoTagToArray(
+      const RepeatedField<bool>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumNoTagToArray(
+      const RepeatedField<int>& value, uint8_t* output);
 
   // Write fields, including tags.
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteInt32ToArray(int field_number,
-                                                         int32 value,
-                                                         uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteInt64ToArray(int field_number,
-                                                         int64 value,
-                                                         uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteUInt32ToArray(int field_number,
-                                                          uint32 value,
-                                                          uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteUInt64ToArray(int field_number,
-                                                          uint64 value,
-                                                          uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSInt32ToArray(int field_number,
-                                                          int32 value,
-                                                          uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSInt64ToArray(int field_number,
-                                                          int64 value,
-                                                          uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFixed32ToArray(int field_number,
-                                                           uint32 value,
-                                                           uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFixed64ToArray(int field_number,
-                                                           uint64 value,
-                                                           uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSFixed32ToArray(int field_number,
-                                                            int32 value,
-                                                            uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSFixed64ToArray(int field_number,
-                                                            int64 value,
-                                                            uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFloatToArray(int field_number,
-                                                         float value,
-                                                         uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteDoubleToArray(int field_number,
-                                                          double value,
-                                                          uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteBoolToArray(int field_number,
-                                                        bool value,
-                                                        uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteEnumToArray(int field_number,
-                                                        int value,
-                                                        uint8* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32ToArray(int field_number,
+                                                           int32_t value,
+                                                           uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64ToArray(int field_number,
+                                                           int64_t value,
+                                                           uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32ToArray(int field_number,
+                                                            uint32_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64ToArray(int field_number,
+                                                            uint64_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32ToArray(int field_number,
+                                                            int32_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64ToArray(int field_number,
+                                                            int64_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32ToArray(int field_number,
+                                                             uint32_t value,
+                                                             uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64ToArray(int field_number,
+                                                             uint64_t value,
+                                                             uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32ToArray(int field_number,
+                                                              int32_t value,
+                                                              uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64ToArray(int field_number,
+                                                              int64_t value,
+                                                              uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatToArray(int field_number,
+                                                           float value,
+                                                           uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleToArray(int field_number,
+                                                            double value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolToArray(int field_number,
+                                                          bool value,
+                                                          uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumToArray(int field_number,
+                                                          int value,
+                                                          uint8_t* target);
 
   template <typename T>
-  PROTOBUF_NDEBUG_INLINE static uint8* WritePrimitiveToArray(
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WritePrimitiveToArray(
       int field_number, const RepeatedField<T>& value,
-      uint8* (*Writer)(int, T, uint8*), uint8* target);
+      uint8_t* (*Writer)(int, T, uint8_t*), uint8_t* target);
 
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteInt32ToArray(
-      int field_number, const RepeatedField<int32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteInt64ToArray(
-      int field_number, const RepeatedField<int64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteUInt32ToArray(
-      int field_number, const RepeatedField<uint32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteUInt64ToArray(
-      int field_number, const RepeatedField<uint64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSInt32ToArray(
-      int field_number, const RepeatedField<int32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSInt64ToArray(
-      int field_number, const RepeatedField<int64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFixed32ToArray(
-      int field_number, const RepeatedField<uint32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFixed64ToArray(
-      int field_number, const RepeatedField<uint64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSFixed32ToArray(
-      int field_number, const RepeatedField<int32>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteSFixed64ToArray(
-      int field_number, const RepeatedField<int64>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteFloatToArray(
-      int field_number, const RepeatedField<float>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteDoubleToArray(
-      int field_number, const RepeatedField<double>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteBoolToArray(
-      int field_number, const RepeatedField<bool>& value, uint8* output);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteEnumToArray(
-      int field_number, const RepeatedField<int>& value, uint8* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32ToArray(
+      int field_number, const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64ToArray(
+      int field_number, const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32ToArray(
+      int field_number, const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64ToArray(
+      int field_number, const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32ToArray(
+      int field_number, const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64ToArray(
+      int field_number, const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32ToArray(
+      int field_number, const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64ToArray(
+      int field_number, const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32ToArray(
+      int field_number, const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64ToArray(
+      int field_number, const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatToArray(
+      int field_number, const RepeatedField<float>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleToArray(
+      int field_number, const RepeatedField<double>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolToArray(
+      int field_number, const RepeatedField<bool>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumToArray(
+      int field_number, const RepeatedField<int>& value, uint8_t* output);
 
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteStringToArray(
-      int field_number, const std::string& value, uint8* target);
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteBytesToArray(
-      int field_number, const std::string& value, uint8* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteStringToArray(
+      int field_number, const std::string& value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBytesToArray(
+      int field_number, const std::string& value, uint8_t* target);
 
   // Whether to serialize deterministically (e.g., map keys are
   // sorted) is a property of a CodedOutputStream, and in the process
@@ -621,43 +621,43 @@
   // have a CodedOutputStream available, so they get an additional parameter
   // telling them whether to serialize deterministically.
   template <typename MessageType>
-  PROTOBUF_NDEBUG_INLINE static uint8* InternalWriteGroup(
-      int field_number, const MessageType& value, uint8* target,
+  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteGroup(
+      int field_number, const MessageType& value, uint8_t* target,
       io::EpsCopyOutputStream* stream);
   template <typename MessageType>
-  PROTOBUF_NDEBUG_INLINE static uint8* InternalWriteMessage(
-      int field_number, const MessageType& value, uint8* target,
+  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteMessage(
+      int field_number, const MessageType& value, uint8_t* target,
       io::EpsCopyOutputStream* stream);
 
   // Like above, but de-virtualize the call to SerializeWithCachedSizes().  The
   // pointer must point at an instance of MessageType, *not* a subclass (or
   // the subclass must not override SerializeWithCachedSizes()).
   template <typename MessageType>
-  PROTOBUF_NDEBUG_INLINE static uint8* InternalWriteGroupNoVirtualToArray(
-      int field_number, const MessageType& value, uint8* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteGroupNoVirtualToArray(
+      int field_number, const MessageType& value, uint8_t* target);
   template <typename MessageType>
-  PROTOBUF_NDEBUG_INLINE static uint8* InternalWriteMessageNoVirtualToArray(
-      int field_number, const MessageType& value, uint8* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteMessageNoVirtualToArray(
+      int field_number, const MessageType& value, uint8_t* target);
 
   // For backward-compatibility, the last four methods also have versions
   // that are non-deterministic always.
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteGroupToArray(
-      int field_number, const MessageLite& value, uint8* target) {
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteGroupToArray(
+      int field_number, const MessageLite& value, uint8_t* target) {
     io::EpsCopyOutputStream stream(
         target,
         value.GetCachedSize() +
             static_cast<int>(2 * io::CodedOutputStream::VarintSize32(
-                                     static_cast<uint32>(field_number) << 3)),
+                                     static_cast<uint32_t>(field_number) << 3)),
         io::CodedOutputStream::IsDefaultSerializationDeterministic());
     return InternalWriteGroup(field_number, value, target, &stream);
   }
-  PROTOBUF_NDEBUG_INLINE static uint8* WriteMessageToArray(
-      int field_number, const MessageLite& value, uint8* target) {
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteMessageToArray(
+      int field_number, const MessageLite& value, uint8_t* target) {
     int size = value.GetCachedSize();
     io::EpsCopyOutputStream stream(
         target,
         size + static_cast<int>(io::CodedOutputStream::VarintSize32(
-                                    static_cast<uint32>(field_number) << 3) +
+                                    static_cast<uint32_t>(field_number) << 3) +
                                 io::CodedOutputStream::VarintSize32(size)),
         io::CodedOutputStream::IsDefaultSerializationDeterministic());
     return InternalWriteMessage(field_number, value, target, &stream);
@@ -667,20 +667,27 @@
   // the tag, so you must also call TagSize().  (This is because, for repeated
   // fields, you should only call TagSize() once and multiply it by the element
   // count, but you may have to call XxSize() for each individual element.)
-  static inline size_t Int32Size(int32 value);
-  static inline size_t Int64Size(int64 value);
-  static inline size_t UInt32Size(uint32 value);
-  static inline size_t UInt64Size(uint64 value);
-  static inline size_t SInt32Size(int32 value);
-  static inline size_t SInt64Size(int64 value);
+  static inline size_t Int32Size(int32_t value);
+  static inline size_t Int64Size(int64_t value);
+  static inline size_t UInt32Size(uint32_t value);
+  static inline size_t UInt64Size(uint64_t value);
+  static inline size_t SInt32Size(int32_t value);
+  static inline size_t SInt64Size(int64_t value);
   static inline size_t EnumSize(int value);
+  static inline size_t Int32SizePlusOne(int32_t value);
+  static inline size_t Int64SizePlusOne(int64_t value);
+  static inline size_t UInt32SizePlusOne(uint32_t value);
+  static inline size_t UInt64SizePlusOne(uint64_t value);
+  static inline size_t SInt32SizePlusOne(int32_t value);
+  static inline size_t SInt64SizePlusOne(int64_t value);
+  static inline size_t EnumSizePlusOne(int value);
 
-  static size_t Int32Size(const RepeatedField<int32>& value);
-  static size_t Int64Size(const RepeatedField<int64>& value);
-  static size_t UInt32Size(const RepeatedField<uint32>& value);
-  static size_t UInt64Size(const RepeatedField<uint64>& value);
-  static size_t SInt32Size(const RepeatedField<int32>& value);
-  static size_t SInt64Size(const RepeatedField<int64>& value);
+  static size_t Int32Size(const RepeatedField<int32_t>& value);
+  static size_t Int64Size(const RepeatedField<int64_t>& value);
+  static size_t UInt32Size(const RepeatedField<uint32_t>& value);
+  static size_t UInt64Size(const RepeatedField<uint64_t>& value);
+  static size_t SInt32Size(const RepeatedField<int32_t>& value);
+  static size_t SInt64Size(const RepeatedField<int64_t>& value);
   static size_t EnumSize(const RepeatedField<int>& value);
 
   // These types always have the same size.
@@ -718,7 +725,7 @@
   // can be read using potentially faster paths.
   template <typename CType, enum FieldType DeclaredType>
   PROTOBUF_NDEBUG_INLINE static bool ReadRepeatedFixedSizePrimitive(
-      int tag_size, uint32 tag, io::CodedInputStream* input,
+      int tag_size, uint32_t tag, io::CodedInputStream* input,
       RepeatedField<CType>* value);
 
   // Like ReadRepeatedFixedSizePrimitive but for packed primitive fields.
@@ -744,7 +751,7 @@
   virtual ~FieldSkipper() {}
 
   // Skip a field whose tag has already been consumed.
-  virtual bool SkipField(io::CodedInputStream* input, uint32 tag);
+  virtual bool SkipField(io::CodedInputStream* input, uint32_t tag);
 
   // Skip an entire message or group, up to an end-group tag (which is consumed)
   // or end-of-stream.
@@ -765,7 +772,7 @@
   ~CodedOutputStreamFieldSkipper() override {}
 
   // implements FieldSkipper -----------------------------------------
-  bool SkipField(io::CodedInputStream* input, uint32 tag) override;
+  bool SkipField(io::CodedInputStream* input, uint32_t tag) override;
   bool SkipMessage(io::CodedInputStream* input) override;
   void SkipUnknownEnum(int field_number, int value) override;
 
@@ -780,23 +787,23 @@
   return kFieldTypeToCppTypeMap[type];
 }
 
-constexpr inline uint32 WireFormatLite::MakeTag(int field_number,
-                                                WireType type) {
+constexpr inline uint32_t WireFormatLite::MakeTag(int field_number,
+                                                  WireType type) {
   return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type);
 }
 
-inline WireFormatLite::WireType WireFormatLite::GetTagWireType(uint32 tag) {
+inline WireFormatLite::WireType WireFormatLite::GetTagWireType(uint32_t tag) {
   return static_cast<WireType>(tag & kTagTypeMask);
 }
 
-inline int WireFormatLite::GetTagFieldNumber(uint32 tag) {
+inline int WireFormatLite::GetTagFieldNumber(uint32_t tag) {
   return static_cast<int>(tag >> kTagTypeBits);
 }
 
 inline size_t WireFormatLite::TagSize(int field_number,
                                       WireFormatLite::FieldType type) {
   size_t result = io::CodedOutputStream::VarintSize32(
-      static_cast<uint32>(field_number << kTagTypeBits));
+      static_cast<uint32_t>(field_number << kTagTypeBits));
   if (type == TYPE_GROUP) {
     // Groups have both a start and an end tag.
     return result * 2;
@@ -805,19 +812,19 @@
   }
 }
 
-inline uint32 WireFormatLite::EncodeFloat(float value) {
-  return bit_cast<uint32>(value);
+inline uint32_t WireFormatLite::EncodeFloat(float value) {
+  return bit_cast<uint32_t>(value);
 }
 
-inline float WireFormatLite::DecodeFloat(uint32 value) {
+inline float WireFormatLite::DecodeFloat(uint32_t value) {
   return bit_cast<float>(value);
 }
 
-inline uint64 WireFormatLite::EncodeDouble(double value) {
-  return bit_cast<uint64>(value);
+inline uint64_t WireFormatLite::EncodeDouble(double value) {
+  return bit_cast<uint64_t>(value);
 }
 
-inline double WireFormatLite::DecodeDouble(uint64 value) {
+inline double WireFormatLite::DecodeDouble(uint64_t value) {
   return bit_cast<double>(value);
 }
 
@@ -832,7 +839,7 @@
 // in such a way that those with a small absolute value will have smaller
 // encoded values, making them appropriate for encoding using varint.
 //
-//       int32 ->     uint32
+//       int32_t ->     uint32_t
 // -------------------------
 //           0 ->          0
 //          -1 ->          1
@@ -845,26 +852,26 @@
 //        >> encode >>
 //        << decode <<
 
-inline uint32 WireFormatLite::ZigZagEncode32(int32 n) {
+inline uint32_t WireFormatLite::ZigZagEncode32(int32_t n) {
   // Note:  the right-shift must be arithmetic
   // Note:  left shift must be unsigned because of overflow
-  return (static_cast<uint32>(n) << 1) ^ static_cast<uint32>(n >> 31);
+  return (static_cast<uint32_t>(n) << 1) ^ static_cast<uint32_t>(n >> 31);
 }
 
-inline int32 WireFormatLite::ZigZagDecode32(uint32 n) {
+inline int32_t WireFormatLite::ZigZagDecode32(uint32_t n) {
   // Note:  Using unsigned types prevent undefined behavior
-  return static_cast<int32>((n >> 1) ^ (~(n & 1) + 1));
+  return static_cast<int32_t>((n >> 1) ^ (~(n & 1) + 1));
 }
 
-inline uint64 WireFormatLite::ZigZagEncode64(int64 n) {
+inline uint64_t WireFormatLite::ZigZagEncode64(int64_t n) {
   // Note:  the right-shift must be arithmetic
   // Note:  left shift must be unsigned because of overflow
-  return (static_cast<uint64>(n) << 1) ^ static_cast<uint64>(n >> 63);
+  return (static_cast<uint64_t>(n) << 1) ^ static_cast<uint64_t>(n >> 63);
 }
 
-inline int64 WireFormatLite::ZigZagDecode64(uint64 n) {
+inline int64_t WireFormatLite::ZigZagDecode64(uint64_t n) {
   // Note:  Using unsigned types prevent undefined behavior
-  return static_cast<int64>((n >> 1) ^ (~(n & 1) + 1));
+  return static_cast<int64_t>((n >> 1) ^ (~(n & 1) + 1));
 }
 
 // String is for UTF-8 text only, but, even so, ReadString() can simply
@@ -880,8 +887,8 @@
   return ReadBytes(input, p);
 }
 
-inline uint8* InternalSerializeUnknownMessageSetItemsToArray(
-    const std::string& unknown_fields, uint8* target,
+inline uint8_t* InternalSerializeUnknownMessageSetItemsToArray(
+    const std::string& unknown_fields, uint8_t* target,
     io::EpsCopyOutputStream* stream) {
   return stream->WriteRaw(unknown_fields.data(),
                           static_cast<int>(unknown_fields.size()), target);
@@ -895,77 +902,83 @@
 // Implementation details of ReadPrimitive.
 
 template <>
-inline bool WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>(
-    io::CodedInputStream* input, int32* value) {
-  uint32 temp;
+inline bool WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_INT32>(
+    io::CodedInputStream* input, int32_t* value) {
+  uint32_t temp;
   if (!input->ReadVarint32(&temp)) return false;
-  *value = static_cast<int32>(temp);
+  *value = static_cast<int32_t>(temp);
   return true;
 }
 template <>
-inline bool WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_INT64>(
-    io::CodedInputStream* input, int64* value) {
-  uint64 temp;
+inline bool WireFormatLite::ReadPrimitive<int64_t, WireFormatLite::TYPE_INT64>(
+    io::CodedInputStream* input, int64_t* value) {
+  uint64_t temp;
   if (!input->ReadVarint64(&temp)) return false;
-  *value = static_cast<int64>(temp);
+  *value = static_cast<int64_t>(temp);
   return true;
 }
 template <>
-inline bool WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(
-    io::CodedInputStream* input, uint32* value) {
+inline bool
+WireFormatLite::ReadPrimitive<uint32_t, WireFormatLite::TYPE_UINT32>(
+    io::CodedInputStream* input, uint32_t* value) {
   return input->ReadVarint32(value);
 }
 template <>
-inline bool WireFormatLite::ReadPrimitive<uint64, WireFormatLite::TYPE_UINT64>(
-    io::CodedInputStream* input, uint64* value) {
+inline bool
+WireFormatLite::ReadPrimitive<uint64_t, WireFormatLite::TYPE_UINT64>(
+    io::CodedInputStream* input, uint64_t* value) {
   return input->ReadVarint64(value);
 }
 template <>
-inline bool WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>(
-    io::CodedInputStream* input, int32* value) {
-  uint32 temp;
+inline bool WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_SINT32>(
+    io::CodedInputStream* input, int32_t* value) {
+  uint32_t temp;
   if (!input->ReadVarint32(&temp)) return false;
   *value = ZigZagDecode32(temp);
   return true;
 }
 template <>
-inline bool WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_SINT64>(
-    io::CodedInputStream* input, int64* value) {
-  uint64 temp;
+inline bool WireFormatLite::ReadPrimitive<int64_t, WireFormatLite::TYPE_SINT64>(
+    io::CodedInputStream* input, int64_t* value) {
+  uint64_t temp;
   if (!input->ReadVarint64(&temp)) return false;
   *value = ZigZagDecode64(temp);
   return true;
 }
 template <>
-inline bool WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_FIXED32>(
-    io::CodedInputStream* input, uint32* value) {
+inline bool
+WireFormatLite::ReadPrimitive<uint32_t, WireFormatLite::TYPE_FIXED32>(
+    io::CodedInputStream* input, uint32_t* value) {
   return input->ReadLittleEndian32(value);
 }
 template <>
-inline bool WireFormatLite::ReadPrimitive<uint64, WireFormatLite::TYPE_FIXED64>(
-    io::CodedInputStream* input, uint64* value) {
+inline bool
+WireFormatLite::ReadPrimitive<uint64_t, WireFormatLite::TYPE_FIXED64>(
+    io::CodedInputStream* input, uint64_t* value) {
   return input->ReadLittleEndian64(value);
 }
 template <>
-inline bool WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SFIXED32>(
-    io::CodedInputStream* input, int32* value) {
-  uint32 temp;
+inline bool
+WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_SFIXED32>(
+    io::CodedInputStream* input, int32_t* value) {
+  uint32_t temp;
   if (!input->ReadLittleEndian32(&temp)) return false;
-  *value = static_cast<int32>(temp);
+  *value = static_cast<int32_t>(temp);
   return true;
 }
 template <>
-inline bool WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_SFIXED64>(
-    io::CodedInputStream* input, int64* value) {
-  uint64 temp;
+inline bool
+WireFormatLite::ReadPrimitive<int64_t, WireFormatLite::TYPE_SFIXED64>(
+    io::CodedInputStream* input, int64_t* value) {
+  uint64_t temp;
   if (!input->ReadLittleEndian64(&temp)) return false;
-  *value = static_cast<int64>(temp);
+  *value = static_cast<int64_t>(temp);
   return true;
 }
 template <>
 inline bool WireFormatLite::ReadPrimitive<float, WireFormatLite::TYPE_FLOAT>(
     io::CodedInputStream* input, float* value) {
-  uint32 temp;
+  uint32_t temp;
   if (!input->ReadLittleEndian32(&temp)) return false;
   *value = DecodeFloat(temp);
   return true;
@@ -973,7 +986,7 @@
 template <>
 inline bool WireFormatLite::ReadPrimitive<double, WireFormatLite::TYPE_DOUBLE>(
     io::CodedInputStream* input, double* value) {
-  uint64 temp;
+  uint64_t temp;
   if (!input->ReadLittleEndian64(&temp)) return false;
   *value = DecodeDouble(temp);
   return true;
@@ -981,7 +994,7 @@
 template <>
 inline bool WireFormatLite::ReadPrimitive<bool, WireFormatLite::TYPE_BOOL>(
     io::CodedInputStream* input, bool* value) {
-  uint64 temp;
+  uint64_t temp;
   if (!input->ReadVarint64(&temp)) return false;
   *value = temp != 0;
   return true;
@@ -989,56 +1002,56 @@
 template <>
 inline bool WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
     io::CodedInputStream* input, int* value) {
-  uint32 temp;
+  uint32_t temp;
   if (!input->ReadVarint32(&temp)) return false;
   *value = static_cast<int>(temp);
   return true;
 }
 
 template <>
-inline const uint8*
-WireFormatLite::ReadPrimitiveFromArray<uint32, WireFormatLite::TYPE_FIXED32>(
-    const uint8* buffer, uint32* value) {
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<uint32_t, WireFormatLite::TYPE_FIXED32>(
+    const uint8_t* buffer, uint32_t* value) {
   return io::CodedInputStream::ReadLittleEndian32FromArray(buffer, value);
 }
 template <>
-inline const uint8*
-WireFormatLite::ReadPrimitiveFromArray<uint64, WireFormatLite::TYPE_FIXED64>(
-    const uint8* buffer, uint64* value) {
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<uint64_t, WireFormatLite::TYPE_FIXED64>(
+    const uint8_t* buffer, uint64_t* value) {
   return io::CodedInputStream::ReadLittleEndian64FromArray(buffer, value);
 }
 template <>
-inline const uint8*
-WireFormatLite::ReadPrimitiveFromArray<int32, WireFormatLite::TYPE_SFIXED32>(
-    const uint8* buffer, int32* value) {
-  uint32 temp;
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<int32_t, WireFormatLite::TYPE_SFIXED32>(
+    const uint8_t* buffer, int32_t* value) {
+  uint32_t temp;
   buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp);
-  *value = static_cast<int32>(temp);
+  *value = static_cast<int32_t>(temp);
   return buffer;
 }
 template <>
-inline const uint8*
-WireFormatLite::ReadPrimitiveFromArray<int64, WireFormatLite::TYPE_SFIXED64>(
-    const uint8* buffer, int64* value) {
-  uint64 temp;
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<int64_t, WireFormatLite::TYPE_SFIXED64>(
+    const uint8_t* buffer, int64_t* value) {
+  uint64_t temp;
   buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp);
-  *value = static_cast<int64>(temp);
+  *value = static_cast<int64_t>(temp);
   return buffer;
 }
 template <>
-inline const uint8*
+inline const uint8_t*
 WireFormatLite::ReadPrimitiveFromArray<float, WireFormatLite::TYPE_FLOAT>(
-    const uint8* buffer, float* value) {
-  uint32 temp;
+    const uint8_t* buffer, float* value) {
+  uint32_t temp;
   buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp);
   *value = DecodeFloat(temp);
   return buffer;
 }
 template <>
-inline const uint8*
+inline const uint8_t*
 WireFormatLite::ReadPrimitiveFromArray<double, WireFormatLite::TYPE_DOUBLE>(
-    const uint8* buffer, double* value) {
-  uint64 temp;
+    const uint8_t* buffer, double* value) {
+  uint64_t temp;
   buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp);
   *value = DecodeDouble(temp);
   return buffer;
@@ -1047,7 +1060,7 @@
 template <typename CType, enum WireFormatLite::FieldType DeclaredType>
 inline bool WireFormatLite::ReadRepeatedPrimitive(
     int,  // tag_size, unused.
-    uint32 tag, io::CodedInputStream* input, RepeatedField<CType>* values) {
+    uint32_t tag, io::CodedInputStream* input, RepeatedField<CType>* values) {
   CType value;
   if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
   values->Add(value);
@@ -1062,7 +1075,7 @@
 
 template <typename CType, enum WireFormatLite::FieldType DeclaredType>
 inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive(
-    int tag_size, uint32 tag, io::CodedInputStream* input,
+    int tag_size, uint32_t tag, io::CodedInputStream* input,
     RepeatedField<CType>* values) {
   GOOGLE_DCHECK_EQ(UInt32Size(tag), static_cast<size_t>(tag_size));
   CType value;
@@ -1082,7 +1095,7 @@
   int size;
   input->GetDirectBufferPointerInline(&void_pointer, &size);
   if (size > 0) {
-    const uint8* buffer = reinterpret_cast<const uint8*>(void_pointer);
+    const uint8_t* buffer = reinterpret_cast<const uint8_t*>(void_pointer);
     // The number of bytes each type occupies on the wire.
     const int per_value_size = tag_size + static_cast<int>(sizeof(value));
 
@@ -1111,17 +1124,17 @@
   template <>                                                             \
   inline bool WireFormatLite::ReadRepeatedPrimitive<                      \
       CPPTYPE, WireFormatLite::DECLARED_TYPE>(                            \
-      int tag_size, uint32 tag, io::CodedInputStream* input,              \
+      int tag_size, uint32_t tag, io::CodedInputStream* input,            \
       RepeatedField<CPPTYPE>* values) {                                   \
     return ReadRepeatedFixedSizePrimitive<CPPTYPE,                        \
                                           WireFormatLite::DECLARED_TYPE>( \
         tag_size, tag, input, values);                                    \
   }
 
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32)
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64)
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32)
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32_t, TYPE_FIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64_t, TYPE_FIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32_t, TYPE_SFIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64_t, TYPE_SFIXED64)
 READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
 READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
 
@@ -1129,7 +1142,7 @@
 
 template <typename CType, enum WireFormatLite::FieldType DeclaredType>
 bool WireFormatLite::ReadRepeatedPrimitiveNoInline(
-    int tag_size, uint32 tag, io::CodedInputStream* input,
+    int tag_size, uint32_t tag, io::CodedInputStream* input,
     RepeatedField<CType>* value) {
   return ReadRepeatedPrimitive<CType, DeclaredType>(tag_size, tag, input,
                                                     value);
@@ -1171,13 +1184,13 @@
   // -1               >= 0   Use fast path if length <= Limit.
   // >= 0             -1     Use slow path.
   // >= 0             >= 0   Use fast path if length <= min(both limits).
-  int64 bytes_limit = input->BytesUntilTotalBytesLimit();
+  int64_t bytes_limit = input->BytesUntilTotalBytesLimit();
   if (bytes_limit == -1) {
     bytes_limit = input->BytesUntilLimit();
   } else {
     // parentheses around (std::min) prevents macro expansion of min(...)
     bytes_limit =
-        (std::min)(bytes_limit, static_cast<int64>(input->BytesUntilLimit()));
+        (std::min)(bytes_limit, static_cast<int64_t>(input->BytesUntilLimit()));
   }
   if (bytes_limit >= new_bytes) {
     // Fast-path that pre-allocates *values to the final size.
@@ -1222,10 +1235,10 @@
         input, values);                                                        \
   }
 
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32)
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64)
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32)
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32_t, TYPE_FIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64_t, TYPE_FIXED64)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32_t, TYPE_SFIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64_t, TYPE_SFIXED64)
 READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
 READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
 
@@ -1271,45 +1284,45 @@
   output->WriteTag(MakeTag(field_number, type));
 }
 
-inline void WireFormatLite::WriteInt32NoTag(int32 value,
+inline void WireFormatLite::WriteInt32NoTag(int32_t value,
                                             io::CodedOutputStream* output) {
   output->WriteVarint32SignExtended(value);
 }
-inline void WireFormatLite::WriteInt64NoTag(int64 value,
+inline void WireFormatLite::WriteInt64NoTag(int64_t value,
                                             io::CodedOutputStream* output) {
-  output->WriteVarint64(static_cast<uint64>(value));
+  output->WriteVarint64(static_cast<uint64_t>(value));
 }
-inline void WireFormatLite::WriteUInt32NoTag(uint32 value,
+inline void WireFormatLite::WriteUInt32NoTag(uint32_t value,
                                              io::CodedOutputStream* output) {
   output->WriteVarint32(value);
 }
-inline void WireFormatLite::WriteUInt64NoTag(uint64 value,
+inline void WireFormatLite::WriteUInt64NoTag(uint64_t value,
                                              io::CodedOutputStream* output) {
   output->WriteVarint64(value);
 }
-inline void WireFormatLite::WriteSInt32NoTag(int32 value,
+inline void WireFormatLite::WriteSInt32NoTag(int32_t value,
                                              io::CodedOutputStream* output) {
   output->WriteVarint32(ZigZagEncode32(value));
 }
-inline void WireFormatLite::WriteSInt64NoTag(int64 value,
+inline void WireFormatLite::WriteSInt64NoTag(int64_t value,
                                              io::CodedOutputStream* output) {
   output->WriteVarint64(ZigZagEncode64(value));
 }
-inline void WireFormatLite::WriteFixed32NoTag(uint32 value,
+inline void WireFormatLite::WriteFixed32NoTag(uint32_t value,
                                               io::CodedOutputStream* output) {
   output->WriteLittleEndian32(value);
 }
-inline void WireFormatLite::WriteFixed64NoTag(uint64 value,
+inline void WireFormatLite::WriteFixed64NoTag(uint64_t value,
                                               io::CodedOutputStream* output) {
   output->WriteLittleEndian64(value);
 }
-inline void WireFormatLite::WriteSFixed32NoTag(int32 value,
+inline void WireFormatLite::WriteSFixed32NoTag(int32_t value,
                                                io::CodedOutputStream* output) {
-  output->WriteLittleEndian32(static_cast<uint32>(value));
+  output->WriteLittleEndian32(static_cast<uint32_t>(value));
 }
-inline void WireFormatLite::WriteSFixed64NoTag(int64 value,
+inline void WireFormatLite::WriteSFixed64NoTag(int64_t value,
                                                io::CodedOutputStream* output) {
-  output->WriteLittleEndian64(static_cast<uint64>(value));
+  output->WriteLittleEndian64(static_cast<uint64_t>(value));
 }
 inline void WireFormatLite::WriteFloatNoTag(float value,
                                             io::CodedOutputStream* output) {
@@ -1350,77 +1363,80 @@
 
 // ===================================================================
 
-inline uint8* WireFormatLite::WriteTagToArray(int field_number, WireType type,
-                                              uint8* target) {
+inline uint8_t* WireFormatLite::WriteTagToArray(int field_number, WireType type,
+                                                uint8_t* target) {
   return io::CodedOutputStream::WriteTagToArray(MakeTag(field_number, type),
                                                 target);
 }
 
-inline uint8* WireFormatLite::WriteInt32NoTagToArray(int32 value,
-                                                     uint8* target) {
+inline uint8_t* WireFormatLite::WriteInt32NoTagToArray(int32_t value,
+                                                       uint8_t* target) {
   return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteInt64NoTagToArray(int64 value,
-                                                     uint8* target) {
-  return io::CodedOutputStream::WriteVarint64ToArray(static_cast<uint64>(value),
-                                                     target);
+inline uint8_t* WireFormatLite::WriteInt64NoTagToArray(int64_t value,
+                                                       uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint64ToArray(
+      static_cast<uint64_t>(value), target);
 }
-inline uint8* WireFormatLite::WriteUInt32NoTagToArray(uint32 value,
-                                                      uint8* target) {
+inline uint8_t* WireFormatLite::WriteUInt32NoTagToArray(uint32_t value,
+                                                        uint8_t* target) {
   return io::CodedOutputStream::WriteVarint32ToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteUInt64NoTagToArray(uint64 value,
-                                                      uint8* target) {
+inline uint8_t* WireFormatLite::WriteUInt64NoTagToArray(uint64_t value,
+                                                        uint8_t* target) {
   return io::CodedOutputStream::WriteVarint64ToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteSInt32NoTagToArray(int32 value,
-                                                      uint8* target) {
+inline uint8_t* WireFormatLite::WriteSInt32NoTagToArray(int32_t value,
+                                                        uint8_t* target) {
   return io::CodedOutputStream::WriteVarint32ToArray(ZigZagEncode32(value),
                                                      target);
 }
-inline uint8* WireFormatLite::WriteSInt64NoTagToArray(int64 value,
-                                                      uint8* target) {
+inline uint8_t* WireFormatLite::WriteSInt64NoTagToArray(int64_t value,
+                                                        uint8_t* target) {
   return io::CodedOutputStream::WriteVarint64ToArray(ZigZagEncode64(value),
                                                      target);
 }
-inline uint8* WireFormatLite::WriteFixed32NoTagToArray(uint32 value,
-                                                       uint8* target) {
+inline uint8_t* WireFormatLite::WriteFixed32NoTagToArray(uint32_t value,
+                                                         uint8_t* target) {
   return io::CodedOutputStream::WriteLittleEndian32ToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteFixed64NoTagToArray(uint64 value,
-                                                       uint8* target) {
+inline uint8_t* WireFormatLite::WriteFixed64NoTagToArray(uint64_t value,
+                                                         uint8_t* target) {
   return io::CodedOutputStream::WriteLittleEndian64ToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteSFixed32NoTagToArray(int32 value,
-                                                        uint8* target) {
+inline uint8_t* WireFormatLite::WriteSFixed32NoTagToArray(int32_t value,
+                                                          uint8_t* target) {
   return io::CodedOutputStream::WriteLittleEndian32ToArray(
-      static_cast<uint32>(value), target);
+      static_cast<uint32_t>(value), target);
 }
-inline uint8* WireFormatLite::WriteSFixed64NoTagToArray(int64 value,
-                                                        uint8* target) {
+inline uint8_t* WireFormatLite::WriteSFixed64NoTagToArray(int64_t value,
+                                                          uint8_t* target) {
   return io::CodedOutputStream::WriteLittleEndian64ToArray(
-      static_cast<uint64>(value), target);
+      static_cast<uint64_t>(value), target);
 }
-inline uint8* WireFormatLite::WriteFloatNoTagToArray(float value,
-                                                     uint8* target) {
+inline uint8_t* WireFormatLite::WriteFloatNoTagToArray(float value,
+                                                       uint8_t* target) {
   return io::CodedOutputStream::WriteLittleEndian32ToArray(EncodeFloat(value),
                                                            target);
 }
-inline uint8* WireFormatLite::WriteDoubleNoTagToArray(double value,
-                                                      uint8* target) {
+inline uint8_t* WireFormatLite::WriteDoubleNoTagToArray(double value,
+                                                        uint8_t* target) {
   return io::CodedOutputStream::WriteLittleEndian64ToArray(EncodeDouble(value),
                                                            target);
 }
-inline uint8* WireFormatLite::WriteBoolNoTagToArray(bool value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteBoolNoTagToArray(bool value,
+                                                      uint8_t* target) {
   return io::CodedOutputStream::WriteVarint32ToArray(value ? 1 : 0, target);
 }
-inline uint8* WireFormatLite::WriteEnumNoTagToArray(int value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteEnumNoTagToArray(int value,
+                                                      uint8_t* target) {
   return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target);
 }
 
 template <typename T>
-inline uint8* WireFormatLite::WritePrimitiveNoTagToArray(
-    const RepeatedField<T>& value, uint8* (*Writer)(T, uint8*), uint8* target) {
+inline uint8_t* WireFormatLite::WritePrimitiveNoTagToArray(
+    const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+    uint8_t* target) {
   const int n = value.size();
   GOOGLE_DCHECK_GT(n, 0);
 
@@ -1434,8 +1450,9 @@
 }
 
 template <typename T>
-inline uint8* WireFormatLite::WriteFixedNoTagToArray(
-    const RepeatedField<T>& value, uint8* (*Writer)(T, uint8*), uint8* target) {
+inline uint8_t* WireFormatLite::WriteFixedNoTagToArray(
+    const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+    uint8_t* target) {
 #if defined(PROTOBUF_LITTLE_ENDIAN)
   (void)Writer;
 
@@ -1451,138 +1468,149 @@
 #endif
 }
 
-inline uint8* WireFormatLite::WriteInt32NoTagToArray(
-    const RepeatedField<int32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteInt32NoTagToArray(
+    const RepeatedField<int32_t>& value, uint8_t* target) {
   return WritePrimitiveNoTagToArray(value, WriteInt32NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteInt64NoTagToArray(
-    const RepeatedField<int64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteInt64NoTagToArray(
+    const RepeatedField<int64_t>& value, uint8_t* target) {
   return WritePrimitiveNoTagToArray(value, WriteInt64NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteUInt32NoTagToArray(
-    const RepeatedField<uint32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteUInt32NoTagToArray(
+    const RepeatedField<uint32_t>& value, uint8_t* target) {
   return WritePrimitiveNoTagToArray(value, WriteUInt32NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteUInt64NoTagToArray(
-    const RepeatedField<uint64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteUInt64NoTagToArray(
+    const RepeatedField<uint64_t>& value, uint8_t* target) {
   return WritePrimitiveNoTagToArray(value, WriteUInt64NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteSInt32NoTagToArray(
-    const RepeatedField<int32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSInt32NoTagToArray(
+    const RepeatedField<int32_t>& value, uint8_t* target) {
   return WritePrimitiveNoTagToArray(value, WriteSInt32NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteSInt64NoTagToArray(
-    const RepeatedField<int64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSInt64NoTagToArray(
+    const RepeatedField<int64_t>& value, uint8_t* target) {
   return WritePrimitiveNoTagToArray(value, WriteSInt64NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteFixed32NoTagToArray(
-    const RepeatedField<uint32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteFixed32NoTagToArray(
+    const RepeatedField<uint32_t>& value, uint8_t* target) {
   return WriteFixedNoTagToArray(value, WriteFixed32NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteFixed64NoTagToArray(
-    const RepeatedField<uint64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteFixed64NoTagToArray(
+    const RepeatedField<uint64_t>& value, uint8_t* target) {
   return WriteFixedNoTagToArray(value, WriteFixed64NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteSFixed32NoTagToArray(
-    const RepeatedField<int32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSFixed32NoTagToArray(
+    const RepeatedField<int32_t>& value, uint8_t* target) {
   return WriteFixedNoTagToArray(value, WriteSFixed32NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteSFixed64NoTagToArray(
-    const RepeatedField<int64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSFixed64NoTagToArray(
+    const RepeatedField<int64_t>& value, uint8_t* target) {
   return WriteFixedNoTagToArray(value, WriteSFixed64NoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteFloatNoTagToArray(
-    const RepeatedField<float>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteFloatNoTagToArray(
+    const RepeatedField<float>& value, uint8_t* target) {
   return WriteFixedNoTagToArray(value, WriteFloatNoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteDoubleNoTagToArray(
-    const RepeatedField<double>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteDoubleNoTagToArray(
+    const RepeatedField<double>& value, uint8_t* target) {
   return WriteFixedNoTagToArray(value, WriteDoubleNoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteBoolNoTagToArray(
-    const RepeatedField<bool>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteBoolNoTagToArray(
+    const RepeatedField<bool>& value, uint8_t* target) {
   return WritePrimitiveNoTagToArray(value, WriteBoolNoTagToArray, target);
 }
-inline uint8* WireFormatLite::WriteEnumNoTagToArray(
-    const RepeatedField<int>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteEnumNoTagToArray(
+    const RepeatedField<int>& value, uint8_t* target) {
   return WritePrimitiveNoTagToArray(value, WriteEnumNoTagToArray, target);
 }
 
-inline uint8* WireFormatLite::WriteInt32ToArray(int field_number, int32 value,
-                                                uint8* target) {
+inline uint8_t* WireFormatLite::WriteInt32ToArray(int field_number,
+                                                  int32_t value,
+                                                  uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
   return WriteInt32NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteInt64ToArray(int field_number, int64 value,
-                                                uint8* target) {
+inline uint8_t* WireFormatLite::WriteInt64ToArray(int field_number,
+                                                  int64_t value,
+                                                  uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
   return WriteInt64NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteUInt32ToArray(int field_number, uint32 value,
-                                                 uint8* target) {
+inline uint8_t* WireFormatLite::WriteUInt32ToArray(int field_number,
+                                                   uint32_t value,
+                                                   uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
   return WriteUInt32NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteUInt64ToArray(int field_number, uint64 value,
-                                                 uint8* target) {
+inline uint8_t* WireFormatLite::WriteUInt64ToArray(int field_number,
+                                                   uint64_t value,
+                                                   uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
   return WriteUInt64NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteSInt32ToArray(int field_number, int32 value,
-                                                 uint8* target) {
+inline uint8_t* WireFormatLite::WriteSInt32ToArray(int field_number,
+                                                   int32_t value,
+                                                   uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
   return WriteSInt32NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteSInt64ToArray(int field_number, int64 value,
-                                                 uint8* target) {
+inline uint8_t* WireFormatLite::WriteSInt64ToArray(int field_number,
+                                                   int64_t value,
+                                                   uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
   return WriteSInt64NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteFixed32ToArray(int field_number,
-                                                  uint32 value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteFixed32ToArray(int field_number,
+                                                    uint32_t value,
+                                                    uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
   return WriteFixed32NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteFixed64ToArray(int field_number,
-                                                  uint64 value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteFixed64ToArray(int field_number,
+                                                    uint64_t value,
+                                                    uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
   return WriteFixed64NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteSFixed32ToArray(int field_number,
-                                                   int32 value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSFixed32ToArray(int field_number,
+                                                     int32_t value,
+                                                     uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
   return WriteSFixed32NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteSFixed64ToArray(int field_number,
-                                                   int64 value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSFixed64ToArray(int field_number,
+                                                     int64_t value,
+                                                     uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
   return WriteSFixed64NoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteFloatToArray(int field_number, float value,
-                                                uint8* target) {
+inline uint8_t* WireFormatLite::WriteFloatToArray(int field_number, float value,
+                                                  uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
   return WriteFloatNoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteDoubleToArray(int field_number, double value,
-                                                 uint8* target) {
+inline uint8_t* WireFormatLite::WriteDoubleToArray(int field_number,
+                                                   double value,
+                                                   uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
   return WriteDoubleNoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteBoolToArray(int field_number, bool value,
-                                               uint8* target) {
+inline uint8_t* WireFormatLite::WriteBoolToArray(int field_number, bool value,
+                                                 uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
   return WriteBoolNoTagToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteEnumToArray(int field_number, int value,
-                                               uint8* target) {
+inline uint8_t* WireFormatLite::WriteEnumToArray(int field_number, int value,
+                                                 uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
   return WriteEnumNoTagToArray(value, target);
 }
 
 template <typename T>
-inline uint8* WireFormatLite::WritePrimitiveToArray(
+inline uint8_t* WireFormatLite::WritePrimitiveToArray(
     int field_number, const RepeatedField<T>& value,
-    uint8* (*Writer)(int, T, uint8*), uint8* target) {
+    uint8_t* (*Writer)(int, T, uint8_t*), uint8_t* target) {
   const int n = value.size();
   if (n == 0) {
     return target;
@@ -1597,71 +1625,69 @@
   return target;
 }
 
-inline uint8* WireFormatLite::WriteInt32ToArray(
-    int field_number, const RepeatedField<int32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteInt32ToArray(
+    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteInt32ToArray, target);
 }
-inline uint8* WireFormatLite::WriteInt64ToArray(
-    int field_number, const RepeatedField<int64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteInt64ToArray(
+    int field_number, const RepeatedField<int64_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteInt64ToArray, target);
 }
-inline uint8* WireFormatLite::WriteUInt32ToArray(
-    int field_number, const RepeatedField<uint32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteUInt32ToArray(
+    int field_number, const RepeatedField<uint32_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteUInt32ToArray, target);
 }
-inline uint8* WireFormatLite::WriteUInt64ToArray(
-    int field_number, const RepeatedField<uint64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteUInt64ToArray(
+    int field_number, const RepeatedField<uint64_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteUInt64ToArray, target);
 }
-inline uint8* WireFormatLite::WriteSInt32ToArray(
-    int field_number, const RepeatedField<int32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSInt32ToArray(
+    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteSInt32ToArray, target);
 }
-inline uint8* WireFormatLite::WriteSInt64ToArray(
-    int field_number, const RepeatedField<int64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSInt64ToArray(
+    int field_number, const RepeatedField<int64_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteSInt64ToArray, target);
 }
-inline uint8* WireFormatLite::WriteFixed32ToArray(
-    int field_number, const RepeatedField<uint32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteFixed32ToArray(
+    int field_number, const RepeatedField<uint32_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteFixed32ToArray,
                                target);
 }
-inline uint8* WireFormatLite::WriteFixed64ToArray(
-    int field_number, const RepeatedField<uint64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteFixed64ToArray(
+    int field_number, const RepeatedField<uint64_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteFixed64ToArray,
                                target);
 }
-inline uint8* WireFormatLite::WriteSFixed32ToArray(
-    int field_number, const RepeatedField<int32>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSFixed32ToArray(
+    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteSFixed32ToArray,
                                target);
 }
-inline uint8* WireFormatLite::WriteSFixed64ToArray(
-    int field_number, const RepeatedField<int64>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteSFixed64ToArray(
+    int field_number, const RepeatedField<int64_t>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteSFixed64ToArray,
                                target);
 }
-inline uint8* WireFormatLite::WriteFloatToArray(
-    int field_number, const RepeatedField<float>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteFloatToArray(
+    int field_number, const RepeatedField<float>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteFloatToArray, target);
 }
-inline uint8* WireFormatLite::WriteDoubleToArray(
-    int field_number, const RepeatedField<double>& value, uint8* target) {
+inline uint8_t* WireFormatLite::WriteDoubleToArray(
+    int field_number, const RepeatedField<double>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteDoubleToArray, target);
 }
-inline uint8* WireFormatLite::WriteBoolToArray(int field_number,
-                                               const RepeatedField<bool>& value,
-                                               uint8* target) {
+inline uint8_t* WireFormatLite::WriteBoolToArray(
+    int field_number, const RepeatedField<bool>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteBoolToArray, target);
 }
-inline uint8* WireFormatLite::WriteEnumToArray(int field_number,
-                                               const RepeatedField<int>& value,
-                                               uint8* target) {
+inline uint8_t* WireFormatLite::WriteEnumToArray(
+    int field_number, const RepeatedField<int>& value, uint8_t* target) {
   return WritePrimitiveToArray(field_number, value, WriteEnumToArray, target);
 }
-inline uint8* WireFormatLite::WriteStringToArray(int field_number,
-                                                 const std::string& value,
-                                                 uint8* target) {
+inline uint8_t* WireFormatLite::WriteStringToArray(int field_number,
+                                                   const std::string& value,
+                                                   uint8_t* target) {
   // String is for UTF-8 text only
   // WARNING:  In wire_format.cc, both strings and bytes are handled by
   //   WriteString() to avoid code duplication.  If the implementations become
@@ -1669,17 +1695,17 @@
   target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
   return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
 }
-inline uint8* WireFormatLite::WriteBytesToArray(int field_number,
-                                                const std::string& value,
-                                                uint8* target) {
+inline uint8_t* WireFormatLite::WriteBytesToArray(int field_number,
+                                                  const std::string& value,
+                                                  uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
   return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
 }
 
 
 template <typename MessageType>
-inline uint8* WireFormatLite::InternalWriteGroup(
-    int field_number, const MessageType& value, uint8* target,
+inline uint8_t* WireFormatLite::InternalWriteGroup(
+    int field_number, const MessageType& value, uint8_t* target,
     io::EpsCopyOutputStream* stream) {
   target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
   target = value._InternalSerialize(target, stream);
@@ -1687,33 +1713,33 @@
   return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
 }
 template <typename MessageType>
-inline uint8* WireFormatLite::InternalWriteMessage(
-    int field_number, const MessageType& value, uint8* target,
+inline uint8_t* WireFormatLite::InternalWriteMessage(
+    int field_number, const MessageType& value, uint8_t* target,
     io::EpsCopyOutputStream* stream) {
   target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
   target = io::CodedOutputStream::WriteVarint32ToArrayOutOfLine(
-      static_cast<uint32>(value.GetCachedSize()), target);
+      static_cast<uint32_t>(value.GetCachedSize()), target);
   return value._InternalSerialize(target, stream);
 }
 
 // See comment on ReadGroupNoVirtual to understand the need for this template
 // parameter name.
 template <typename MessageType_WorkAroundCppLookupDefect>
-inline uint8* WireFormatLite::InternalWriteGroupNoVirtualToArray(
+inline uint8_t* WireFormatLite::InternalWriteGroupNoVirtualToArray(
     int field_number, const MessageType_WorkAroundCppLookupDefect& value,
-    uint8* target) {
+    uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
   target = value.MessageType_WorkAroundCppLookupDefect::
                SerializeWithCachedSizesToArray(target);
   return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
 }
 template <typename MessageType_WorkAroundCppLookupDefect>
-inline uint8* WireFormatLite::InternalWriteMessageNoVirtualToArray(
+inline uint8_t* WireFormatLite::InternalWriteMessageNoVirtualToArray(
     int field_number, const MessageType_WorkAroundCppLookupDefect& value,
-    uint8* target) {
+    uint8_t* target) {
   target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
   target = io::CodedOutputStream::WriteVarint32ToArray(
-      static_cast<uint32>(
+      static_cast<uint32_t>(
           value.MessageType_WorkAroundCppLookupDefect::GetCachedSize()),
       target);
   return value
@@ -1723,27 +1749,49 @@
 
 // ===================================================================
 
-inline size_t WireFormatLite::Int32Size(int32 value) {
+inline size_t WireFormatLite::Int32Size(int32_t value) {
   return io::CodedOutputStream::VarintSize32SignExtended(value);
 }
-inline size_t WireFormatLite::Int64Size(int64 value) {
-  return io::CodedOutputStream::VarintSize64(static_cast<uint64>(value));
+inline size_t WireFormatLite::Int64Size(int64_t value) {
+  return io::CodedOutputStream::VarintSize64(static_cast<uint64_t>(value));
 }
-inline size_t WireFormatLite::UInt32Size(uint32 value) {
+inline size_t WireFormatLite::UInt32Size(uint32_t value) {
   return io::CodedOutputStream::VarintSize32(value);
 }
-inline size_t WireFormatLite::UInt64Size(uint64 value) {
+inline size_t WireFormatLite::UInt64Size(uint64_t value) {
   return io::CodedOutputStream::VarintSize64(value);
 }
-inline size_t WireFormatLite::SInt32Size(int32 value) {
+inline size_t WireFormatLite::SInt32Size(int32_t value) {
   return io::CodedOutputStream::VarintSize32(ZigZagEncode32(value));
 }
-inline size_t WireFormatLite::SInt64Size(int64 value) {
+inline size_t WireFormatLite::SInt64Size(int64_t value) {
   return io::CodedOutputStream::VarintSize64(ZigZagEncode64(value));
 }
 inline size_t WireFormatLite::EnumSize(int value) {
   return io::CodedOutputStream::VarintSize32SignExtended(value);
 }
+inline size_t WireFormatLite::Int32SizePlusOne(int32_t value) {
+  return io::CodedOutputStream::VarintSize32SignExtendedPlusOne(value);
+}
+inline size_t WireFormatLite::Int64SizePlusOne(int64_t value) {
+  return io::CodedOutputStream::VarintSize64PlusOne(
+      static_cast<uint64_t>(value));
+}
+inline size_t WireFormatLite::UInt32SizePlusOne(uint32_t value) {
+  return io::CodedOutputStream::VarintSize32PlusOne(value);
+}
+inline size_t WireFormatLite::UInt64SizePlusOne(uint64_t value) {
+  return io::CodedOutputStream::VarintSize64PlusOne(value);
+}
+inline size_t WireFormatLite::SInt32SizePlusOne(int32_t value) {
+  return io::CodedOutputStream::VarintSize32PlusOne(ZigZagEncode32(value));
+}
+inline size_t WireFormatLite::SInt64SizePlusOne(int64_t value) {
+  return io::CodedOutputStream::VarintSize64PlusOne(ZigZagEncode64(value));
+}
+inline size_t WireFormatLite::EnumSizePlusOne(int value) {
+  return io::CodedOutputStream::VarintSize32SignExtendedPlusOne(value);
+}
 
 inline size_t WireFormatLite::StringSize(const std::string& value) {
   return LengthDelimitedSize(value.size());
@@ -1778,11 +1826,11 @@
 
 inline size_t WireFormatLite::LengthDelimitedSize(size_t length) {
   // The static_cast here prevents an error in certain compiler configurations
-  // but is not technically correct--if length is too large to fit in a uint32
+  // but is not technically correct--if length is too large to fit in a uint32_t
   // then it will be silently truncated. We will need to fix this if we ever
   // decide to start supporting serialized messages greater than 2 GiB in size.
   return length +
-         io::CodedOutputStream::VarintSize32(static_cast<uint32>(length));
+         io::CodedOutputStream::VarintSize32(static_cast<uint32_t>(length));
 }
 
 template <typename MS>
@@ -1791,19 +1839,19 @@
   //   required int32 type_id = 2;
   //   required data message = 3;
 
-  uint32 last_type_id = 0;
+  uint32_t last_type_id = 0;
 
   // If we see message data before the type_id, we'll append it to this so
   // we can parse it later.
   std::string message_data;
 
   while (true) {
-    const uint32 tag = input->ReadTagNoLastTag();
+    const uint32_t tag = input->ReadTagNoLastTag();
     if (tag == 0) return false;
 
     switch (tag) {
       case WireFormatLite::kMessageSetTypeIdTag: {
-        uint32 type_id;
+        uint32_t type_id;
         if (!input->ReadVarint32(&type_id)) return false;
         last_type_id = type_id;
 
@@ -1811,7 +1859,7 @@
           // We saw some message data before the type_id.  Have to parse it
           // now.
           io::CodedInputStream sub_input(
-              reinterpret_cast<const uint8*>(message_data.data()),
+              reinterpret_cast<const uint8_t*>(message_data.data()),
               static_cast<int>(message_data.size()));
           sub_input.SetRecursionLimit(input->RecursionBudget());
           if (!ms.ParseField(last_type_id, &sub_input)) {
@@ -1826,13 +1874,13 @@
       case WireFormatLite::kMessageSetMessageTag: {
         if (last_type_id == 0) {
           // We haven't seen a type_id yet.  Append this data to message_data.
-          uint32 length;
+          uint32_t length;
           if (!input->ReadVarint32(&length)) return false;
-          if (static_cast<int32>(length) < 0) return false;
-          uint32 size = static_cast<uint32>(
+          if (static_cast<int32_t>(length) < 0) return false;
+          uint32_t size = static_cast<uint32_t>(
               length + io::CodedOutputStream::VarintSize32(length));
           message_data.resize(size);
-          auto ptr = reinterpret_cast<uint8*>(&message_data[0]);
+          auto ptr = reinterpret_cast<uint8_t*>(&message_data[0]);
           ptr = io::CodedOutputStream::WriteVarint32ToArray(length, ptr);
           if (!input->ReadRaw(ptr, length)) return false;
         } else {
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
index 4393066..f1ed951 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -34,1553 +34,33 @@
 
 #include <google/protobuf/wire_format.h>
 
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/test_util.h>
-#include <google/protobuf/test_util2.h>
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/unittest_mset.pb.h>
 #include <google/protobuf/unittest_mset_wire_format.pb.h>
 #include <google/protobuf/unittest_proto3_arena.pb.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/testing/googletest.h>
-#include <google/protobuf/stubs/logging.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <google/protobuf/stubs/casts.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/stl_util.h>
 
+#define UNITTEST ::protobuf_unittest
+#define UNITTEST_IMPORT ::protobuf_unittest_import
+#define UNITTEST_PACKAGE_NAME "protobuf_unittest"
+#define PROTO2_WIREFORMAT_UNITTEST ::proto2_wireformat_unittest
+#define PROTO3_ARENA_UNITTEST ::proto3_arena_unittest
+
+// Must include after defining UNITTEST, etc.
 // clang-format off
-#include <google/protobuf/port_def.inc>
+#include <google/protobuf/test_util.inc>
+#include <google/protobuf/wire_format_unittest.inc>
 // clang-format on
 
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
 namespace google {
 namespace protobuf {
 namespace internal {
 namespace {
 
-TEST(WireFormatTest, EnumsInSync) {
-  // Verify that WireFormatLite::FieldType and WireFormatLite::CppType match
-  // FieldDescriptor::Type and FieldDescriptor::CppType.
-
-  EXPECT_EQ(implicit_cast<int>(FieldDescriptor::MAX_TYPE),
-            implicit_cast<int>(WireFormatLite::MAX_FIELD_TYPE));
-  EXPECT_EQ(implicit_cast<int>(FieldDescriptor::MAX_CPPTYPE),
-            implicit_cast<int>(WireFormatLite::MAX_CPPTYPE));
-
-  for (int i = 1; i <= WireFormatLite::MAX_FIELD_TYPE; i++) {
-    EXPECT_EQ(implicit_cast<int>(FieldDescriptor::TypeToCppType(
-                  static_cast<FieldDescriptor::Type>(i))),
-              implicit_cast<int>(WireFormatLite::FieldTypeToCppType(
-                  static_cast<WireFormatLite::FieldType>(i))));
-  }
-}
-
-TEST(WireFormatTest, MaxFieldNumber) {
-  // Make sure the max field number constant is accurate.
-  EXPECT_EQ((1 << (32 - WireFormatLite::kTagTypeBits)) - 1,
-            FieldDescriptor::kMaxNumber);
-}
-
-TEST(WireFormatTest, Parse) {
-  unittest::TestAllTypes source, dest;
-  std::string data;
-
-  // Serialize using the generated code.
-  TestUtil::SetAllFields(&source);
-  source.SerializeToString(&data);
-
-  // Parse using WireFormat.
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream input(&raw_input);
-  WireFormat::ParseAndMergePartial(&input, &dest);
-
-  // Check.
-  TestUtil::ExpectAllFieldsSet(dest);
-}
-
-TEST(WireFormatTest, ParseExtensions) {
-  unittest::TestAllExtensions source, dest;
-  std::string data;
-
-  // Serialize using the generated code.
-  TestUtil::SetAllExtensions(&source);
-  source.SerializeToString(&data);
-
-  // Parse using WireFormat.
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream input(&raw_input);
-  WireFormat::ParseAndMergePartial(&input, &dest);
-
-  // Check.
-  TestUtil::ExpectAllExtensionsSet(dest);
-}
-
-TEST(WireFormatTest, ParsePacked) {
-  unittest::TestPackedTypes source, dest;
-  std::string data;
-
-  // Serialize using the generated code.
-  TestUtil::SetPackedFields(&source);
-  source.SerializeToString(&data);
-
-  // Parse using WireFormat.
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream input(&raw_input);
-  WireFormat::ParseAndMergePartial(&input, &dest);
-
-  // Check.
-  TestUtil::ExpectPackedFieldsSet(dest);
-}
-
-TEST(WireFormatTest, ParsePackedFromUnpacked) {
-  // Serialize using the generated code.
-  unittest::TestUnpackedTypes source;
-  TestUtil::SetUnpackedFields(&source);
-  std::string data = source.SerializeAsString();
-
-  // Parse using WireFormat.
-  unittest::TestPackedTypes dest;
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream input(&raw_input);
-  WireFormat::ParseAndMergePartial(&input, &dest);
-
-  // Check.
-  TestUtil::ExpectPackedFieldsSet(dest);
-}
-
-TEST(WireFormatTest, ParseUnpackedFromPacked) {
-  // Serialize using the generated code.
-  unittest::TestPackedTypes source;
-  TestUtil::SetPackedFields(&source);
-  std::string data = source.SerializeAsString();
-
-  // Parse using WireFormat.
-  unittest::TestUnpackedTypes dest;
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream input(&raw_input);
-  WireFormat::ParseAndMergePartial(&input, &dest);
-
-  // Check.
-  TestUtil::ExpectUnpackedFieldsSet(dest);
-}
-
-TEST(WireFormatTest, ParsePackedExtensions) {
-  unittest::TestPackedExtensions source, dest;
-  std::string data;
-
-  // Serialize using the generated code.
-  TestUtil::SetPackedExtensions(&source);
-  source.SerializeToString(&data);
-
-  // Parse using WireFormat.
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream input(&raw_input);
-  WireFormat::ParseAndMergePartial(&input, &dest);
-
-  // Check.
-  TestUtil::ExpectPackedExtensionsSet(dest);
-}
-
-TEST(WireFormatTest, ParseOneof) {
-  unittest::TestOneof2 source, dest;
-  std::string data;
-
-  // Serialize using the generated code.
-  TestUtil::SetOneof1(&source);
-  source.SerializeToString(&data);
-
-  // Parse using WireFormat.
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream input(&raw_input);
-  WireFormat::ParseAndMergePartial(&input, &dest);
-
-  // Check.
-  TestUtil::ExpectOneofSet1(dest);
-}
-
-TEST(WireFormatTest, OneofOnlySetLast) {
-  unittest::TestOneofBackwardsCompatible source;
-  unittest::TestOneof oneof_dest;
-  std::string data;
-
-  // Set two fields
-  source.set_foo_int(100);
-  source.set_foo_string("101");
-
-  // Serialize and parse to oneof message. Generated serializer may not order
-  // fields in tag order. Use WireFormat::SerializeWithCachedSizes instead as
-  // it sorts fields beforehand.
-  {
-    io::StringOutputStream raw_output(&data);
-    io::CodedOutputStream output(&raw_output);
-    WireFormat::SerializeWithCachedSizes(source, source.ByteSizeLong(),
-                                         &output);
-    ASSERT_FALSE(output.HadError());
-  }
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream input(&raw_input);
-  WireFormat::ParseAndMergePartial(&input, &oneof_dest);
-
-  // Only the last field is set.
-  EXPECT_FALSE(oneof_dest.has_foo_int());
-  EXPECT_TRUE(oneof_dest.has_foo_string());
-}
-
-TEST(WireFormatTest, ByteSize) {
-  unittest::TestAllTypes message;
-  TestUtil::SetAllFields(&message);
-
-  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
-  message.Clear();
-  EXPECT_EQ(0, message.ByteSizeLong());
-  EXPECT_EQ(0, WireFormat::ByteSize(message));
-}
-
-TEST(WireFormatTest, ByteSizeExtensions) {
-  unittest::TestAllExtensions message;
-  TestUtil::SetAllExtensions(&message);
-
-  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
-  message.Clear();
-  EXPECT_EQ(0, message.ByteSizeLong());
-  EXPECT_EQ(0, WireFormat::ByteSize(message));
-}
-
-TEST(WireFormatTest, ByteSizePacked) {
-  unittest::TestPackedTypes message;
-  TestUtil::SetPackedFields(&message);
-
-  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
-  message.Clear();
-  EXPECT_EQ(0, message.ByteSizeLong());
-  EXPECT_EQ(0, WireFormat::ByteSize(message));
-}
-
-TEST(WireFormatTest, ByteSizePackedExtensions) {
-  unittest::TestPackedExtensions message;
-  TestUtil::SetPackedExtensions(&message);
-
-  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
-  message.Clear();
-  EXPECT_EQ(0, message.ByteSizeLong());
-  EXPECT_EQ(0, WireFormat::ByteSize(message));
-}
-
-TEST(WireFormatTest, ByteSizeOneof) {
-  unittest::TestOneof2 message;
-  TestUtil::SetOneof1(&message);
-
-  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
-  message.Clear();
-
-  EXPECT_EQ(0, message.ByteSizeLong());
-  EXPECT_EQ(0, WireFormat::ByteSize(message));
-}
-
-TEST(WireFormatTest, Serialize) {
-  unittest::TestAllTypes message;
-  std::string generated_data;
-  std::string dynamic_data;
-
-  TestUtil::SetAllFields(&message);
-  size_t size = message.ByteSizeLong();
-
-  // Serialize using the generated code.
-  {
-    io::StringOutputStream raw_output(&generated_data);
-    io::CodedOutputStream output(&raw_output);
-    message.SerializeWithCachedSizes(&output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Serialize using WireFormat.
-  {
-    io::StringOutputStream raw_output(&dynamic_data);
-    io::CodedOutputStream output(&raw_output);
-    WireFormat::SerializeWithCachedSizes(message, size, &output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Should parse to the same message.
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
-}
-
-TEST(WireFormatTest, SerializeExtensions) {
-  unittest::TestAllExtensions message;
-  std::string generated_data;
-  std::string dynamic_data;
-
-  TestUtil::SetAllExtensions(&message);
-  size_t size = message.ByteSizeLong();
-
-  // Serialize using the generated code.
-  {
-    io::StringOutputStream raw_output(&generated_data);
-    io::CodedOutputStream output(&raw_output);
-    message.SerializeWithCachedSizes(&output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Serialize using WireFormat.
-  {
-    io::StringOutputStream raw_output(&dynamic_data);
-    io::CodedOutputStream output(&raw_output);
-    WireFormat::SerializeWithCachedSizes(message, size, &output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Should parse to the same message.
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
-}
-
-TEST(WireFormatTest, SerializeFieldsAndExtensions) {
-  unittest::TestFieldOrderings message;
-  std::string generated_data;
-  std::string dynamic_data;
-
-  TestUtil::SetAllFieldsAndExtensions(&message);
-  size_t size = message.ByteSizeLong();
-
-  // Serialize using the generated code.
-  {
-    io::StringOutputStream raw_output(&generated_data);
-    io::CodedOutputStream output(&raw_output);
-    message.SerializeWithCachedSizes(&output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Serialize using WireFormat.
-  {
-    io::StringOutputStream raw_output(&dynamic_data);
-    io::CodedOutputStream output(&raw_output);
-    WireFormat::SerializeWithCachedSizes(message, size, &output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Should parse to the same message.
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
-}
-
-TEST(WireFormatTest, SerializeOneof) {
-  unittest::TestOneof2 message;
-  std::string generated_data;
-  std::string dynamic_data;
-
-  TestUtil::SetOneof1(&message);
-  size_t size = message.ByteSizeLong();
-
-  // Serialize using the generated code.
-  {
-    io::StringOutputStream raw_output(&generated_data);
-    io::CodedOutputStream output(&raw_output);
-    message.SerializeWithCachedSizes(&output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Serialize using WireFormat.
-  {
-    io::StringOutputStream raw_output(&dynamic_data);
-    io::CodedOutputStream output(&raw_output);
-    WireFormat::SerializeWithCachedSizes(message, size, &output);
-    ASSERT_FALSE(output.HadError());
-  }
-
-  // Should parse to the same message.
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
-  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
-}
-
-TEST(WireFormatTest, ParseMultipleExtensionRanges) {
-  // Make sure we can parse a message that contains multiple extensions ranges.
-  unittest::TestFieldOrderings source;
-  std::string data;
-
-  TestUtil::SetAllFieldsAndExtensions(&source);
-  source.SerializeToString(&data);
-
-  {
-    unittest::TestFieldOrderings dest;
-    EXPECT_TRUE(dest.ParseFromString(data));
-    EXPECT_EQ(source.DebugString(), dest.DebugString());
-  }
-
-  // Also test using reflection-based parsing.
-  {
-    unittest::TestFieldOrderings dest;
-    io::ArrayInputStream raw_input(data.data(), data.size());
-    io::CodedInputStream coded_input(&raw_input);
-    EXPECT_TRUE(WireFormat::ParseAndMergePartial(&coded_input, &dest));
-    EXPECT_EQ(source.DebugString(), dest.DebugString());
-  }
-}
-
-const int kUnknownTypeId = 1550055;
-
-TEST(WireFormatTest, SerializeMessageSet) {
-  // Set up a TestMessageSet with two known messages and an unknown one.
-  proto2_wireformat_unittest::TestMessageSet message_set;
-  message_set
-      .MutableExtension(
-          unittest::TestMessageSetExtension1::message_set_extension)
-      ->set_i(123);
-  message_set
-      .MutableExtension(
-          unittest::TestMessageSetExtension2::message_set_extension)
-      ->set_str("foo");
-  message_set.mutable_unknown_fields()->AddLengthDelimited(kUnknownTypeId,
-                                                           "bar");
-
-  std::string data;
-  ASSERT_TRUE(message_set.SerializeToString(&data));
-
-  // Parse back using RawMessageSet and check the contents.
-  unittest::RawMessageSet raw;
-  ASSERT_TRUE(raw.ParseFromString(data));
-
-  EXPECT_EQ(0, raw.unknown_fields().field_count());
-
-  ASSERT_EQ(3, raw.item_size());
-  EXPECT_EQ(
-      unittest::TestMessageSetExtension1::descriptor()->extension(0)->number(),
-      raw.item(0).type_id());
-  EXPECT_EQ(
-      unittest::TestMessageSetExtension2::descriptor()->extension(0)->number(),
-      raw.item(1).type_id());
-  EXPECT_EQ(kUnknownTypeId, raw.item(2).type_id());
-
-  unittest::TestMessageSetExtension1 message1;
-  EXPECT_TRUE(message1.ParseFromString(raw.item(0).message()));
-  EXPECT_EQ(123, message1.i());
-
-  unittest::TestMessageSetExtension2 message2;
-  EXPECT_TRUE(message2.ParseFromString(raw.item(1).message()));
-  EXPECT_EQ("foo", message2.str());
-
-  EXPECT_EQ("bar", raw.item(2).message());
-}
-
-TEST(WireFormatTest, SerializeMessageSetVariousWaysAreEqual) {
-  // Serialize a MessageSet to a stream and to a flat array using generated
-  // code, and also using WireFormat, and check that the results are equal.
-  // Set up a TestMessageSet with two known messages and an unknown one, as
-  // above.
-
-  proto2_wireformat_unittest::TestMessageSet message_set;
-  message_set
-      .MutableExtension(
-          unittest::TestMessageSetExtension1::message_set_extension)
-      ->set_i(123);
-  message_set
-      .MutableExtension(
-          unittest::TestMessageSetExtension2::message_set_extension)
-      ->set_str("foo");
-  message_set.mutable_unknown_fields()->AddLengthDelimited(kUnknownTypeId,
-                                                           "bar");
-
-  size_t size = message_set.ByteSizeLong();
-  EXPECT_EQ(size, message_set.GetCachedSize());
-  ASSERT_EQ(size, WireFormat::ByteSize(message_set));
-
-  std::string flat_data;
-  std::string stream_data;
-  std::string dynamic_data;
-  flat_data.resize(size);
-  stream_data.resize(size);
-
-  // Serialize to flat array
-  {
-    uint8* target = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&flat_data));
-    uint8* end = message_set.SerializeWithCachedSizesToArray(target);
-    EXPECT_EQ(size, end - target);
-  }
-
-  // Serialize to buffer
-  {
-    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&stream_data), size,
-                                       1);
-    io::CodedOutputStream output_stream(&array_stream);
-    message_set.SerializeWithCachedSizes(&output_stream);
-    ASSERT_FALSE(output_stream.HadError());
-  }
-
-  // Serialize to buffer with WireFormat.
-  {
-    io::StringOutputStream string_stream(&dynamic_data);
-    io::CodedOutputStream output_stream(&string_stream);
-    WireFormat::SerializeWithCachedSizes(message_set, size, &output_stream);
-    ASSERT_FALSE(output_stream.HadError());
-  }
-
-  EXPECT_TRUE(flat_data == stream_data);
-  EXPECT_TRUE(flat_data == dynamic_data);
-}
-
-TEST(WireFormatTest, ParseMessageSet) {
-  // Set up a RawMessageSet with two known messages and an unknown one.
-  unittest::RawMessageSet raw;
-
-  {
-    unittest::RawMessageSet::Item* item = raw.add_item();
-    item->set_type_id(unittest::TestMessageSetExtension1::descriptor()
-                          ->extension(0)
-                          ->number());
-    unittest::TestMessageSetExtension1 message;
-    message.set_i(123);
-    message.SerializeToString(item->mutable_message());
-  }
-
-  {
-    unittest::RawMessageSet::Item* item = raw.add_item();
-    item->set_type_id(unittest::TestMessageSetExtension2::descriptor()
-                          ->extension(0)
-                          ->number());
-    unittest::TestMessageSetExtension2 message;
-    message.set_str("foo");
-    message.SerializeToString(item->mutable_message());
-  }
-
-  {
-    unittest::RawMessageSet::Item* item = raw.add_item();
-    item->set_type_id(kUnknownTypeId);
-    item->set_message("bar");
-  }
-
-  std::string data;
-  ASSERT_TRUE(raw.SerializeToString(&data));
-
-  // Parse as a TestMessageSet and check the contents.
-  proto2_wireformat_unittest::TestMessageSet message_set;
-  ASSERT_TRUE(message_set.ParseFromString(data));
-
-  EXPECT_EQ(123,
-            message_set
-                .GetExtension(
-                    unittest::TestMessageSetExtension1::message_set_extension)
-                .i());
-  EXPECT_EQ("foo",
-            message_set
-                .GetExtension(
-                    unittest::TestMessageSetExtension2::message_set_extension)
-                .str());
-
-  ASSERT_EQ(1, message_set.unknown_fields().field_count());
-  ASSERT_EQ(UnknownField::TYPE_LENGTH_DELIMITED,
-            message_set.unknown_fields().field(0).type());
-  EXPECT_EQ("bar", message_set.unknown_fields().field(0).length_delimited());
-
-  // Also parse using WireFormat.
-  proto2_wireformat_unittest::TestMessageSet dynamic_message_set;
-  io::CodedInputStream input(reinterpret_cast<const uint8*>(data.data()),
-                             data.size());
-  ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &dynamic_message_set));
-  EXPECT_EQ(message_set.DebugString(), dynamic_message_set.DebugString());
-}
-
-TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) {
-  std::string data;
-  {
-    unittest::TestMessageSetExtension1 message;
-    message.set_i(123);
-    // Build a MessageSet manually with its message content put before its
-    // type_id.
-    io::StringOutputStream output_stream(&data);
-    io::CodedOutputStream coded_output(&output_stream);
-    coded_output.WriteTag(WireFormatLite::kMessageSetItemStartTag);
-    // Write the message content first.
-    WireFormatLite::WriteTag(WireFormatLite::kMessageSetMessageNumber,
-                             WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-                             &coded_output);
-    coded_output.WriteVarint32(message.ByteSizeLong());
-    message.SerializeWithCachedSizes(&coded_output);
-    // Write the type id.
-    uint32 type_id = message.GetDescriptor()->extension(0)->number();
-    WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
-                                type_id, &coded_output);
-    coded_output.WriteTag(WireFormatLite::kMessageSetItemEndTag);
-  }
-  {
-    proto2_wireformat_unittest::TestMessageSet message_set;
-    ASSERT_TRUE(message_set.ParseFromString(data));
-
-    EXPECT_EQ(123,
-              message_set
-                  .GetExtension(
-                      unittest::TestMessageSetExtension1::message_set_extension)
-                  .i());
-  }
-  {
-    // Test parse the message via Reflection.
-    proto2_wireformat_unittest::TestMessageSet message_set;
-    io::CodedInputStream input(reinterpret_cast<const uint8*>(data.data()),
-                               data.size());
-    EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set));
-    EXPECT_TRUE(input.ConsumedEntireMessage());
-
-    EXPECT_EQ(123,
-              message_set
-                  .GetExtension(
-                      unittest::TestMessageSetExtension1::message_set_extension)
-                  .i());
-  }
-}
-
-void SerializeReverseOrder(
-    const proto2_wireformat_unittest::TestMessageSet& mset,
-    io::CodedOutputStream* coded_output);
-
-void SerializeReverseOrder(const unittest::TestMessageSetExtension1& message,
-                           io::CodedOutputStream* coded_output) {
-  WireFormatLite::WriteTag(15,  // i
-                           WireFormatLite::WIRETYPE_VARINT, coded_output);
-  coded_output->WriteVarint64(message.i());
-  WireFormatLite::WriteTag(16,  // recursive
-                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-                           coded_output);
-  coded_output->WriteVarint32(message.recursive().GetCachedSize());
-  SerializeReverseOrder(message.recursive(), coded_output);
-}
-
-void SerializeReverseOrder(
-    const proto2_wireformat_unittest::TestMessageSet& mset,
-    io::CodedOutputStream* coded_output) {
-  if (!mset.HasExtension(
-          unittest::TestMessageSetExtension1::message_set_extension))
-    return;
-  coded_output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
-  // Write the message content first.
-  WireFormatLite::WriteTag(WireFormatLite::kMessageSetMessageNumber,
-                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-                           coded_output);
-  auto& message = mset.GetExtension(
-      unittest::TestMessageSetExtension1::message_set_extension);
-  coded_output->WriteVarint32(message.GetCachedSize());
-  SerializeReverseOrder(message, coded_output);
-  // Write the type id.
-  uint32 type_id = message.GetDescriptor()->extension(0)->number();
-  WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, type_id,
-                              coded_output);
-  coded_output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
-}
-
-TEST(WireFormatTest, ParseMessageSetWithDeepRecReverseOrder) {
-  std::string data;
-  {
-    proto2_wireformat_unittest::TestMessageSet message_set;
-    proto2_wireformat_unittest::TestMessageSet* mset = &message_set;
-    for (int i = 0; i < 200; i++) {
-      auto m = mset->MutableExtension(
-          unittest::TestMessageSetExtension1::message_set_extension);
-      m->set_i(i);
-      mset = m->mutable_recursive();
-    }
-    message_set.ByteSizeLong();
-    // Serialize with reverse payload tag order
-    io::StringOutputStream output_stream(&data);
-    io::CodedOutputStream coded_output(&output_stream);
-    SerializeReverseOrder(message_set, &coded_output);
-  }
-  proto2_wireformat_unittest::TestMessageSet message_set;
-  EXPECT_FALSE(message_set.ParseFromString(data));
-}
-
-TEST(WireFormatTest, ParseFailMalformedMessageSet) {
-  constexpr int kDepth = 5;
-  std::string data;
-  {
-    proto2_wireformat_unittest::TestMessageSet message_set;
-    proto2_wireformat_unittest::TestMessageSet* mset = &message_set;
-    for (int i = 0; i < kDepth; i++) {
-      auto m = mset->MutableExtension(
-          unittest::TestMessageSetExtension1::message_set_extension);
-      m->set_i(i);
-      mset = m->mutable_recursive();
-    }
-    auto m = mset->MutableExtension(
-        unittest::TestMessageSetExtension1::message_set_extension);
-    // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
-    m->set_i(-1);
-
-    EXPECT_TRUE(message_set.SerializeToString(&data));
-    // Make the proto mal-formed.
-    data[data.size() - 2 - kDepth] = 0xFF;
-  }
-
-  proto2_wireformat_unittest::TestMessageSet message_set;
-  EXPECT_FALSE(message_set.ParseFromString(data));
-}
-
-TEST(WireFormatTest, ParseFailMalformedMessageSetReverseOrder) {
-  constexpr int kDepth = 5;
-  std::string data;
-  {
-    proto2_wireformat_unittest::TestMessageSet message_set;
-    proto2_wireformat_unittest::TestMessageSet* mset = &message_set;
-    for (int i = 0; i < kDepth; i++) {
-      auto m = mset->MutableExtension(
-          unittest::TestMessageSetExtension1::message_set_extension);
-      m->set_i(i);
-      mset = m->mutable_recursive();
-    }
-    auto m = mset->MutableExtension(
-        unittest::TestMessageSetExtension1::message_set_extension);
-    // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
-    m->set_i(-1);
-    // SerializeReverseOrder() assumes "recursive" is always present.
-    m->mutable_recursive();
-
-    message_set.ByteSizeLong();
-
-    // Serialize with reverse payload tag order
-    io::StringOutputStream output_stream(&data);
-    io::CodedOutputStream coded_output(&output_stream);
-    SerializeReverseOrder(message_set, &coded_output);
-  }
-
-  // Make varint for -1 malformed.
-  data[data.size() - 5 * (kDepth + 1) - 4] = 0xFF;
-
-  proto2_wireformat_unittest::TestMessageSet message_set;
-  EXPECT_FALSE(message_set.ParseFromString(data));
-}
-
-TEST(WireFormatTest, ParseBrokenMessageSet) {
-  proto2_wireformat_unittest::TestMessageSet message_set;
-  std::string input("goodbye");  // Invalid wire format data.
-  EXPECT_FALSE(message_set.ParseFromString(input));
-}
-
-TEST(WireFormatTest, RecursionLimit) {
-  unittest::TestRecursiveMessage message;
-  message.mutable_a()->mutable_a()->mutable_a()->mutable_a()->set_i(1);
-  std::string data;
-  message.SerializeToString(&data);
-
-  {
-    io::ArrayInputStream raw_input(data.data(), data.size());
-    io::CodedInputStream input(&raw_input);
-    input.SetRecursionLimit(4);
-    unittest::TestRecursiveMessage message2;
-    EXPECT_TRUE(message2.ParseFromCodedStream(&input));
-  }
-
-  {
-    io::ArrayInputStream raw_input(data.data(), data.size());
-    io::CodedInputStream input(&raw_input);
-    input.SetRecursionLimit(3);
-    unittest::TestRecursiveMessage message2;
-    EXPECT_FALSE(message2.ParseFromCodedStream(&input));
-  }
-}
-
-TEST(WireFormatTest, UnknownFieldRecursionLimit) {
-  unittest::TestEmptyMessage message;
-  message.mutable_unknown_fields()
-      ->AddGroup(1234)
-      ->AddGroup(1234)
-      ->AddGroup(1234)
-      ->AddGroup(1234)
-      ->AddVarint(1234, 123);
-  std::string data;
-  message.SerializeToString(&data);
-
-  {
-    io::ArrayInputStream raw_input(data.data(), data.size());
-    io::CodedInputStream input(&raw_input);
-    input.SetRecursionLimit(4);
-    unittest::TestEmptyMessage message2;
-    EXPECT_TRUE(message2.ParseFromCodedStream(&input));
-  }
-
-  {
-    io::ArrayInputStream raw_input(data.data(), data.size());
-    io::CodedInputStream input(&raw_input);
-    input.SetRecursionLimit(3);
-    unittest::TestEmptyMessage message2;
-    EXPECT_FALSE(message2.ParseFromCodedStream(&input));
-  }
-}
-
-TEST(WireFormatTest, ZigZag) {
-// avoid line-wrapping
-#define LL(x) static_cast<int64_t>(ULL(x))
-#define ULL(x) uint64_t{x##u}
-#define ZigZagEncode32(x) WireFormatLite::ZigZagEncode32(x)
-#define ZigZagDecode32(x) WireFormatLite::ZigZagDecode32(x)
-#define ZigZagEncode64(x) WireFormatLite::ZigZagEncode64(x)
-#define ZigZagDecode64(x) WireFormatLite::ZigZagDecode64(x)
-
-  EXPECT_EQ(0u, ZigZagEncode32(0));
-  EXPECT_EQ(1u, ZigZagEncode32(-1));
-  EXPECT_EQ(2u, ZigZagEncode32(1));
-  EXPECT_EQ(3u, ZigZagEncode32(-2));
-  EXPECT_EQ(0x7FFFFFFEu, ZigZagEncode32(0x3FFFFFFF));
-  EXPECT_EQ(0x7FFFFFFFu, ZigZagEncode32(0xC0000000));
-  EXPECT_EQ(0xFFFFFFFEu, ZigZagEncode32(0x7FFFFFFF));
-  EXPECT_EQ(0xFFFFFFFFu, ZigZagEncode32(0x80000000));
-
-  EXPECT_EQ(0, ZigZagDecode32(0u));
-  EXPECT_EQ(-1, ZigZagDecode32(1u));
-  EXPECT_EQ(1, ZigZagDecode32(2u));
-  EXPECT_EQ(-2, ZigZagDecode32(3u));
-  EXPECT_EQ(0x3FFFFFFF, ZigZagDecode32(0x7FFFFFFEu));
-  EXPECT_EQ(0xC0000000, ZigZagDecode32(0x7FFFFFFFu));
-  EXPECT_EQ(0x7FFFFFFF, ZigZagDecode32(0xFFFFFFFEu));
-  EXPECT_EQ(0x80000000, ZigZagDecode32(0xFFFFFFFFu));
-
-  EXPECT_EQ(0u, ZigZagEncode64(0));
-  EXPECT_EQ(1u, ZigZagEncode64(-1));
-  EXPECT_EQ(2u, ZigZagEncode64(1));
-  EXPECT_EQ(3u, ZigZagEncode64(-2));
-  EXPECT_EQ(ULL(0x000000007FFFFFFE), ZigZagEncode64(LL(0x000000003FFFFFFF)));
-  EXPECT_EQ(ULL(0x000000007FFFFFFF), ZigZagEncode64(LL(0xFFFFFFFFC0000000)));
-  EXPECT_EQ(ULL(0x00000000FFFFFFFE), ZigZagEncode64(LL(0x000000007FFFFFFF)));
-  EXPECT_EQ(ULL(0x00000000FFFFFFFF), ZigZagEncode64(LL(0xFFFFFFFF80000000)));
-  EXPECT_EQ(ULL(0xFFFFFFFFFFFFFFFE), ZigZagEncode64(LL(0x7FFFFFFFFFFFFFFF)));
-  EXPECT_EQ(ULL(0xFFFFFFFFFFFFFFFF), ZigZagEncode64(LL(0x8000000000000000)));
-
-  EXPECT_EQ(0, ZigZagDecode64(0u));
-  EXPECT_EQ(-1, ZigZagDecode64(1u));
-  EXPECT_EQ(1, ZigZagDecode64(2u));
-  EXPECT_EQ(-2, ZigZagDecode64(3u));
-  EXPECT_EQ(LL(0x000000003FFFFFFF), ZigZagDecode64(ULL(0x000000007FFFFFFE)));
-  EXPECT_EQ(LL(0xFFFFFFFFC0000000), ZigZagDecode64(ULL(0x000000007FFFFFFF)));
-  EXPECT_EQ(LL(0x000000007FFFFFFF), ZigZagDecode64(ULL(0x00000000FFFFFFFE)));
-  EXPECT_EQ(LL(0xFFFFFFFF80000000), ZigZagDecode64(ULL(0x00000000FFFFFFFF)));
-  EXPECT_EQ(LL(0x7FFFFFFFFFFFFFFF), ZigZagDecode64(ULL(0xFFFFFFFFFFFFFFFE)));
-  EXPECT_EQ(LL(0x8000000000000000), ZigZagDecode64(ULL(0xFFFFFFFFFFFFFFFF)));
-
-  // Some easier-to-verify round-trip tests.  The inputs (other than 0, 1, -1)
-  // were chosen semi-randomly via keyboard bashing.
-  EXPECT_EQ(0, ZigZagDecode32(ZigZagEncode32(0)));
-  EXPECT_EQ(1, ZigZagDecode32(ZigZagEncode32(1)));
-  EXPECT_EQ(-1, ZigZagDecode32(ZigZagEncode32(-1)));
-  EXPECT_EQ(14927, ZigZagDecode32(ZigZagEncode32(14927)));
-  EXPECT_EQ(-3612, ZigZagDecode32(ZigZagEncode32(-3612)));
-
-  EXPECT_EQ(0, ZigZagDecode64(ZigZagEncode64(0)));
-  EXPECT_EQ(1, ZigZagDecode64(ZigZagEncode64(1)));
-  EXPECT_EQ(-1, ZigZagDecode64(ZigZagEncode64(-1)));
-  EXPECT_EQ(14927, ZigZagDecode64(ZigZagEncode64(14927)));
-  EXPECT_EQ(-3612, ZigZagDecode64(ZigZagEncode64(-3612)));
-
-  EXPECT_EQ(LL(856912304801416),
-            ZigZagDecode64(ZigZagEncode64(LL(856912304801416))));
-  EXPECT_EQ(LL(-75123905439571256),
-            ZigZagDecode64(ZigZagEncode64(LL(-75123905439571256))));
-}
-
-TEST(WireFormatTest, RepeatedScalarsDifferentTagSizes) {
-  // At one point checks would trigger when parsing repeated fixed scalar
-  // fields.
-  protobuf_unittest::TestRepeatedScalarDifferentTagSizes msg1, msg2;
-  for (int i = 0; i < 100; ++i) {
-    msg1.add_repeated_fixed32(i);
-    msg1.add_repeated_int32(i);
-    msg1.add_repeated_fixed64(i);
-    msg1.add_repeated_int64(i);
-    msg1.add_repeated_float(i);
-    msg1.add_repeated_uint64(i);
-  }
-
-  // Make sure that we have a variety of tag sizes.
-  const Descriptor* desc = msg1.GetDescriptor();
-  const FieldDescriptor* field;
-  field = desc->FindFieldByName("repeated_fixed32");
-  ASSERT_TRUE(field != NULL);
-  ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type()));
-  field = desc->FindFieldByName("repeated_int32");
-  ASSERT_TRUE(field != NULL);
-  ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type()));
-  field = desc->FindFieldByName("repeated_fixed64");
-  ASSERT_TRUE(field != NULL);
-  ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type()));
-  field = desc->FindFieldByName("repeated_int64");
-  ASSERT_TRUE(field != NULL);
-  ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type()));
-  field = desc->FindFieldByName("repeated_float");
-  ASSERT_TRUE(field != NULL);
-  ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type()));
-  field = desc->FindFieldByName("repeated_uint64");
-  ASSERT_TRUE(field != NULL);
-  ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type()));
-
-  EXPECT_TRUE(msg2.ParseFromString(msg1.SerializeAsString()));
-  EXPECT_EQ(msg1.DebugString(), msg2.DebugString());
-}
-
-TEST(WireFormatTest, CompatibleTypes) {
-  const int64 data = 0x100000000LL;
-  unittest::Int64Message msg1;
-  msg1.set_data(data);
-  std::string serialized;
-  msg1.SerializeToString(&serialized);
-
-  // Test int64 is compatible with bool
-  unittest::BoolMessage msg2;
-  ASSERT_TRUE(msg2.ParseFromString(serialized));
-  ASSERT_EQ(static_cast<bool>(data), msg2.data());
-
-  // Test int64 is compatible with uint64
-  unittest::Uint64Message msg3;
-  ASSERT_TRUE(msg3.ParseFromString(serialized));
-  ASSERT_EQ(static_cast<uint64>(data), msg3.data());
-
-  // Test int64 is compatible with int32
-  unittest::Int32Message msg4;
-  ASSERT_TRUE(msg4.ParseFromString(serialized));
-  ASSERT_EQ(static_cast<int32>(data), msg4.data());
-
-  // Test int64 is compatible with uint32
-  unittest::Uint32Message msg5;
-  ASSERT_TRUE(msg5.ParseFromString(serialized));
-  ASSERT_EQ(static_cast<uint32>(data), msg5.data());
-}
-
-class Proto3PrimitiveRepeatedWireFormatTest : public ::testing::Test {
- protected:
-  Proto3PrimitiveRepeatedWireFormatTest()
-      : packedTestAllTypes_(
-            "\xFA\x01\x01\x01"
-            "\x82\x02\x01\x01"
-            "\x8A\x02\x01\x01"
-            "\x92\x02\x01\x01"
-            "\x9A\x02\x01\x02"
-            "\xA2\x02\x01\x02"
-            "\xAA\x02\x04\x01\x00\x00\x00"
-            "\xB2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00"
-            "\xBA\x02\x04\x01\x00\x00\x00"
-            "\xC2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00"
-            "\xCA\x02\x04\x00\x00\x80\x3f"
-            "\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xf0\x3f"
-            "\xDA\x02\x01\x01"
-            "\x9A\x03\x01\x01",
-            86),
-        packedTestUnpackedTypes_(
-            "\x0A\x01\x01"
-            "\x12\x01\x01"
-            "\x1A\x01\x01"
-            "\x22\x01\x01"
-            "\x2A\x01\x02"
-            "\x32\x01\x02"
-            "\x3A\x04\x01\x00\x00\x00"
-            "\x42\x08\x01\x00\x00\x00\x00\x00\x00\x00"
-            "\x4A\x04\x01\x00\x00\x00"
-            "\x52\x08\x01\x00\x00\x00\x00\x00\x00\x00"
-            "\x5A\x04\x00\x00\x80\x3f"
-            "\x62\x08\x00\x00\x00\x00\x00\x00\xf0\x3f"
-            "\x6A\x01\x01"
-            "\x72\x01\x01",
-            72),
-        unpackedTestAllTypes_(
-            "\xF8\x01\x01"
-            "\x80\x02\x01"
-            "\x88\x02\x01"
-            "\x90\x02\x01"
-            "\x98\x02\x02"
-            "\xA0\x02\x02"
-            "\xAD\x02\x01\x00\x00\x00"
-            "\xB1\x02\x01\x00\x00\x00\x00\x00\x00\x00"
-            "\xBD\x02\x01\x00\x00\x00"
-            "\xC1\x02\x01\x00\x00\x00\x00\x00\x00\x00"
-            "\xCD\x02\x00\x00\x80\x3f"
-            "\xD1\x02\x00\x00\x00\x00\x00\x00\xf0\x3f"
-            "\xD8\x02\x01"
-            "\x98\x03\x01",
-            72),
-        unpackedTestUnpackedTypes_(
-            "\x08\x01"
-            "\x10\x01"
-            "\x18\x01"
-            "\x20\x01"
-            "\x28\x02"
-            "\x30\x02"
-            "\x3D\x01\x00\x00\x00"
-            "\x41\x01\x00\x00\x00\x00\x00\x00\x00"
-            "\x4D\x01\x00\x00\x00"
-            "\x51\x01\x00\x00\x00\x00\x00\x00\x00"
-            "\x5D\x00\x00\x80\x3f"
-            "\x61\x00\x00\x00\x00\x00\x00\xf0\x3f"
-            "\x68\x01"
-            "\x70\x01",
-            58) {}
-  template <class Proto>
-  void SetProto3PrimitiveRepeatedFields(Proto* message) {
-    message->add_repeated_int32(1);
-    message->add_repeated_int64(1);
-    message->add_repeated_uint32(1);
-    message->add_repeated_uint64(1);
-    message->add_repeated_sint32(1);
-    message->add_repeated_sint64(1);
-    message->add_repeated_fixed32(1);
-    message->add_repeated_fixed64(1);
-    message->add_repeated_sfixed32(1);
-    message->add_repeated_sfixed64(1);
-    message->add_repeated_float(1.0);
-    message->add_repeated_double(1.0);
-    message->add_repeated_bool(true);
-    message->add_repeated_nested_enum(proto3_arena_unittest::TestAllTypes::FOO);
-  }
-
-  template <class Proto>
-  void ExpectProto3PrimitiveRepeatedFieldsSet(const Proto& message) {
-    EXPECT_EQ(1, message.repeated_int32(0));
-    EXPECT_EQ(1, message.repeated_int64(0));
-    EXPECT_EQ(1, message.repeated_uint32(0));
-    EXPECT_EQ(1, message.repeated_uint64(0));
-    EXPECT_EQ(1, message.repeated_sint32(0));
-    EXPECT_EQ(1, message.repeated_sint64(0));
-    EXPECT_EQ(1, message.repeated_fixed32(0));
-    EXPECT_EQ(1, message.repeated_fixed64(0));
-    EXPECT_EQ(1, message.repeated_sfixed32(0));
-    EXPECT_EQ(1, message.repeated_sfixed64(0));
-    EXPECT_EQ(1.0, message.repeated_float(0));
-    EXPECT_EQ(1.0, message.repeated_double(0));
-    EXPECT_EQ(true, message.repeated_bool(0));
-    EXPECT_EQ(proto3_arena_unittest::TestAllTypes::FOO,
-              message.repeated_nested_enum(0));
-  }
-
-  template <class Proto>
-  void TestSerialization(Proto* message, const std::string& expected) {
-    SetProto3PrimitiveRepeatedFields(message);
-
-    size_t size = message->ByteSizeLong();
-
-    // Serialize using the generated code.
-    std::string generated_data;
-    {
-      io::StringOutputStream raw_output(&generated_data);
-      io::CodedOutputStream output(&raw_output);
-      message->SerializeWithCachedSizes(&output);
-      ASSERT_FALSE(output.HadError());
-    }
-    EXPECT_TRUE(TestUtil::EqualsToSerialized(*message, generated_data));
-
-    // Serialize using the dynamic code.
-    std::string dynamic_data;
-    {
-      io::StringOutputStream raw_output(&dynamic_data);
-      io::CodedOutputStream output(&raw_output);
-      WireFormat::SerializeWithCachedSizes(*message, size, &output);
-      ASSERT_FALSE(output.HadError());
-    }
-    EXPECT_TRUE(expected == dynamic_data);
-  }
-
-  template <class Proto>
-  void TestParsing(Proto* message, const std::string& compatible_data) {
-    message->Clear();
-    message->ParseFromString(compatible_data);
-    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
-
-    message->Clear();
-    io::CodedInputStream input(
-        reinterpret_cast<const uint8*>(compatible_data.data()),
-        compatible_data.size());
-    WireFormat::ParseAndMergePartial(&input, message);
-    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
-  }
-
-  const std::string packedTestAllTypes_;
-  const std::string packedTestUnpackedTypes_;
-  const std::string unpackedTestAllTypes_;
-  const std::string unpackedTestUnpackedTypes_;
-};
-
-TEST_F(Proto3PrimitiveRepeatedWireFormatTest, Proto3PrimitiveRepeated) {
-  proto3_arena_unittest::TestAllTypes packed_message;
-  proto3_arena_unittest::TestUnpackedTypes unpacked_message;
-  TestSerialization(&packed_message, packedTestAllTypes_);
-  TestParsing(&packed_message, packedTestAllTypes_);
-  TestParsing(&packed_message, unpackedTestAllTypes_);
-  TestSerialization(&unpacked_message, unpackedTestUnpackedTypes_);
-  TestParsing(&unpacked_message, packedTestUnpackedTypes_);
-  TestParsing(&unpacked_message, unpackedTestUnpackedTypes_);
-}
-
-class WireFormatInvalidInputTest : public testing::Test {
- protected:
-  // Make a serialized TestAllTypes in which the field optional_nested_message
-  // contains exactly the given bytes, which may be invalid.
-  std::string MakeInvalidEmbeddedMessage(const char* bytes, int size) {
-    const FieldDescriptor* field =
-        unittest::TestAllTypes::descriptor()->FindFieldByName(
-            "optional_nested_message");
-    GOOGLE_CHECK(field != NULL);
-
-    std::string result;
-
-    {
-      io::StringOutputStream raw_output(&result);
-      io::CodedOutputStream output(&raw_output);
-
-      WireFormatLite::WriteBytes(field->number(), std::string(bytes, size),
-                                 &output);
-    }
-
-    return result;
-  }
-
-  // Make a serialized TestAllTypes in which the field optionalgroup
-  // contains exactly the given bytes -- which may be invalid -- and
-  // possibly no end tag.
-  std::string MakeInvalidGroup(const char* bytes, int size,
-                               bool include_end_tag) {
-    const FieldDescriptor* field =
-        unittest::TestAllTypes::descriptor()->FindFieldByName("optionalgroup");
-    GOOGLE_CHECK(field != NULL);
-
-    std::string result;
-
-    {
-      io::StringOutputStream raw_output(&result);
-      io::CodedOutputStream output(&raw_output);
-
-      output.WriteVarint32(WireFormat::MakeTag(field));
-      output.WriteString(std::string(bytes, size));
-      if (include_end_tag) {
-        output.WriteVarint32(WireFormatLite::MakeTag(
-            field->number(), WireFormatLite::WIRETYPE_END_GROUP));
-      }
-    }
-
-    return result;
-  }
-};
-
-TEST_F(WireFormatInvalidInputTest, InvalidSubMessage) {
-  unittest::TestAllTypes message;
-
-  // Control case.
-  EXPECT_TRUE(message.ParseFromString(MakeInvalidEmbeddedMessage("", 0)));
-
-  // The byte is a valid varint, but not a valid tag (zero).
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\0", 1)));
-
-  // The byte is a malformed varint.
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\200", 1)));
-
-  // The byte is an endgroup tag, but we aren't parsing a group.
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\014", 1)));
-
-  // The byte is a valid varint but not a valid tag (bad wire type).
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\017", 1)));
-}
-
-TEST_F(WireFormatInvalidInputTest, InvalidMessageWithExtraZero) {
-  std::string data;
-  {
-    // Serialize a valid proto
-    unittest::TestAllTypes message;
-    message.set_optional_int32(1);
-    message.SerializeToString(&data);
-    data.push_back(0);  // Append invalid zero tag
-  }
-
-  // Control case.
-  {
-    io::ArrayInputStream ais(data.data(), data.size());
-    io::CodedInputStream is(&ais);
-    unittest::TestAllTypes message;
-    // It should fail but currently passes.
-    EXPECT_TRUE(message.MergePartialFromCodedStream(&is));
-    // Parsing from the string should fail.
-    EXPECT_FALSE(message.ParseFromString(data));
-  }
-}
-
-TEST_F(WireFormatInvalidInputTest, InvalidGroup) {
-  unittest::TestAllTypes message;
-
-  // Control case.
-  EXPECT_TRUE(message.ParseFromString(MakeInvalidGroup("", 0, true)));
-
-  // Missing end tag.  Groups cannot end at EOF.
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("", 0, false)));
-
-  // The byte is a valid varint, but not a valid tag (zero).
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\0", 1, false)));
-
-  // The byte is a malformed varint.
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\200", 1, false)));
-
-  // The byte is an endgroup tag, but not the right one for this group.
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\014", 1, false)));
-
-  // The byte is a valid varint but not a valid tag (bad wire type).
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\017", 1, true)));
-}
-
-TEST_F(WireFormatInvalidInputTest, InvalidUnknownGroup) {
-  // Use TestEmptyMessage so that the group made by MakeInvalidGroup will not
-  // be a known tag number.
-  unittest::TestEmptyMessage message;
-
-  // Control case.
-  EXPECT_TRUE(message.ParseFromString(MakeInvalidGroup("", 0, true)));
-
-  // Missing end tag.  Groups cannot end at EOF.
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("", 0, false)));
-
-  // The byte is a valid varint, but not a valid tag (zero).
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\0", 1, false)));
-
-  // The byte is a malformed varint.
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\200", 1, false)));
-
-  // The byte is an endgroup tag, but not the right one for this group.
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\014", 1, false)));
-
-  // The byte is a valid varint but not a valid tag (bad wire type).
-  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\017", 1, true)));
-}
-
-TEST_F(WireFormatInvalidInputTest, InvalidStringInUnknownGroup) {
-  // Test a bug fix:  SkipMessage should fail if the message contains a
-  // string whose length would extend beyond the message end.
-
-  unittest::TestAllTypes message;
-  message.set_optional_string("foo foo foo foo");
-  std::string data;
-  message.SerializeToString(&data);
-
-  // Chop some bytes off the end.
-  data.resize(data.size() - 4);
-
-  // Try to skip it.  Note that the bug was only present when parsing to an
-  // UnknownFieldSet.
-  io::ArrayInputStream raw_input(data.data(), data.size());
-  io::CodedInputStream coded_input(&raw_input);
-  UnknownFieldSet unknown_fields;
-  EXPECT_FALSE(WireFormat::SkipMessage(&coded_input, &unknown_fields));
-}
-
-// Test differences between string and bytes.
-// Value of a string type must be valid UTF-8 string.  When UTF-8
-// validation is enabled (GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED):
-// WriteInvalidUTF8String:  see error message.
-// ReadInvalidUTF8String:  see error message.
-// WriteValidUTF8String: fine.
-// ReadValidUTF8String:  fine.
-// WriteAnyBytes: fine.
-// ReadAnyBytes: fine.
-const char* kInvalidUTF8String = "Invalid UTF-8: \xA0\xB0\xC0\xD0";
-// This used to be "Valid UTF-8: \x01\x02\u8C37\u6B4C", but MSVC seems to
-// interpret \u differently from GCC.
-const char* kValidUTF8String = "Valid UTF-8: \x01\x02\350\260\267\346\255\214";
-
-template <typename T>
-bool WriteMessage(const char* value, T* message, std::string* wire_buffer) {
-  message->set_data(value);
-  wire_buffer->clear();
-  message->AppendToString(wire_buffer);
-  return (wire_buffer->size() > 0);
-}
-
-template <typename T>
-bool ReadMessage(const std::string& wire_buffer, T* message) {
-  return message->ParseFromArray(wire_buffer.data(), wire_buffer.size());
-}
-
-class Utf8ValidationTest : public ::testing::Test {
- protected:
-  Utf8ValidationTest() {}
-  virtual ~Utf8ValidationTest() {}
-  virtual void SetUp() {
-  }
-
-};
-
-TEST_F(Utf8ValidationTest, WriteInvalidUTF8String) {
-  std::string wire_buffer;
-  protobuf_unittest::OneString input;
-  std::vector<std::string> errors;
-  {
-    ScopedMemoryLog log;
-    WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
-    errors = log.GetMessages(ERROR);
-  }
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  ASSERT_EQ(1, errors.size());
-  EXPECT_TRUE(
-      HasPrefixString(errors[0],
-                       "String field 'protobuf_unittest.OneString.data' "
-                       "contains invalid UTF-8 data when "
-                       "serializing a protocol buffer. Use the "
-                       "'bytes' type if you intend to send raw bytes."));
-#else
-  ASSERT_EQ(0, errors.size());
-#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-}
-
-
-TEST_F(Utf8ValidationTest, ReadInvalidUTF8String) {
-  std::string wire_buffer;
-  protobuf_unittest::OneString input;
-  WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
-  protobuf_unittest::OneString output;
-  std::vector<std::string> errors;
-  {
-    ScopedMemoryLog log;
-    ReadMessage(wire_buffer, &output);
-    errors = log.GetMessages(ERROR);
-  }
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  ASSERT_EQ(1, errors.size());
-  EXPECT_TRUE(
-      HasPrefixString(errors[0],
-                       "String field 'protobuf_unittest.OneString.data' "
-                       "contains invalid UTF-8 data when "
-                       "parsing a protocol buffer. Use the "
-                       "'bytes' type if you intend to send raw bytes."));
-
-#else
-  ASSERT_EQ(0, errors.size());
-#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-}
-
-
-TEST_F(Utf8ValidationTest, WriteValidUTF8String) {
-  std::string wire_buffer;
-  protobuf_unittest::OneString input;
-  std::vector<std::string> errors;
-  {
-    ScopedMemoryLog log;
-    WriteMessage(kValidUTF8String, &input, &wire_buffer);
-    errors = log.GetMessages(ERROR);
-  }
-  ASSERT_EQ(0, errors.size());
-}
-
-TEST_F(Utf8ValidationTest, ReadValidUTF8String) {
-  std::string wire_buffer;
-  protobuf_unittest::OneString input;
-  WriteMessage(kValidUTF8String, &input, &wire_buffer);
-  protobuf_unittest::OneString output;
-  std::vector<std::string> errors;
-  {
-    ScopedMemoryLog log;
-    ReadMessage(wire_buffer, &output);
-    errors = log.GetMessages(ERROR);
-  }
-  ASSERT_EQ(0, errors.size());
-  EXPECT_EQ(input.data(), output.data());
-}
-
-// Bytes: anything can pass as bytes, use invalid UTF-8 string to test
-TEST_F(Utf8ValidationTest, WriteArbitraryBytes) {
-  std::string wire_buffer;
-  protobuf_unittest::OneBytes input;
-  std::vector<std::string> errors;
-  {
-    ScopedMemoryLog log;
-    WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
-    errors = log.GetMessages(ERROR);
-  }
-  ASSERT_EQ(0, errors.size());
-}
-
-TEST_F(Utf8ValidationTest, ReadArbitraryBytes) {
-  std::string wire_buffer;
-  protobuf_unittest::OneBytes input;
-  WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
-  protobuf_unittest::OneBytes output;
-  std::vector<std::string> errors;
-  {
-    ScopedMemoryLog log;
-    ReadMessage(wire_buffer, &output);
-    errors = log.GetMessages(ERROR);
-  }
-  ASSERT_EQ(0, errors.size());
-  EXPECT_EQ(input.data(), output.data());
-}
-
-TEST_F(Utf8ValidationTest, ParseRepeatedString) {
-  protobuf_unittest::MoreBytes input;
-  input.add_data(kValidUTF8String);
-  input.add_data(kInvalidUTF8String);
-  input.add_data(kInvalidUTF8String);
-  std::string wire_buffer = input.SerializeAsString();
-
-  protobuf_unittest::MoreString output;
-  std::vector<std::string> errors;
-  {
-    ScopedMemoryLog log;
-    ReadMessage(wire_buffer, &output);
-    errors = log.GetMessages(ERROR);
-  }
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  ASSERT_EQ(2, errors.size());
-#else
-  ASSERT_EQ(0, errors.size());
-#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  EXPECT_EQ(wire_buffer, output.SerializeAsString());
-}
-
-// Test the old VerifyUTF8String() function, which may still be called by old
-// generated code.
-TEST_F(Utf8ValidationTest, OldVerifyUTF8String) {
-  std::string data(kInvalidUTF8String);
-
-  std::vector<std::string> errors;
-  {
-    ScopedMemoryLog log;
-    WireFormat::VerifyUTF8String(data.data(), data.size(),
-                                 WireFormat::SERIALIZE);
-    errors = log.GetMessages(ERROR);
-  }
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  ASSERT_EQ(1, errors.size());
-  EXPECT_TRUE(
-      HasPrefixString(errors[0],
-                       "String field contains invalid UTF-8 data when "
-                       "serializing a protocol buffer. Use the "
-                       "'bytes' type if you intend to send raw bytes."));
-#else
-  ASSERT_EQ(0, errors.size());
-#endif
-}
-
-
-TEST(RepeatedVarint, Int32) {
-  RepeatedField<int32> v;
-
-  // Insert -2^n, 2^n and 2^n-1.
-  for (int n = 0; n < 10; n++) {
-    v.Add(-(1 << n));
-    v.Add(1 << n);
-    v.Add((1 << n) - 1);
-  }
-
-  // Check consistency with the scalar Int32Size.
-  size_t expected = 0;
-  for (int i = 0; i < v.size(); i++) {
-    expected += WireFormatLite::Int32Size(v[i]);
-  }
-
-  EXPECT_EQ(expected, WireFormatLite::Int32Size(v));
-}
-
-TEST(RepeatedVarint, Int64) {
-  RepeatedField<int64> v;
-
-  // Insert -2^n, 2^n and 2^n-1.
-  for (int n = 0; n < 10; n++) {
-    v.Add(-(1 << n));
-    v.Add(1 << n);
-    v.Add((1 << n) - 1);
-  }
-
-  // Check consistency with the scalar Int64Size.
-  size_t expected = 0;
-  for (int i = 0; i < v.size(); i++) {
-    expected += WireFormatLite::Int64Size(v[i]);
-  }
-
-  EXPECT_EQ(expected, WireFormatLite::Int64Size(v));
-}
-
-TEST(RepeatedVarint, SInt32) {
-  RepeatedField<int32> v;
-
-  // Insert -2^n, 2^n and 2^n-1.
-  for (int n = 0; n < 10; n++) {
-    v.Add(-(1 << n));
-    v.Add(1 << n);
-    v.Add((1 << n) - 1);
-  }
-
-  // Check consistency with the scalar SInt32Size.
-  size_t expected = 0;
-  for (int i = 0; i < v.size(); i++) {
-    expected += WireFormatLite::SInt32Size(v[i]);
-  }
-
-  EXPECT_EQ(expected, WireFormatLite::SInt32Size(v));
-}
-
-TEST(RepeatedVarint, SInt64) {
-  RepeatedField<int64> v;
-
-  // Insert -2^n, 2^n and 2^n-1.
-  for (int n = 0; n < 10; n++) {
-    v.Add(-(1 << n));
-    v.Add(1 << n);
-    v.Add((1 << n) - 1);
-  }
-
-  // Check consistency with the scalar SInt64Size.
-  size_t expected = 0;
-  for (int i = 0; i < v.size(); i++) {
-    expected += WireFormatLite::SInt64Size(v[i]);
-  }
-
-  EXPECT_EQ(expected, WireFormatLite::SInt64Size(v));
-}
-
-TEST(RepeatedVarint, UInt32) {
-  RepeatedField<uint32> v;
-
-  // Insert 2^n and 2^n-1.
-  for (int n = 0; n < 10; n++) {
-    v.Add(1 << n);
-    v.Add((1 << n) - 1);
-  }
-
-  // Check consistency with the scalar UInt32Size.
-  size_t expected = 0;
-  for (int i = 0; i < v.size(); i++) {
-    expected += WireFormatLite::UInt32Size(v[i]);
-  }
-
-  EXPECT_EQ(expected, WireFormatLite::UInt32Size(v));
-}
-
-TEST(RepeatedVarint, UInt64) {
-  RepeatedField<uint64> v;
-
-  // Insert 2^n and 2^n-1.
-  for (int n = 0; n < 10; n++) {
-    v.Add(1 << n);
-    v.Add((1 << n) - 1);
-  }
-
-  // Check consistency with the scalar UInt64Size.
-  size_t expected = 0;
-  for (int i = 0; i < v.size(); i++) {
-    expected += WireFormatLite::UInt64Size(v[i]);
-  }
-
-  EXPECT_EQ(expected, WireFormatLite::UInt64Size(v));
-}
-
-TEST(RepeatedVarint, Enum) {
-  RepeatedField<int> v;
-
-  // Insert 2^n and 2^n-1.
-  for (int n = 0; n < 10; n++) {
-    v.Add(1 << n);
-    v.Add((1 << n) - 1);
-  }
-
-  // Check consistency with the scalar EnumSize.
-  size_t expected = 0;
-  for (int i = 0; i < v.size(); i++) {
-    expected += WireFormatLite::EnumSize(v[i]);
-  }
-
-  EXPECT_EQ(expected, WireFormatLite::EnumSize(v));
-}
-
 
 }  // namespace
 }  // namespace internal
diff --git a/src/google/protobuf/wire_format_unittest.inc b/src/google/protobuf/wire_format_unittest.inc
new file mode 100644
index 0000000..3f3ddff
--- /dev/null
+++ b/src/google/protobuf/wire_format_unittest.inc
@@ -0,0 +1,1585 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: [email protected] (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/wire_format.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/test_util2.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/testing/googletest.h>
+#include <google/protobuf/stubs/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+TEST(WireFormatTest, EnumsInSync) {
+  // Verify that WireFormatLite::FieldType and WireFormatLite::CppType match
+  // FieldDescriptor::Type and FieldDescriptor::CppType.
+
+  EXPECT_EQ(implicit_cast<int>(FieldDescriptor::MAX_TYPE),
+            implicit_cast<int>(WireFormatLite::MAX_FIELD_TYPE));
+  EXPECT_EQ(implicit_cast<int>(FieldDescriptor::MAX_CPPTYPE),
+            implicit_cast<int>(WireFormatLite::MAX_CPPTYPE));
+
+  for (int i = 1; i <= WireFormatLite::MAX_FIELD_TYPE; i++) {
+    EXPECT_EQ(implicit_cast<int>(FieldDescriptor::TypeToCppType(
+                  static_cast<FieldDescriptor::Type>(i))),
+              implicit_cast<int>(WireFormatLite::FieldTypeToCppType(
+                  static_cast<WireFormatLite::FieldType>(i))));
+  }
+}
+
+TEST(WireFormatTest, MaxFieldNumber) {
+  // Make sure the max field number constant is accurate.
+  EXPECT_EQ((1 << (32 - WireFormatLite::kTagTypeBits)) - 1,
+            FieldDescriptor::kMaxNumber);
+}
+
+TEST(WireFormatTest, Parse) {
+  UNITTEST::TestAllTypes source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetAllFields(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectAllFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParseExtensions) {
+  UNITTEST::TestAllExtensions source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetAllExtensions(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectAllExtensionsSet(dest);
+}
+
+TEST(WireFormatTest, ParsePacked) {
+  UNITTEST::TestPackedTypes source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetPackedFields(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectPackedFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParsePackedFromUnpacked) {
+  // Serialize using the generated code.
+  UNITTEST::TestUnpackedTypes source;
+  TestUtil::SetUnpackedFields(&source);
+  std::string data = source.SerializeAsString();
+
+  // Parse using WireFormat.
+  UNITTEST::TestPackedTypes dest;
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectPackedFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParseUnpackedFromPacked) {
+  // Serialize using the generated code.
+  UNITTEST::TestPackedTypes source;
+  TestUtil::SetPackedFields(&source);
+  std::string data = source.SerializeAsString();
+
+  // Parse using WireFormat.
+  UNITTEST::TestUnpackedTypes dest;
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectUnpackedFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParsePackedExtensions) {
+  UNITTEST::TestPackedExtensions source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetPackedExtensions(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectPackedExtensionsSet(dest);
+}
+
+TEST(WireFormatTest, ParseOneof) {
+  UNITTEST::TestOneof2 source, dest;
+  std::string data;
+
+  // Serialize using the generated code.
+  TestUtil::SetOneof1(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  TestUtil::ExpectOneofSet1(dest);
+}
+
+TEST(WireFormatTest, OneofOnlySetLast) {
+  UNITTEST::TestOneofBackwardsCompatible source;
+  UNITTEST::TestOneof oneof_dest;
+  std::string data;
+
+  // Set two fields
+  source.set_foo_int(100);
+  source.set_foo_string("101");
+
+  // Serialize and parse to oneof message. Generated serializer may not order
+  // fields in tag order. Use WireFormat::SerializeWithCachedSizes instead as
+  // it sorts fields beforehand.
+  {
+    io::StringOutputStream raw_output(&data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(source, source.ByteSizeLong(),
+                                         &output);
+    ASSERT_FALSE(output.HadError());
+  }
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &oneof_dest);
+
+  // Only the last field is set.
+  EXPECT_FALSE(oneof_dest.has_foo_int());
+  EXPECT_TRUE(oneof_dest.has_foo_string());
+}
+
+TEST(WireFormatTest, ByteSize) {
+  UNITTEST::TestAllTypes message;
+  TestUtil::SetAllFields(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, ByteSizeExtensions) {
+  UNITTEST::TestAllExtensions message;
+  TestUtil::SetAllExtensions(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, ByteSizePacked) {
+  UNITTEST::TestPackedTypes message;
+  TestUtil::SetPackedFields(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, ByteSizePackedExtensions) {
+  UNITTEST::TestPackedExtensions message;
+  TestUtil::SetPackedExtensions(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, ByteSizeOneof) {
+  UNITTEST::TestOneof2 message;
+  TestUtil::SetOneof1(&message);
+
+  EXPECT_EQ(message.ByteSizeLong(), WireFormat::ByteSize(message));
+  message.Clear();
+
+  EXPECT_EQ(0, message.ByteSizeLong());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, Serialize) {
+  UNITTEST::TestAllTypes message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  TestUtil::SetAllFields(&message);
+  size_t size = message.ByteSizeLong();
+
+  // Serialize using the generated code.
+  {
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatTest, SerializeExtensions) {
+  UNITTEST::TestAllExtensions message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  TestUtil::SetAllExtensions(&message);
+  size_t size = message.ByteSizeLong();
+
+  // Serialize using the generated code.
+  {
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatTest, SerializeFieldsAndExtensions) {
+  UNITTEST::TestFieldOrderings message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  TestUtil::SetAllFieldsAndExtensions(&message);
+  size_t size = message.ByteSizeLong();
+
+  // Serialize using the generated code.
+  {
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatTest, SerializeOneof) {
+  UNITTEST::TestOneof2 message;
+  std::string generated_data;
+  std::string dynamic_data;
+
+  TestUtil::SetOneof1(&message);
+  size_t size = message.ByteSizeLong();
+
+  // Serialize using the generated code.
+  {
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should parse to the same message.
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, generated_data));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(message, dynamic_data));
+}
+
+TEST(WireFormatTest, ParseMultipleExtensionRanges) {
+  // Make sure we can parse a message that contains multiple extensions ranges.
+  UNITTEST::TestFieldOrderings source;
+  std::string data;
+
+  TestUtil::SetAllFieldsAndExtensions(&source);
+  source.SerializeToString(&data);
+
+  {
+    UNITTEST::TestFieldOrderings dest;
+    EXPECT_TRUE(dest.ParseFromString(data));
+    EXPECT_EQ(source.DebugString(), dest.DebugString());
+  }
+
+  // Also test using reflection-based parsing.
+  {
+    UNITTEST::TestFieldOrderings dest;
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream coded_input(&raw_input);
+    EXPECT_TRUE(WireFormat::ParseAndMergePartial(&coded_input, &dest));
+    EXPECT_EQ(source.DebugString(), dest.DebugString());
+  }
+}
+
+const int kUnknownTypeId = 1550055;
+
+TEST(WireFormatTest, SerializeMessageSet) {
+  // Set up a TestMessageSet with two known messages and an unknown one.
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  message_set
+      .MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension)
+      ->set_i(123);
+  message_set
+      .MutableExtension(
+          UNITTEST::TestMessageSetExtension2::message_set_extension)
+      ->set_str("foo");
+  message_set.mutable_unknown_fields()->AddLengthDelimited(kUnknownTypeId,
+                                                           "bar");
+
+  std::string data;
+  ASSERT_TRUE(message_set.SerializeToString(&data));
+
+  // Parse back using RawMessageSet and check the contents.
+  UNITTEST::RawMessageSet raw;
+  ASSERT_TRUE(raw.ParseFromString(data));
+
+  EXPECT_EQ(0, raw.unknown_fields().field_count());
+
+  ASSERT_EQ(3, raw.item_size());
+  EXPECT_EQ(
+      UNITTEST::TestMessageSetExtension1::descriptor()->extension(0)->number(),
+      raw.item(0).type_id());
+  EXPECT_EQ(
+      UNITTEST::TestMessageSetExtension2::descriptor()->extension(0)->number(),
+      raw.item(1).type_id());
+  EXPECT_EQ(kUnknownTypeId, raw.item(2).type_id());
+
+  UNITTEST::TestMessageSetExtension1 message1;
+  EXPECT_TRUE(message1.ParseFromString(raw.item(0).message()));
+  EXPECT_EQ(123, message1.i());
+
+  UNITTEST::TestMessageSetExtension2 message2;
+  EXPECT_TRUE(message2.ParseFromString(raw.item(1).message()));
+  EXPECT_EQ("foo", message2.str());
+
+  EXPECT_EQ("bar", raw.item(2).message());
+}
+
+TEST(WireFormatTest, SerializeMessageSetVariousWaysAreEqual) {
+  // Serialize a MessageSet to a stream and to a flat array using generated
+  // code, and also using WireFormat, and check that the results are equal.
+  // Set up a TestMessageSet with two known messages and an unknown one, as
+  // above.
+
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  message_set
+      .MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension)
+      ->set_i(123);
+  message_set
+      .MutableExtension(
+          UNITTEST::TestMessageSetExtension2::message_set_extension)
+      ->set_str("foo");
+  message_set.mutable_unknown_fields()->AddLengthDelimited(kUnknownTypeId,
+                                                           "bar");
+
+  size_t size = message_set.ByteSizeLong();
+  EXPECT_EQ(size, message_set.GetCachedSize());
+  ASSERT_EQ(size, WireFormat::ByteSize(message_set));
+
+  std::string flat_data;
+  std::string stream_data;
+  std::string dynamic_data;
+  flat_data.resize(size);
+  stream_data.resize(size);
+
+  // Serialize to flat array
+  {
+    uint8* target = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&flat_data));
+    uint8* end = message_set.SerializeWithCachedSizesToArray(target);
+    EXPECT_EQ(size, end - target);
+  }
+
+  // Serialize to buffer
+  {
+    io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&stream_data), size,
+                                       1);
+    io::CodedOutputStream output_stream(&array_stream);
+    message_set.SerializeWithCachedSizes(&output_stream);
+    ASSERT_FALSE(output_stream.HadError());
+  }
+
+  // Serialize to buffer with WireFormat.
+  {
+    io::StringOutputStream string_stream(&dynamic_data);
+    io::CodedOutputStream output_stream(&string_stream);
+    WireFormat::SerializeWithCachedSizes(message_set, size, &output_stream);
+    ASSERT_FALSE(output_stream.HadError());
+  }
+
+  EXPECT_TRUE(flat_data == stream_data);
+  EXPECT_TRUE(flat_data == dynamic_data);
+}
+
+TEST(WireFormatTest, ParseMessageSet) {
+  // Set up a RawMessageSet with two known messages and an unknown one.
+  UNITTEST::RawMessageSet raw;
+
+  {
+    UNITTEST::RawMessageSet::Item* item = raw.add_item();
+    item->set_type_id(UNITTEST::TestMessageSetExtension1::descriptor()
+                          ->extension(0)
+                          ->number());
+    UNITTEST::TestMessageSetExtension1 message;
+    message.set_i(123);
+    message.SerializeToString(item->mutable_message());
+  }
+
+  {
+    UNITTEST::RawMessageSet::Item* item = raw.add_item();
+    item->set_type_id(UNITTEST::TestMessageSetExtension2::descriptor()
+                          ->extension(0)
+                          ->number());
+    UNITTEST::TestMessageSetExtension2 message;
+    message.set_str("foo");
+    message.SerializeToString(item->mutable_message());
+  }
+
+  {
+    UNITTEST::RawMessageSet::Item* item = raw.add_item();
+    item->set_type_id(kUnknownTypeId);
+    item->set_message("bar");
+  }
+
+  std::string data;
+  ASSERT_TRUE(raw.SerializeToString(&data));
+
+  // Parse as a TestMessageSet and check the contents.
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  ASSERT_TRUE(message_set.ParseFromString(data));
+
+  EXPECT_EQ(123,
+            message_set
+                .GetExtension(
+                    UNITTEST::TestMessageSetExtension1::message_set_extension)
+                .i());
+  EXPECT_EQ("foo",
+            message_set
+                .GetExtension(
+                    UNITTEST::TestMessageSetExtension2::message_set_extension)
+                .str());
+
+  ASSERT_EQ(1, message_set.unknown_fields().field_count());
+  ASSERT_EQ(UnknownField::TYPE_LENGTH_DELIMITED,
+            message_set.unknown_fields().field(0).type());
+  EXPECT_EQ("bar", message_set.unknown_fields().field(0).length_delimited());
+
+  // Also parse using WireFormat.
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet dynamic_message_set;
+  io::CodedInputStream input(reinterpret_cast<const uint8*>(data.data()),
+                             data.size());
+  ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &dynamic_message_set));
+  EXPECT_EQ(message_set.DebugString(), dynamic_message_set.DebugString());
+}
+
+TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) {
+  std::string data;
+  {
+    UNITTEST::TestMessageSetExtension1 message;
+    message.set_i(123);
+    // Build a MessageSet manually with its message content put before its
+    // type_id.
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    coded_output.WriteTag(WireFormatLite::kMessageSetItemStartTag);
+    // Write the message content first.
+    WireFormatLite::WriteTag(WireFormatLite::kMessageSetMessageNumber,
+                             WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                             &coded_output);
+    coded_output.WriteVarint32(message.ByteSizeLong());
+    message.SerializeWithCachedSizes(&coded_output);
+    // Write the type id.
+    uint32 type_id = message.GetDescriptor()->extension(0)->number();
+    WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
+                                type_id, &coded_output);
+    coded_output.WriteTag(WireFormatLite::kMessageSetItemEndTag);
+  }
+  {
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    ASSERT_TRUE(message_set.ParseFromString(data));
+
+    EXPECT_EQ(123,
+              message_set
+                  .GetExtension(
+                      UNITTEST::TestMessageSetExtension1::message_set_extension)
+                  .i());
+  }
+  {
+    // Test parse the message via Reflection.
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    io::CodedInputStream input(reinterpret_cast<const uint8*>(data.data()),
+                               data.size());
+    EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set));
+    EXPECT_TRUE(input.ConsumedEntireMessage());
+
+    EXPECT_EQ(123,
+              message_set
+                  .GetExtension(
+                      UNITTEST::TestMessageSetExtension1::message_set_extension)
+                  .i());
+  }
+}
+
+void SerializeReverseOrder(
+    const PROTO2_WIREFORMAT_UNITTEST::TestMessageSet& mset,
+    io::CodedOutputStream* coded_output);
+
+void SerializeReverseOrder(const UNITTEST::TestMessageSetExtension1& message,
+                           io::CodedOutputStream* coded_output) {
+  WireFormatLite::WriteTag(15,  // i
+                           WireFormatLite::WIRETYPE_VARINT, coded_output);
+  coded_output->WriteVarint64(message.i());
+  WireFormatLite::WriteTag(16,  // recursive
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                           coded_output);
+  coded_output->WriteVarint32(message.recursive().GetCachedSize());
+  SerializeReverseOrder(message.recursive(), coded_output);
+}
+
+void SerializeReverseOrder(
+    const PROTO2_WIREFORMAT_UNITTEST::TestMessageSet& mset,
+    io::CodedOutputStream* coded_output) {
+  if (!mset.HasExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension))
+    return;
+  coded_output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
+  // Write the message content first.
+  WireFormatLite::WriteTag(WireFormatLite::kMessageSetMessageNumber,
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                           coded_output);
+  auto& message = mset.GetExtension(
+      UNITTEST::TestMessageSetExtension1::message_set_extension);
+  coded_output->WriteVarint32(message.GetCachedSize());
+  SerializeReverseOrder(message, coded_output);
+  // Write the type id.
+  uint32 type_id = message.GetDescriptor()->extension(0)->number();
+  WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, type_id,
+                              coded_output);
+  coded_output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
+}
+
+TEST(WireFormatTest, ParseMessageSetWithDeepRecReverseOrder) {
+  std::string data;
+  {
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet* mset = &message_set;
+    for (int i = 0; i < 200; i++) {
+      auto m = mset->MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension);
+      m->set_i(i);
+      mset = m->mutable_recursive();
+    }
+    message_set.ByteSizeLong();
+    // Serialize with reverse payload tag order
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    SerializeReverseOrder(message_set, &coded_output);
+  }
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  EXPECT_FALSE(message_set.ParseFromString(data));
+}
+
+TEST(WireFormatTest, ParseFailMalformedMessageSet) {
+  constexpr int kDepth = 5;
+  std::string data;
+  {
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet* mset = &message_set;
+    for (int i = 0; i < kDepth; i++) {
+      auto m = mset->MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension);
+      m->set_i(i);
+      mset = m->mutable_recursive();
+    }
+    auto m = mset->MutableExtension(
+        UNITTEST::TestMessageSetExtension1::message_set_extension);
+    // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+    m->set_i(-1);
+
+    EXPECT_TRUE(message_set.SerializeToString(&data));
+    // Make the proto mal-formed.
+    data[data.size() - 2 - kDepth] = 0xFF;
+  }
+
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  EXPECT_FALSE(message_set.ParseFromString(data));
+}
+
+TEST(WireFormatTest, ParseFailMalformedMessageSetReverseOrder) {
+  constexpr int kDepth = 5;
+  std::string data;
+  {
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+    PROTO2_WIREFORMAT_UNITTEST::TestMessageSet* mset = &message_set;
+    for (int i = 0; i < kDepth; i++) {
+      auto m = mset->MutableExtension(
+          UNITTEST::TestMessageSetExtension1::message_set_extension);
+      m->set_i(i);
+      mset = m->mutable_recursive();
+    }
+    auto m = mset->MutableExtension(
+        UNITTEST::TestMessageSetExtension1::message_set_extension);
+    // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+    m->set_i(-1);
+    // SerializeReverseOrder() assumes "recursive" is always present.
+    m->mutable_recursive();
+
+    message_set.ByteSizeLong();
+
+    // Serialize with reverse payload tag order
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    SerializeReverseOrder(message_set, &coded_output);
+  }
+
+  // Make varint for -1 malformed.
+  data[data.size() - 5 * (kDepth + 1) - 4] = 0xFF;
+
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  EXPECT_FALSE(message_set.ParseFromString(data));
+}
+
+TEST(WireFormatTest, ParseBrokenMessageSet) {
+  PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
+  std::string input("goodbye");  // Invalid wire format data.
+  EXPECT_FALSE(message_set.ParseFromString(input));
+}
+
+TEST(WireFormatTest, RecursionLimit) {
+  UNITTEST::TestRecursiveMessage message;
+  message.mutable_a()->mutable_a()->mutable_a()->mutable_a()->set_i(1);
+  std::string data;
+  message.SerializeToString(&data);
+
+  {
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(4);
+    UNITTEST::TestRecursiveMessage message2;
+    EXPECT_TRUE(message2.ParseFromCodedStream(&input));
+  }
+
+  {
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(3);
+    UNITTEST::TestRecursiveMessage message2;
+    EXPECT_FALSE(message2.ParseFromCodedStream(&input));
+  }
+}
+
+TEST(WireFormatTest, UnknownFieldRecursionLimit) {
+  UNITTEST::TestEmptyMessage message;
+  message.mutable_unknown_fields()
+      ->AddGroup(1234)
+      ->AddGroup(1234)
+      ->AddGroup(1234)
+      ->AddGroup(1234)
+      ->AddVarint(1234, 123);
+  std::string data;
+  message.SerializeToString(&data);
+
+  {
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(4);
+    UNITTEST::TestEmptyMessage message2;
+    EXPECT_TRUE(message2.ParseFromCodedStream(&input));
+  }
+
+  {
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(3);
+    UNITTEST::TestEmptyMessage message2;
+    EXPECT_FALSE(message2.ParseFromCodedStream(&input));
+  }
+}
+
+TEST(WireFormatTest, ZigZag) {
+// avoid line-wrapping
+#define LL(x) static_cast<int64_t>(ULL(x))
+#define ULL(x) uint64_t{x##u}
+#define ZigZagEncode32(x) WireFormatLite::ZigZagEncode32(x)
+#define ZigZagDecode32(x) WireFormatLite::ZigZagDecode32(x)
+#define ZigZagEncode64(x) WireFormatLite::ZigZagEncode64(x)
+#define ZigZagDecode64(x) WireFormatLite::ZigZagDecode64(x)
+
+  EXPECT_EQ(0u, ZigZagEncode32(0));
+  EXPECT_EQ(1u, ZigZagEncode32(-1));
+  EXPECT_EQ(2u, ZigZagEncode32(1));
+  EXPECT_EQ(3u, ZigZagEncode32(-2));
+  EXPECT_EQ(0x7FFFFFFEu, ZigZagEncode32(0x3FFFFFFF));
+  EXPECT_EQ(0x7FFFFFFFu, ZigZagEncode32(0xC0000000));
+  EXPECT_EQ(0xFFFFFFFEu, ZigZagEncode32(0x7FFFFFFF));
+  EXPECT_EQ(0xFFFFFFFFu, ZigZagEncode32(0x80000000));
+
+  EXPECT_EQ(0, ZigZagDecode32(0u));
+  EXPECT_EQ(-1, ZigZagDecode32(1u));
+  EXPECT_EQ(1, ZigZagDecode32(2u));
+  EXPECT_EQ(-2, ZigZagDecode32(3u));
+  EXPECT_EQ(0x3FFFFFFF, ZigZagDecode32(0x7FFFFFFEu));
+  EXPECT_EQ(0xC0000000, ZigZagDecode32(0x7FFFFFFFu));
+  EXPECT_EQ(0x7FFFFFFF, ZigZagDecode32(0xFFFFFFFEu));
+  EXPECT_EQ(0x80000000, ZigZagDecode32(0xFFFFFFFFu));
+
+  EXPECT_EQ(0u, ZigZagEncode64(0));
+  EXPECT_EQ(1u, ZigZagEncode64(-1));
+  EXPECT_EQ(2u, ZigZagEncode64(1));
+  EXPECT_EQ(3u, ZigZagEncode64(-2));
+  EXPECT_EQ(ULL(0x000000007FFFFFFE), ZigZagEncode64(LL(0x000000003FFFFFFF)));
+  EXPECT_EQ(ULL(0x000000007FFFFFFF), ZigZagEncode64(LL(0xFFFFFFFFC0000000)));
+  EXPECT_EQ(ULL(0x00000000FFFFFFFE), ZigZagEncode64(LL(0x000000007FFFFFFF)));
+  EXPECT_EQ(ULL(0x00000000FFFFFFFF), ZigZagEncode64(LL(0xFFFFFFFF80000000)));
+  EXPECT_EQ(ULL(0xFFFFFFFFFFFFFFFE), ZigZagEncode64(LL(0x7FFFFFFFFFFFFFFF)));
+  EXPECT_EQ(ULL(0xFFFFFFFFFFFFFFFF), ZigZagEncode64(LL(0x8000000000000000)));
+
+  EXPECT_EQ(0, ZigZagDecode64(0u));
+  EXPECT_EQ(-1, ZigZagDecode64(1u));
+  EXPECT_EQ(1, ZigZagDecode64(2u));
+  EXPECT_EQ(-2, ZigZagDecode64(3u));
+  EXPECT_EQ(LL(0x000000003FFFFFFF), ZigZagDecode64(ULL(0x000000007FFFFFFE)));
+  EXPECT_EQ(LL(0xFFFFFFFFC0000000), ZigZagDecode64(ULL(0x000000007FFFFFFF)));
+  EXPECT_EQ(LL(0x000000007FFFFFFF), ZigZagDecode64(ULL(0x00000000FFFFFFFE)));
+  EXPECT_EQ(LL(0xFFFFFFFF80000000), ZigZagDecode64(ULL(0x00000000FFFFFFFF)));
+  EXPECT_EQ(LL(0x7FFFFFFFFFFFFFFF), ZigZagDecode64(ULL(0xFFFFFFFFFFFFFFFE)));
+  EXPECT_EQ(LL(0x8000000000000000), ZigZagDecode64(ULL(0xFFFFFFFFFFFFFFFF)));
+
+  // Some easier-to-verify round-trip tests.  The inputs (other than 0, 1, -1)
+  // were chosen semi-randomly via keyboard bashing.
+  EXPECT_EQ(0, ZigZagDecode32(ZigZagEncode32(0)));
+  EXPECT_EQ(1, ZigZagDecode32(ZigZagEncode32(1)));
+  EXPECT_EQ(-1, ZigZagDecode32(ZigZagEncode32(-1)));
+  EXPECT_EQ(14927, ZigZagDecode32(ZigZagEncode32(14927)));
+  EXPECT_EQ(-3612, ZigZagDecode32(ZigZagEncode32(-3612)));
+
+  EXPECT_EQ(0, ZigZagDecode64(ZigZagEncode64(0)));
+  EXPECT_EQ(1, ZigZagDecode64(ZigZagEncode64(1)));
+  EXPECT_EQ(-1, ZigZagDecode64(ZigZagEncode64(-1)));
+  EXPECT_EQ(14927, ZigZagDecode64(ZigZagEncode64(14927)));
+  EXPECT_EQ(-3612, ZigZagDecode64(ZigZagEncode64(-3612)));
+
+  EXPECT_EQ(LL(856912304801416),
+            ZigZagDecode64(ZigZagEncode64(LL(856912304801416))));
+  EXPECT_EQ(LL(-75123905439571256),
+            ZigZagDecode64(ZigZagEncode64(LL(-75123905439571256))));
+}
+
+TEST(WireFormatTest, RepeatedScalarsDifferentTagSizes) {
+  // At one point checks would trigger when parsing repeated fixed scalar
+  // fields.
+  UNITTEST::TestRepeatedScalarDifferentTagSizes msg1, msg2;
+  for (int i = 0; i < 100; ++i) {
+    msg1.add_repeated_fixed32(i);
+    msg1.add_repeated_int32(i);
+    msg1.add_repeated_fixed64(i);
+    msg1.add_repeated_int64(i);
+    msg1.add_repeated_float(i);
+    msg1.add_repeated_uint64(i);
+  }
+
+  // Make sure that we have a variety of tag sizes.
+  const Descriptor* desc = msg1.GetDescriptor();
+  const FieldDescriptor* field;
+  field = desc->FindFieldByName("repeated_fixed32");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_int32");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_fixed64");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_int64");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_float");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type()));
+  field = desc->FindFieldByName("repeated_uint64");
+  ASSERT_TRUE(field != nullptr);
+  ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type()));
+
+  EXPECT_TRUE(msg2.ParseFromString(msg1.SerializeAsString()));
+  EXPECT_EQ(msg1.DebugString(), msg2.DebugString());
+}
+
+TEST(WireFormatTest, CompatibleTypes) {
+  const int64 data = 0x100000000LL;
+  UNITTEST::Int64Message msg1;
+  msg1.set_data(data);
+  std::string serialized;
+  msg1.SerializeToString(&serialized);
+
+  // Test int64 is compatible with bool
+  UNITTEST::BoolMessage msg2;
+  ASSERT_TRUE(msg2.ParseFromString(serialized));
+  ASSERT_EQ(static_cast<bool>(data), msg2.data());
+
+  // Test int64 is compatible with uint64
+  UNITTEST::Uint64Message msg3;
+  ASSERT_TRUE(msg3.ParseFromString(serialized));
+  ASSERT_EQ(static_cast<uint64>(data), msg3.data());
+
+  // Test int64 is compatible with int32
+  UNITTEST::Int32Message msg4;
+  ASSERT_TRUE(msg4.ParseFromString(serialized));
+  ASSERT_EQ(static_cast<int32>(data), msg4.data());
+
+  // Test int64 is compatible with uint32
+  UNITTEST::Uint32Message msg5;
+  ASSERT_TRUE(msg5.ParseFromString(serialized));
+  ASSERT_EQ(static_cast<uint32>(data), msg5.data());
+}
+
+class Proto3PrimitiveRepeatedWireFormatTest : public ::testing::Test {
+ protected:
+  Proto3PrimitiveRepeatedWireFormatTest()
+      : packedTestAllTypes_(
+            "\xFA\x01\x01\x01"
+            "\x82\x02\x01\x01"
+            "\x8A\x02\x01\x01"
+            "\x92\x02\x01\x01"
+            "\x9A\x02\x01\x02"
+            "\xA2\x02\x01\x02"
+            "\xAA\x02\x04\x01\x00\x00\x00"
+            "\xB2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\xBA\x02\x04\x01\x00\x00\x00"
+            "\xC2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\xCA\x02\x04\x00\x00\x80\x3f"
+            "\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xf0\x3f"
+            "\xDA\x02\x01\x01"
+            "\x9A\x03\x01\x01",
+            86),
+        packedTestUnpackedTypes_(
+            "\x0A\x01\x01"
+            "\x12\x01\x01"
+            "\x1A\x01\x01"
+            "\x22\x01\x01"
+            "\x2A\x01\x02"
+            "\x32\x01\x02"
+            "\x3A\x04\x01\x00\x00\x00"
+            "\x42\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\x4A\x04\x01\x00\x00\x00"
+            "\x52\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\x5A\x04\x00\x00\x80\x3f"
+            "\x62\x08\x00\x00\x00\x00\x00\x00\xf0\x3f"
+            "\x6A\x01\x01"
+            "\x72\x01\x01",
+            72),
+        unpackedTestAllTypes_(
+            "\xF8\x01\x01"
+            "\x80\x02\x01"
+            "\x88\x02\x01"
+            "\x90\x02\x01"
+            "\x98\x02\x02"
+            "\xA0\x02\x02"
+            "\xAD\x02\x01\x00\x00\x00"
+            "\xB1\x02\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\xBD\x02\x01\x00\x00\x00"
+            "\xC1\x02\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\xCD\x02\x00\x00\x80\x3f"
+            "\xD1\x02\x00\x00\x00\x00\x00\x00\xf0\x3f"
+            "\xD8\x02\x01"
+            "\x98\x03\x01",
+            72),
+        unpackedTestUnpackedTypes_(
+            "\x08\x01"
+            "\x10\x01"
+            "\x18\x01"
+            "\x20\x01"
+            "\x28\x02"
+            "\x30\x02"
+            "\x3D\x01\x00\x00\x00"
+            "\x41\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\x4D\x01\x00\x00\x00"
+            "\x51\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\x5D\x00\x00\x80\x3f"
+            "\x61\x00\x00\x00\x00\x00\x00\xf0\x3f"
+            "\x68\x01"
+            "\x70\x01",
+            58) {}
+  template <class Proto>
+  void SetProto3PrimitiveRepeatedFields(Proto* message) {
+    message->add_repeated_int32(1);
+    message->add_repeated_int64(1);
+    message->add_repeated_uint32(1);
+    message->add_repeated_uint64(1);
+    message->add_repeated_sint32(1);
+    message->add_repeated_sint64(1);
+    message->add_repeated_fixed32(1);
+    message->add_repeated_fixed64(1);
+    message->add_repeated_sfixed32(1);
+    message->add_repeated_sfixed64(1);
+    message->add_repeated_float(1.0);
+    message->add_repeated_double(1.0);
+    message->add_repeated_bool(true);
+    message->add_repeated_nested_enum(PROTO3_ARENA_UNITTEST::TestAllTypes::FOO);
+  }
+
+  template <class Proto>
+  void ExpectProto3PrimitiveRepeatedFieldsSet(const Proto& message) {
+    EXPECT_EQ(1, message.repeated_int32(0));
+    EXPECT_EQ(1, message.repeated_int64(0));
+    EXPECT_EQ(1, message.repeated_uint32(0));
+    EXPECT_EQ(1, message.repeated_uint64(0));
+    EXPECT_EQ(1, message.repeated_sint32(0));
+    EXPECT_EQ(1, message.repeated_sint64(0));
+    EXPECT_EQ(1, message.repeated_fixed32(0));
+    EXPECT_EQ(1, message.repeated_fixed64(0));
+    EXPECT_EQ(1, message.repeated_sfixed32(0));
+    EXPECT_EQ(1, message.repeated_sfixed64(0));
+    EXPECT_EQ(1.0, message.repeated_float(0));
+    EXPECT_EQ(1.0, message.repeated_double(0));
+    EXPECT_EQ(true, message.repeated_bool(0));
+    EXPECT_EQ(PROTO3_ARENA_UNITTEST::TestAllTypes::FOO,
+              message.repeated_nested_enum(0));
+  }
+
+  template <class Proto>
+  void TestSerialization(Proto* message, const std::string& expected) {
+    SetProto3PrimitiveRepeatedFields(message);
+
+    size_t size = message->ByteSizeLong();
+
+    // Serialize using the generated code.
+    std::string generated_data;
+    {
+      io::StringOutputStream raw_output(&generated_data);
+      io::CodedOutputStream output(&raw_output);
+      message->SerializeWithCachedSizes(&output);
+      ASSERT_FALSE(output.HadError());
+    }
+    EXPECT_TRUE(TestUtil::EqualsToSerialized(*message, generated_data));
+
+    // Serialize using the dynamic code.
+    std::string dynamic_data;
+    {
+      io::StringOutputStream raw_output(&dynamic_data);
+      io::CodedOutputStream output(&raw_output);
+      WireFormat::SerializeWithCachedSizes(*message, size, &output);
+      ASSERT_FALSE(output.HadError());
+    }
+    EXPECT_TRUE(expected == dynamic_data);
+  }
+
+  template <class Proto>
+  void TestParsing(Proto* message, const std::string& compatible_data) {
+    message->Clear();
+    message->ParseFromString(compatible_data);
+    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
+
+    message->Clear();
+    io::CodedInputStream input(
+        reinterpret_cast<const uint8*>(compatible_data.data()),
+        compatible_data.size());
+    WireFormat::ParseAndMergePartial(&input, message);
+    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
+  }
+
+  const std::string packedTestAllTypes_;
+  const std::string packedTestUnpackedTypes_;
+  const std::string unpackedTestAllTypes_;
+  const std::string unpackedTestUnpackedTypes_;
+};
+
+TEST_F(Proto3PrimitiveRepeatedWireFormatTest, Proto3PrimitiveRepeated) {
+  PROTO3_ARENA_UNITTEST::TestAllTypes packed_message;
+  PROTO3_ARENA_UNITTEST::TestUnpackedTypes unpacked_message;
+  TestSerialization(&packed_message, packedTestAllTypes_);
+  TestParsing(&packed_message, packedTestAllTypes_);
+  TestParsing(&packed_message, unpackedTestAllTypes_);
+  TestSerialization(&unpacked_message, unpackedTestUnpackedTypes_);
+  TestParsing(&unpacked_message, packedTestUnpackedTypes_);
+  TestParsing(&unpacked_message, unpackedTestUnpackedTypes_);
+}
+
+class WireFormatInvalidInputTest : public testing::Test {
+ protected:
+  // Make a serialized TestAllTypes in which the field optional_nested_message
+  // contains exactly the given bytes, which may be invalid.
+  std::string MakeInvalidEmbeddedMessage(const char* bytes, int size) {
+    const FieldDescriptor* field =
+        UNITTEST::TestAllTypes::descriptor()->FindFieldByName(
+            "optional_nested_message");
+    GOOGLE_CHECK(field != nullptr);
+
+    std::string result;
+
+    {
+      io::StringOutputStream raw_output(&result);
+      io::CodedOutputStream output(&raw_output);
+
+      WireFormatLite::WriteBytes(field->number(), std::string(bytes, size),
+                                 &output);
+    }
+
+    return result;
+  }
+
+  // Make a serialized TestAllTypes in which the field optionalgroup
+  // contains exactly the given bytes -- which may be invalid -- and
+  // possibly no end tag.
+  std::string MakeInvalidGroup(const char* bytes, int size,
+                               bool include_end_tag) {
+    const FieldDescriptor* field =
+        UNITTEST::TestAllTypes::descriptor()->FindFieldByName("optionalgroup");
+    GOOGLE_CHECK(field != nullptr);
+
+    std::string result;
+
+    {
+      io::StringOutputStream raw_output(&result);
+      io::CodedOutputStream output(&raw_output);
+
+      output.WriteVarint32(WireFormat::MakeTag(field));
+      output.WriteString(std::string(bytes, size));
+      if (include_end_tag) {
+        output.WriteVarint32(WireFormatLite::MakeTag(
+            field->number(), WireFormatLite::WIRETYPE_END_GROUP));
+      }
+    }
+
+    return result;
+  }
+};
+
+TEST_F(WireFormatInvalidInputTest, InvalidSubMessage) {
+  UNITTEST::TestAllTypes message;
+
+  // Control case.
+  EXPECT_TRUE(message.ParseFromString(MakeInvalidEmbeddedMessage("", 0)));
+
+  // The byte is a valid varint, but not a valid tag (zero).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\0", 1)));
+
+  // The byte is a malformed varint.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\200", 1)));
+
+  // The byte is an endgroup tag, but we aren't parsing a group.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\014", 1)));
+
+  // The byte is a valid varint but not a valid tag (bad wire type).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidEmbeddedMessage("\017", 1)));
+}
+
+TEST_F(WireFormatInvalidInputTest, InvalidMessageWithExtraZero) {
+  std::string data;
+  {
+    // Serialize a valid proto
+    UNITTEST::TestAllTypes message;
+    message.set_optional_int32(1);
+    message.SerializeToString(&data);
+    data.push_back(0);  // Append invalid zero tag
+  }
+
+  // Control case.
+  {
+    io::ArrayInputStream ais(data.data(), data.size());
+    io::CodedInputStream is(&ais);
+    UNITTEST::TestAllTypes message;
+    // It should fail but currently passes.
+    EXPECT_TRUE(message.MergePartialFromCodedStream(&is));
+    // Parsing from the string should fail.
+    EXPECT_FALSE(message.ParseFromString(data));
+  }
+}
+
+TEST_F(WireFormatInvalidInputTest, InvalidGroup) {
+  UNITTEST::TestAllTypes message;
+
+  // Control case.
+  EXPECT_TRUE(message.ParseFromString(MakeInvalidGroup("", 0, true)));
+
+  // Missing end tag.  Groups cannot end at EOF.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("", 0, false)));
+
+  // The byte is a valid varint, but not a valid tag (zero).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\0", 1, false)));
+
+  // The byte is a malformed varint.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\200", 1, false)));
+
+  // The byte is an endgroup tag, but not the right one for this group.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\014", 1, false)));
+
+  // The byte is a valid varint but not a valid tag (bad wire type).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\017", 1, true)));
+}
+
+TEST_F(WireFormatInvalidInputTest, InvalidUnknownGroup) {
+  // Use TestEmptyMessage so that the group made by MakeInvalidGroup will not
+  // be a known tag number.
+  UNITTEST::TestEmptyMessage message;
+
+  // Control case.
+  EXPECT_TRUE(message.ParseFromString(MakeInvalidGroup("", 0, true)));
+
+  // Missing end tag.  Groups cannot end at EOF.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("", 0, false)));
+
+  // The byte is a valid varint, but not a valid tag (zero).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\0", 1, false)));
+
+  // The byte is a malformed varint.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\200", 1, false)));
+
+  // The byte is an endgroup tag, but not the right one for this group.
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\014", 1, false)));
+
+  // The byte is a valid varint but not a valid tag (bad wire type).
+  EXPECT_FALSE(message.ParseFromString(MakeInvalidGroup("\017", 1, true)));
+}
+
+TEST_F(WireFormatInvalidInputTest, InvalidStringInUnknownGroup) {
+  // Test a bug fix:  SkipMessage should fail if the message contains a
+  // string whose length would extend beyond the message end.
+
+  UNITTEST::TestAllTypes message;
+  message.set_optional_string("foo foo foo foo");
+  std::string data;
+  message.SerializeToString(&data);
+
+  // Chop some bytes off the end.
+  data.resize(data.size() - 4);
+
+  // Try to skip it.  Note that the bug was only present when parsing to an
+  // UnknownFieldSet.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream coded_input(&raw_input);
+  UnknownFieldSet unknown_fields;
+  EXPECT_FALSE(WireFormat::SkipMessage(&coded_input, &unknown_fields));
+}
+
+// Test differences between string and bytes.
+// Value of a string type must be valid UTF-8 string.  When UTF-8
+// validation is enabled (GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED):
+// WriteInvalidUTF8String:  see error message.
+// ReadInvalidUTF8String:  see error message.
+// WriteValidUTF8String: fine.
+// ReadValidUTF8String:  fine.
+// WriteAnyBytes: fine.
+// ReadAnyBytes: fine.
+const char* kInvalidUTF8String = "Invalid UTF-8: \xA0\xB0\xC0\xD0";
+// This used to be "Valid UTF-8: \x01\x02\u8C37\u6B4C", but MSVC seems to
+// interpret \u differently from GCC.
+const char* kValidUTF8String = "Valid UTF-8: \x01\x02\350\260\267\346\255\214";
+
+template <typename T>
+bool WriteMessage(const char* value, T* message, std::string* wire_buffer) {
+  message->set_data(value);
+  wire_buffer->clear();
+  message->AppendToString(wire_buffer);
+  return (wire_buffer->size() > 0);
+}
+
+template <typename T>
+bool ReadMessage(const std::string& wire_buffer, T* message) {
+  return message->ParseFromArray(wire_buffer.data(), wire_buffer.size());
+}
+
+class Utf8ValidationTest : public ::testing::Test {
+ protected:
+  Utf8ValidationTest() {}
+  virtual ~Utf8ValidationTest() {}
+  virtual void SetUp() {
+  }
+
+};
+
+TEST_F(Utf8ValidationTest, WriteInvalidUTF8String) {
+  std::string wire_buffer;
+  UNITTEST::OneString input;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
+    errors = log.GetMessages(ERROR);
+  }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  EXPECT_THAT(errors,
+              testing::ElementsAre(
+                  "String field '" + std::string(UNITTEST_PACKAGE_NAME) +
+                  ".OneString.data' "
+                  "contains invalid UTF-8 data when "
+                  "serializing a protocol buffer. Use the "
+                  "'bytes' type if you intend to send raw bytes. "));
+#else
+  ASSERT_EQ(0, errors.size());
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+}
+
+
+TEST_F(Utf8ValidationTest, ReadInvalidUTF8String) {
+  std::string wire_buffer;
+  UNITTEST::OneString input;
+  WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
+  UNITTEST::OneString output;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    ReadMessage(wire_buffer, &output);
+    errors = log.GetMessages(ERROR);
+  }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  EXPECT_THAT(errors,
+              testing::ElementsAre(
+                  "String field '" + std::string(UNITTEST_PACKAGE_NAME) +
+                  ".OneString.data' "
+                  "contains invalid UTF-8 data when "
+                  "parsing a protocol buffer. Use the "
+                  "'bytes' type if you intend to send raw bytes. "));
+
+#else
+  ASSERT_EQ(0, errors.size());
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+}
+
+
+TEST_F(Utf8ValidationTest, WriteValidUTF8String) {
+  std::string wire_buffer;
+  UNITTEST::OneString input;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    WriteMessage(kValidUTF8String, &input, &wire_buffer);
+    errors = log.GetMessages(ERROR);
+  }
+  ASSERT_EQ(0, errors.size());
+}
+
+TEST_F(Utf8ValidationTest, ReadValidUTF8String) {
+  std::string wire_buffer;
+  UNITTEST::OneString input;
+  WriteMessage(kValidUTF8String, &input, &wire_buffer);
+  UNITTEST::OneString output;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    ReadMessage(wire_buffer, &output);
+    errors = log.GetMessages(ERROR);
+  }
+  ASSERT_EQ(0, errors.size());
+  EXPECT_EQ(input.data(), output.data());
+}
+
+// Bytes: anything can pass as bytes, use invalid UTF-8 string to test
+TEST_F(Utf8ValidationTest, WriteArbitraryBytes) {
+  std::string wire_buffer;
+  UNITTEST::OneBytes input;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
+    errors = log.GetMessages(ERROR);
+  }
+  ASSERT_EQ(0, errors.size());
+}
+
+TEST_F(Utf8ValidationTest, ReadArbitraryBytes) {
+  std::string wire_buffer;
+  UNITTEST::OneBytes input;
+  WriteMessage(kInvalidUTF8String, &input, &wire_buffer);
+  UNITTEST::OneBytes output;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    ReadMessage(wire_buffer, &output);
+    errors = log.GetMessages(ERROR);
+  }
+  ASSERT_EQ(0, errors.size());
+  EXPECT_EQ(input.data(), output.data());
+}
+
+TEST_F(Utf8ValidationTest, ParseRepeatedString) {
+  UNITTEST::MoreBytes input;
+  input.add_data(kValidUTF8String);
+  input.add_data(kInvalidUTF8String);
+  input.add_data(kInvalidUTF8String);
+  std::string wire_buffer = input.SerializeAsString();
+
+  UNITTEST::MoreString output;
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    ReadMessage(wire_buffer, &output);
+    errors = log.GetMessages(ERROR);
+  }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  ASSERT_EQ(2, errors.size());
+#else
+  ASSERT_EQ(0, errors.size());
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  EXPECT_EQ(wire_buffer, output.SerializeAsString());
+}
+
+// Test the old VerifyUTF8String() function, which may still be called by old
+// generated code.
+TEST_F(Utf8ValidationTest, OldVerifyUTF8String) {
+  std::string data(kInvalidUTF8String);
+
+  std::vector<std::string> errors;
+  {
+    ScopedMemoryLog log;
+    WireFormat::VerifyUTF8String(data.data(), data.size(),
+                                 WireFormat::SERIALIZE);
+    errors = log.GetMessages(ERROR);
+  }
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  ASSERT_EQ(1, errors.size());
+  EXPECT_TRUE(
+      HasPrefixString(errors[0],
+                       "String field contains invalid UTF-8 data when "
+                       "serializing a protocol buffer. Use the "
+                       "'bytes' type if you intend to send raw bytes."));
+#else
+  ASSERT_EQ(0, errors.size());
+#endif
+}
+
+
+TEST(RepeatedVarint, Int32) {
+  RepeatedField<int32> v;
+
+  // Insert -2^n, 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(-(1 << n));
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar Int32Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::Int32Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::Int32Size(v));
+}
+
+TEST(RepeatedVarint, Int64) {
+  RepeatedField<int64> v;
+
+  // Insert -2^n, 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(-(1 << n));
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar Int64Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::Int64Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::Int64Size(v));
+}
+
+TEST(RepeatedVarint, SInt32) {
+  RepeatedField<int32> v;
+
+  // Insert -2^n, 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(-(1 << n));
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar SInt32Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::SInt32Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::SInt32Size(v));
+}
+
+TEST(RepeatedVarint, SInt64) {
+  RepeatedField<int64> v;
+
+  // Insert -2^n, 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(-(1 << n));
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar SInt64Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::SInt64Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::SInt64Size(v));
+}
+
+TEST(RepeatedVarint, UInt32) {
+  RepeatedField<uint32> v;
+
+  // Insert 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar UInt32Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::UInt32Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::UInt32Size(v));
+}
+
+TEST(RepeatedVarint, UInt64) {
+  RepeatedField<uint64> v;
+
+  // Insert 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar UInt64Size.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::UInt64Size(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::UInt64Size(v));
+}
+
+TEST(RepeatedVarint, Enum) {
+  RepeatedField<int> v;
+
+  // Insert 2^n and 2^n-1.
+  for (int n = 0; n < 10; n++) {
+    v.Add(1 << n);
+    v.Add((1 << n) - 1);
+  }
+
+  // Check consistency with the scalar EnumSize.
+  size_t expected = 0;
+  for (int i = 0; i < v.size(); i++) {
+    expected += WireFormatLite::EnumSize(v[i]);
+  }
+
+  EXPECT_EQ(expected, WireFormatLite::EnumSize(v));
+}
+
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 128ddfc..8bc8a00 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -136,66 +136,75 @@
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::DoubleValue, value_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FloatValue, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::FloatValue, value_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Int64Value, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Int64Value, value_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::UInt64Value, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::UInt64Value, value_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Int32Value, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::Int32Value, value_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::UInt32Value, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::UInt32Value, value_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::BoolValue, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::BoolValue, value_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::StringValue, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::StringValue, value_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::BytesValue, _internal_metadata_),
   ~0u,  // no _extensions_
   ~0u,  // no _oneof_case_
   ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(PROTOBUF_NAMESPACE_ID::BytesValue, value_),
 };
 static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, -1, sizeof(PROTOBUF_NAMESPACE_ID::DoubleValue)},
-  { 6, -1, sizeof(PROTOBUF_NAMESPACE_ID::FloatValue)},
-  { 12, -1, sizeof(PROTOBUF_NAMESPACE_ID::Int64Value)},
-  { 18, -1, sizeof(PROTOBUF_NAMESPACE_ID::UInt64Value)},
-  { 24, -1, sizeof(PROTOBUF_NAMESPACE_ID::Int32Value)},
-  { 30, -1, sizeof(PROTOBUF_NAMESPACE_ID::UInt32Value)},
-  { 36, -1, sizeof(PROTOBUF_NAMESPACE_ID::BoolValue)},
-  { 42, -1, sizeof(PROTOBUF_NAMESPACE_ID::StringValue)},
-  { 48, -1, sizeof(PROTOBUF_NAMESPACE_ID::BytesValue)},
+  { 0, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::DoubleValue)},
+  { 7, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::FloatValue)},
+  { 14, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Int64Value)},
+  { 21, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::UInt64Value)},
+  { 28, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::Int32Value)},
+  { 35, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::UInt32Value)},
+  { 42, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::BoolValue)},
+  { 49, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::StringValue)},
+  { 56, -1, -1, sizeof(PROTOBUF_NAMESPACE_ID::BytesValue)},
 };
 
 static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
@@ -307,28 +316,29 @@
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 9)) {
           value_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<double>(ptr);
           ptr += sizeof(double);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -365,13 +375,7 @@
     total_size += 1 + 8;
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DoubleValue::_class_data_ = {
@@ -380,8 +384,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DoubleValue::GetClassData() const { return &_class_data_; }
 
-void DoubleValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void DoubleValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<DoubleValue *>(to)->MergeFrom(
       static_cast<const DoubleValue &>(from));
 }
@@ -490,28 +494,29 @@
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 13)) {
           value_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<float>(ptr);
           ptr += sizeof(float);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -548,13 +553,7 @@
     total_size += 1 + 4;
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FloatValue::_class_data_ = {
@@ -563,8 +562,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FloatValue::GetClassData() const { return &_class_data_; }
 
-void FloatValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void FloatValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<FloatValue *>(to)->MergeFrom(
       static_cast<const FloatValue &>(from));
 }
@@ -673,28 +672,29 @@
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) {
           value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -728,18 +728,10 @@
 
   // int64 value = 1;
   if (this->_internal_value() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64Size(
-        this->_internal_value());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_value());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Int64Value::_class_data_ = {
@@ -748,8 +740,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Int64Value::GetClassData() const { return &_class_data_; }
 
-void Int64Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Int64Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Int64Value *>(to)->MergeFrom(
       static_cast<const Int64Value &>(from));
 }
@@ -858,28 +850,29 @@
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) {
           value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -913,18 +906,10 @@
 
   // uint64 value = 1;
   if (this->_internal_value() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64Size(
-        this->_internal_value());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64SizePlusOne(this->_internal_value());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UInt64Value::_class_data_ = {
@@ -933,8 +918,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UInt64Value::GetClassData() const { return &_class_data_; }
 
-void UInt64Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void UInt64Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<UInt64Value *>(to)->MergeFrom(
       static_cast<const UInt64Value &>(from));
 }
@@ -1043,28 +1028,29 @@
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) {
           value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1098,18 +1084,10 @@
 
   // int32 value = 1;
   if (this->_internal_value() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-        this->_internal_value());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_value());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Int32Value::_class_data_ = {
@@ -1118,8 +1096,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Int32Value::GetClassData() const { return &_class_data_; }
 
-void Int32Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void Int32Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<Int32Value *>(to)->MergeFrom(
       static_cast<const Int32Value &>(from));
 }
@@ -1228,28 +1206,29 @@
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) {
           value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1283,18 +1262,10 @@
 
   // uint32 value = 1;
   if (this->_internal_value() != 0) {
-    total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32Size(
-        this->_internal_value());
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32SizePlusOne(this->_internal_value());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UInt32Value::_class_data_ = {
@@ -1303,8 +1274,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UInt32Value::GetClassData() const { return &_class_data_; }
 
-void UInt32Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void UInt32Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<UInt32Value *>(to)->MergeFrom(
       static_cast<const UInt32Value &>(from));
 }
@@ -1413,28 +1384,29 @@
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 8)) {
           value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1471,13 +1443,7 @@
     total_size += 1 + 1;
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData BoolValue::_class_data_ = {
@@ -1486,8 +1452,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*BoolValue::GetClassData() const { return &_class_data_; }
 
-void BoolValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void BoolValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<BoolValue *>(to)->MergeFrom(
       static_cast<const BoolValue &>(from));
 }
@@ -1603,28 +1569,29 @@
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.StringValue.value"));
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1667,13 +1634,7 @@
         this->_internal_value());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData StringValue::_class_data_ = {
@@ -1682,8 +1643,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*StringValue::GetClassData() const { return &_class_data_; }
 
-void StringValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void StringValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<StringValue *>(to)->MergeFrom(
       static_cast<const StringValue &>(from));
 }
@@ -1714,11 +1675,13 @@
 
 void StringValue::InternalSwap(StringValue* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &value_, GetArenaForAllocation(),
-      &other->value_, other->GetArenaForAllocation()
+      &value_, lhs_arena,
+      &other->value_, rhs_arena
   );
 }
 
@@ -1802,28 +1765,29 @@
           auto str = _internal_mutable_value();
           ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
-        } else goto handle_unusual;
+        } else
+          goto handle_unusual;
         continue;
-      default: {
-      handle_unusual:
-        if ((tag == 0) || ((tag & 7) == 4)) {
-          CHK_(ptr);
-          ctx->SetLastTag(tag);
-          goto success;
-        }
-        ptr = UnknownFieldParse(tag,
-            _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
-            ptr, ctx);
-        CHK_(ptr != nullptr);
-        continue;
-      }
+      default:
+        goto handle_unusual;
     }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
   }  // while
-success:
+message_done:
   return ptr;
 failure:
   ptr = nullptr;
-  goto success;
+  goto message_done;
 #undef CHK_
 }
 
@@ -1862,13 +1826,7 @@
         this->_internal_value());
   }
 
-  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
-        _internal_metadata_, total_size, &_cached_size_);
-  }
-  int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
-  SetCachedSize(cached_size);
-  return total_size;
+  return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
 }
 
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData BytesValue::_class_data_ = {
@@ -1877,8 +1835,8 @@
 };
 const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*BytesValue::GetClassData() const { return &_class_data_; }
 
-void BytesValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to,
-                      const ::PROTOBUF_NAMESPACE_ID::Message&from) {
+void BytesValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to,
+                      const ::PROTOBUF_NAMESPACE_ID::Message& from) {
   static_cast<BytesValue *>(to)->MergeFrom(
       static_cast<const BytesValue &>(from));
 }
@@ -1909,11 +1867,13 @@
 
 void BytesValue::InternalSwap(BytesValue* other) {
   using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
   _internal_metadata_.InternalSwap(&other->_internal_metadata_);
   ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
       &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
-      &value_, GetArenaForAllocation(),
-      &other->value_, other->GetArenaForAllocation()
+      &value_, lhs_arena,
+      &other->value_, rhs_arena
   );
 }
 
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 1be7ae0..defdf68 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -174,7 +174,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const DoubleValue& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -313,7 +313,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const FloatValue& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -452,7 +452,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Int64Value& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -591,7 +591,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const UInt64Value& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -730,7 +730,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const Int32Value& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -869,7 +869,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const UInt32Value& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -1008,7 +1008,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const BoolValue& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -1147,7 +1147,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const StringValue& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
@@ -1291,7 +1291,7 @@
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   void MergeFrom(const BytesValue& from);
   private:
-  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message*to, const ::PROTOBUF_NAMESPACE_ID::Message&from);
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
   public:
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;